table: enforce NameTree max depth universally

refs #4262

Change-Id: Ia9b04a89c12cd09aa244201b513cc1808c0c473f
This commit is contained in:
Junxiao Shi
2018-03-20 17:14:18 +00:00
parent 7003e0bc66
commit 057d149fda
9 changed files with 130 additions and 113 deletions
+2 -6
View File
@@ -85,19 +85,15 @@ public: // lookup
public: // mutation
/** \brief Maximum number of components in a FIB entry prefix.
*
* This constant is currently advisory, but will become mandatory later.
*/
static constexpr size_t
getMaxDepth()
{
static_assert(FIB_MAX_DEPTH == NameTree::getMaxDepth(), "");
return FIB_MAX_DEPTH;
}
/** \brief inserts a FIB entry for prefix
*
* If an entry for exact same prefix exists, that entry is returned.
/** \brief find or insert a FIB entry
* \param prefix FIB entry name; it must have no more than \c getMaxDepth() components.
* \return the entry, and true for new entry or false for existing entry
*/
std::pair<Entry*, bool>
+4 -6
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2017, Regents of the University of California,
* Copyright (c) 2014-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -40,8 +40,6 @@ Measurements::Measurements(NameTree& nameTree)
Entry&
Measurements::get(name_tree::Entry& nte)
{
BOOST_ASSERT(nte.getName().size() <= NameTree::getMaxDepth());
Entry* entry = nte.getMeasurementsEntry();
if (entry != nullptr) {
return *entry;
@@ -61,21 +59,21 @@ Measurements::get(name_tree::Entry& nte)
Entry&
Measurements::get(const Name& name)
{
name_tree::Entry& nte = m_nameTree.lookup(name, true);
name_tree::Entry& nte = m_nameTree.lookup(name, std::min(name.size(), getMaxDepth()));
return this->get(nte);
}
Entry&
Measurements::get(const fib::Entry& fibEntry)
{
name_tree::Entry& nte = m_nameTree.lookup(fibEntry.getPrefix(), true);
name_tree::Entry& nte = m_nameTree.lookup(fibEntry);
return this->get(nte);
}
Entry&
Measurements::get(const pit::Entry& pitEntry)
{
name_tree::Entry& nte = m_nameTree.lookup(pitEntry.getName(), true);
name_tree::Entry& nte = m_nameTree.lookup(pitEntry);
return this->get(nte);
}
+30 -13
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2016, Regents of the University of California,
/*
* Copyright (c) 2014-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -45,7 +45,7 @@ namespace measurements {
*/
typedef std::function<bool(const Entry&)> EntryPredicate;
/** \brief an \p EntryPredicate that accepts any entry
/** \brief an \c EntryPredicate that accepts any entry
*/
class AnyEntry
{
@@ -57,7 +57,7 @@ public:
}
};
/** \brief an \p EntryPredicate that accepts an entry if it has StrategyInfo of type T
/** \brief an \c EntryPredicate that accepts an entry if it has StrategyInfo of type T
*/
template<typename T>
class EntryWithStrategyInfo
@@ -70,31 +70,48 @@ public:
}
};
/** \brief represents the Measurements table
/** \brief the Measurements table
*
* The Measurements table is a data structure for forwarding strategies to store per name prefix
* measurements. A strategy can access this table via \c Strategy::getMeasurements(), and then
* place any object that derive from \c StrategyInfo type onto Measurements entries.
*/
class Measurements : noncopyable
{
public:
explicit
Measurements(NameTree& nametree);
Measurements(NameTree& nameTree);
/** \brief find or insert a Measurements entry for \p name
/** \brief maximum depth of a Measurements entry
*/
static constexpr size_t
getMaxDepth()
{
return NameTree::getMaxDepth();
}
/** \brief find or insert an entry by name
*
* An entry name can have at most \c getMaxDepth() components. If \p name exceeds this limit,
* it is truncated to the first \c getMaxDepth() components.
*/
Entry&
get(const Name& name);
/** \brief find or insert a Measurements entry for \p fibEntry.getPrefix()
/** \brief equivalent to `get(fibEntry.getPrefix())`
*/
Entry&
get(const fib::Entry& fibEntry);
/** \brief find or insert a Measurements entry for \p pitEntry.getName()
/** \brief equivalent to
* `get(pitEntry.getName(), std::min(pitEntry.getName().size(), getMaxDepth()))`
*/
Entry&
get(const pit::Entry& pitEntry);
/** \brief find or insert a Measurements entry for child's parent
* \retval nullptr if child is the root entry
/** \brief find or insert a parent entry
* \retval nullptr child is the root entry
* \return get(child.getName().getPrefix(-1))
*/
Entry*
getParent(const Entry& child);
@@ -105,7 +122,7 @@ public:
findLongestPrefixMatch(const Name& name,
const EntryPredicate& pred = AnyEntry()) const;
/** \brief perform a longest prefix match for \p pitEntry.getName()
/** \brief perform a longest prefix match for `pitEntry.getName()`
*/
Entry*
findLongestPrefixMatch(const pit::Entry& pitEntry,
@@ -136,7 +153,7 @@ private:
Entry&
get(name_tree::Entry& nte);
/** \tparam K a parameter acceptable to NameTree::findLongestPrefixMatch
/** \tparam K a parameter acceptable to \c NameTree::findLongestPrefixMatch
*/
template<typename K>
Entry*
+4 -2
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2016, Regents of the University of California,
/*
* Copyright (c) 2014-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -24,6 +24,7 @@
*/
#include "name-tree-entry.hpp"
#include "name-tree.hpp"
namespace nfd {
namespace name_tree {
@@ -34,6 +35,7 @@ Entry::Entry(const Name& name, Node* node)
, m_parent(nullptr)
{
BOOST_ASSERT(node != nullptr);
BOOST_ASSERT(name.size() <= NameTree::getMaxDepth());
}
void
+34 -25
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2017, Regents of the University of California,
* Copyright (c) 2014-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -41,18 +41,19 @@ NameTree::NameTree(size_t nBuckets)
}
Entry&
NameTree::lookup(const Name& name, bool enforceMaxDepth)
NameTree::lookup(const Name& name, size_t prefixLen)
{
NFD_LOG_TRACE("lookup " << name);
size_t depth = enforceMaxDepth ? std::min(name.size(), getMaxDepth()) : name.size();
NFD_LOG_TRACE("lookup(" << name << ", " << prefixLen << ')');
BOOST_ASSERT(prefixLen <= name.size());
BOOST_ASSERT(prefixLen <= getMaxDepth());
HashSequence hashes = computeHashes(name, depth);
HashSequence hashes = computeHashes(name, prefixLen);
const Node* node = nullptr;
Entry* parent = nullptr;
for (size_t prefixLen = 0; prefixLen <= depth; ++prefixLen) {
for (size_t i = 0; i <= prefixLen; ++i) {
bool isNew = false;
std::tie(node, isNew) = m_ht.insert(name, prefixLen, hashes);
std::tie(node, isNew) = m_ht.insert(name, i, hashes);
if (isNew && parent != nullptr) {
node->entry.setParent(*parent);
@@ -65,6 +66,7 @@ NameTree::lookup(const Name& name, bool enforceMaxDepth)
Entry&
NameTree::lookup(const fib::Entry& fibEntry)
{
NFD_LOG_TRACE("lookup(FIB " << fibEntry.getPrefix() << ')');
Entry* nte = this->getEntry(fibEntry);
if (nte == nullptr) {
// special case: Fib::s_emptyEntry is unattached
@@ -79,28 +81,26 @@ NameTree::lookup(const fib::Entry& fibEntry)
Entry&
NameTree::lookup(const pit::Entry& pitEntry)
{
const Name& name = pitEntry.getName();
NFD_LOG_TRACE("lookup(PIT " << name << ')');
bool hasDigest = name.size() > 0 && name[-1].isImplicitSha256Digest();
if (hasDigest && name.size() <= getMaxDepth()) {
return this->lookup(name);
}
Entry* nte = this->getEntry(pitEntry);
BOOST_ASSERT(nte != nullptr);
BOOST_ASSERT(std::count_if(nte->getPitEntries().begin(), nte->getPitEntries().end(),
[&pitEntry] (const shared_ptr<pit::Entry>& pitEntry1) {
return pitEntry1.get() == &pitEntry;
}) == 1);
if (nte->getName().size() == pitEntry.getName().size()) {
return *nte;
}
// special case: PIT entry whose Interest name ends with an implicit digest
// are attached to the name tree entry with one-shorter-prefix.
BOOST_ASSERT(pitEntry.getName().at(-1).isImplicitSha256Digest());
BOOST_ASSERT(nte->getName() == pitEntry.getName().getPrefix(-1));
return this->lookup(pitEntry.getName());
return *nte;
}
Entry&
NameTree::lookup(const measurements::Entry& measurementsEntry)
{
NFD_LOG_TRACE("lookup(M " << measurementsEntry.getName() << ')');
Entry* nte = this->getEntry(measurementsEntry);
BOOST_ASSERT(nte != nullptr);
@@ -111,6 +111,7 @@ NameTree::lookup(const measurements::Entry& measurementsEntry)
Entry&
NameTree::lookup(const strategy_choice::Entry& strategyChoiceEntry)
{
NFD_LOG_TRACE("lookup(SC " << strategyChoiceEntry.getPrefix() << ')');
Entry* nte = this->getEntry(strategyChoiceEntry);
BOOST_ASSERT(nte != nullptr);
@@ -148,17 +149,23 @@ NameTree::eraseIfEmpty(Entry* entry, bool canEraseAncestors)
Entry*
NameTree::findExactMatch(const Name& name, size_t prefixLen) const
{
const Node* node = m_ht.find(name, std::min(name.size(), prefixLen));
prefixLen = std::min(name.size(), prefixLen);
if (prefixLen > getMaxDepth()) {
return nullptr;
}
const Node* node = m_ht.find(name, prefixLen);
return node == nullptr ? nullptr : &node->entry;
}
Entry*
NameTree::findLongestPrefixMatch(const Name& name, const EntrySelector& entrySelector) const
{
HashSequence hashes = computeHashes(name);
size_t depth = std::min(name.size(), getMaxDepth());
HashSequence hashes = computeHashes(name, depth);
for (ssize_t prefixLen = name.size(); prefixLen >= 0; --prefixLen) {
const Node* node = m_ht.find(name, prefixLen, hashes);
for (ssize_t i = depth; i >= 0; --i) {
const Node* node = m_ht.find(name, i, hashes);
if (node != nullptr && entrySelector(node->entry)) {
return &node->entry;
}
@@ -186,10 +193,12 @@ NameTree::findLongestPrefixMatch(const pit::Entry& pitEntry, const EntrySelector
const Entry* nte = this->getEntry(pitEntry);
BOOST_ASSERT(nte != nullptr);
// PIT entry Interest name either exceeds depth limit or ends with an implicit digest: go deeper
const Name& name = pitEntry.getName();
size_t depth = std::min(name.size(), getMaxDepth());
if (nte->getName().size() < pitEntry.getName().size()) {
for (size_t prefixLen = nte->getName().size() + 1; prefixLen <= pitEntry.getName().size(); ++prefixLen) {
const Entry* exact = this->findExactMatch(pitEntry.getName(), prefixLen);
// PIT entry name either exceeds depth limit or ends with an implicit digest: go deeper
for (size_t i = nte->getName().size() + 1; i <= depth; ++i) {
const Entry* exact = this->findExactMatch(name, i);
if (exact == nullptr) {
break;
}
+43 -33
View File
@@ -28,6 +28,8 @@
#include "name-tree-iterator.hpp"
#include "core/fib-max-depth.hpp"
namespace nfd {
namespace name_tree {
@@ -40,20 +42,17 @@ public:
NameTree(size_t nBuckets = 1024);
public: // information
/** \brief Maximum depth of the name tree.
/** \brief maximum depth of the name tree
*
* Calling NameTree::lookup with a name with many components would cause the creation of many
* Calling \c NameTree::lookup with a name with many components would cause the creation of many
* NameTree entries, which could take very long time. This constant limits the maximum number of
* name components in the name of a NameTree entry. Thus, it limits the number of NameTree
* entries created from a long name, bounding the processing complexity.
*
* This constant is currently advisory. It is enforced in NameTree::lookup only if
* \p enforceMaxDepth is set to true. This will become mandatory later.
*/
static constexpr size_t
getMaxDepth()
{
return 32;
return FIB_MAX_DEPTH;
}
/** \return number of name tree entries
@@ -83,40 +82,51 @@ public: // information
}
public: // mutation
/** \brief find or insert an entry with specified name
* \param name a name prefix
* \param enforceMaxDepth if true, use \p name.getPrefix(getMaxDepth()) in place of \p name
* \return an entry with \p name
* \post an entry with \p name and all ancestors are created
* \note Existing iterators are unaffected.
/** \brief find or insert an entry by name
*
* This method seeks a name tree entry of name \c name.getPrefix(prefixLen).
* If the entry does not exist, it is created along with all ancestors.
* Existing iterators are unaffected during this operation.
*
* \warning \p prefixLen must not exceed \c name.size().
* \warning \p prefixLen must not exceed \c getMaxDepth().
*/
Entry&
lookup(const Name& name, bool enforceMaxDepth = false);
lookup(const Name& name, size_t prefixLen);
/** \brief equivalent to .lookup(fibEntry.getPrefix())
* \param fibEntry a FIB entry attached to this name tree, or Fib::s_emptyEntry
* \note This overload is more efficient than .lookup(const Name&) in common cases.
/** \brief equivalent to `lookup(name, name.size())`
*/
Entry&
lookup(const Name& name)
{
return this->lookup(name, name.size());
}
/** \brief equivalent to `lookup(fibEntry.getPrefix())`
* \param fibEntry a FIB entry attached to this name tree, or \c Fib::s_emptyEntry
* \note This overload is more efficient than `lookup(const Name&)` in common cases.
*/
Entry&
lookup(const fib::Entry& fibEntry);
/** \brief equivalent to .lookup(pitEntry.getName()).
/** \brief equivalent to
* `lookup(pitEntry.getName(), std::min(pitEntry.getName().size(), getMaxDepth()))`
* \param pitEntry a PIT entry attached to this name tree
* \note This overload is more efficient than .lookup(const Name&) in common cases.
* \note This overload is more efficient than `lookup(const Name&)` in common cases.
*/
Entry&
lookup(const pit::Entry& pitEntry);
/** \brief equivalent to .lookup(measurementsEntry.getName())
/** \brief equivalent to `lookup(measurementsEntry.getName())`
* \param measurementsEntry a Measurements entry attached to this name tree
* \note This overload is more efficient than .lookup(const Name&) in common cases.
* \note This overload is more efficient than `lookup(const Name&)` in common cases.
*/
Entry&
lookup(const measurements::Entry& measurementsEntry);
/** \brief equivalent to .lookup(strategyChoiceEntry.getPrefix())
/** \brief equivalent to `lookup(strategyChoiceEntry.getPrefix())`
* \param strategyChoiceEntry a StrategyChoice entry attached to this name tree
* \note This overload is more efficient than .lookup(const Name&) in common cases.
* \note This overload is more efficient than `lookup(const Name&)` in common cases.
*/
Entry&
lookup(const strategy_choice::Entry& strategyChoiceEntry);
@@ -126,7 +136,7 @@ public: // mutation
* \param canEraseAncestors whether ancestors should be deleted if they become empty
* \return number of deleted entries
* \sa Entry::isEmpty()
* \post If the entry is empty, it's deleted. If canEraseAncestors is true,
* \post If the entry is empty, it's deleted. If \p canEraseAncestors is true,
* ancestors of the entry are also deleted if they become empty.
* \note This function must be called after detaching a table entry from a name tree entry,
* \note Existing iterators, except those pointing to deleted entries, are unaffected.
@@ -136,7 +146,7 @@ public: // mutation
public: // matching
/** \brief exact match lookup
* \return entry with \p name.getPrefix(prefixLen), or nullptr if it does not exist
* \return entry with \c name.getPrefix(prefixLen), or nullptr if it does not exist
*/
Entry*
findExactMatch(const Name& name, size_t prefixLen = std::numeric_limits<size_t>::max()) const;
@@ -150,19 +160,19 @@ public: // matching
findLongestPrefixMatch(const Name& name,
const EntrySelector& entrySelector = AnyEntry()) const;
/** \brief equivalent to .findLongestPrefixMatch(entry.getName(), entrySelector)
/** \brief equivalent to `findLongestPrefixMatch(entry.getName(), entrySelector)`
* \note This overload is more efficient than
* .findLongestPrefixMatch(const Name&, const EntrySelector&) in common cases.
* `findLongestPrefixMatch(const Name&, const EntrySelector&)` in common cases.
*/
Entry*
findLongestPrefixMatch(const Entry& entry,
const EntrySelector& entrySelector = AnyEntry()) const;
/** \brief equivalent to .findLongestPrefixMatch(getEntry(tableEntry)->getName(), entrySelector)
* \tparam EntryT fib::Entry or measurements::Entry or strategy_choice::Entry
/** \brief equivalent to `findLongestPrefixMatch(getEntry(tableEntry)->getName(), entrySelector)`
* \tparam EntryT \c fib::Entry or \c measurements::Entry or \c strategy_choice::Entry
* \note This overload is more efficient than
* .findLongestPrefixMatch(const Name&, const EntrySelector&) in common cases.
* \warning Undefined behavior may occur if tableEntry is not attached to this name tree.
* `findLongestPrefixMatch(const Name&, const EntrySelector&)` in common cases.
* \warning Undefined behavior may occur if \p tableEntry is not attached to this name tree.
*/
template<typename EntryT>
Entry*
@@ -174,10 +184,10 @@ public: // matching
return this->findLongestPrefixMatch(*nte, entrySelector);
}
/** \brief equivalent to .findLongestPrefixMatch(pitEntry.getName(), entrySelector)
/** \brief equivalent to `findLongestPrefixMatch(pitEntry.getName(), entrySelector)`
* \note This overload is more efficient than
* .findLongestPrefixMatch(const Name&, const EntrySelector&) in common cases.
* \warning Undefined behavior may occur if pitEntry is not attached to this name tree.
* `findLongestPrefixMatch(const Name&, const EntrySelector&)` in common cases.
* \warning Undefined behavior may occur if \p pitEntry is not attached to this name tree.
*/
Entry*
findLongestPrefixMatch(const pit::Entry& pitEntry,
+10 -11
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2017, Regents of the University of California,
* Copyright (c) 2014-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -45,29 +45,28 @@ Pit::findOrInsert(const Interest& interest, bool allowInsert)
{
// determine which NameTree entry should the PIT entry be attached onto
const Name& name = interest.getName();
bool isEndWithDigest = name.size() > 0 && name[-1].isImplicitSha256Digest();
const Name& nteName = isEndWithDigest ? name.getPrefix(-1) : name;
bool hasDigest = name.size() > 0 && name[-1].isImplicitSha256Digest();
size_t nteDepth = name.size() - static_cast<int>(hasDigest);
nteDepth = std::min(nteDepth, NameTree::getMaxDepth());
// ensure NameTree entry exists
name_tree::Entry* nte = nullptr;
if (allowInsert) {
nte = &m_nameTree.lookup(nteName, true);
nte = &m_nameTree.lookup(name, nteDepth);
}
else {
nte = m_nameTree.findExactMatch(nteName);
nte = m_nameTree.findExactMatch(name, nteDepth);
if (nte == nullptr) {
return {nullptr, true};
}
}
// check if PIT entry already exists
size_t nteNameLen = nte->getName().size();
const std::vector<shared_ptr<Entry>>& pitEntries = nte->getPitEntries();
const auto& pitEntries = nte->getPitEntries();
auto it = std::find_if(pitEntries.begin(), pitEntries.end(),
[&interest, nteNameLen] (const shared_ptr<Entry>& entry) {
// initial part of name is guaranteed to be equal by NameTree
// check implicit digest (or its absence) only
return entry->canMatch(interest, nteNameLen);
[&interest, nteDepth] (const shared_ptr<Entry>& entry) {
// NameTree guarantees first nteDepth components are equal
return entry->canMatch(interest, nteDepth);
});
if (it != pitEntries.end()) {
return {*it, false};
+2 -2
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2017, Regents of the University of California,
* Copyright (c) 2014-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -87,7 +87,7 @@ StrategyChoice::insert(const Name& prefix, const Name& strategyName)
return InsertResult::NOT_REGISTERED;
}
name_tree::Entry& nte = m_nameTree.lookup(prefix, true);
name_tree::Entry& nte = m_nameTree.lookup(prefix);
Entry* entry = nte.getStrategyChoiceEntry();
Strategy* oldStrategy = nullptr;
if (entry != nullptr) {
+1 -15
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2017, Regents of the University of California,
* Copyright (c) 2014-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -417,20 +417,6 @@ BOOST_AUTO_TEST_CASE(Basic)
BOOST_CHECK_EQUAL(nt.size(), 8);
}
BOOST_AUTO_TEST_CASE(LongName)
{
Name name;
for (int i = 0; i < 2000; ++i) {
name.append("X");
}
NameTree nt;
Entry& entry1 = nt.lookup(name, true);
BOOST_CHECK_EQUAL(entry1.getName().size(), NameTree::getMaxDepth());
BOOST_CHECK_EQUAL(nt.size(), NameTree::getMaxDepth() + 1);
}
/** \brief verify a NameTree enumeration contains expected entries
*
* Example: