blob: 3dc788a9fc41c6488e392b2dd4746ba24898c60b [file] [log] [blame]
Junxiao Shi0fcb41e2014-01-24 10:29:43 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (C) 2014 Named Data Networking Project
4 * See COPYING for copyright and distribution information.
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -08005 *
6 * Author: Ilya Moiseenko <iliamo@ucla.edu>
Junxiao Shi0fcb41e2014-01-24 10:29:43 -07007 */
8
Junxiao Shi0fcb41e2014-01-24 10:29:43 -07009#include "cs.hpp"
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060010#include "core/logger.hpp"
11
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080012#include <ndn-cpp-dev/util/crypto.hpp>
13
14#define SKIPLIST_MAX_LAYERS 32
15#define SKIPLIST_PROBABILITY 50 // 50% ( p = 1/2 )
16
17NFD_LOG_INIT("ContentStore");
Alexander Afanasyevb927a3a2014-01-24 10:41:47 -080018
Alexander Afanasyev18bbf812014-01-29 01:40:23 -080019namespace nfd {
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070020
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080021Cs::Cs(int nMaxPackets)
22 : m_nMaxPackets(nMaxPackets)
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070023{
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -070024 srand (time::toUnixTimestamp(time::system_clock::now()).count());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080025 SkipListLayer* zeroLayer = new SkipListLayer();
26 m_skipList.push_back(zeroLayer);
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070027}
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080028
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070029Cs::~Cs()
30{
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080031 /// \todo Fix memory leak
32}
33
34size_t
35Cs::size() const
36{
37 return (*m_skipList.begin())->size(); // size of the first layer in a skip list
38}
39
40void
41Cs::setLimit(size_t nMaxPackets)
42{
43 m_nMaxPackets = nMaxPackets;
44
45 while (isFull())
46 {
47 evictItem();
48 }
49}
50
51size_t
52Cs::getLimit() const
53{
54 return m_nMaxPackets;
55}
56
57//Reference: "Skip Lists: A Probabilistic Alternative to Balanced Trees" by W.Pugh
58std::pair< shared_ptr<cs::Entry>, bool>
59Cs::insertToSkipList(const Data& data, bool isUnsolicited)
60{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -070061 NFD_LOG_TRACE("insertToSkipList() " << data.getName() << ", "
62 << "skipList size " << size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080063
64 shared_ptr<cs::Entry> entry = make_shared<cs::Entry>(data, isUnsolicited);
65
66 bool insertInFront = false;
67 bool isIterated = false;
68 SkipList::reverse_iterator topLayer = m_skipList.rbegin();
69 SkipListLayer::iterator updateTable[SKIPLIST_MAX_LAYERS];
70 SkipListLayer::iterator head = (*topLayer)->begin();
71
72 if ( !(*topLayer)->empty() )
73 {
74 //start from the upper layer towards bottom
75 int layer = m_skipList.size() - 1;
76 for (SkipList::reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
77 {
78 //if we didn't do any iterations on the higher layers, start from the begin() again
79 if ( !isIterated )
80 head = (*rit)->begin();
81
82 updateTable[layer] = head;
83
84 if (head != (*rit)->end())
85 {
86 // it can happen when begin() contains the element in front of which we need to insert
87 if ( !isIterated && ((*head)->getName() >= entry->getName()) )
88 {
89 --updateTable[layer];
90 insertInFront = true;
91 }
92 else
93 {
94 SkipListLayer::iterator it = head;
95
96 while ((*it)->getName() < entry->getName())
97 {
98 head = it;
99 updateTable[layer] = it;
100 isIterated = true;
101
102 ++it;
103 if (it == (*rit)->end())
104 break;
105 }
106 }
107 }
108
109 if (layer > 0)
110 head = (*head)->getIterators().find(layer - 1)->second; // move HEAD to the lower layer
111
112 layer--;
113 }
114 }
115 else
116 {
117 updateTable[0] = (*topLayer)->begin(); //initialization
118 }
119
120 head = updateTable[0];
121 ++head; // look at the next slot to check if it contains a duplicate
122
123 bool isCsEmpty = (size() == 0);
124 bool isInBoundaries = (head != (*m_skipList.begin())->end());
125 bool isNameIdentical = false;
126 if (!isCsEmpty && isInBoundaries)
127 {
128 isNameIdentical = (*head)->getName() == entry->getName();
129 }
130
131 //check if this is a duplicate packet
132 if (isNameIdentical)
133 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700134 NFD_LOG_TRACE("Duplicate name (with digest)");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800135
136 (*head)->setData(data, entry->getDigest()); //updates stale time
137
138 return std::make_pair(*head, false);
139 }
140
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700141 NFD_LOG_TRACE("Not a duplicate");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800142
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700143 size_t randomLayer = pickRandomLayer();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800144
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700145 while ( m_skipList.size() < randomLayer + 1)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800146 {
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700147 SkipListLayer* newLayer = new SkipListLayer();
148 m_skipList.push_back(newLayer);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800149
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700150 updateTable[(m_skipList.size() - 1)] = newLayer->begin();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800151 }
152
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700153 size_t layer = 0;
154 for (SkipList::iterator i = m_skipList.begin();
155 i != m_skipList.end() && layer <= randomLayer; ++i)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800156 {
157 if (updateTable[layer] == (*i)->end() && !insertInFront)
158 {
159 (*i)->push_back(entry);
160 SkipListLayer::iterator last = (*i)->end();
161 --last;
162 entry->setIterator(layer, last);
163
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700164 NFD_LOG_TRACE("pushback " << &(*last));
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800165 }
166 else if (updateTable[layer] == (*i)->end() && insertInFront)
167 {
168 (*i)->push_front(entry);
169 entry->setIterator(layer, (*i)->begin());
170
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700171 NFD_LOG_TRACE("pushfront ");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800172 }
173 else
174 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700175 NFD_LOG_TRACE("insertafter");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800176 ++updateTable[layer]; // insert after
177 SkipListLayer::iterator position = (*i)->insert(updateTable[layer], entry);
178 entry->setIterator(layer, position); // save iterator where item was inserted
179 }
180 layer++;
181 }
182
183 printSkipList();
184
185 return std::make_pair(entry, true);
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700186}
187
188bool
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800189Cs::insert(const Data& data, bool isUnsolicited)
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700190{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700191 NFD_LOG_TRACE("insert() " << data.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800192
193 if (isFull())
194 {
195 evictItem();
196 }
197
198 //pointer and insertion status
199 std::pair< shared_ptr<cs::Entry>, bool> entry = insertToSkipList(data, isUnsolicited);
200
201 //new entry
202 if (entry.first && (entry.second == true))
203 {
204 m_contentByArrival.push(entry.first);
205 m_contentByStaleness.push(entry.first);
206
207 if (entry.first->isUnsolicited())
208 m_unsolicitedContent.push(entry.first);
209
210 return true;
211 }
212
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700213 return false;
214}
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800215
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700216size_t
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800217Cs::pickRandomLayer() const
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700218{
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800219 int layer = -1;
220 int randomValue;
221
222 do
223 {
224 layer++;
225 randomValue = rand() % 100 + 1;
226 }
227 while ( (randomValue < SKIPLIST_PROBABILITY) && (layer < SKIPLIST_MAX_LAYERS) );
228
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700229 return static_cast<size_t>(layer);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800230}
231
232bool
233Cs::isFull() const
234{
235 if (size() >= m_nMaxPackets) //size of the first layer vs. max size
236 return true;
237
238 return false;
239}
240
241bool
242Cs::eraseFromSkipList(shared_ptr<cs::Entry> entry)
243{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700244 NFD_LOG_TRACE("eraseFromSkipList() " << entry->getName());
245 NFD_LOG_TRACE("SkipList size " << size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800246
247 bool isErased = false;
248
249 int layer = m_skipList.size() - 1;
250 for (SkipList::reverse_iterator rit = m_skipList.rbegin(); rit != m_skipList.rend(); ++rit)
251 {
252 const std::map<int, std::list< shared_ptr<cs::Entry> >::iterator>& iterators = entry->getIterators();
253 std::map<int, std::list< shared_ptr<cs::Entry> >::iterator>::const_iterator it = iterators.find(layer);
254 if (it != iterators.end())
255 {
256 (*rit)->erase(it->second);
257 entry->removeIterator(layer);
258 isErased = true;
259 }
260
261 layer--;
262 }
263
264 printSkipList();
265
266 //remove layers that do not contain any elements (starting from the second layer)
267 for (SkipList::iterator it = (++m_skipList.begin()); it != m_skipList.end();)
268 {
269 if ((*it)->empty())
270 {
271 it = m_skipList.erase(it);
272 }
273 else
274 ++it;
275 }
276
277 return isErased;
278}
279
280bool
281Cs::evictItem()
282{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700283 NFD_LOG_TRACE("evictItem()");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800284
285 //because there is a possibility that this item is in a queue, but no longer in skiplist
286 while ( !m_unsolicitedContent.empty() )
287 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700288 NFD_LOG_TRACE("Evict from unsolicited queue");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800289
290 shared_ptr<cs::Entry> entry = m_unsolicitedContent.front();
291 m_unsolicitedContent.pop();
292 bool isErased = eraseFromSkipList(entry);
293
294 if (isErased)
295 return true;
296 }
297
298 //because there is a possibility that this item is in a queue, but no longer in skiplist
299 int nIterations = size() * 0.01; // 1% of the Content Store
300 while ( !m_contentByStaleness.empty() )
301 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700302 NFD_LOG_TRACE("Evict from staleness queue");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800303
304 shared_ptr<cs::Entry> entry = m_contentByStaleness.top();
305
306 //because stale time could be updated by the duplicate packet
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -0700307 if (entry->getStaleTime() < time::steady_clock::now())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800308 {
309 m_contentByStaleness.pop();
310 bool isErased = eraseFromSkipList(entry);
311
312 if (isErased)
313 return true;
314 }
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -0700315 else if ( (entry->getStaleTime() > time::steady_clock::now()) && entry->wasRefreshedByDuplicate() )
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800316 {
317 m_contentByStaleness.pop();
318 m_contentByStaleness.push(entry); // place in a right order
319
320 nIterations--;
321 // if 1% of the CS are non-expired refreshed CS entries (allocated sequentially),
322 // then stop to prevent too many iterations
323 if ( nIterations <= 0 )
324 break;
325 }
326 else //no further item will be expired, stop
327 {
328 break;
329 }
330 }
331
332 //because there is a possibility that this item is in a queue, but no longer in skiplist
333 while ( !m_contentByArrival.empty() )
334 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700335 NFD_LOG_TRACE("Evict from arrival queue");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800336
337 shared_ptr<cs::Entry> entry = m_contentByArrival.front();
338 m_contentByArrival.pop();
339 bool isErased = eraseFromSkipList(entry);
340
341 if (isErased)
342 return true;
343 }
344
345 return false;
346}
347
348const Data*
349Cs::find(const Interest& interest) const
350{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700351 NFD_LOG_TRACE("find() " << interest.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800352
353 bool isIterated = false;
354 SkipList::const_reverse_iterator topLayer = m_skipList.rbegin();
355 SkipListLayer::iterator head = (*topLayer)->begin();
356
357 if ( !(*topLayer)->empty() )
358 {
359 //start from the upper layer towards bottom
360 int layer = m_skipList.size() - 1;
361 for (SkipList::const_reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
362 {
363 //if we didn't do any iterations on the higher layers, start from the begin() again
364 if (!isIterated)
365 head = (*rit)->begin();
366
367 if (head != (*rit)->end())
368 {
369 // it happens when begin() contains the element we want to find
370 if ( !isIterated && (interest.getName().isPrefixOf((*head)->getName())) )
371 {
372 if (layer > 0)
373 {
374 layer--;
375 continue; // try lower layer
376 }
377 else
378 {
379 isIterated = true;
380 }
381 }
382 else
383 {
384 SkipListLayer::iterator it = head;
385
386 while ( (*it)->getName() < interest.getName() )
387 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700388 NFD_LOG_TRACE((*it)->getName() << " < " << interest.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800389 head = it;
390 isIterated = true;
391
392 ++it;
393 if (it == (*rit)->end())
394 break;
395 }
396 }
397 }
398
399 if (layer > 0)
400 {
401 head = (*head)->getIterators().find(layer - 1)->second; // move HEAD to the lower layer
402 }
403 else //if we reached the first layer
404 {
405 if ( isIterated )
406 return selectChild(interest, head);
407 }
408
409 layer--;
410 }
411 }
412
Alexander Afanasyevc9765df2014-01-25 19:24:27 -0800413 return 0;
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700414}
415
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800416// because skip list is a probabilistic data structure and the way it is traversed,
417// there is no guarantee that startingPoint is an element preceding the leftmost child
418const Data*
419Cs::selectChild(const Interest& interest, SkipListLayer::iterator startingPoint) const
420{
421 BOOST_ASSERT( startingPoint != (*m_skipList.begin())->end() );
422
423 if (startingPoint != (*m_skipList.begin())->begin())
424 {
425 BOOST_ASSERT( (*startingPoint)->getName() < interest.getName() );
426 }
427
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700428 NFD_LOG_TRACE("selectChild() " << interest.getChildSelector() << " " << (*startingPoint)->getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800429
430 bool hasLeftmostSelector = (interest.getChildSelector() <= 0);
431 bool hasRightmostSelector = !hasLeftmostSelector;
432
433 if (hasLeftmostSelector)
434 {
435 bool doesInterestContainDigest = recognizeInterestWithDigest(interest, *startingPoint);
436 bool isInPrefix = false;
437
438 if (doesInterestContainDigest)
439 {
440 isInPrefix = interest.getName().getPrefix(-1).isPrefixOf((*startingPoint)->getName());
441 }
442 else
443 {
444 isInPrefix = interest.getName().isPrefixOf((*startingPoint)->getName());
445 }
446
447 if (isInPrefix)
448 {
449 if (doesComplyWithSelectors(interest, *startingPoint))
450 {
451 return &(*startingPoint)->getData();
452 }
453 }
454 }
455
456 //iterate to the right
457 SkipListLayer::iterator rightmost = startingPoint;
458 if (startingPoint != (*m_skipList.begin())->end())
459 {
460 SkipListLayer::iterator rightmostCandidate = startingPoint;
461 Name currentChildPrefix("");
462
463 while (true)
464 {
465 ++rightmostCandidate;
466
467 bool isInBoundaries = (rightmostCandidate != (*m_skipList.begin())->end());
468 bool isInPrefix = false;
469 bool doesInterestContainDigest = false;
470 if (isInBoundaries)
471 {
472 doesInterestContainDigest = recognizeInterestWithDigest(interest, *rightmostCandidate);
473
474 if (doesInterestContainDigest)
475 {
476 isInPrefix = interest.getName().getPrefix(-1).isPrefixOf((*rightmostCandidate)->getName());
477 }
478 else
479 {
480 isInPrefix = interest.getName().isPrefixOf((*rightmostCandidate)->getName());
481 }
482 }
483
484 if (isInPrefix)
485 {
486 if (doesComplyWithSelectors(interest, *rightmostCandidate))
487 {
488 if (hasLeftmostSelector)
489 {
490 return &(*rightmostCandidate)->getData();
491 }
492
493 if (hasRightmostSelector)
494 {
495 if (doesInterestContainDigest)
496 {
497 // get prefix which is one component longer than Interest name (without digest)
498 const Name& childPrefix = (*rightmostCandidate)->getName().getPrefix(interest.getName().size());
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700499 NFD_LOG_TRACE("Child prefix" << childPrefix);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800500
501 if ( currentChildPrefix.empty() || (childPrefix != currentChildPrefix) )
502 {
503 currentChildPrefix = childPrefix;
504 rightmost = rightmostCandidate;
505 }
506 }
507 else
508 {
509 // get prefix which is one component longer than Interest name
510 const Name& childPrefix = (*rightmostCandidate)->getName().getPrefix(interest.getName().size() + 1);
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700511 NFD_LOG_TRACE("Child prefix" << childPrefix);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800512
513 if ( currentChildPrefix.empty() || (childPrefix != currentChildPrefix) )
514 {
515 currentChildPrefix = childPrefix;
516 rightmost = rightmostCandidate;
517 }
518 }
519 }
520 }
521 }
522 else
523 break;
524 }
525 }
526
527 if (rightmost != startingPoint)
528 {
529 return &(*rightmost)->getData();
530 }
531
532 if (hasRightmostSelector) // if rightmost was not found, try starting point
533 {
534 bool doesInterestContainDigest = recognizeInterestWithDigest(interest, *startingPoint);
535 bool isInPrefix = false;
536
537 if (doesInterestContainDigest)
538 {
539 isInPrefix = interest.getName().getPrefix(-1).isPrefixOf((*startingPoint)->getName());
540 }
541 else
542 {
543 isInPrefix = interest.getName().isPrefixOf((*startingPoint)->getName());
544 }
545
546 if (isInPrefix)
547 {
548 if (doesComplyWithSelectors(interest, *startingPoint))
549 {
550 return &(*startingPoint)->getData();
551 }
552 }
553 }
554
555 return 0;
556}
557
558bool
559Cs::doesComplyWithSelectors(const Interest& interest, shared_ptr<cs::Entry> entry) const
560{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700561 NFD_LOG_TRACE("doesComplyWithSelectors()");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800562
563 /// \todo The following detection is not correct
564 /// 1. If data name ends with 32-octet component doesn't mean that this component is digest
565 /// 2. Only min/max selectors (both 0) can be specified, all other selectors do not make sense
566 /// for interests with digest (though not sure if we need to enforce this)
567 bool doesInterestContainDigest = recognizeInterestWithDigest(interest, entry);
568 if ( doesInterestContainDigest )
569 {
570 const ndn::name::Component& last = interest.getName().get(-1);
571 const ndn::ConstBufferPtr& digest = entry->getDigest();
572
573 BOOST_ASSERT(digest->size() == last.value_size());
574 BOOST_ASSERT(digest->size() == ndn::crypto::SHA256_DIGEST_SIZE);
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700575
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800576 if (std::memcmp(digest->buf(), last.value(), ndn::crypto::SHA256_DIGEST_SIZE) != 0)
577 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700578 NFD_LOG_TRACE("violates implicit digest");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800579 return false;
580 }
581 }
582
583 if ( !doesInterestContainDigest )
584 {
585 if (interest.getMinSuffixComponents() >= 0)
586 {
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700587 size_t minDataNameLength = interest.getName().size() + interest.getMinSuffixComponents();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800588
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700589 bool isSatisfied = (minDataNameLength <= entry->getName().size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800590 if ( !isSatisfied )
591 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700592 NFD_LOG_TRACE("violates minComponents");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800593 return false;
594 }
595 }
596
597 if (interest.getMaxSuffixComponents() >= 0)
598 {
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700599 size_t maxDataNameLength = interest.getName().size() + interest.getMaxSuffixComponents();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800600
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700601 bool isSatisfied = (maxDataNameLength >= entry->getName().size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800602 if ( !isSatisfied )
603 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700604 NFD_LOG_TRACE("violates maxComponents");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800605 return false;
606 }
607 }
608 }
609
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -0700610 if (interest.getMustBeFresh() && entry->getStaleTime() < time::steady_clock::now())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800611 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700612 NFD_LOG_TRACE("violates mustBeFresh");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800613 return false;
614 }
615
616 if ( doesInterestContainDigest )
617 {
618 const ndn::name::Component& lastComponent = entry->getName().get(-1);
619
620 if ( !lastComponent.empty() )
621 {
622 if (interest.getExclude().isExcluded(lastComponent))
623 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700624 NFD_LOG_TRACE("violates exclusion");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800625 return false;
626 }
627 }
628 }
629 else
630 {
631 if (entry->getName().size() >= interest.getName().size() + 1)
632 {
633 const ndn::name::Component& nextComponent = entry->getName().get(interest.getName().size());
634
635 if ( !nextComponent.empty() )
636 {
637 if (interest.getExclude().isExcluded(nextComponent))
638 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700639 NFD_LOG_TRACE("violates exclusion");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800640 return false;
641 }
642 }
643 }
644 }
645
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700646 NFD_LOG_TRACE("complies");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800647 return true;
648}
649
650bool
651Cs::recognizeInterestWithDigest(const Interest& interest, shared_ptr<cs::Entry> entry) const
652{
653 // only when min selector is not specified or specified with value of 0
654 // and Interest's name length is exactly the length of the name of CS entry
655 if (interest.getMinSuffixComponents() <= 0 &&
656 interest.getName().size() == (entry->getName().size()))
657 {
658 const ndn::name::Component& last = interest.getName().get(-1);
659 if (last.value_size() == ndn::crypto::SHA256_DIGEST_SIZE)
660 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700661 NFD_LOG_TRACE("digest recognized");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800662 return true;
663 }
664 }
665
666 return false;
667}
668
669void
670Cs::erase(const Name& exactName)
671{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700672 NFD_LOG_TRACE("insert() " << exactName << ", "
673 << "skipList size " << size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800674
675 bool isIterated = false;
676 SkipListLayer::iterator updateTable[SKIPLIST_MAX_LAYERS];
677 SkipList::reverse_iterator topLayer = m_skipList.rbegin();
678 SkipListLayer::iterator head = (*topLayer)->begin();
679
680 if ( !(*topLayer)->empty() )
681 {
682 //start from the upper layer towards bottom
683 int layer = m_skipList.size() - 1;
684 for (SkipList::reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
685 {
686 //if we didn't do any iterations on the higher layers, start from the begin() again
687 if ( !isIterated )
688 head = (*rit)->begin();
689
690 updateTable[layer] = head;
691
692 if (head != (*rit)->end())
693 {
694 // it can happen when begin() contains the element we want to remove
695 if ( !isIterated && ((*head)->getName() == exactName) )
696 {
697 eraseFromSkipList(*head);
698 return;
699 }
700 else
701 {
702 SkipListLayer::iterator it = head;
703
704 while ((*it)->getName() < exactName)
705 {
706 head = it;
707 updateTable[layer] = it;
708 isIterated = true;
709
710 ++it;
711 if ( it == (*rit)->end() )
712 break;
713 }
714 }
715 }
716
717 if (layer > 0)
718 head = (*head)->getIterators().find(layer - 1)->second; // move HEAD to the lower layer
719
720 layer--;
721 }
722 }
723 else
724 {
725 return;
726 }
727
728 head = updateTable[0];
729 ++head; // look at the next slot to check if it contains the item we want to remove
730
731 bool isCsEmpty = (size() == 0);
732 bool isInBoundaries = (head != (*m_skipList.begin())->end());
733 bool isNameIdentical = false;
734 if (!isCsEmpty && isInBoundaries)
735 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700736 NFD_LOG_TRACE("Identical? " << (*head)->getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800737 isNameIdentical = (*head)->getName() == exactName;
738 }
739
740 if (isNameIdentical)
741 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700742 NFD_LOG_TRACE("Found target " << (*head)->getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800743 eraseFromSkipList(*head);
744 }
745
746 printSkipList();
747}
748
749void
750Cs::printSkipList() const
751{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700752 NFD_LOG_TRACE("print()");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800753 //start from the upper layer towards bottom
754 int layer = m_skipList.size() - 1;
755 for (SkipList::const_reverse_iterator rit = m_skipList.rbegin(); rit != m_skipList.rend(); ++rit)
756 {
757 for (SkipListLayer::iterator it = (*rit)->begin(); it != (*rit)->end(); ++it)
758 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700759 NFD_LOG_TRACE("Layer " << layer << " " << (*it)->getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800760 }
761 layer--;
762 }
763}
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700764
Alexander Afanasyev18bbf812014-01-29 01:40:23 -0800765} //namespace nfd