blob: 1758532ff2ba7e9788c53e1c168b442596d27c2a [file] [log] [blame]
HYuana9b85752014-02-26 02:32:30 -06001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesaventoc0a5a392017-08-19 16:49:30 -04002/*
Davide Pesaventoe422f9e2022-06-03 01:30:23 -04003 * Copyright (c) 2014-2022, Regents of the University of California,
Alexander Afanasyev319f2c82015-01-07 14:56:53 -08004 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis.
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -070010 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
Junxiao Shi2b73ca32014-11-17 19:16:08 -070024 */
HYuana9b85752014-02-26 02:32:30 -060025
26#include "name-tree.hpp"
Davide Pesavento2cae8ca2019-04-18 20:48:05 -040027#include "common/logger.hpp"
Davide Pesavento52a18f92014-04-10 00:55:01 +020028
Alexander Afanasyev09fc3d92015-01-03 02:02:37 -080029#include <boost/concept/assert.hpp>
30#include <boost/concept_check.hpp>
31#include <type_traits>
32
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040033namespace nfd::name_tree {
HYuana9b85752014-02-26 02:32:30 -060034
Davide Pesaventoa3148082018-04-12 18:21:54 -040035NFD_LOG_INIT(NameTree);
HYuana9b85752014-02-26 02:32:30 -060036
HYuana9b85752014-02-26 02:32:30 -060037NameTree::NameTree(size_t nBuckets)
Junxiao Shib660b4c2016-08-06 20:47:44 +000038 : m_ht(HashtableOptions(nBuckets))
HYuana9b85752014-02-26 02:32:30 -060039{
HYuana9b85752014-02-26 02:32:30 -060040}
41
Junxiao Shi7f358432016-08-11 17:06:33 +000042Entry&
Junxiao Shi057d1492018-03-20 17:14:18 +000043NameTree::lookup(const Name& name, size_t prefixLen)
HYuana9b85752014-02-26 02:32:30 -060044{
Junxiao Shi057d1492018-03-20 17:14:18 +000045 NFD_LOG_TRACE("lookup(" << name << ", " << prefixLen << ')');
46 BOOST_ASSERT(prefixLen <= name.size());
47 BOOST_ASSERT(prefixLen <= getMaxDepth());
HYuana9b85752014-02-26 02:32:30 -060048
Junxiao Shi057d1492018-03-20 17:14:18 +000049 HashSequence hashes = computeHashes(name, prefixLen);
Junxiao Shib660b4c2016-08-06 20:47:44 +000050 const Node* node = nullptr;
51 Entry* parent = nullptr;
HYuana9b85752014-02-26 02:32:30 -060052
Junxiao Shi057d1492018-03-20 17:14:18 +000053 for (size_t i = 0; i <= prefixLen; ++i) {
Junxiao Shi2570f3e2016-07-27 02:48:29 +000054 bool isNew = false;
Junxiao Shi057d1492018-03-20 17:14:18 +000055 std::tie(node, isNew) = m_ht.insert(name, i, hashes);
HYuana9b85752014-02-26 02:32:30 -060056
Junxiao Shib660b4c2016-08-06 20:47:44 +000057 if (isNew && parent != nullptr) {
Junxiao Shi340d5532016-08-13 04:00:35 +000058 node->entry.setParent(*parent);
HYuana9b85752014-02-26 02:32:30 -060059 }
Junxiao Shi340d5532016-08-13 04:00:35 +000060 parent = &node->entry;
Junxiao Shi2570f3e2016-07-27 02:48:29 +000061 }
Junxiao Shi340d5532016-08-13 04:00:35 +000062 return node->entry;
HYuana9b85752014-02-26 02:32:30 -060063}
64
Junxiao Shi7f358432016-08-11 17:06:33 +000065Entry&
Junxiao Shif2420fc2016-08-11 13:18:21 +000066NameTree::lookup(const fib::Entry& fibEntry)
Junxiao Shib184e532016-05-26 18:09:57 +000067{
Junxiao Shi057d1492018-03-20 17:14:18 +000068 NFD_LOG_TRACE("lookup(FIB " << fibEntry.getPrefix() << ')');
Junxiao Shi7f358432016-08-11 17:06:33 +000069 Entry* nte = this->getEntry(fibEntry);
Junxiao Shif2420fc2016-08-11 13:18:21 +000070 if (nte == nullptr) {
71 // special case: Fib::s_emptyEntry is unattached
72 BOOST_ASSERT(fibEntry.getPrefix().empty());
73 return this->lookup(fibEntry.getPrefix());
74 }
75
76 BOOST_ASSERT(nte->getFibEntry() == &fibEntry);
Junxiao Shi7f358432016-08-11 17:06:33 +000077 return *nte;
Junxiao Shib184e532016-05-26 18:09:57 +000078}
79
Junxiao Shi7f358432016-08-11 17:06:33 +000080Entry&
Junxiao Shib184e532016-05-26 18:09:57 +000081NameTree::lookup(const pit::Entry& pitEntry)
82{
Junxiao Shi057d1492018-03-20 17:14:18 +000083 const Name& name = pitEntry.getName();
84 NFD_LOG_TRACE("lookup(PIT " << name << ')');
85 bool hasDigest = name.size() > 0 && name[-1].isImplicitSha256Digest();
86 if (hasDigest && name.size() <= getMaxDepth()) {
87 return this->lookup(name);
88 }
89
Junxiao Shi7f358432016-08-11 17:06:33 +000090 Entry* nte = this->getEntry(pitEntry);
Junxiao Shif2420fc2016-08-11 13:18:21 +000091 BOOST_ASSERT(nte != nullptr);
Junxiao Shif2420fc2016-08-11 13:18:21 +000092 BOOST_ASSERT(std::count_if(nte->getPitEntries().begin(), nte->getPitEntries().end(),
Davide Pesavento50a6af32019-02-21 00:04:40 -050093 [&pitEntry] (const auto& pitEntry1) {
94 return pitEntry1.get() == &pitEntry;
95 }) == 1);
Junxiao Shi057d1492018-03-20 17:14:18 +000096 return *nte;
Junxiao Shib184e532016-05-26 18:09:57 +000097}
98
Junxiao Shi7f358432016-08-11 17:06:33 +000099Entry&
Junxiao Shif2420fc2016-08-11 13:18:21 +0000100NameTree::lookup(const measurements::Entry& measurementsEntry)
Junxiao Shib184e532016-05-26 18:09:57 +0000101{
Junxiao Shi057d1492018-03-20 17:14:18 +0000102 NFD_LOG_TRACE("lookup(M " << measurementsEntry.getName() << ')');
Junxiao Shi7f358432016-08-11 17:06:33 +0000103 Entry* nte = this->getEntry(measurementsEntry);
Junxiao Shif2420fc2016-08-11 13:18:21 +0000104 BOOST_ASSERT(nte != nullptr);
105
106 BOOST_ASSERT(nte->getMeasurementsEntry() == &measurementsEntry);
Junxiao Shi7f358432016-08-11 17:06:33 +0000107 return *nte;
Junxiao Shib184e532016-05-26 18:09:57 +0000108}
109
Junxiao Shi7f358432016-08-11 17:06:33 +0000110Entry&
Junxiao Shif2420fc2016-08-11 13:18:21 +0000111NameTree::lookup(const strategy_choice::Entry& strategyChoiceEntry)
Junxiao Shib184e532016-05-26 18:09:57 +0000112{
Junxiao Shi057d1492018-03-20 17:14:18 +0000113 NFD_LOG_TRACE("lookup(SC " << strategyChoiceEntry.getPrefix() << ')');
Junxiao Shi7f358432016-08-11 17:06:33 +0000114 Entry* nte = this->getEntry(strategyChoiceEntry);
Junxiao Shif2420fc2016-08-11 13:18:21 +0000115 BOOST_ASSERT(nte != nullptr);
116
117 BOOST_ASSERT(nte->getStrategyChoiceEntry() == &strategyChoiceEntry);
Junxiao Shi7f358432016-08-11 17:06:33 +0000118 return *nte;
Junxiao Shib184e532016-05-26 18:09:57 +0000119}
120
Junxiao Shib660b4c2016-08-06 20:47:44 +0000121size_t
Junxiao Shie7258ff2016-08-12 23:55:47 +0000122NameTree::eraseIfEmpty(Entry* entry, bool canEraseAncestors)
Junxiao Shi4370fde2016-02-24 12:20:46 -0700123{
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000124 BOOST_ASSERT(entry != nullptr);
Junxiao Shi4370fde2016-02-24 12:20:46 -0700125
Junxiao Shib660b4c2016-08-06 20:47:44 +0000126 size_t nErased = 0;
127 for (Entry* parent = nullptr; entry != nullptr && entry->isEmpty(); entry = parent) {
128 parent = entry->getParent();
Junxiao Shi4370fde2016-02-24 12:20:46 -0700129
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000130 if (parent != nullptr) {
Junxiao Shib660b4c2016-08-06 20:47:44 +0000131 entry->unsetParent();
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000132 }
Junxiao Shi4370fde2016-02-24 12:20:46 -0700133
Junxiao Shib660b4c2016-08-06 20:47:44 +0000134 m_ht.erase(getNode(*entry));
135 ++nErased;
Junxiao Shie7258ff2016-08-12 23:55:47 +0000136
137 if (!canEraseAncestors) {
138 break;
139 }
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000140 }
141
Junxiao Shib660b4c2016-08-06 20:47:44 +0000142 if (nErased == 0) {
143 NFD_LOG_TRACE("not-erase " << entry->getName());
144 }
145 return nErased;
Junxiao Shi4370fde2016-02-24 12:20:46 -0700146}
147
Junxiao Shi811c0102016-08-10 04:12:45 +0000148Entry*
Junxiao Shi042a3312017-09-15 02:51:20 +0000149NameTree::findExactMatch(const Name& name, size_t prefixLen) const
HYuana9b85752014-02-26 02:32:30 -0600150{
Junxiao Shi057d1492018-03-20 17:14:18 +0000151 prefixLen = std::min(name.size(), prefixLen);
152 if (prefixLen > getMaxDepth()) {
153 return nullptr;
154 }
155
156 const Node* node = m_ht.find(name, prefixLen);
Junxiao Shi340d5532016-08-13 04:00:35 +0000157 return node == nullptr ? nullptr : &node->entry;
HYuana9b85752014-02-26 02:32:30 -0600158}
159
Junxiao Shi811c0102016-08-10 04:12:45 +0000160Entry*
Junxiao Shib660b4c2016-08-06 20:47:44 +0000161NameTree::findLongestPrefixMatch(const Name& name, const EntrySelector& entrySelector) const
HYuana9b85752014-02-26 02:32:30 -0600162{
Junxiao Shi057d1492018-03-20 17:14:18 +0000163 size_t depth = std::min(name.size(), getMaxDepth());
164 HashSequence hashes = computeHashes(name, depth);
HYuana9b85752014-02-26 02:32:30 -0600165
Junxiao Shi057d1492018-03-20 17:14:18 +0000166 for (ssize_t i = depth; i >= 0; --i) {
167 const Node* node = m_ht.find(name, i, hashes);
Junxiao Shi340d5532016-08-13 04:00:35 +0000168 if (node != nullptr && entrySelector(node->entry)) {
169 return &node->entry;
HYuana9b85752014-02-26 02:32:30 -0600170 }
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000171 }
HYuana9b85752014-02-26 02:32:30 -0600172
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000173 return nullptr;
HYuana9b85752014-02-26 02:32:30 -0600174}
175
Junxiao Shi811c0102016-08-10 04:12:45 +0000176Entry*
177NameTree::findLongestPrefixMatch(const Entry& entry1, const EntrySelector& entrySelector) const
HangZhangcb4fc832014-03-11 16:57:11 +0800178{
Junxiao Shi811c0102016-08-10 04:12:45 +0000179 Entry* entry = const_cast<Entry*>(&entry1);
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000180 while (entry != nullptr) {
181 if (entrySelector(*entry)) {
Junxiao Shi811c0102016-08-10 04:12:45 +0000182 return entry;
HangZhangcb4fc832014-03-11 16:57:11 +0800183 }
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000184 entry = entry->getParent();
185 }
186 return nullptr;
HangZhangcb4fc832014-03-11 16:57:11 +0800187}
188
Junxiao Shi811c0102016-08-10 04:12:45 +0000189Entry*
Junxiao Shif2420fc2016-08-11 13:18:21 +0000190NameTree::findLongestPrefixMatch(const pit::Entry& pitEntry, const EntrySelector& entrySelector) const
HYuana9b85752014-02-26 02:32:30 -0600191{
Junxiao Shi7f358432016-08-11 17:06:33 +0000192 const Entry* nte = this->getEntry(pitEntry);
Junxiao Shib184e532016-05-26 18:09:57 +0000193 BOOST_ASSERT(nte != nullptr);
Junxiao Shif2420fc2016-08-11 13:18:21 +0000194
Junxiao Shi057d1492018-03-20 17:14:18 +0000195 const Name& name = pitEntry.getName();
196 size_t depth = std::min(name.size(), getMaxDepth());
Junxiao Shif2420fc2016-08-11 13:18:21 +0000197 if (nte->getName().size() < pitEntry.getName().size()) {
Junxiao Shi057d1492018-03-20 17:14:18 +0000198 // PIT entry name either exceeds depth limit or ends with an implicit digest: go deeper
199 for (size_t i = nte->getName().size() + 1; i <= depth; ++i) {
200 const Entry* exact = this->findExactMatch(name, i);
Junxiao Shi042a3312017-09-15 02:51:20 +0000201 if (exact == nullptr) {
202 break;
203 }
Junxiao Shif2420fc2016-08-11 13:18:21 +0000204 nte = exact;
205 }
Junxiao Shi4370fde2016-02-24 12:20:46 -0700206 }
HYuana9b85752014-02-26 02:32:30 -0600207
Junxiao Shif2420fc2016-08-11 13:18:21 +0000208 return this->findLongestPrefixMatch(*nte, entrySelector);
Junxiao Shi4370fde2016-02-24 12:20:46 -0700209}
HYuana9b85752014-02-26 02:32:30 -0600210
Junxiao Shi4370fde2016-02-24 12:20:46 -0700211boost::iterator_range<NameTree::const_iterator>
Junxiao Shie3cf2852016-08-09 03:50:56 +0000212NameTree::findAllMatches(const Name& name, const EntrySelector& entrySelector) const
Junxiao Shi4370fde2016-02-24 12:20:46 -0700213{
Junxiao Shi4370fde2016-02-24 12:20:46 -0700214 // As we are using Name Prefix Hash Table, and the current LPM() is
215 // implemented as starting from full name, and reduce the number of
216 // components by 1 each time, we could use it here.
217 // For trie-like design, it could be more efficient by walking down the
218 // trie from the root node.
HYuana9b85752014-02-26 02:32:30 -0600219
Junxiao Shi7f358432016-08-11 17:06:33 +0000220 Entry* entry = this->findLongestPrefixMatch(name, entrySelector);
Junxiao Shi811c0102016-08-10 04:12:45 +0000221 return {Iterator(make_shared<PrefixMatchImpl>(*this, entrySelector), entry), end()};
HYuana9b85752014-02-26 02:32:30 -0600222}
223
Junxiao Shi5ccd0c22014-12-02 23:54:42 -0700224boost::iterator_range<NameTree::const_iterator>
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000225NameTree::fullEnumerate(const EntrySelector& entrySelector) const
HYuana9b85752014-02-26 02:32:30 -0600226{
Junxiao Shi029401f2016-08-05 12:55:14 +0000227 return {Iterator(make_shared<FullEnumerationImpl>(*this, entrySelector), nullptr), end()};
Haowei Yuane1079fc2014-03-08 14:41:25 -0600228}
229
Junxiao Shi5ccd0c22014-12-02 23:54:42 -0700230boost::iterator_range<NameTree::const_iterator>
Haowei Yuane1079fc2014-03-08 14:41:25 -0600231NameTree::partialEnumerate(const Name& prefix,
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000232 const EntrySubTreeSelector& entrySubTreeSelector) const
Haowei Yuane1079fc2014-03-08 14:41:25 -0600233{
Junxiao Shi811c0102016-08-10 04:12:45 +0000234 Entry* entry = this->findExactMatch(prefix);
235 return {Iterator(make_shared<PartialEnumerationImpl>(*this, entrySubTreeSelector), entry), end()};
HYuana9b85752014-02-26 02:32:30 -0600236}
237
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400238} // namespace nfd::name_tree