diff --git a/daemon/table/fib.hpp b/daemon/table/fib.hpp index ac864e8f..4b94c211 100644 --- a/daemon/table/fib.hpp +++ b/daemon/table/fib.hpp @@ -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 diff --git a/daemon/table/measurements.cpp b/daemon/table/measurements.cpp index 2ed0f65a..4d84746c 100644 --- a/daemon/table/measurements.cpp +++ b/daemon/table/measurements.cpp @@ -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); } diff --git a/daemon/table/measurements.hpp b/daemon/table/measurements.hpp index 80c938a1..d110ed62 100644 --- a/daemon/table/measurements.hpp +++ b/daemon/table/measurements.hpp @@ -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 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 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 Entry* diff --git a/daemon/table/name-tree-entry.cpp b/daemon/table/name-tree-entry.cpp index 8d33a89c..889d84f1 100644 --- a/daemon/table/name-tree-entry.cpp +++ b/daemon/table/name-tree-entry.cpp @@ -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 diff --git a/daemon/table/name-tree.cpp b/daemon/table/name-tree.cpp index 1fa54af9..02553cb6 100644 --- a/daemon/table/name-tree.cpp +++ b/daemon/table/name-tree.cpp @@ -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& 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; } diff --git a/daemon/table/name-tree.hpp b/daemon/table/name-tree.hpp index 805be566..4ecca809 100644 --- a/daemon/table/name-tree.hpp +++ b/daemon/table/name-tree.hpp @@ -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::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 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, diff --git a/daemon/table/pit.cpp b/daemon/table/pit.cpp index 2050417c..7a708da4 100644 --- a/daemon/table/pit.cpp +++ b/daemon/table/pit.cpp @@ -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(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>& pitEntries = nte->getPitEntries(); + const auto& pitEntries = nte->getPitEntries(); auto it = std::find_if(pitEntries.begin(), pitEntries.end(), - [&interest, nteNameLen] (const shared_ptr& 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) { + // NameTree guarantees first nteDepth components are equal + return entry->canMatch(interest, nteDepth); }); if (it != pitEntries.end()) { return {*it, false}; diff --git a/daemon/table/strategy-choice.cpp b/daemon/table/strategy-choice.cpp index 55db0958..7d25b4bd 100644 --- a/daemon/table/strategy-choice.cpp +++ b/daemon/table/strategy-choice.cpp @@ -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) { diff --git a/tests/daemon/table/name-tree.t.cpp b/tests/daemon/table/name-tree.t.cpp index 8b7307ab..458d7e3d 100644 --- a/tests/daemon/table/name-tree.t.cpp +++ b/tests/daemon/table/name-tree.t.cpp @@ -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: