blob: abc5672e21dbb501e1f1736696b0a3fd159e5e46 [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
Haowei Yuane1079fc2014-03-08 14:41:25 -0600121 , m_endIterator(FULL_ENUMERATE_TYPE, *this, m_end)
HYuana9b85752014-02-26 02:32:30 -0600122{
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000123 m_enlargeThreshold = static_cast<size_t>(m_enlargeLoadFactor * static_cast<double>(m_nBuckets));
124 m_shrinkThreshold = static_cast<size_t>(m_shrinkLoadFactor * static_cast<double>(m_nBuckets));
HYuana9b85752014-02-26 02:32:30 -0600125
126 // array of node pointers
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000127 m_buckets = new Node*[m_nBuckets];
HYuana9b85752014-02-26 02:32:30 -0600128 // Initialize the pointer array
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000129 for (size_t i = 0; i < m_nBuckets; ++i) {
130 m_buckets[i] = nullptr;
131 }
HYuana9b85752014-02-26 02:32:30 -0600132}
133
134NameTree::~NameTree()
135{
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000136 for (size_t i = 0; i < m_nBuckets; ++i) {
137 if (m_buckets[i] != nullptr) {
138 delete m_buckets[i];
HYuana9b85752014-02-26 02:32:30 -0600139 }
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000140 }
HYuana9b85752014-02-26 02:32:30 -0600141
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000142 delete[] m_buckets;
HYuana9b85752014-02-26 02:32:30 -0600143}
144
145// insert() is a private function, and called by only lookup()
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000146std::pair<shared_ptr<Entry>, bool>
HYuana9b85752014-02-26 02:32:30 -0600147NameTree::insert(const Name& prefix)
148{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700149 NFD_LOG_TRACE("insert " << prefix);
HYuana9b85752014-02-26 02:32:30 -0600150
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000151 size_t hashValue = computeHash(prefix);
Haowei Yuanf52dac72014-03-24 23:35:03 -0500152 size_t loc = hashValue % m_nBuckets;
HYuana9b85752014-02-26 02:32:30 -0600153
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700154 NFD_LOG_TRACE("Name " << prefix << " hash value = " << hashValue << " location = " << loc);
HYuana9b85752014-02-26 02:32:30 -0600155
156 // Check if this Name has been stored
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000157 Node* node = m_buckets[loc];
158 Node* nodePrev = node;
HYuana9b85752014-02-26 02:32:30 -0600159
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000160 for (node = m_buckets[loc]; node != nullptr; node = node->m_next) {
161 if (node->m_entry != nullptr) {
162 if (prefix == node->m_entry->m_prefix) {
163 return {node->m_entry, false}; // false: old entry
164 }
HYuana9b85752014-02-26 02:32:30 -0600165 }
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000166 nodePrev = node;
167 }
HYuana9b85752014-02-26 02:32:30 -0600168
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700169 NFD_LOG_TRACE("Did not find " << prefix << ", need to insert it to the table");
HYuana9b85752014-02-26 02:32:30 -0600170
171 // If no bucket is empty occupied, we need to create a new node, and it is
172 // linked from nodePrev
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000173 node = new Node();
HYuana9b85752014-02-26 02:32:30 -0600174 node->m_prev = nodePrev;
175
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000176 if (nodePrev == nullptr) {
177 m_buckets[loc] = node;
178 }
179 else{
180 nodePrev->m_next = node;
181 }
HYuana9b85752014-02-26 02:32:30 -0600182
183 // Create a new Entry
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000184 auto entry = make_shared<Entry>(prefix);
HYuana9b85752014-02-26 02:32:30 -0600185 entry->setHash(hashValue);
186 node->m_entry = entry; // link the Entry to its Node
187 entry->m_node = node; // link the node to Entry. Used in eraseEntryIfEmpty.
188
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000189 return {entry, true}; // true: new entry
HYuana9b85752014-02-26 02:32:30 -0600190}
191
192// Name Prefix Lookup. Create Name Tree Entry if not found
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000193shared_ptr<Entry>
HYuana9b85752014-02-26 02:32:30 -0600194NameTree::lookup(const Name& prefix)
195{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700196 NFD_LOG_TRACE("lookup " << prefix);
HYuana9b85752014-02-26 02:32:30 -0600197
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000198 shared_ptr<Entry> entry;
199 shared_ptr<Entry> parent;
HYuana9b85752014-02-26 02:32:30 -0600200
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000201 for (size_t i = 0; i <= prefix.size(); ++i) {
202 Name temp = prefix.getPrefix(i);
HYuana9b85752014-02-26 02:32:30 -0600203
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000204 // insert() will create the entry if it does not exist.
205 bool isNew = false;
206 std::tie(entry, isNew) = insert(temp);
HYuana9b85752014-02-26 02:32:30 -0600207
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000208 if (isNew) {
209 ++m_nItems; // Increase the counter
210 entry->m_parent = parent;
HYuana9b85752014-02-26 02:32:30 -0600211
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000212 if (parent != nullptr) {
213 parent->m_children.push_back(entry);
214 }
HYuana9b85752014-02-26 02:32:30 -0600215 }
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000216
217 if (m_nItems > m_enlargeThreshold) {
218 resize(m_enlargeFactor * m_nBuckets);
219 }
220
221 parent = entry;
222 }
HYuana9b85752014-02-26 02:32:30 -0600223 return entry;
224}
225
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000226shared_ptr<Entry>
Junxiao Shib184e532016-05-26 18:09:57 +0000227NameTree::lookup(const fib::Entry& fibEntry) const
228{
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000229 shared_ptr<Entry> nte = this->getEntry(fibEntry);
Junxiao Shia6de4292016-07-12 02:08:10 +0000230 BOOST_ASSERT(nte == nullptr || nte->getFibEntry() == &fibEntry);
Junxiao Shib184e532016-05-26 18:09:57 +0000231 return nte;
232}
233
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000234shared_ptr<Entry>
Junxiao Shib184e532016-05-26 18:09:57 +0000235NameTree::lookup(const pit::Entry& pitEntry)
236{
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000237 shared_ptr<Entry> nte = this->getEntry(pitEntry);
Junxiao Shib184e532016-05-26 18:09:57 +0000238 if (nte == nullptr) {
239 return nullptr;
240 }
241
242 if (nte->getPrefix().size() == pitEntry.getName().size()) {
243 return nte;
244 }
245
246 BOOST_ASSERT(pitEntry.getName().at(-1).isImplicitSha256Digest());
247 BOOST_ASSERT(nte->getPrefix() == pitEntry.getName().getPrefix(-1));
248 return this->lookup(pitEntry.getName());
249}
250
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000251shared_ptr<Entry>
Junxiao Shib184e532016-05-26 18:09:57 +0000252NameTree::lookup(const measurements::Entry& measurementsEntry) const
253{
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000254 shared_ptr<Entry> nte = this->getEntry(measurementsEntry);
Junxiao Shi80f9fcd2016-07-23 02:48:36 +0000255 BOOST_ASSERT(nte == nullptr || nte->getMeasurementsEntry() == &measurementsEntry);
Junxiao Shib184e532016-05-26 18:09:57 +0000256 return nte;
257}
258
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000259shared_ptr<Entry>
Junxiao Shib184e532016-05-26 18:09:57 +0000260NameTree::lookup(const strategy_choice::Entry& strategyChoiceEntry) const
261{
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000262 shared_ptr<Entry> nte = this->getEntry(strategyChoiceEntry);
Junxiao Shiff10da62016-07-13 17:57:43 +0000263 BOOST_ASSERT(nte == nullptr || nte->getStrategyChoiceEntry() == &strategyChoiceEntry);
Junxiao Shib184e532016-05-26 18:09:57 +0000264 return nte;
265}
266
Junxiao Shi4370fde2016-02-24 12:20:46 -0700267// return {false: this entry is not empty, true: this entry is empty and erased}
268bool
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000269NameTree::eraseEntryIfEmpty(shared_ptr<Entry> entry)
Junxiao Shi4370fde2016-02-24 12:20:46 -0700270{
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000271 BOOST_ASSERT(entry != nullptr);
Junxiao Shi4370fde2016-02-24 12:20:46 -0700272
273 NFD_LOG_TRACE("eraseEntryIfEmpty " << entry->getPrefix());
274
275 // first check if this Entry can be erased
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000276 if (entry->isEmpty()) {
277 // update child-related info in the parent
278 shared_ptr<Entry> parent = entry->getParent();
Junxiao Shi4370fde2016-02-24 12:20:46 -0700279
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000280 if (parent != nullptr) {
281 std::vector<shared_ptr<Entry>>& parentChildrenList = parent->getChildren();
Junxiao Shi4370fde2016-02-24 12:20:46 -0700282
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000283 bool isFound = false;
284 size_t size = parentChildrenList.size();
285 for (size_t i = 0; i < size; ++i) {
286 if (parentChildrenList[i] == entry) {
287 parentChildrenList[i] = parentChildrenList[size - 1];
288 parentChildrenList.pop_back();
289 isFound = true;
290 break;
Junxiao Shi4370fde2016-02-24 12:20:46 -0700291 }
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000292 }
Junxiao Shi4370fde2016-02-24 12:20:46 -0700293
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000294 BOOST_VERIFY(isFound == true);
295 }
Junxiao Shi4370fde2016-02-24 12:20:46 -0700296
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000297 // remove this Entry and its Name Tree Node
298 Node* node = entry->m_node;
299 Node* nodePrev = node->m_prev;
Junxiao Shi4370fde2016-02-24 12:20:46 -0700300
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000301 // configure the previous node
302 if (nodePrev != nullptr) {
303 // link the previous node to the next node
304 nodePrev->m_next = node->m_next;
305 }
306 else {
307 m_buckets[entry->getHash() % m_nBuckets] = node->m_next;
308 }
Junxiao Shi4370fde2016-02-24 12:20:46 -0700309
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000310 // link the previous node with the next node (skip the erased one)
311 if (node->m_next != nullptr) {
312 node->m_next->m_prev = nodePrev;
313 node->m_next = 0;
314 }
Junxiao Shi4370fde2016-02-24 12:20:46 -0700315
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000316 BOOST_ASSERT(node->m_next == nullptr);
Junxiao Shi4370fde2016-02-24 12:20:46 -0700317
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000318 --m_nItems;
319 delete node;
Junxiao Shi4370fde2016-02-24 12:20:46 -0700320
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000321 if (parent != nullptr) {
322 eraseEntryIfEmpty(parent);
323 }
Junxiao Shi4370fde2016-02-24 12:20:46 -0700324
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000325 size_t newNBuckets = static_cast<size_t>(m_shrinkFactor * static_cast<double>(m_nBuckets));
Junxiao Shi4370fde2016-02-24 12:20:46 -0700326
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000327 if (newNBuckets >= m_minNBuckets && m_nItems < m_shrinkThreshold) {
328 resize(newNBuckets);
329 }
Junxiao Shi4370fde2016-02-24 12:20:46 -0700330
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000331 return true;
Junxiao Shi4370fde2016-02-24 12:20:46 -0700332
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000333 }
334
335 return false;
Junxiao Shi4370fde2016-02-24 12:20:46 -0700336}
337
HYuana9b85752014-02-26 02:32:30 -0600338// Exact Match
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000339shared_ptr<Entry>
HYuana9b85752014-02-26 02:32:30 -0600340NameTree::findExactMatch(const Name& prefix) const
341{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700342 NFD_LOG_TRACE("findExactMatch " << prefix);
HYuana9b85752014-02-26 02:32:30 -0600343
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000344 size_t hashValue = computeHash(prefix);
Haowei Yuanf52dac72014-03-24 23:35:03 -0500345 size_t loc = hashValue % m_nBuckets;
HYuana9b85752014-02-26 02:32:30 -0600346
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000347 NFD_LOG_TRACE("Name " << prefix << " hash value = " << hashValue << " location = " << loc);
HYuana9b85752014-02-26 02:32:30 -0600348
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000349 shared_ptr<Entry> entry;
350 Node* node = nullptr;
HYuana9b85752014-02-26 02:32:30 -0600351
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000352 for (node = m_buckets[loc]; node != nullptr; node = node->m_next) {
353 entry = node->m_entry;
354 if (entry != nullptr) {
355 if (hashValue == entry->getHash() && prefix == entry->getPrefix()) {
356 return entry;
357 }
358 }
359 }
HYuana9b85752014-02-26 02:32:30 -0600360
361 // if not found, the default value of entry (null pointer) will be returned
362 entry.reset();
363 return entry;
364}
365
366// Longest Prefix Match
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000367shared_ptr<Entry>
368NameTree::findLongestPrefixMatch(const Name& prefix, const EntrySelector& entrySelector) const
HYuana9b85752014-02-26 02:32:30 -0600369{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700370 NFD_LOG_TRACE("findLongestPrefixMatch " << prefix);
HYuana9b85752014-02-26 02:32:30 -0600371
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000372 shared_ptr<Entry> entry;
373 std::vector<size_t> hashValueSet = computeHashSet(prefix);
HYuana9b85752014-02-26 02:32:30 -0600374
Haowei Yuanf52dac72014-03-24 23:35:03 -0500375 size_t hashValue = 0;
376 size_t loc = 0;
377
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000378 for (int i = static_cast<int>(prefix.size()); i >= 0; --i) {
379 hashValue = hashValueSet[i];
380 loc = hashValue % m_nBuckets;
Haowei Yuanf52dac72014-03-24 23:35:03 -0500381
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000382 Node* node = nullptr;
383 for (node = m_buckets[loc]; node != nullptr; node = node->m_next) {
384 entry = node->m_entry;
385 if (entry != nullptr) {
386 // isPrefixOf() is used to avoid making a copy of the name
387 if (hashValue == entry->getHash() &&
388 entry->getPrefix().isPrefixOf(prefix) &&
389 entrySelector(*entry)) {
390 return entry;
391 }
392 }
HYuana9b85752014-02-26 02:32:30 -0600393 }
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000394 }
HYuana9b85752014-02-26 02:32:30 -0600395
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000396 return nullptr;
HYuana9b85752014-02-26 02:32:30 -0600397}
398
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000399shared_ptr<Entry>
400NameTree::findLongestPrefixMatch(shared_ptr<Entry> entry,
401 const EntrySelector& entrySelector) const
HangZhangcb4fc832014-03-11 16:57:11 +0800402{
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000403 while (entry != nullptr) {
404 if (entrySelector(*entry)) {
405 return entry;
HangZhangcb4fc832014-03-11 16:57:11 +0800406 }
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000407 entry = entry->getParent();
408 }
409 return nullptr;
HangZhangcb4fc832014-03-11 16:57:11 +0800410}
411
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000412shared_ptr<Entry>
Junxiao Shi4370fde2016-02-24 12:20:46 -0700413NameTree::findLongestPrefixMatch(const pit::Entry& pitEntry) const
HYuana9b85752014-02-26 02:32:30 -0600414{
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000415 shared_ptr<Entry> nte = this->getEntry(pitEntry);
Junxiao Shib184e532016-05-26 18:09:57 +0000416 BOOST_ASSERT(nte != nullptr);
Junxiao Shi4370fde2016-02-24 12:20:46 -0700417 if (nte->getPrefix().size() == pitEntry.getName().size()) {
418 return nte;
419 }
HYuana9b85752014-02-26 02:32:30 -0600420
Junxiao Shi4370fde2016-02-24 12:20:46 -0700421 BOOST_ASSERT(pitEntry.getName().at(-1).isImplicitSha256Digest());
422 BOOST_ASSERT(nte->getPrefix() == pitEntry.getName().getPrefix(-1));
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000423 shared_ptr<Entry> exact = this->findExactMatch(pitEntry.getName());
Junxiao Shi4370fde2016-02-24 12:20:46 -0700424 return exact == nullptr ? nte : exact;
425}
HYuana9b85752014-02-26 02:32:30 -0600426
Junxiao Shi4370fde2016-02-24 12:20:46 -0700427boost::iterator_range<NameTree::const_iterator>
428NameTree::findAllMatches(const Name& prefix,
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000429 const EntrySelector& entrySelector) const
Junxiao Shi4370fde2016-02-24 12:20:46 -0700430{
431 NFD_LOG_TRACE("NameTree::findAllMatches" << prefix);
HYuana9b85752014-02-26 02:32:30 -0600432
Junxiao Shi4370fde2016-02-24 12:20:46 -0700433 // As we are using Name Prefix Hash Table, and the current LPM() is
434 // implemented as starting from full name, and reduce the number of
435 // components by 1 each time, we could use it here.
436 // For trie-like design, it could be more efficient by walking down the
437 // trie from the root node.
HYuana9b85752014-02-26 02:32:30 -0600438
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000439 shared_ptr<Entry> entry = findLongestPrefixMatch(prefix, entrySelector);
HYuana9b85752014-02-26 02:32:30 -0600440
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000441 if (entry != nullptr) {
Junxiao Shi4370fde2016-02-24 12:20:46 -0700442 const_iterator begin(FIND_ALL_MATCHES_TYPE, *this, entry, entrySelector);
443 return {begin, end()};
444 }
445 // If none of the entry satisfies the requirements, then return the end() iterator.
446 return {end(), end()};
HYuana9b85752014-02-26 02:32:30 -0600447}
448
Junxiao Shi5ccd0c22014-12-02 23:54:42 -0700449boost::iterator_range<NameTree::const_iterator>
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000450NameTree::fullEnumerate(const EntrySelector& entrySelector) const
HYuana9b85752014-02-26 02:32:30 -0600451{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700452 NFD_LOG_TRACE("fullEnumerate");
HYuana9b85752014-02-26 02:32:30 -0600453
Haowei Yuane1079fc2014-03-08 14:41:25 -0600454 // find the first eligible entry
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000455 for (size_t i = 0; i < m_nBuckets; ++i) {
456 for (Node* node = m_buckets[i]; node != nullptr; node = node->m_next) {
457 if (node->m_entry != nullptr && entrySelector(*node->m_entry)) {
Junxiao Shi60607c72014-11-26 22:40:36 -0700458 const_iterator it(FULL_ENUMERATE_TYPE, *this, node->m_entry, entrySelector);
459 return {it, end()};
460 }
Haowei Yuane1079fc2014-03-08 14:41:25 -0600461 }
Junxiao Shi60607c72014-11-26 22:40:36 -0700462 }
Haowei Yuane1079fc2014-03-08 14:41:25 -0600463
464 // If none of the entry satisfies the requirements, then return the end() iterator.
Junxiao Shi60607c72014-11-26 22:40:36 -0700465 return {end(), end()};
Haowei Yuane1079fc2014-03-08 14:41:25 -0600466}
467
Junxiao Shi5ccd0c22014-12-02 23:54:42 -0700468boost::iterator_range<NameTree::const_iterator>
Haowei Yuane1079fc2014-03-08 14:41:25 -0600469NameTree::partialEnumerate(const Name& prefix,
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000470 const EntrySubTreeSelector& entrySubTreeSelector) const
Haowei Yuane1079fc2014-03-08 14:41:25 -0600471{
472 // the first step is to process the root node
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000473 shared_ptr<Entry> entry = findExactMatch(prefix);
474 if (entry == nullptr) {
Junxiao Shi60607c72014-11-26 22:40:36 -0700475 return {end(), end()};
476 }
Haowei Yuane1079fc2014-03-08 14:41:25 -0600477
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000478 std::pair<bool, bool> result = entrySubTreeSelector(*entry);
Haowei Yuane1079fc2014-03-08 14:41:25 -0600479 const_iterator it(PARTIAL_ENUMERATE_TYPE,
480 *this,
481 entry,
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000482 AnyEntry(),
Haowei Yuane1079fc2014-03-08 14:41:25 -0600483 entrySubTreeSelector);
484
485 it.m_shouldVisitChildren = (result.second && entry->hasChildren());
486
Junxiao Shi60607c72014-11-26 22:40:36 -0700487 if (result.first) {
488 // root node is acceptable
489 }
490 else {
491 // let the ++ operator handle it
492 ++it;
493 }
494 return {it, end()};
HYuana9b85752014-02-26 02:32:30 -0600495}
496
HYuana9b85752014-02-26 02:32:30 -0600497// Hash Table Resize
498void
499NameTree::resize(size_t newNBuckets)
500{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700501 NFD_LOG_TRACE("resize");
HYuana9b85752014-02-26 02:32:30 -0600502
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000503 Node** newBuckets = new Node*[newNBuckets];
Junxiao Shi40631842014-03-01 13:52:37 -0700504 size_t count = 0;
HYuana9b85752014-02-26 02:32:30 -0600505
506 // referenced ccnx hashtb.c hashtb_rehash()
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000507 Node** pp = nullptr;
508 Node* p = nullptr;
509 Node* pre = nullptr;
510 Node* q = nullptr; // record p->m_next
HYuana9b85752014-02-26 02:32:30 -0600511
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000512 for (size_t i = 0; i < newNBuckets; ++i) {
513 newBuckets[i] = nullptr;
514 }
HYuana9b85752014-02-26 02:32:30 -0600515
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000516 for (size_t i = 0; i < m_nBuckets; ++i) {
517 for (p = m_buckets[i]; p != nullptr; p = q) {
518 ++count;
519 q = p->m_next;
520 BOOST_ASSERT(p->m_entry != nullptr);
521 uint32_t h = p->m_entry->m_hash;
522 uint32_t b = h % newNBuckets;
523 pre = nullptr;
524 for (pp = &newBuckets[b]; *pp != nullptr; pp = &((*pp)->m_next)) {
525 pre = *pp;
526 }
527 p->m_prev = pre;
528 p->m_next = *pp; // Actually *pp always == nullptr in this case
529 *pp = p;
HYuana9b85752014-02-26 02:32:30 -0600530 }
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000531 }
HYuana9b85752014-02-26 02:32:30 -0600532
533 BOOST_ASSERT(count == m_nItems);
534
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000535 Node** oldBuckets = m_buckets;
HYuana9b85752014-02-26 02:32:30 -0600536 m_buckets = newBuckets;
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000537 delete[] oldBuckets;
HYuana9b85752014-02-26 02:32:30 -0600538
539 m_nBuckets = newNBuckets;
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000540 m_enlargeThreshold = static_cast<size_t>(m_enlargeLoadFactor * static_cast<double>(m_nBuckets));
541 m_shrinkThreshold = static_cast<size_t>(m_shrinkLoadFactor * static_cast<double>(m_nBuckets));
HYuana9b85752014-02-26 02:32:30 -0600542}
543
544// For debugging
545void
Haowei Yuane1079fc2014-03-08 14:41:25 -0600546NameTree::dump(std::ostream& output) const
HYuana9b85752014-02-26 02:32:30 -0600547{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700548 NFD_LOG_TRACE("dump()");
HYuana9b85752014-02-26 02:32:30 -0600549
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000550 Node* node = nullptr;
551 shared_ptr<Entry> entry;
HYuana9b85752014-02-26 02:32:30 -0600552
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000553 for (size_t i = 0; i < m_nBuckets; ++i) {
554 for (node = m_buckets[i]; node != nullptr; node = node->m_next) {
555 entry = node->m_entry;
HYuana9b85752014-02-26 02:32:30 -0600556
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000557 // if the Entry exist, dump its information
558 if (entry != nullptr) {
559 output << "Bucket" << i << '\t' << entry->m_prefix.toUri() << '\n';
560 output << "\t\tHash " << entry->m_hash << '\n';
HYuana9b85752014-02-26 02:32:30 -0600561
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000562 if (entry->m_parent != nullptr) {
563 output << "\t\tparent->" << entry->m_parent->m_prefix.toUri();
564 }
565 else {
566 output << "\t\tROOT";
567 }
568 output << '\n';
HYuana9b85752014-02-26 02:32:30 -0600569
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000570 if (!entry->m_children.empty()) {
571 output << "\t\tchildren = " << entry->m_children.size() << '\n';
HYuana9b85752014-02-26 02:32:30 -0600572
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000573 for (size_t j = 0; j < entry->m_children.size(); ++j) {
574 output << "\t\t\tChild " << j << " " << entry->m_children[j]->getPrefix() << '\n';
575 }
576 }
HYuana9b85752014-02-26 02:32:30 -0600577
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000578 }
HYuana9b85752014-02-26 02:32:30 -0600579
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000580 }
581 }
HYuana9b85752014-02-26 02:32:30 -0600582
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000583 output << "Bucket count = " << m_nBuckets << '\n';
584 output << "Stored item = " << m_nItems << '\n';
HYuana9b85752014-02-26 02:32:30 -0600585 output << "--------------------------\n";
586}
587
Alexander Afanasyev09fc3d92015-01-03 02:02:37 -0800588NameTree::const_iterator::const_iterator()
589 : m_nameTree(nullptr)
590{
591}
592
Haowei Yuane1079fc2014-03-08 14:41:25 -0600593NameTree::const_iterator::const_iterator(NameTree::IteratorType type,
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000594 const NameTree& nameTree,
595 shared_ptr<Entry> entry,
596 const EntrySelector& entrySelector,
597 const EntrySubTreeSelector& entrySubTreeSelector)
Alexander Afanasyev09fc3d92015-01-03 02:02:37 -0800598 : m_nameTree(&nameTree)
Haowei Yuane1079fc2014-03-08 14:41:25 -0600599 , m_entry(entry)
600 , m_subTreeRoot(entry)
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000601 , m_entrySelector(make_shared<EntrySelector>(entrySelector))
602 , m_entrySubTreeSelector(make_shared<EntrySubTreeSelector>(entrySubTreeSelector))
Haowei Yuane1079fc2014-03-08 14:41:25 -0600603 , m_type(type)
604 , m_shouldVisitChildren(true)
605{
606}
607
608// operator++()
609NameTree::const_iterator
610NameTree::const_iterator::operator++()
611{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700612 NFD_LOG_TRACE("const_iterator::operator++()");
Haowei Yuane1079fc2014-03-08 14:41:25 -0600613
Alexander Afanasyev09fc3d92015-01-03 02:02:37 -0800614 BOOST_ASSERT(m_entry != m_nameTree->m_end);
Haowei Yuane1079fc2014-03-08 14:41:25 -0600615
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000616 if (m_type == FULL_ENUMERATE_TYPE) {
617 // process the entries in the same bucket first
618 while (m_entry->m_node->m_next != nullptr) {
619 m_entry = m_entry->m_node->m_next->m_entry;
620 if ((*m_entrySelector)(*m_entry)) {
621 return *this;
622 }
Haowei Yuane1079fc2014-03-08 14:41:25 -0600623 }
624
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000625 // process other buckets
626
627 for (int newLocation = m_entry->m_hash % m_nameTree->m_nBuckets + 1;
628 newLocation < static_cast<int>(m_nameTree->m_nBuckets);
629 ++newLocation) {
630 // process each bucket
631 Node* node = m_nameTree->m_buckets[newLocation];
632 while (node != nullptr) {
633 m_entry = node->m_entry;
634 if ((*m_entrySelector)(*m_entry)) {
635 return *this;
Haowei Yuane1079fc2014-03-08 14:41:25 -0600636 }
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000637 node = node->m_next;
638 }
Haowei Yuane1079fc2014-03-08 14:41:25 -0600639 }
640
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000641 // Reach the end()
642 m_entry = m_nameTree->m_end;
643 return *this;
644 }
Haowei Yuane1079fc2014-03-08 14:41:25 -0600645
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000646 if (m_type == PARTIAL_ENUMERATE_TYPE) {
647 // We use pre-order traversal.
648 // if at the root, it could have already been accepted, or this
649 // iterator was just declared, and root doesn't satisfy the
650 // requirement
651 // The if() section handles this special case
652 // Essentially, we need to check root's fist child, and the rest will
653 // be the same as normal process
654 if (m_entry == m_subTreeRoot) {
655 if (m_shouldVisitChildren) {
656 m_entry = m_entry->getChildren()[0];
657 std::pair<bool, bool> result = ((*m_entrySubTreeSelector)(*m_entry));
658 m_shouldVisitChildren = (result.second && m_entry->hasChildren());
659 if (result.first) {
660 return *this;
661 }
662 else {
663 // the first child did not meet the requirement
664 // the rest of the process can just fall through the while loop as normal
665 }
666 }
667 else {
668 // no children, should return end();
669 // just fall through
670 }
671 }
672
673 // The first thing to do is to visit its child, or go to find its possible siblings
674 while (m_entry != m_subTreeRoot) {
675 if (m_shouldVisitChildren) {
676 // If this subtree should be visited
677 m_entry = m_entry->getChildren()[0];
678 std::pair<bool, bool> result = ((*m_entrySubTreeSelector)(*m_entry));
679 m_shouldVisitChildren = (result.second && m_entry->hasChildren());
680 if (result.first) { // if this node is acceptable
681 return *this;
682 }
683 else {
684 // do nothing, as this node is essentially ignored
685 // send this node to the while loop.
686 }
687 }
688 else {
689 // Should try to find its sibling
690 shared_ptr<Entry> parent = m_entry->getParent();
691
692 std::vector<shared_ptr<Entry>>& parentChildrenList = parent->getChildren();
693 bool isFound = false;
694 size_t i = 0;
695 for (i = 0; i < parentChildrenList.size(); ++i) {
696 if (parentChildrenList[i] == m_entry) {
697 isFound = true;
698 break;
699 }
700 }
701
702 BOOST_VERIFY(isFound == true);
703 if (i < parentChildrenList.size() - 1) { // m_entry not the last child
704 m_entry = parentChildrenList[i + 1];
705 std::pair<bool, bool> result = ((*m_entrySubTreeSelector)(*m_entry));
706 m_shouldVisitChildren = (result.second && m_entry->hasChildren());
707 if (result.first) { // if this node is acceptable
Haowei Yuane1079fc2014-03-08 14:41:25 -0600708 return *this;
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000709 }
710 else {
711 // do nothing, as this node is essentially ignored
712 // send this node to the while loop.
713 }
Haowei Yuane1079fc2014-03-08 14:41:25 -0600714 }
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000715 else {
716 // m_entry is the last child, no more sibling, should try to find parent's sibling
717 m_shouldVisitChildren = false;
718 m_entry = parent;
719 }
720 }
Haowei Yuane1079fc2014-03-08 14:41:25 -0600721 }
Junxiao Shiefceadc2014-03-09 18:52:57 -0700722
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000723 m_entry = m_nameTree->m_end;
724 return *this;
725 }
726
727 if (m_type == FIND_ALL_MATCHES_TYPE) {
728 // Assumption: at the beginning, m_entry was initialized with the first
729 // eligible Name Tree entry (i.e., has a PIT entry that can be satisfied
730 // by the Data packet)
731
732 while (m_entry->getParent() != nullptr) {
733 m_entry = m_entry->getParent();
734 if ((*m_entrySelector)(*m_entry)) {
735 return *this;
736 }
737 }
738
739 // Reach to the end (Root)
740 m_entry = m_nameTree->m_end;
741 return *this;
742 }
743
Junxiao Shiefceadc2014-03-09 18:52:57 -0700744 BOOST_ASSERT(false); // unknown type
745 return *this;
Haowei Yuane1079fc2014-03-08 14:41:25 -0600746}
747
Junxiao Shi2570f3e2016-07-27 02:48:29 +0000748} // namespace name_tree
HYuana9b85752014-02-26 02:32:30 -0600749} // namespace nfd