blob: aac885cee67cb6838204342e8bbb96086af694da [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 Pesavento50a6af32019-02-21 00:04:40 -05003 * Copyright (c) 2014-2019, 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
HYuana9b85752014-02-26 02:32:30 -060033namespace nfd {
Junxiao Shi2570f3e2016-07-27 02:48:29 +000034namespace name_tree {
HYuana9b85752014-02-26 02:32:30 -060035
Davide Pesaventoa3148082018-04-12 18:21:54 -040036NFD_LOG_INIT(NameTree);
HYuana9b85752014-02-26 02:32:30 -060037
HYuana9b85752014-02-26 02:32:30 -060038NameTree::NameTree(size_t nBuckets)
Junxiao Shib660b4c2016-08-06 20:47:44 +000039 : m_ht(HashtableOptions(nBuckets))
HYuana9b85752014-02-26 02:32:30 -060040{
HYuana9b85752014-02-26 02:32:30 -060041}
42
Junxiao Shi7f358432016-08-11 17:06:33 +000043Entry&
Junxiao Shi057d1492018-03-20 17:14:18 +000044NameTree::lookup(const Name& name, size_t prefixLen)
HYuana9b85752014-02-26 02:32:30 -060045{
Junxiao Shi057d1492018-03-20 17:14:18 +000046 NFD_LOG_TRACE("lookup(" << name << ", " << prefixLen << ')');
47 BOOST_ASSERT(prefixLen <= name.size());
48 BOOST_ASSERT(prefixLen <= getMaxDepth());
HYuana9b85752014-02-26 02:32:30 -060049
Junxiao Shi057d1492018-03-20 17:14:18 +000050 HashSequence hashes = computeHashes(name, prefixLen);
Junxiao Shib660b4c2016-08-06 20:47:44 +000051 const Node* node = nullptr;
52 Entry* parent = nullptr;
HYuana9b85752014-02-26 02:32:30 -060053
Junxiao Shi057d1492018-03-20 17:14:18 +000054 for (size_t i = 0; i <= prefixLen; ++i) {
Junxiao Shi2570f3e2016-07-27 02:48:29 +000055 bool isNew = false;
Junxiao Shi057d1492018-03-20 17:14:18 +000056 std::tie(node, isNew) = m_ht.insert(name, i, hashes);
HYuana9b85752014-02-26 02:32:30 -060057
Junxiao Shib660b4c2016-08-06 20:47:44 +000058 if (isNew && parent != nullptr) {
Junxiao Shi340d5532016-08-13 04:00:35 +000059 node->entry.setParent(*parent);
HYuana9b85752014-02-26 02:32:30 -060060 }
Junxiao Shi340d5532016-08-13 04:00:35 +000061 parent = &node->entry;
Junxiao Shi2570f3e2016-07-27 02:48:29 +000062 }
Junxiao Shi340d5532016-08-13 04:00:35 +000063 return node->entry;
HYuana9b85752014-02-26 02:32:30 -060064}
65
Junxiao Shi7f358432016-08-11 17:06:33 +000066Entry&
Junxiao Shif2420fc2016-08-11 13:18:21 +000067NameTree::lookup(const fib::Entry& fibEntry)
Junxiao Shib184e532016-05-26 18:09:57 +000068{
Junxiao Shi057d1492018-03-20 17:14:18 +000069 NFD_LOG_TRACE("lookup(FIB " << fibEntry.getPrefix() << ')');
Junxiao Shi7f358432016-08-11 17:06:33 +000070 Entry* nte = this->getEntry(fibEntry);
Junxiao Shif2420fc2016-08-11 13:18:21 +000071 if (nte == nullptr) {
72 // special case: Fib::s_emptyEntry is unattached
73 BOOST_ASSERT(fibEntry.getPrefix().empty());
74 return this->lookup(fibEntry.getPrefix());
75 }
76
77 BOOST_ASSERT(nte->getFibEntry() == &fibEntry);
Junxiao Shi7f358432016-08-11 17:06:33 +000078 return *nte;
Junxiao Shib184e532016-05-26 18:09:57 +000079}
80
Junxiao Shi7f358432016-08-11 17:06:33 +000081Entry&
Junxiao Shib184e532016-05-26 18:09:57 +000082NameTree::lookup(const pit::Entry& pitEntry)
83{
Junxiao Shi057d1492018-03-20 17:14:18 +000084 const Name& name = pitEntry.getName();
85 NFD_LOG_TRACE("lookup(PIT " << name << ')');
86 bool hasDigest = name.size() > 0 && name[-1].isImplicitSha256Digest();
87 if (hasDigest && name.size() <= getMaxDepth()) {
88 return this->lookup(name);
89 }
90
Junxiao Shi7f358432016-08-11 17:06:33 +000091 Entry* nte = this->getEntry(pitEntry);
Junxiao Shif2420fc2016-08-11 13:18:21 +000092 BOOST_ASSERT(nte != nullptr);
Junxiao Shif2420fc2016-08-11 13:18:21 +000093 BOOST_ASSERT(std::count_if(nte->getPitEntries().begin(), nte->getPitEntries().end(),
Davide Pesavento50a6af32019-02-21 00:04:40 -050094 [&pitEntry] (const auto& pitEntry1) {
95 return pitEntry1.get() == &pitEntry;
96 }) == 1);
Junxiao Shi057d1492018-03-20 17:14:18 +000097 return *nte;
Junxiao Shib184e532016-05-26 18:09:57 +000098}
99
Junxiao Shi7f358432016-08-11 17:06:33 +0000100Entry&
Junxiao Shif2420fc2016-08-11 13:18:21 +0000101NameTree::lookup(const measurements::Entry& measurementsEntry)
Junxiao Shib184e532016-05-26 18:09:57 +0000102{
Junxiao Shi057d1492018-03-20 17:14:18 +0000103 NFD_LOG_TRACE("lookup(M " << measurementsEntry.getName() << ')');
Junxiao Shi7f358432016-08-11 17:06:33 +0000104 Entry* nte = this->getEntry(measurementsEntry);
Junxiao Shif2420fc2016-08-11 13:18:21 +0000105 BOOST_ASSERT(nte != nullptr);
106
107 BOOST_ASSERT(nte->getMeasurementsEntry() == &measurementsEntry);
Junxiao Shi7f358432016-08-11 17:06:33 +0000108 return *nte;
Junxiao Shib184e532016-05-26 18:09:57 +0000109}
110
Junxiao Shi7f358432016-08-11 17:06:33 +0000111Entry&
Junxiao Shif2420fc2016-08-11 13:18:21 +0000112NameTree::lookup(const strategy_choice::Entry& strategyChoiceEntry)
Junxiao Shib184e532016-05-26 18:09:57 +0000113{
Junxiao Shi057d1492018-03-20 17:14:18 +0000114 NFD_LOG_TRACE("lookup(SC " << strategyChoiceEntry.getPrefix() << ')');
Junxiao Shi7f358432016-08-11 17:06:33 +0000115 Entry* nte = this->getEntry(strategyChoiceEntry);
Junxiao Shif2420fc2016-08-11 13:18:21 +0000116 BOOST_ASSERT(nte != nullptr);
117
118 BOOST_ASSERT(nte->getStrategyChoiceEntry() == &strategyChoiceEntry);
Junxiao Shi7f358432016-08-11 17:06:33 +0000119 return *nte;
Junxiao Shib184e532016-05-26 18:09:57 +0000120}
121
Junxiao Shib660b4c2016-08-06 20:47:44 +0000122size_t
Junxiao Shie7258ff2016-08-12 23:55:47 +0000123NameTree::eraseIfEmpty(Entry* entry, bool canEraseAncestors)
Junxiao Shi4370fde2016-02-24 12:20:46 -0700124{
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000125 BOOST_ASSERT(entry != nullptr);
Junxiao Shi4370fde2016-02-24 12:20:46 -0700126
Junxiao Shib660b4c2016-08-06 20:47:44 +0000127 size_t nErased = 0;
128 for (Entry* parent = nullptr; entry != nullptr && entry->isEmpty(); entry = parent) {
129 parent = entry->getParent();
Junxiao Shi4370fde2016-02-24 12:20:46 -0700130
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000131 if (parent != nullptr) {
Junxiao Shib660b4c2016-08-06 20:47:44 +0000132 entry->unsetParent();
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000133 }
Junxiao Shi4370fde2016-02-24 12:20:46 -0700134
Junxiao Shib660b4c2016-08-06 20:47:44 +0000135 m_ht.erase(getNode(*entry));
136 ++nErased;
Junxiao Shie7258ff2016-08-12 23:55:47 +0000137
138 if (!canEraseAncestors) {
139 break;
140 }
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000141 }
142
Junxiao Shib660b4c2016-08-06 20:47:44 +0000143 if (nErased == 0) {
144 NFD_LOG_TRACE("not-erase " << entry->getName());
145 }
146 return nErased;
Junxiao Shi4370fde2016-02-24 12:20:46 -0700147}
148
Junxiao Shi811c0102016-08-10 04:12:45 +0000149Entry*
Junxiao Shi042a3312017-09-15 02:51:20 +0000150NameTree::findExactMatch(const Name& name, size_t prefixLen) const
HYuana9b85752014-02-26 02:32:30 -0600151{
Junxiao Shi057d1492018-03-20 17:14:18 +0000152 prefixLen = std::min(name.size(), prefixLen);
153 if (prefixLen > getMaxDepth()) {
154 return nullptr;
155 }
156
157 const Node* node = m_ht.find(name, prefixLen);
Junxiao Shi340d5532016-08-13 04:00:35 +0000158 return node == nullptr ? nullptr : &node->entry;
HYuana9b85752014-02-26 02:32:30 -0600159}
160
Junxiao Shi811c0102016-08-10 04:12:45 +0000161Entry*
Junxiao Shib660b4c2016-08-06 20:47:44 +0000162NameTree::findLongestPrefixMatch(const Name& name, const EntrySelector& entrySelector) const
HYuana9b85752014-02-26 02:32:30 -0600163{
Junxiao Shi057d1492018-03-20 17:14:18 +0000164 size_t depth = std::min(name.size(), getMaxDepth());
165 HashSequence hashes = computeHashes(name, depth);
HYuana9b85752014-02-26 02:32:30 -0600166
Junxiao Shi057d1492018-03-20 17:14:18 +0000167 for (ssize_t i = depth; i >= 0; --i) {
168 const Node* node = m_ht.find(name, i, hashes);
Junxiao Shi340d5532016-08-13 04:00:35 +0000169 if (node != nullptr && entrySelector(node->entry)) {
170 return &node->entry;
HYuana9b85752014-02-26 02:32:30 -0600171 }
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000172 }
HYuana9b85752014-02-26 02:32:30 -0600173
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000174 return nullptr;
HYuana9b85752014-02-26 02:32:30 -0600175}
176
Junxiao Shi811c0102016-08-10 04:12:45 +0000177Entry*
178NameTree::findLongestPrefixMatch(const Entry& entry1, const EntrySelector& entrySelector) const
HangZhangcb4fc832014-03-11 16:57:11 +0800179{
Junxiao Shi811c0102016-08-10 04:12:45 +0000180 Entry* entry = const_cast<Entry*>(&entry1);
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000181 while (entry != nullptr) {
182 if (entrySelector(*entry)) {
Junxiao Shi811c0102016-08-10 04:12:45 +0000183 return entry;
HangZhangcb4fc832014-03-11 16:57:11 +0800184 }
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000185 entry = entry->getParent();
186 }
187 return nullptr;
HangZhangcb4fc832014-03-11 16:57:11 +0800188}
189
Junxiao Shi811c0102016-08-10 04:12:45 +0000190Entry*
Junxiao Shif2420fc2016-08-11 13:18:21 +0000191NameTree::findLongestPrefixMatch(const pit::Entry& pitEntry, const EntrySelector& entrySelector) const
HYuana9b85752014-02-26 02:32:30 -0600192{
Junxiao Shi7f358432016-08-11 17:06:33 +0000193 const Entry* nte = this->getEntry(pitEntry);
Junxiao Shib184e532016-05-26 18:09:57 +0000194 BOOST_ASSERT(nte != nullptr);
Junxiao Shif2420fc2016-08-11 13:18:21 +0000195
Junxiao Shi057d1492018-03-20 17:14:18 +0000196 const Name& name = pitEntry.getName();
197 size_t depth = std::min(name.size(), getMaxDepth());
Junxiao Shif2420fc2016-08-11 13:18:21 +0000198 if (nte->getName().size() < pitEntry.getName().size()) {
Junxiao Shi057d1492018-03-20 17:14:18 +0000199 // PIT entry name either exceeds depth limit or ends with an implicit digest: go deeper
200 for (size_t i = nte->getName().size() + 1; i <= depth; ++i) {
201 const Entry* exact = this->findExactMatch(name, i);
Junxiao Shi042a3312017-09-15 02:51:20 +0000202 if (exact == nullptr) {
203 break;
204 }
Junxiao Shif2420fc2016-08-11 13:18:21 +0000205 nte = exact;
206 }
Junxiao Shi4370fde2016-02-24 12:20:46 -0700207 }
HYuana9b85752014-02-26 02:32:30 -0600208
Junxiao Shif2420fc2016-08-11 13:18:21 +0000209 return this->findLongestPrefixMatch(*nte, entrySelector);
Junxiao Shi4370fde2016-02-24 12:20:46 -0700210}
HYuana9b85752014-02-26 02:32:30 -0600211
Junxiao Shi4370fde2016-02-24 12:20:46 -0700212boost::iterator_range<NameTree::const_iterator>
Junxiao Shie3cf2852016-08-09 03:50:56 +0000213NameTree::findAllMatches(const Name& name, const EntrySelector& entrySelector) const
Junxiao Shi4370fde2016-02-24 12:20:46 -0700214{
Junxiao Shi4370fde2016-02-24 12:20:46 -0700215 // As we are using Name Prefix Hash Table, and the current LPM() is
216 // implemented as starting from full name, and reduce the number of
217 // components by 1 each time, we could use it here.
218 // For trie-like design, it could be more efficient by walking down the
219 // trie from the root node.
HYuana9b85752014-02-26 02:32:30 -0600220
Junxiao Shi7f358432016-08-11 17:06:33 +0000221 Entry* entry = this->findLongestPrefixMatch(name, entrySelector);
Junxiao Shi811c0102016-08-10 04:12:45 +0000222 return {Iterator(make_shared<PrefixMatchImpl>(*this, entrySelector), entry), end()};
HYuana9b85752014-02-26 02:32:30 -0600223}
224
Junxiao Shi5ccd0c22014-12-02 23:54:42 -0700225boost::iterator_range<NameTree::const_iterator>
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000226NameTree::fullEnumerate(const EntrySelector& entrySelector) const
HYuana9b85752014-02-26 02:32:30 -0600227{
Junxiao Shi029401f2016-08-05 12:55:14 +0000228 return {Iterator(make_shared<FullEnumerationImpl>(*this, entrySelector), nullptr), end()};
Haowei Yuane1079fc2014-03-08 14:41:25 -0600229}
230
Junxiao Shi5ccd0c22014-12-02 23:54:42 -0700231boost::iterator_range<NameTree::const_iterator>
Haowei Yuane1079fc2014-03-08 14:41:25 -0600232NameTree::partialEnumerate(const Name& prefix,
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000233 const EntrySubTreeSelector& entrySubTreeSelector) const
Haowei Yuane1079fc2014-03-08 14:41:25 -0600234{
Junxiao Shi811c0102016-08-10 04:12:45 +0000235 Entry* entry = this->findExactMatch(prefix);
236 return {Iterator(make_shared<PartialEnumerationImpl>(*this, entrySubTreeSelector), entry), end()};
HYuana9b85752014-02-26 02:32:30 -0600237}
238
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000239} // namespace name_tree
HYuana9b85752014-02-26 02:32:30 -0600240} // namespace nfd