blob: 09b57f732d08e6be2183fdd25ad5ab1e968af98e [file] [log] [blame]
HYuana9b85752014-02-26 02:32:30 -06001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Junxiao Shi4370fde2016-02-24 12:20:46 -07003 * Copyright (c) 2014-2016, 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"
27#include "core/logger.hpp"
Haowei Yuanf52dac72014-03-24 23:35:03 -050028#include "core/city-hash.hpp"
Davide Pesavento52a18f92014-04-10 00:55:01 +020029
Alexander Afanasyev09fc3d92015-01-03 02:02:37 -080030#include <boost/concept/assert.hpp>
31#include <boost/concept_check.hpp>
32#include <type_traits>
33
HYuana9b85752014-02-26 02:32:30 -060034namespace nfd {
Junxiao Shi2570f3e2016-07-27 02:48:29 +000035namespace name_tree {
HYuana9b85752014-02-26 02:32:30 -060036
37NFD_LOG_INIT("NameTree");
38
Alexander Afanasyev09fc3d92015-01-03 02:02:37 -080039// http://en.cppreference.com/w/cpp/concept/ForwardIterator
40BOOST_CONCEPT_ASSERT((boost::ForwardIterator<NameTree::const_iterator>));
41// boost::ForwardIterator follows SGI standard http://www.sgi.com/tech/stl/ForwardIterator.html,
42// which doesn't require DefaultConstructible
43#ifdef HAVE_IS_DEFAULT_CONSTRUCTIBLE
44static_assert(std::is_default_constructible<NameTree::const_iterator>::value,
45 "NameTree::const_iterator must be default-constructible");
46#else
47BOOST_CONCEPT_ASSERT((boost::DefaultConstructible<NameTree::const_iterator>));
48#endif // HAVE_IS_DEFAULT_CONSTRUCTIBLE
49
Haowei Yuanf52dac72014-03-24 23:35:03 -050050class Hash32
HYuana9b85752014-02-26 02:32:30 -060051{
Haowei Yuanf52dac72014-03-24 23:35:03 -050052public:
53 static size_t
54 compute(const char* buffer, size_t length)
55 {
56 return static_cast<size_t>(CityHash32(buffer, length));
57 }
58};
HYuana9b85752014-02-26 02:32:30 -060059
Haowei Yuanf52dac72014-03-24 23:35:03 -050060class Hash64
61{
62public:
63 static size_t
64 compute(const char* buffer, size_t length)
65 {
66 return static_cast<size_t>(CityHash64(buffer, length));
67 }
68};
HYuana9b85752014-02-26 02:32:30 -060069
Alexander Afanasyevb755e9d2015-10-20 17:35:51 -050070/// @cond NoDocumentation
Haowei Yuanf52dac72014-03-24 23:35:03 -050071typedef boost::mpl::if_c<sizeof(size_t) >= 8, Hash64, Hash32>::type CityHash;
Alexander Afanasyevb755e9d2015-10-20 17:35:51 -050072/// @endcond
Haowei Yuanf52dac72014-03-24 23:35:03 -050073
74// Interface of different hash functions
75size_t
76computeHash(const Name& prefix)
77{
78 prefix.wireEncode(); // guarantees prefix's wire buffer is not empty
79
80 size_t hashValue = 0;
81 size_t hashUpdate = 0;
82
Junxiao Shi2570f3e2016-07-27 02:48:29 +000083 for (Name::const_iterator it = prefix.begin(); it != prefix.end(); ++it) {
84 const char* wireFormat = reinterpret_cast<const char*>( it->wire() );
85 hashUpdate = CityHash::compute(wireFormat, it->size());
86 hashValue ^= hashUpdate;
87 }
Haowei Yuanf52dac72014-03-24 23:35:03 -050088
89 return hashValue;
90}
91
92std::vector<size_t>
93computeHashSet(const Name& prefix)
94{
Junxiao Shi2570f3e2016-07-27 02:48:29 +000095 prefix.wireEncode(); // guarantees prefix's wire buffer is not empty
Haowei Yuanf52dac72014-03-24 23:35:03 -050096
97 size_t hashValue = 0;
98 size_t hashUpdate = 0;
99
100 std::vector<size_t> hashValueSet;
101 hashValueSet.push_back(hashValue);
102
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000103 for (Name::const_iterator it = prefix.begin(); it != prefix.end(); ++it) {
104 const char* wireFormat = reinterpret_cast<const char*>( it->wire() );
105 hashUpdate = CityHash::compute(wireFormat, it->size());
106 hashValue ^= hashUpdate;
107 hashValueSet.push_back(hashValue);
108 }
Haowei Yuanf52dac72014-03-24 23:35:03 -0500109
110 return hashValueSet;
HYuana9b85752014-02-26 02:32:30 -0600111}
112
HYuana9b85752014-02-26 02:32:30 -0600113NameTree::NameTree(size_t nBuckets)
114 : m_nItems(0)
115 , m_nBuckets(nBuckets)
Haowei Yuanf52dac72014-03-24 23:35:03 -0500116 , m_minNBuckets(nBuckets)
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000117 , m_enlargeLoadFactor(0.5) // more than 50% buckets loaded
Haowei Yuanf52dac72014-03-24 23:35:03 -0500118 , m_enlargeFactor(2) // double the hash table size
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000119 , m_shrinkLoadFactor(0.1) // less than 10% buckets loaded
120 , m_shrinkFactor(0.5) // reduce the number of buckets by half
HYuana9b85752014-02-26 02:32:30 -0600121{
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000122 m_enlargeThreshold = static_cast<size_t>(m_enlargeLoadFactor * static_cast<double>(m_nBuckets));
123 m_shrinkThreshold = static_cast<size_t>(m_shrinkLoadFactor * static_cast<double>(m_nBuckets));
HYuana9b85752014-02-26 02:32:30 -0600124
125 // array of node pointers
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000126 m_buckets = new Node*[m_nBuckets];
HYuana9b85752014-02-26 02:32:30 -0600127 // Initialize the pointer array
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000128 for (size_t i = 0; i < m_nBuckets; ++i) {
129 m_buckets[i] = nullptr;
130 }
HYuana9b85752014-02-26 02:32:30 -0600131}
132
133NameTree::~NameTree()
134{
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000135 for (size_t i = 0; i < m_nBuckets; ++i) {
136 if (m_buckets[i] != nullptr) {
137 delete m_buckets[i];
HYuana9b85752014-02-26 02:32:30 -0600138 }
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000139 }
HYuana9b85752014-02-26 02:32:30 -0600140
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000141 delete[] m_buckets;
HYuana9b85752014-02-26 02:32:30 -0600142}
143
144// insert() is a private function, and called by only lookup()
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000145std::pair<shared_ptr<Entry>, bool>
HYuana9b85752014-02-26 02:32:30 -0600146NameTree::insert(const Name& prefix)
147{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700148 NFD_LOG_TRACE("insert " << prefix);
HYuana9b85752014-02-26 02:32:30 -0600149
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000150 size_t hashValue = computeHash(prefix);
Haowei Yuanf52dac72014-03-24 23:35:03 -0500151 size_t loc = hashValue % m_nBuckets;
HYuana9b85752014-02-26 02:32:30 -0600152
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700153 NFD_LOG_TRACE("Name " << prefix << " hash value = " << hashValue << " location = " << loc);
HYuana9b85752014-02-26 02:32:30 -0600154
155 // Check if this Name has been stored
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000156 Node* node = m_buckets[loc];
157 Node* nodePrev = node;
HYuana9b85752014-02-26 02:32:30 -0600158
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000159 for (node = m_buckets[loc]; node != nullptr; node = node->m_next) {
160 if (node->m_entry != nullptr) {
161 if (prefix == node->m_entry->m_prefix) {
162 return {node->m_entry, false}; // false: old entry
163 }
HYuana9b85752014-02-26 02:32:30 -0600164 }
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000165 nodePrev = node;
166 }
HYuana9b85752014-02-26 02:32:30 -0600167
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700168 NFD_LOG_TRACE("Did not find " << prefix << ", need to insert it to the table");
HYuana9b85752014-02-26 02:32:30 -0600169
170 // If no bucket is empty occupied, we need to create a new node, and it is
171 // linked from nodePrev
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000172 node = new Node();
HYuana9b85752014-02-26 02:32:30 -0600173 node->m_prev = nodePrev;
174
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000175 if (nodePrev == nullptr) {
176 m_buckets[loc] = node;
177 }
178 else{
179 nodePrev->m_next = node;
180 }
HYuana9b85752014-02-26 02:32:30 -0600181
182 // Create a new Entry
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000183 auto entry = make_shared<Entry>(prefix);
HYuana9b85752014-02-26 02:32:30 -0600184 entry->setHash(hashValue);
185 node->m_entry = entry; // link the Entry to its Node
186 entry->m_node = node; // link the node to Entry. Used in eraseEntryIfEmpty.
187
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000188 return {entry, true}; // true: new entry
HYuana9b85752014-02-26 02:32:30 -0600189}
190
191// Name Prefix Lookup. Create Name Tree Entry if not found
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000192shared_ptr<Entry>
HYuana9b85752014-02-26 02:32:30 -0600193NameTree::lookup(const Name& prefix)
194{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700195 NFD_LOG_TRACE("lookup " << prefix);
HYuana9b85752014-02-26 02:32:30 -0600196
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000197 shared_ptr<Entry> entry;
198 shared_ptr<Entry> parent;
HYuana9b85752014-02-26 02:32:30 -0600199
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000200 for (size_t i = 0; i <= prefix.size(); ++i) {
201 Name temp = prefix.getPrefix(i);
HYuana9b85752014-02-26 02:32:30 -0600202
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000203 // insert() will create the entry if it does not exist.
204 bool isNew = false;
205 std::tie(entry, isNew) = insert(temp);
HYuana9b85752014-02-26 02:32:30 -0600206
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000207 if (isNew) {
208 ++m_nItems; // Increase the counter
209 entry->m_parent = parent;
HYuana9b85752014-02-26 02:32:30 -0600210
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000211 if (parent != nullptr) {
212 parent->m_children.push_back(entry);
213 }
HYuana9b85752014-02-26 02:32:30 -0600214 }
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000215
216 if (m_nItems > m_enlargeThreshold) {
217 resize(m_enlargeFactor * m_nBuckets);
218 }
219
220 parent = entry;
221 }
HYuana9b85752014-02-26 02:32:30 -0600222 return entry;
223}
224
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000225shared_ptr<Entry>
Junxiao Shib184e532016-05-26 18:09:57 +0000226NameTree::lookup(const fib::Entry& fibEntry) const
227{
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000228 shared_ptr<Entry> nte = this->getEntry(fibEntry);
Junxiao Shia6de4292016-07-12 02:08:10 +0000229 BOOST_ASSERT(nte == nullptr || nte->getFibEntry() == &fibEntry);
Junxiao Shib184e532016-05-26 18:09:57 +0000230 return nte;
231}
232
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000233shared_ptr<Entry>
Junxiao Shib184e532016-05-26 18:09:57 +0000234NameTree::lookup(const pit::Entry& pitEntry)
235{
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000236 shared_ptr<Entry> nte = this->getEntry(pitEntry);
Junxiao Shib184e532016-05-26 18:09:57 +0000237 if (nte == nullptr) {
238 return nullptr;
239 }
240
241 if (nte->getPrefix().size() == pitEntry.getName().size()) {
242 return nte;
243 }
244
245 BOOST_ASSERT(pitEntry.getName().at(-1).isImplicitSha256Digest());
246 BOOST_ASSERT(nte->getPrefix() == pitEntry.getName().getPrefix(-1));
247 return this->lookup(pitEntry.getName());
248}
249
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000250shared_ptr<Entry>
Junxiao Shib184e532016-05-26 18:09:57 +0000251NameTree::lookup(const measurements::Entry& measurementsEntry) const
252{
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000253 shared_ptr<Entry> nte = this->getEntry(measurementsEntry);
Junxiao Shi80f9fcd2016-07-23 02:48:36 +0000254 BOOST_ASSERT(nte == nullptr || nte->getMeasurementsEntry() == &measurementsEntry);
Junxiao Shib184e532016-05-26 18:09:57 +0000255 return nte;
256}
257
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000258shared_ptr<Entry>
Junxiao Shib184e532016-05-26 18:09:57 +0000259NameTree::lookup(const strategy_choice::Entry& strategyChoiceEntry) const
260{
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000261 shared_ptr<Entry> nte = this->getEntry(strategyChoiceEntry);
Junxiao Shiff10da62016-07-13 17:57:43 +0000262 BOOST_ASSERT(nte == nullptr || nte->getStrategyChoiceEntry() == &strategyChoiceEntry);
Junxiao Shib184e532016-05-26 18:09:57 +0000263 return nte;
264}
265
Junxiao Shi4370fde2016-02-24 12:20:46 -0700266// return {false: this entry is not empty, true: this entry is empty and erased}
267bool
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000268NameTree::eraseEntryIfEmpty(shared_ptr<Entry> entry)
Junxiao Shi4370fde2016-02-24 12:20:46 -0700269{
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000270 BOOST_ASSERT(entry != nullptr);
Junxiao Shi4370fde2016-02-24 12:20:46 -0700271
272 NFD_LOG_TRACE("eraseEntryIfEmpty " << entry->getPrefix());
273
274 // first check if this Entry can be erased
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000275 if (entry->isEmpty()) {
276 // update child-related info in the parent
277 shared_ptr<Entry> parent = entry->getParent();
Junxiao Shi4370fde2016-02-24 12:20:46 -0700278
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000279 if (parent != nullptr) {
280 std::vector<shared_ptr<Entry>>& parentChildrenList = parent->getChildren();
Junxiao Shi4370fde2016-02-24 12:20:46 -0700281
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000282 bool isFound = false;
283 size_t size = parentChildrenList.size();
284 for (size_t i = 0; i < size; ++i) {
285 if (parentChildrenList[i] == entry) {
286 parentChildrenList[i] = parentChildrenList[size - 1];
287 parentChildrenList.pop_back();
288 isFound = true;
289 break;
Junxiao Shi4370fde2016-02-24 12:20:46 -0700290 }
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000291 }
Junxiao Shi4370fde2016-02-24 12:20:46 -0700292
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000293 BOOST_VERIFY(isFound == true);
294 }
Junxiao Shi4370fde2016-02-24 12:20:46 -0700295
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000296 // remove this Entry and its Name Tree Node
297 Node* node = entry->m_node;
298 Node* nodePrev = node->m_prev;
Junxiao Shi4370fde2016-02-24 12:20:46 -0700299
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000300 // configure the previous node
301 if (nodePrev != nullptr) {
302 // link the previous node to the next node
303 nodePrev->m_next = node->m_next;
304 }
305 else {
306 m_buckets[entry->getHash() % m_nBuckets] = node->m_next;
307 }
Junxiao Shi4370fde2016-02-24 12:20:46 -0700308
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000309 // link the previous node with the next node (skip the erased one)
310 if (node->m_next != nullptr) {
311 node->m_next->m_prev = nodePrev;
312 node->m_next = 0;
313 }
Junxiao Shi4370fde2016-02-24 12:20:46 -0700314
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000315 BOOST_ASSERT(node->m_next == nullptr);
Junxiao Shi4370fde2016-02-24 12:20:46 -0700316
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000317 --m_nItems;
318 delete node;
Junxiao Shi4370fde2016-02-24 12:20:46 -0700319
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000320 if (parent != nullptr) {
321 eraseEntryIfEmpty(parent);
322 }
Junxiao Shi4370fde2016-02-24 12:20:46 -0700323
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000324 size_t newNBuckets = static_cast<size_t>(m_shrinkFactor * static_cast<double>(m_nBuckets));
Junxiao Shi4370fde2016-02-24 12:20:46 -0700325
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000326 if (newNBuckets >= m_minNBuckets && m_nItems < m_shrinkThreshold) {
327 resize(newNBuckets);
328 }
Junxiao Shi4370fde2016-02-24 12:20:46 -0700329
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000330 return true;
Junxiao Shi4370fde2016-02-24 12:20:46 -0700331
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000332 }
333
334 return false;
Junxiao Shi4370fde2016-02-24 12:20:46 -0700335}
336
HYuana9b85752014-02-26 02:32:30 -0600337// Exact Match
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000338shared_ptr<Entry>
HYuana9b85752014-02-26 02:32:30 -0600339NameTree::findExactMatch(const Name& prefix) const
340{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700341 NFD_LOG_TRACE("findExactMatch " << prefix);
HYuana9b85752014-02-26 02:32:30 -0600342
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000343 size_t hashValue = computeHash(prefix);
Haowei Yuanf52dac72014-03-24 23:35:03 -0500344 size_t loc = hashValue % m_nBuckets;
HYuana9b85752014-02-26 02:32:30 -0600345
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000346 NFD_LOG_TRACE("Name " << prefix << " hash value = " << hashValue << " location = " << loc);
HYuana9b85752014-02-26 02:32:30 -0600347
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000348 shared_ptr<Entry> entry;
349 Node* node = nullptr;
HYuana9b85752014-02-26 02:32:30 -0600350
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000351 for (node = m_buckets[loc]; node != nullptr; node = node->m_next) {
352 entry = node->m_entry;
353 if (entry != nullptr) {
354 if (hashValue == entry->getHash() && prefix == entry->getPrefix()) {
355 return entry;
356 }
357 }
358 }
HYuana9b85752014-02-26 02:32:30 -0600359
360 // if not found, the default value of entry (null pointer) will be returned
361 entry.reset();
362 return entry;
363}
364
365// Longest Prefix Match
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000366shared_ptr<Entry>
367NameTree::findLongestPrefixMatch(const Name& prefix, const EntrySelector& entrySelector) const
HYuana9b85752014-02-26 02:32:30 -0600368{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700369 NFD_LOG_TRACE("findLongestPrefixMatch " << prefix);
HYuana9b85752014-02-26 02:32:30 -0600370
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000371 shared_ptr<Entry> entry;
372 std::vector<size_t> hashValueSet = computeHashSet(prefix);
HYuana9b85752014-02-26 02:32:30 -0600373
Haowei Yuanf52dac72014-03-24 23:35:03 -0500374 size_t hashValue = 0;
375 size_t loc = 0;
376
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000377 for (int i = static_cast<int>(prefix.size()); i >= 0; --i) {
378 hashValue = hashValueSet[i];
379 loc = hashValue % m_nBuckets;
Haowei Yuanf52dac72014-03-24 23:35:03 -0500380
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000381 Node* node = nullptr;
382 for (node = m_buckets[loc]; node != nullptr; node = node->m_next) {
383 entry = node->m_entry;
384 if (entry != nullptr) {
385 // isPrefixOf() is used to avoid making a copy of the name
386 if (hashValue == entry->getHash() &&
387 entry->getPrefix().isPrefixOf(prefix) &&
388 entrySelector(*entry)) {
389 return entry;
390 }
391 }
HYuana9b85752014-02-26 02:32:30 -0600392 }
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000393 }
HYuana9b85752014-02-26 02:32:30 -0600394
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000395 return nullptr;
HYuana9b85752014-02-26 02:32:30 -0600396}
397
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000398shared_ptr<Entry>
399NameTree::findLongestPrefixMatch(shared_ptr<Entry> entry,
400 const EntrySelector& entrySelector) const
HangZhangcb4fc832014-03-11 16:57:11 +0800401{
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000402 while (entry != nullptr) {
403 if (entrySelector(*entry)) {
404 return entry;
HangZhangcb4fc832014-03-11 16:57:11 +0800405 }
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000406 entry = entry->getParent();
407 }
408 return nullptr;
HangZhangcb4fc832014-03-11 16:57:11 +0800409}
410
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000411shared_ptr<Entry>
Junxiao Shi4370fde2016-02-24 12:20:46 -0700412NameTree::findLongestPrefixMatch(const pit::Entry& pitEntry) const
HYuana9b85752014-02-26 02:32:30 -0600413{
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000414 shared_ptr<Entry> nte = this->getEntry(pitEntry);
Junxiao Shib184e532016-05-26 18:09:57 +0000415 BOOST_ASSERT(nte != nullptr);
Junxiao Shi4370fde2016-02-24 12:20:46 -0700416 if (nte->getPrefix().size() == pitEntry.getName().size()) {
417 return nte;
418 }
HYuana9b85752014-02-26 02:32:30 -0600419
Junxiao Shi4370fde2016-02-24 12:20:46 -0700420 BOOST_ASSERT(pitEntry.getName().at(-1).isImplicitSha256Digest());
421 BOOST_ASSERT(nte->getPrefix() == pitEntry.getName().getPrefix(-1));
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000422 shared_ptr<Entry> exact = this->findExactMatch(pitEntry.getName());
Junxiao Shi4370fde2016-02-24 12:20:46 -0700423 return exact == nullptr ? nte : exact;
424}
HYuana9b85752014-02-26 02:32:30 -0600425
Junxiao Shi4370fde2016-02-24 12:20:46 -0700426boost::iterator_range<NameTree::const_iterator>
427NameTree::findAllMatches(const Name& prefix,
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000428 const EntrySelector& entrySelector) const
Junxiao Shi4370fde2016-02-24 12:20:46 -0700429{
430 NFD_LOG_TRACE("NameTree::findAllMatches" << prefix);
HYuana9b85752014-02-26 02:32:30 -0600431
Junxiao Shi4370fde2016-02-24 12:20:46 -0700432 // As we are using Name Prefix Hash Table, and the current LPM() is
433 // implemented as starting from full name, and reduce the number of
434 // components by 1 each time, we could use it here.
435 // For trie-like design, it could be more efficient by walking down the
436 // trie from the root node.
HYuana9b85752014-02-26 02:32:30 -0600437
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000438 shared_ptr<Entry> entry = findLongestPrefixMatch(prefix, entrySelector);
Junxiao Shi029401f2016-08-05 12:55:14 +0000439 return {Iterator(make_shared<PrefixMatchImpl>(*this, entrySelector), entry), end()};
HYuana9b85752014-02-26 02:32:30 -0600440}
441
Junxiao Shi5ccd0c22014-12-02 23:54:42 -0700442boost::iterator_range<NameTree::const_iterator>
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000443NameTree::fullEnumerate(const EntrySelector& entrySelector) const
HYuana9b85752014-02-26 02:32:30 -0600444{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700445 NFD_LOG_TRACE("fullEnumerate");
HYuana9b85752014-02-26 02:32:30 -0600446
Junxiao Shi029401f2016-08-05 12:55:14 +0000447 return {Iterator(make_shared<FullEnumerationImpl>(*this, entrySelector), nullptr), end()};
Haowei Yuane1079fc2014-03-08 14:41:25 -0600448}
449
Junxiao Shi5ccd0c22014-12-02 23:54:42 -0700450boost::iterator_range<NameTree::const_iterator>
Haowei Yuane1079fc2014-03-08 14:41:25 -0600451NameTree::partialEnumerate(const Name& prefix,
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000452 const EntrySubTreeSelector& entrySubTreeSelector) const
Haowei Yuane1079fc2014-03-08 14:41:25 -0600453{
454 // the first step is to process the root node
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000455 shared_ptr<Entry> entry = findExactMatch(prefix);
Junxiao Shi029401f2016-08-05 12:55:14 +0000456 return {Iterator(make_shared<PartialEnumerationImpl>(*this, entrySubTreeSelector), entry), end()};
HYuana9b85752014-02-26 02:32:30 -0600457}
458
HYuana9b85752014-02-26 02:32:30 -0600459// Hash Table Resize
460void
461NameTree::resize(size_t newNBuckets)
462{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700463 NFD_LOG_TRACE("resize");
HYuana9b85752014-02-26 02:32:30 -0600464
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000465 Node** newBuckets = new Node*[newNBuckets];
Junxiao Shi40631842014-03-01 13:52:37 -0700466 size_t count = 0;
HYuana9b85752014-02-26 02:32:30 -0600467
468 // referenced ccnx hashtb.c hashtb_rehash()
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000469 Node** pp = nullptr;
470 Node* p = nullptr;
471 Node* pre = nullptr;
472 Node* q = nullptr; // record p->m_next
HYuana9b85752014-02-26 02:32:30 -0600473
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000474 for (size_t i = 0; i < newNBuckets; ++i) {
475 newBuckets[i] = nullptr;
476 }
HYuana9b85752014-02-26 02:32:30 -0600477
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000478 for (size_t i = 0; i < m_nBuckets; ++i) {
479 for (p = m_buckets[i]; p != nullptr; p = q) {
480 ++count;
481 q = p->m_next;
482 BOOST_ASSERT(p->m_entry != nullptr);
483 uint32_t h = p->m_entry->m_hash;
484 uint32_t b = h % newNBuckets;
485 pre = nullptr;
486 for (pp = &newBuckets[b]; *pp != nullptr; pp = &((*pp)->m_next)) {
487 pre = *pp;
488 }
489 p->m_prev = pre;
490 p->m_next = *pp; // Actually *pp always == nullptr in this case
491 *pp = p;
HYuana9b85752014-02-26 02:32:30 -0600492 }
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000493 }
HYuana9b85752014-02-26 02:32:30 -0600494
495 BOOST_ASSERT(count == m_nItems);
496
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000497 Node** oldBuckets = m_buckets;
HYuana9b85752014-02-26 02:32:30 -0600498 m_buckets = newBuckets;
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000499 delete[] oldBuckets;
HYuana9b85752014-02-26 02:32:30 -0600500
501 m_nBuckets = newNBuckets;
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000502 m_enlargeThreshold = static_cast<size_t>(m_enlargeLoadFactor * static_cast<double>(m_nBuckets));
503 m_shrinkThreshold = static_cast<size_t>(m_shrinkLoadFactor * static_cast<double>(m_nBuckets));
HYuana9b85752014-02-26 02:32:30 -0600504}
505
506// For debugging
507void
Haowei Yuane1079fc2014-03-08 14:41:25 -0600508NameTree::dump(std::ostream& output) const
HYuana9b85752014-02-26 02:32:30 -0600509{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700510 NFD_LOG_TRACE("dump()");
HYuana9b85752014-02-26 02:32:30 -0600511
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000512 Node* node = nullptr;
513 shared_ptr<Entry> entry;
HYuana9b85752014-02-26 02:32:30 -0600514
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000515 for (size_t i = 0; i < m_nBuckets; ++i) {
516 for (node = m_buckets[i]; node != nullptr; node = node->m_next) {
517 entry = node->m_entry;
HYuana9b85752014-02-26 02:32:30 -0600518
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000519 // if the Entry exist, dump its information
520 if (entry != nullptr) {
521 output << "Bucket" << i << '\t' << entry->m_prefix.toUri() << '\n';
522 output << "\t\tHash " << entry->m_hash << '\n';
HYuana9b85752014-02-26 02:32:30 -0600523
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000524 if (entry->m_parent != nullptr) {
525 output << "\t\tparent->" << entry->m_parent->m_prefix.toUri();
526 }
527 else {
528 output << "\t\tROOT";
529 }
530 output << '\n';
HYuana9b85752014-02-26 02:32:30 -0600531
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000532 if (!entry->m_children.empty()) {
533 output << "\t\tchildren = " << entry->m_children.size() << '\n';
HYuana9b85752014-02-26 02:32:30 -0600534
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000535 for (size_t j = 0; j < entry->m_children.size(); ++j) {
536 output << "\t\t\tChild " << j << " " << entry->m_children[j]->getPrefix() << '\n';
537 }
538 }
HYuana9b85752014-02-26 02:32:30 -0600539
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000540 }
HYuana9b85752014-02-26 02:32:30 -0600541
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000542 }
543 }
HYuana9b85752014-02-26 02:32:30 -0600544
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000545 output << "Bucket count = " << m_nBuckets << '\n';
546 output << "Stored item = " << m_nItems << '\n';
HYuana9b85752014-02-26 02:32:30 -0600547 output << "--------------------------\n";
548}
549
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000550} // namespace name_tree
HYuana9b85752014-02-26 02:32:30 -0600551} // namespace nfd