blob: 1654bb210d9c9ed827b4501b29368b1d01f781ba [file] [log] [blame]
Junxiao Shi0fcb41e2014-01-24 10:29:43 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Steve DiBenedetto3a4f83d2014-06-02 14:58:54 -06003 * Copyright (c) 2014, Regents of the University of California,
4 * 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
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080010 *
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -070011 * 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/>.
24 *
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -070025 * \author Ilya Moiseenko <http://ilyamoiseenko.com/>
26 * \author Junxiao Shi <http://www.cs.arizona.edu/people/shijunxiao/>
27 * \author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070028 */
29
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070030#include "cs.hpp"
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060031#include "core/logger.hpp"
Junxiao Shiaf6569a2014-06-14 00:01:34 -070032#include "core/random.hpp"
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -070033
Alexander Afanasyev4a771362014-04-24 21:29:33 -070034#include <ndn-cxx/util/crypto.hpp>
Junxiao Shiaf6569a2014-06-14 00:01:34 -070035#include <ndn-cxx/security/signature-sha256-with-rsa.hpp>
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -070036
Junxiao Shiaf6569a2014-06-14 00:01:34 -070037#include <boost/random/bernoulli_distribution.hpp>
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080038
Junxiao Shiaf6569a2014-06-14 00:01:34 -070039/// max skip list layers
40static const size_t SKIPLIST_MAX_LAYERS = 32;
41/// probability for an entry in layer N to appear also in layer N+1
42static const double SKIPLIST_PROBABILITY = 0.25;
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080043
44NFD_LOG_INIT("ContentStore");
Alexander Afanasyevb927a3a2014-01-24 10:41:47 -080045
Alexander Afanasyev18bbf812014-01-29 01:40:23 -080046namespace nfd {
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070047
Steve DiBenedetto3a4f83d2014-06-02 14:58:54 -060048Cs::Cs(size_t nMaxPackets)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080049 : m_nMaxPackets(nMaxPackets)
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040050 , m_nPackets(0)
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070051{
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080052 SkipListLayer* zeroLayer = new SkipListLayer();
53 m_skipList.push_back(zeroLayer);
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040054
55 for (size_t i = 0; i < m_nMaxPackets; i++)
56 m_freeCsEntries.push(new cs::Entry());
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070057}
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080058
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070059Cs::~Cs()
60{
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040061 // evict all items from CS
62 while (evictItem())
63 ;
64
65 BOOST_ASSERT(m_freeCsEntries.size() == m_nMaxPackets);
66
67 while (!m_freeCsEntries.empty())
68 {
69 delete m_freeCsEntries.front();
70 m_freeCsEntries.pop();
71 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080072}
73
74size_t
75Cs::size() const
76{
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040077 return m_nPackets; // size of the first layer in a skip list
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080078}
79
80void
81Cs::setLimit(size_t nMaxPackets)
82{
Alexander Afanasyev281b9162014-06-08 10:15:20 +030083 size_t oldNMaxPackets = m_nMaxPackets;
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080084 m_nMaxPackets = nMaxPackets;
85
Alexander Afanasyev281b9162014-06-08 10:15:20 +030086 while (size() > m_nMaxPackets) {
87 evictItem();
88 }
89
90 if (m_nMaxPackets >= oldNMaxPackets) {
91 for (size_t i = oldNMaxPackets; i < m_nMaxPackets; i++) {
92 m_freeCsEntries.push(new cs::Entry());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080093 }
Alexander Afanasyev281b9162014-06-08 10:15:20 +030094 }
95 else {
96 for (size_t i = oldNMaxPackets; i > m_nMaxPackets; i--) {
97 delete m_freeCsEntries.front();
98 m_freeCsEntries.pop();
99 }
100 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800101}
102
103size_t
104Cs::getLimit() const
105{
106 return m_nMaxPackets;
107}
108
109//Reference: "Skip Lists: A Probabilistic Alternative to Balanced Trees" by W.Pugh
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400110std::pair<cs::Entry*, bool>
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800111Cs::insertToSkipList(const Data& data, bool isUnsolicited)
112{
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700113 NFD_LOG_TRACE("insertToSkipList() " << data.getFullName() << ", "
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700114 << "skipList size " << size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800115
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400116 BOOST_ASSERT(m_cleanupIndex.size() <= size());
117 BOOST_ASSERT(m_freeCsEntries.size() > 0);
118
119 // take entry for the memory pool
120 cs::Entry* entry = m_freeCsEntries.front();
121 m_freeCsEntries.pop();
122 m_nPackets++;
123 entry->setData(data, isUnsolicited);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800124
125 bool insertInFront = false;
126 bool isIterated = false;
127 SkipList::reverse_iterator topLayer = m_skipList.rbegin();
128 SkipListLayer::iterator updateTable[SKIPLIST_MAX_LAYERS];
129 SkipListLayer::iterator head = (*topLayer)->begin();
130
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400131 if (!(*topLayer)->empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800132 {
133 //start from the upper layer towards bottom
134 int layer = m_skipList.size() - 1;
135 for (SkipList::reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
136 {
137 //if we didn't do any iterations on the higher layers, start from the begin() again
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400138 if (!isIterated)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800139 head = (*rit)->begin();
140
141 updateTable[layer] = head;
142
143 if (head != (*rit)->end())
144 {
145 // it can happen when begin() contains the element in front of which we need to insert
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700146 if (!isIterated && ((*head)->getFullName() >= entry->getFullName()))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800147 {
148 --updateTable[layer];
149 insertInFront = true;
150 }
151 else
152 {
153 SkipListLayer::iterator it = head;
154
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700155 while ((*it)->getFullName() < entry->getFullName())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800156 {
157 head = it;
158 updateTable[layer] = it;
159 isIterated = true;
160
161 ++it;
162 if (it == (*rit)->end())
163 break;
164 }
165 }
166 }
167
168 if (layer > 0)
169 head = (*head)->getIterators().find(layer - 1)->second; // move HEAD to the lower layer
170
171 layer--;
172 }
173 }
174 else
175 {
176 updateTable[0] = (*topLayer)->begin(); //initialization
177 }
178
179 head = updateTable[0];
180 ++head; // look at the next slot to check if it contains a duplicate
181
182 bool isCsEmpty = (size() == 0);
183 bool isInBoundaries = (head != (*m_skipList.begin())->end());
184 bool isNameIdentical = false;
185 if (!isCsEmpty && isInBoundaries)
186 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700187 isNameIdentical = (*head)->getFullName() == entry->getFullName();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800188 }
189
190 //check if this is a duplicate packet
191 if (isNameIdentical)
192 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700193 NFD_LOG_TRACE("Duplicate name (with digest)");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800194
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700195 (*head)->setData(data, isUnsolicited); //updates stale time
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800196
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400197 // new entry not needed, returning to the pool
198 entry->release();
199 m_freeCsEntries.push(entry);
200 m_nPackets--;
201
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800202 return std::make_pair(*head, false);
203 }
204
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700205 NFD_LOG_TRACE("Not a duplicate");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800206
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700207 size_t randomLayer = pickRandomLayer();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800208
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400209 while (m_skipList.size() < randomLayer + 1)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800210 {
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700211 SkipListLayer* newLayer = new SkipListLayer();
212 m_skipList.push_back(newLayer);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800213
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700214 updateTable[(m_skipList.size() - 1)] = newLayer->begin();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800215 }
216
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700217 size_t layer = 0;
218 for (SkipList::iterator i = m_skipList.begin();
219 i != m_skipList.end() && layer <= randomLayer; ++i)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800220 {
221 if (updateTable[layer] == (*i)->end() && !insertInFront)
222 {
223 (*i)->push_back(entry);
224 SkipListLayer::iterator last = (*i)->end();
225 --last;
226 entry->setIterator(layer, last);
227
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700228 NFD_LOG_TRACE("pushback " << &(*last));
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800229 }
230 else if (updateTable[layer] == (*i)->end() && insertInFront)
231 {
232 (*i)->push_front(entry);
233 entry->setIterator(layer, (*i)->begin());
234
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700235 NFD_LOG_TRACE("pushfront ");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800236 }
237 else
238 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700239 NFD_LOG_TRACE("insertafter");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800240 ++updateTable[layer]; // insert after
241 SkipListLayer::iterator position = (*i)->insert(updateTable[layer], entry);
242 entry->setIterator(layer, position); // save iterator where item was inserted
243 }
244 layer++;
245 }
246
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800247 return std::make_pair(entry, true);
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700248}
249
250bool
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800251Cs::insert(const Data& data, bool isUnsolicited)
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700252{
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700253 NFD_LOG_TRACE("insert() " << data.getFullName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800254
255 if (isFull())
256 {
257 evictItem();
258 }
259
260 //pointer and insertion status
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400261 std::pair<cs::Entry*, bool> entry = insertToSkipList(data, isUnsolicited);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800262
263 //new entry
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400264 if (static_cast<bool>(entry.first) && (entry.second == true))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800265 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400266 m_cleanupIndex.push_back(entry.first);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800267 return true;
268 }
269
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700270 return false;
271}
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800272
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700273size_t
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800274Cs::pickRandomLayer() const
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700275{
Junxiao Shiaf6569a2014-06-14 00:01:34 -0700276 static boost::random::bernoulli_distribution<> dist(SKIPLIST_PROBABILITY);
277 // TODO rewrite using geometry_distribution
278 size_t layer;
279 for (layer = 0; layer < SKIPLIST_MAX_LAYERS; ++layer) {
280 if (!dist(getGlobalRng())) {
281 break;
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800282 }
Junxiao Shiaf6569a2014-06-14 00:01:34 -0700283 }
284 return layer;
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800285}
286
287bool
288Cs::isFull() const
289{
290 if (size() >= m_nMaxPackets) //size of the first layer vs. max size
291 return true;
292
293 return false;
294}
295
296bool
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400297Cs::eraseFromSkipList(cs::Entry* entry)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800298{
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700299 NFD_LOG_TRACE("eraseFromSkipList() " << entry->getFullName());
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700300 NFD_LOG_TRACE("SkipList size " << size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800301
302 bool isErased = false;
303
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400304 const std::map<int, std::list<cs::Entry*>::iterator>& iterators = entry->getIterators();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800305
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400306 if (!iterators.empty())
307 {
308 int layer = 0;
309
310 for (SkipList::iterator it = m_skipList.begin(); it != m_skipList.end(); )
311 {
312 std::map<int, std::list<cs::Entry*>::iterator>::const_iterator i = iterators.find(layer);
313
314 if (i != iterators.end())
315 {
316 (*it)->erase(i->second);
317 entry->removeIterator(layer);
318 isErased = true;
319
320 //remove layers that do not contain any elements (starting from the second layer)
321 if ((layer != 0) && (*it)->empty())
322 {
323 delete *it;
324 it = m_skipList.erase(it);
325 }
326 else
327 ++it;
328
329 layer++;
330 }
331 else
332 break;
333 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800334 }
335
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400336 //delete entry;
337 if (isErased)
338 {
339 entry->release();
340 m_freeCsEntries.push(entry);
341 m_nPackets--;
342 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800343
344 return isErased;
345}
346
347bool
348Cs::evictItem()
349{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700350 NFD_LOG_TRACE("evictItem()");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800351
Alexander Afanasyev4cf41702014-10-19 23:46:10 -0400352 if (!m_cleanupIndex.get<unsolicited>().empty()) {
353 CleanupIndex::index<unsolicited>::type::const_iterator firstSolicited =
354 m_cleanupIndex.get<unsolicited>().upper_bound(false);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800355
Alexander Afanasyev4cf41702014-10-19 23:46:10 -0400356 if (firstSolicited != m_cleanupIndex.get<unsolicited>().begin()) {
357 --firstSolicited;
358 BOOST_ASSERT((*firstSolicited)->isUnsolicited());
359 NFD_LOG_TRACE("Evict from unsolicited queue");
360
361 eraseFromSkipList(*firstSolicited);
362 m_cleanupIndex.get<unsolicited>().erase(firstSolicited);
363 return true;
364 }
365 else {
366 BOOST_ASSERT(!(*m_cleanupIndex.get<unsolicited>().begin())->isUnsolicited());
367 }
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400368 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800369
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400370 if (!m_cleanupIndex.get<byStaleness>().empty() &&
371 (*m_cleanupIndex.get<byStaleness>().begin())->getStaleTime() < time::steady_clock::now())
372 {
373 NFD_LOG_TRACE("Evict from staleness queue");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800374
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400375 eraseFromSkipList(*m_cleanupIndex.get<byStaleness>().begin());
376 m_cleanupIndex.get<byStaleness>().erase(m_cleanupIndex.get<byStaleness>().begin());
377 return true;
378 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800379
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400380 if (!m_cleanupIndex.get<byArrival>().empty())
381 {
382 NFD_LOG_TRACE("Evict from arrival queue");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800383
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400384 eraseFromSkipList(*m_cleanupIndex.get<byArrival>().begin());
385 m_cleanupIndex.get<byArrival>().erase(m_cleanupIndex.get<byArrival>().begin());
386 return true;
387 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800388
389 return false;
390}
391
392const Data*
393Cs::find(const Interest& interest) const
394{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700395 NFD_LOG_TRACE("find() " << interest.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800396
397 bool isIterated = false;
398 SkipList::const_reverse_iterator topLayer = m_skipList.rbegin();
399 SkipListLayer::iterator head = (*topLayer)->begin();
400
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400401 if (!(*topLayer)->empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800402 {
403 //start from the upper layer towards bottom
404 int layer = m_skipList.size() - 1;
405 for (SkipList::const_reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
406 {
407 //if we didn't do any iterations on the higher layers, start from the begin() again
408 if (!isIterated)
409 head = (*rit)->begin();
410
411 if (head != (*rit)->end())
412 {
413 // it happens when begin() contains the element we want to find
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700414 if (!isIterated && (interest.getName().isPrefixOf((*head)->getFullName())))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800415 {
416 if (layer > 0)
417 {
418 layer--;
419 continue; // try lower layer
420 }
421 else
422 {
423 isIterated = true;
424 }
425 }
426 else
427 {
428 SkipListLayer::iterator it = head;
429
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700430 while ((*it)->getFullName() < interest.getName())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800431 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700432 NFD_LOG_TRACE((*it)->getFullName() << " < " << interest.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800433 head = it;
434 isIterated = true;
435
436 ++it;
437 if (it == (*rit)->end())
438 break;
439 }
440 }
441 }
442
443 if (layer > 0)
444 {
445 head = (*head)->getIterators().find(layer - 1)->second; // move HEAD to the lower layer
446 }
447 else //if we reached the first layer
448 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400449 if (isIterated)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800450 return selectChild(interest, head);
451 }
452
453 layer--;
454 }
455 }
456
Alexander Afanasyevc9765df2014-01-25 19:24:27 -0800457 return 0;
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700458}
459
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800460const Data*
461Cs::selectChild(const Interest& interest, SkipListLayer::iterator startingPoint) const
462{
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400463 BOOST_ASSERT(startingPoint != (*m_skipList.begin())->end());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800464
465 if (startingPoint != (*m_skipList.begin())->begin())
466 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700467 BOOST_ASSERT((*startingPoint)->getFullName() < interest.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800468 }
469
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400470 NFD_LOG_TRACE("selectChild() " << interest.getChildSelector() << " "
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700471 << (*startingPoint)->getFullName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800472
473 bool hasLeftmostSelector = (interest.getChildSelector() <= 0);
474 bool hasRightmostSelector = !hasLeftmostSelector;
475
476 if (hasLeftmostSelector)
477 {
478 bool doesInterestContainDigest = recognizeInterestWithDigest(interest, *startingPoint);
479 bool isInPrefix = false;
480
481 if (doesInterestContainDigest)
482 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700483 isInPrefix = interest.getName().getPrefix(-1).isPrefixOf((*startingPoint)->getFullName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800484 }
485 else
486 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700487 isInPrefix = interest.getName().isPrefixOf((*startingPoint)->getFullName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800488 }
489
490 if (isInPrefix)
491 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400492 if (doesComplyWithSelectors(interest, *startingPoint, doesInterestContainDigest))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800493 {
494 return &(*startingPoint)->getData();
495 }
496 }
497 }
498
499 //iterate to the right
500 SkipListLayer::iterator rightmost = startingPoint;
501 if (startingPoint != (*m_skipList.begin())->end())
502 {
503 SkipListLayer::iterator rightmostCandidate = startingPoint;
504 Name currentChildPrefix("");
505
506 while (true)
507 {
508 ++rightmostCandidate;
509
510 bool isInBoundaries = (rightmostCandidate != (*m_skipList.begin())->end());
511 bool isInPrefix = false;
512 bool doesInterestContainDigest = false;
513 if (isInBoundaries)
514 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400515 doesInterestContainDigest = recognizeInterestWithDigest(interest,
516 *rightmostCandidate);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800517
518 if (doesInterestContainDigest)
519 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400520 isInPrefix = interest.getName().getPrefix(-1)
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700521 .isPrefixOf((*rightmostCandidate)->getFullName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800522 }
523 else
524 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700525 isInPrefix = interest.getName().isPrefixOf((*rightmostCandidate)->getFullName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800526 }
527 }
528
529 if (isInPrefix)
530 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400531 if (doesComplyWithSelectors(interest, *rightmostCandidate, doesInterestContainDigest))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800532 {
533 if (hasLeftmostSelector)
534 {
535 return &(*rightmostCandidate)->getData();
536 }
537
538 if (hasRightmostSelector)
539 {
540 if (doesInterestContainDigest)
541 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400542 // get prefix which is one component longer than Interest name
543 // (without digest)
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700544 const Name& childPrefix = (*rightmostCandidate)->getFullName()
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400545 .getPrefix(interest.getName().size());
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700546 NFD_LOG_TRACE("Child prefix" << childPrefix);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800547
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400548 if (currentChildPrefix.empty() || (childPrefix != currentChildPrefix))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800549 {
550 currentChildPrefix = childPrefix;
551 rightmost = rightmostCandidate;
552 }
553 }
554 else
555 {
556 // get prefix which is one component longer than Interest name
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700557 const Name& childPrefix = (*rightmostCandidate)->getFullName()
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400558 .getPrefix(interest.getName().size() + 1);
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700559 NFD_LOG_TRACE("Child prefix" << childPrefix);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800560
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400561 if (currentChildPrefix.empty() || (childPrefix != currentChildPrefix))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800562 {
563 currentChildPrefix = childPrefix;
564 rightmost = rightmostCandidate;
565 }
566 }
567 }
568 }
569 }
570 else
571 break;
572 }
573 }
574
575 if (rightmost != startingPoint)
576 {
577 return &(*rightmost)->getData();
578 }
579
580 if (hasRightmostSelector) // if rightmost was not found, try starting point
581 {
582 bool doesInterestContainDigest = recognizeInterestWithDigest(interest, *startingPoint);
583 bool isInPrefix = false;
584
585 if (doesInterestContainDigest)
586 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700587 isInPrefix = interest.getName().getPrefix(-1).isPrefixOf((*startingPoint)->getFullName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800588 }
589 else
590 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700591 isInPrefix = interest.getName().isPrefixOf((*startingPoint)->getFullName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800592 }
593
594 if (isInPrefix)
595 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400596 if (doesComplyWithSelectors(interest, *startingPoint, doesInterestContainDigest))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800597 {
598 return &(*startingPoint)->getData();
599 }
600 }
601 }
602
603 return 0;
604}
605
606bool
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400607Cs::doesComplyWithSelectors(const Interest& interest,
608 cs::Entry* entry,
609 bool doesInterestContainDigest) const
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800610{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700611 NFD_LOG_TRACE("doesComplyWithSelectors()");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800612
613 /// \todo The following detection is not correct
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700614 /// 1. If Interest name ends with 32-octet component doesn't mean that this component is
615 /// digest
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400616 /// 2. Only min/max selectors (both 0) can be specified, all other selectors do not
617 /// make sense for interests with digest (though not sure if we need to enforce this)
618
619 if (doesInterestContainDigest)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800620 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700621 if (interest.getName().get(-1) != entry->getFullName().get(-1))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800622 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700623 NFD_LOG_TRACE("violates implicit digest");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800624 return false;
625 }
626 }
627
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400628 if (!doesInterestContainDigest)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800629 {
630 if (interest.getMinSuffixComponents() >= 0)
631 {
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700632 size_t minDataNameLength = interest.getName().size() + interest.getMinSuffixComponents();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800633
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700634 bool isSatisfied = (minDataNameLength <= entry->getFullName().size());
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400635 if (!isSatisfied)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800636 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700637 NFD_LOG_TRACE("violates minComponents");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800638 return false;
639 }
640 }
641
642 if (interest.getMaxSuffixComponents() >= 0)
643 {
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700644 size_t maxDataNameLength = interest.getName().size() + interest.getMaxSuffixComponents();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800645
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700646 bool isSatisfied = (maxDataNameLength >= entry->getFullName().size());
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400647 if (!isSatisfied)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800648 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700649 NFD_LOG_TRACE("violates maxComponents");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800650 return false;
651 }
652 }
653 }
654
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -0700655 if (interest.getMustBeFresh() && entry->getStaleTime() < time::steady_clock::now())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800656 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700657 NFD_LOG_TRACE("violates mustBeFresh");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800658 return false;
659 }
660
Ilya Moiseenko9c9231b2014-04-10 11:05:12 -0400661 if (!interest.getPublisherPublicKeyLocator().empty())
662 {
663 if (entry->getData().getSignature().getType() == ndn::Signature::Sha256WithRsa)
664 {
665 ndn::SignatureSha256WithRsa rsaSignature(entry->getData().getSignature());
666 if (rsaSignature.getKeyLocator() != interest.getPublisherPublicKeyLocator())
667 {
668 NFD_LOG_TRACE("violates publisher key selector");
669 return false;
670 }
671 }
672 else
673 {
674 NFD_LOG_TRACE("violates publisher key selector");
675 return false;
676 }
677 }
678
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400679 if (doesInterestContainDigest)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800680 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700681 const ndn::name::Component& lastComponent = entry->getFullName().get(-1);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800682
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400683 if (!lastComponent.empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800684 {
685 if (interest.getExclude().isExcluded(lastComponent))
686 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700687 NFD_LOG_TRACE("violates exclusion");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800688 return false;
689 }
690 }
691 }
692 else
693 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700694 if (entry->getFullName().size() >= interest.getName().size() + 1)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800695 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700696 const ndn::name::Component& nextComponent = entry->getFullName()
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400697 .get(interest.getName().size());
698 if (!nextComponent.empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800699 {
700 if (interest.getExclude().isExcluded(nextComponent))
701 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700702 NFD_LOG_TRACE("violates exclusion");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800703 return false;
704 }
705 }
706 }
707 }
708
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700709 NFD_LOG_TRACE("complies");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800710 return true;
711}
712
713bool
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400714Cs::recognizeInterestWithDigest(const Interest& interest, cs::Entry* entry) const
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800715{
716 // only when min selector is not specified or specified with value of 0
717 // and Interest's name length is exactly the length of the name of CS entry
718 if (interest.getMinSuffixComponents() <= 0 &&
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700719 interest.getName().size() == (entry->getFullName().size()))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800720 {
721 const ndn::name::Component& last = interest.getName().get(-1);
722 if (last.value_size() == ndn::crypto::SHA256_DIGEST_SIZE)
723 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700724 NFD_LOG_TRACE("digest recognized");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800725 return true;
726 }
727 }
728
729 return false;
730}
731
732void
733Cs::erase(const Name& exactName)
734{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700735 NFD_LOG_TRACE("insert() " << exactName << ", "
736 << "skipList size " << size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800737
738 bool isIterated = false;
739 SkipListLayer::iterator updateTable[SKIPLIST_MAX_LAYERS];
740 SkipList::reverse_iterator topLayer = m_skipList.rbegin();
741 SkipListLayer::iterator head = (*topLayer)->begin();
742
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400743 if (!(*topLayer)->empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800744 {
745 //start from the upper layer towards bottom
746 int layer = m_skipList.size() - 1;
747 for (SkipList::reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
748 {
749 //if we didn't do any iterations on the higher layers, start from the begin() again
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400750 if (!isIterated)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800751 head = (*rit)->begin();
752
753 updateTable[layer] = head;
754
755 if (head != (*rit)->end())
756 {
757 // it can happen when begin() contains the element we want to remove
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700758 if (!isIterated && ((*head)->getFullName() == exactName))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800759 {
Alexander Afanasyev8934c422015-01-05 15:58:46 -0800760 cs::Entry* entryToDelete = *head;
761 NFD_LOG_TRACE("Found target " << entryToDelete->getFullName());
762 eraseFromSkipList(entryToDelete);
763 // head can become invalid after eraseFromSkipList
764 m_cleanupIndex.remove(entryToDelete);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800765 return;
766 }
767 else
768 {
769 SkipListLayer::iterator it = head;
770
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700771 while ((*it)->getFullName() < exactName)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800772 {
773 head = it;
774 updateTable[layer] = it;
775 isIterated = true;
776
777 ++it;
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400778 if (it == (*rit)->end())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800779 break;
780 }
781 }
782 }
783
784 if (layer > 0)
785 head = (*head)->getIterators().find(layer - 1)->second; // move HEAD to the lower layer
786
787 layer--;
788 }
789 }
790 else
791 {
792 return;
793 }
794
795 head = updateTable[0];
796 ++head; // look at the next slot to check if it contains the item we want to remove
797
798 bool isCsEmpty = (size() == 0);
799 bool isInBoundaries = (head != (*m_skipList.begin())->end());
800 bool isNameIdentical = false;
801 if (!isCsEmpty && isInBoundaries)
802 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700803 NFD_LOG_TRACE("Identical? " << (*head)->getFullName());
804 isNameIdentical = (*head)->getFullName() == exactName;
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800805 }
806
807 if (isNameIdentical)
808 {
Alexander Afanasyev8934c422015-01-05 15:58:46 -0800809 cs::Entry* entryToDelete = *head;
810 NFD_LOG_TRACE("Found target " << entryToDelete->getFullName());
811 eraseFromSkipList(entryToDelete);
812 // head can become invalid after eraseFromSkipList
813 m_cleanupIndex.remove(entryToDelete);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800814 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800815}
816
817void
818Cs::printSkipList() const
819{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700820 NFD_LOG_TRACE("print()");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800821 //start from the upper layer towards bottom
822 int layer = m_skipList.size() - 1;
823 for (SkipList::const_reverse_iterator rit = m_skipList.rbegin(); rit != m_skipList.rend(); ++rit)
824 {
825 for (SkipListLayer::iterator it = (*rit)->begin(); it != (*rit)->end(); ++it)
826 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700827 NFD_LOG_TRACE("Layer " << layer << " " << (*it)->getFullName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800828 }
829 layer--;
830 }
831}
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700832
Alexander Afanasyev18bbf812014-01-29 01:40:23 -0800833} //namespace nfd