blob: bad684ec16de27ef4732a693361afd92d16658a5 [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"
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080010#include <ndn-cpp-dev/util/crypto.hpp>
11
12#define SKIPLIST_MAX_LAYERS 32
13#define SKIPLIST_PROBABILITY 50 // 50% ( p = 1/2 )
14
15NFD_LOG_INIT("ContentStore");
Alexander Afanasyevb927a3a2014-01-24 10:41:47 -080016
Alexander Afanasyev18bbf812014-01-29 01:40:23 -080017namespace nfd {
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070018
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080019Cs::Cs(int nMaxPackets)
20 : m_nMaxPackets(nMaxPackets)
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070021{
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -070022 srand (time::toUnixTimestamp(time::system_clock::now()).count());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080023 SkipListLayer* zeroLayer = new SkipListLayer();
24 m_skipList.push_back(zeroLayer);
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070025}
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080026
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070027Cs::~Cs()
28{
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080029 /// \todo Fix memory leak
30}
31
32size_t
33Cs::size() const
34{
35 return (*m_skipList.begin())->size(); // size of the first layer in a skip list
36}
37
38void
39Cs::setLimit(size_t nMaxPackets)
40{
41 m_nMaxPackets = nMaxPackets;
42
43 while (isFull())
44 {
45 evictItem();
46 }
47}
48
49size_t
50Cs::getLimit() const
51{
52 return m_nMaxPackets;
53}
54
55//Reference: "Skip Lists: A Probabilistic Alternative to Balanced Trees" by W.Pugh
56std::pair< shared_ptr<cs::Entry>, bool>
57Cs::insertToSkipList(const Data& data, bool isUnsolicited)
58{
59 NFD_LOG_INFO("insertToSkipList() " << data.getName());
60 NFD_LOG_DEBUG("SkipList size " << size());
61
62 shared_ptr<cs::Entry> entry = make_shared<cs::Entry>(data, isUnsolicited);
63
64 bool insertInFront = false;
65 bool isIterated = false;
66 SkipList::reverse_iterator topLayer = m_skipList.rbegin();
67 SkipListLayer::iterator updateTable[SKIPLIST_MAX_LAYERS];
68 SkipListLayer::iterator head = (*topLayer)->begin();
69
70 if ( !(*topLayer)->empty() )
71 {
72 //start from the upper layer towards bottom
73 int layer = m_skipList.size() - 1;
74 for (SkipList::reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
75 {
76 //if we didn't do any iterations on the higher layers, start from the begin() again
77 if ( !isIterated )
78 head = (*rit)->begin();
79
80 updateTable[layer] = head;
81
82 if (head != (*rit)->end())
83 {
84 // it can happen when begin() contains the element in front of which we need to insert
85 if ( !isIterated && ((*head)->getName() >= entry->getName()) )
86 {
87 --updateTable[layer];
88 insertInFront = true;
89 }
90 else
91 {
92 SkipListLayer::iterator it = head;
93
94 while ((*it)->getName() < entry->getName())
95 {
96 head = it;
97 updateTable[layer] = it;
98 isIterated = true;
99
100 ++it;
101 if (it == (*rit)->end())
102 break;
103 }
104 }
105 }
106
107 if (layer > 0)
108 head = (*head)->getIterators().find(layer - 1)->second; // move HEAD to the lower layer
109
110 layer--;
111 }
112 }
113 else
114 {
115 updateTable[0] = (*topLayer)->begin(); //initialization
116 }
117
118 head = updateTable[0];
119 ++head; // look at the next slot to check if it contains a duplicate
120
121 bool isCsEmpty = (size() == 0);
122 bool isInBoundaries = (head != (*m_skipList.begin())->end());
123 bool isNameIdentical = false;
124 if (!isCsEmpty && isInBoundaries)
125 {
126 isNameIdentical = (*head)->getName() == entry->getName();
127 }
128
129 //check if this is a duplicate packet
130 if (isNameIdentical)
131 {
132 NFD_LOG_DEBUG("Duplicate name (with digest)");
133
134 (*head)->setData(data, entry->getDigest()); //updates stale time
135
136 return std::make_pair(*head, false);
137 }
138
139 NFD_LOG_DEBUG("Not a duplicate");
140
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700141 size_t randomLayer = pickRandomLayer();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800142
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700143 while ( m_skipList.size() < randomLayer + 1)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800144 {
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700145 SkipListLayer* newLayer = new SkipListLayer();
146 m_skipList.push_back(newLayer);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800147
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700148 updateTable[(m_skipList.size() - 1)] = newLayer->begin();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800149 }
150
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700151 size_t layer = 0;
152 for (SkipList::iterator i = m_skipList.begin();
153 i != m_skipList.end() && layer <= randomLayer; ++i)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800154 {
155 if (updateTable[layer] == (*i)->end() && !insertInFront)
156 {
157 (*i)->push_back(entry);
158 SkipListLayer::iterator last = (*i)->end();
159 --last;
160 entry->setIterator(layer, last);
161
162 NFD_LOG_DEBUG("pushback " << &(*last));
163 }
164 else if (updateTable[layer] == (*i)->end() && insertInFront)
165 {
166 (*i)->push_front(entry);
167 entry->setIterator(layer, (*i)->begin());
168
169 NFD_LOG_DEBUG("pushfront ");
170 }
171 else
172 {
173 NFD_LOG_DEBUG("insertafter");
174 ++updateTable[layer]; // insert after
175 SkipListLayer::iterator position = (*i)->insert(updateTable[layer], entry);
176 entry->setIterator(layer, position); // save iterator where item was inserted
177 }
178 layer++;
179 }
180
181 printSkipList();
182
183 return std::make_pair(entry, true);
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700184}
185
186bool
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800187Cs::insert(const Data& data, bool isUnsolicited)
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700188{
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800189 NFD_LOG_INFO("insert() " << data.getName());
190
191 if (isFull())
192 {
193 evictItem();
194 }
195
196 //pointer and insertion status
197 std::pair< shared_ptr<cs::Entry>, bool> entry = insertToSkipList(data, isUnsolicited);
198
199 //new entry
200 if (entry.first && (entry.second == true))
201 {
202 m_contentByArrival.push(entry.first);
203 m_contentByStaleness.push(entry.first);
204
205 if (entry.first->isUnsolicited())
206 m_unsolicitedContent.push(entry.first);
207
208 return true;
209 }
210
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700211 return false;
212}
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800213
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700214size_t
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800215Cs::pickRandomLayer() const
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700216{
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800217 int layer = -1;
218 int randomValue;
219
220 do
221 {
222 layer++;
223 randomValue = rand() % 100 + 1;
224 }
225 while ( (randomValue < SKIPLIST_PROBABILITY) && (layer < SKIPLIST_MAX_LAYERS) );
226
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700227 return static_cast<size_t>(layer);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800228}
229
230bool
231Cs::isFull() const
232{
233 if (size() >= m_nMaxPackets) //size of the first layer vs. max size
234 return true;
235
236 return false;
237}
238
239bool
240Cs::eraseFromSkipList(shared_ptr<cs::Entry> entry)
241{
242 NFD_LOG_INFO("eraseFromSkipList() " << entry->getName());
243 NFD_LOG_DEBUG("SkipList size " << size());
244
245 bool isErased = false;
246
247 int layer = m_skipList.size() - 1;
248 for (SkipList::reverse_iterator rit = m_skipList.rbegin(); rit != m_skipList.rend(); ++rit)
249 {
250 const std::map<int, std::list< shared_ptr<cs::Entry> >::iterator>& iterators = entry->getIterators();
251 std::map<int, std::list< shared_ptr<cs::Entry> >::iterator>::const_iterator it = iterators.find(layer);
252 if (it != iterators.end())
253 {
254 (*rit)->erase(it->second);
255 entry->removeIterator(layer);
256 isErased = true;
257 }
258
259 layer--;
260 }
261
262 printSkipList();
263
264 //remove layers that do not contain any elements (starting from the second layer)
265 for (SkipList::iterator it = (++m_skipList.begin()); it != m_skipList.end();)
266 {
267 if ((*it)->empty())
268 {
269 it = m_skipList.erase(it);
270 }
271 else
272 ++it;
273 }
274
275 return isErased;
276}
277
278bool
279Cs::evictItem()
280{
281 NFD_LOG_INFO("evictItem()");
282
283 //because there is a possibility that this item is in a queue, but no longer in skiplist
284 while ( !m_unsolicitedContent.empty() )
285 {
286 NFD_LOG_DEBUG("Evict from unsolicited queue");
287
288 shared_ptr<cs::Entry> entry = m_unsolicitedContent.front();
289 m_unsolicitedContent.pop();
290 bool isErased = eraseFromSkipList(entry);
291
292 if (isErased)
293 return true;
294 }
295
296 //because there is a possibility that this item is in a queue, but no longer in skiplist
297 int nIterations = size() * 0.01; // 1% of the Content Store
298 while ( !m_contentByStaleness.empty() )
299 {
300 NFD_LOG_DEBUG("Evict from staleness queue");
301
302 shared_ptr<cs::Entry> entry = m_contentByStaleness.top();
303
304 //because stale time could be updated by the duplicate packet
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -0700305 if (entry->getStaleTime() < time::steady_clock::now())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800306 {
307 m_contentByStaleness.pop();
308 bool isErased = eraseFromSkipList(entry);
309
310 if (isErased)
311 return true;
312 }
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -0700313 else if ( (entry->getStaleTime() > time::steady_clock::now()) && entry->wasRefreshedByDuplicate() )
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800314 {
315 m_contentByStaleness.pop();
316 m_contentByStaleness.push(entry); // place in a right order
317
318 nIterations--;
319 // if 1% of the CS are non-expired refreshed CS entries (allocated sequentially),
320 // then stop to prevent too many iterations
321 if ( nIterations <= 0 )
322 break;
323 }
324 else //no further item will be expired, stop
325 {
326 break;
327 }
328 }
329
330 //because there is a possibility that this item is in a queue, but no longer in skiplist
331 while ( !m_contentByArrival.empty() )
332 {
333 NFD_LOG_DEBUG("Evict from arrival queue");
334
335 shared_ptr<cs::Entry> entry = m_contentByArrival.front();
336 m_contentByArrival.pop();
337 bool isErased = eraseFromSkipList(entry);
338
339 if (isErased)
340 return true;
341 }
342
343 return false;
344}
345
346const Data*
347Cs::find(const Interest& interest) const
348{
349 NFD_LOG_INFO("find() " << interest.getName());
350
351 bool isIterated = false;
352 SkipList::const_reverse_iterator topLayer = m_skipList.rbegin();
353 SkipListLayer::iterator head = (*topLayer)->begin();
354
355 if ( !(*topLayer)->empty() )
356 {
357 //start from the upper layer towards bottom
358 int layer = m_skipList.size() - 1;
359 for (SkipList::const_reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
360 {
361 //if we didn't do any iterations on the higher layers, start from the begin() again
362 if (!isIterated)
363 head = (*rit)->begin();
364
365 if (head != (*rit)->end())
366 {
367 // it happens when begin() contains the element we want to find
368 if ( !isIterated && (interest.getName().isPrefixOf((*head)->getName())) )
369 {
370 if (layer > 0)
371 {
372 layer--;
373 continue; // try lower layer
374 }
375 else
376 {
377 isIterated = true;
378 }
379 }
380 else
381 {
382 SkipListLayer::iterator it = head;
383
384 while ( (*it)->getName() < interest.getName() )
385 {
386 NFD_LOG_DEBUG((*it)->getName() << " < " << interest.getName());
387 head = it;
388 isIterated = true;
389
390 ++it;
391 if (it == (*rit)->end())
392 break;
393 }
394 }
395 }
396
397 if (layer > 0)
398 {
399 head = (*head)->getIterators().find(layer - 1)->second; // move HEAD to the lower layer
400 }
401 else //if we reached the first layer
402 {
403 if ( isIterated )
404 return selectChild(interest, head);
405 }
406
407 layer--;
408 }
409 }
410
Alexander Afanasyevc9765df2014-01-25 19:24:27 -0800411 return 0;
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700412}
413
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800414// because skip list is a probabilistic data structure and the way it is traversed,
415// there is no guarantee that startingPoint is an element preceding the leftmost child
416const Data*
417Cs::selectChild(const Interest& interest, SkipListLayer::iterator startingPoint) const
418{
419 BOOST_ASSERT( startingPoint != (*m_skipList.begin())->end() );
420
421 if (startingPoint != (*m_skipList.begin())->begin())
422 {
423 BOOST_ASSERT( (*startingPoint)->getName() < interest.getName() );
424 }
425
426 NFD_LOG_INFO("selectChild() " << interest.getChildSelector() << " " << (*startingPoint)->getName());
427
428 bool hasLeftmostSelector = (interest.getChildSelector() <= 0);
429 bool hasRightmostSelector = !hasLeftmostSelector;
430
431 if (hasLeftmostSelector)
432 {
433 bool doesInterestContainDigest = recognizeInterestWithDigest(interest, *startingPoint);
434 bool isInPrefix = false;
435
436 if (doesInterestContainDigest)
437 {
438 isInPrefix = interest.getName().getPrefix(-1).isPrefixOf((*startingPoint)->getName());
439 }
440 else
441 {
442 isInPrefix = interest.getName().isPrefixOf((*startingPoint)->getName());
443 }
444
445 if (isInPrefix)
446 {
447 if (doesComplyWithSelectors(interest, *startingPoint))
448 {
449 return &(*startingPoint)->getData();
450 }
451 }
452 }
453
454 //iterate to the right
455 SkipListLayer::iterator rightmost = startingPoint;
456 if (startingPoint != (*m_skipList.begin())->end())
457 {
458 SkipListLayer::iterator rightmostCandidate = startingPoint;
459 Name currentChildPrefix("");
460
461 while (true)
462 {
463 ++rightmostCandidate;
464
465 bool isInBoundaries = (rightmostCandidate != (*m_skipList.begin())->end());
466 bool isInPrefix = false;
467 bool doesInterestContainDigest = false;
468 if (isInBoundaries)
469 {
470 doesInterestContainDigest = recognizeInterestWithDigest(interest, *rightmostCandidate);
471
472 if (doesInterestContainDigest)
473 {
474 isInPrefix = interest.getName().getPrefix(-1).isPrefixOf((*rightmostCandidate)->getName());
475 }
476 else
477 {
478 isInPrefix = interest.getName().isPrefixOf((*rightmostCandidate)->getName());
479 }
480 }
481
482 if (isInPrefix)
483 {
484 if (doesComplyWithSelectors(interest, *rightmostCandidate))
485 {
486 if (hasLeftmostSelector)
487 {
488 return &(*rightmostCandidate)->getData();
489 }
490
491 if (hasRightmostSelector)
492 {
493 if (doesInterestContainDigest)
494 {
495 // get prefix which is one component longer than Interest name (without digest)
496 const Name& childPrefix = (*rightmostCandidate)->getName().getPrefix(interest.getName().size());
497 NFD_LOG_DEBUG("Child prefix" << childPrefix);
498
499 if ( currentChildPrefix.empty() || (childPrefix != currentChildPrefix) )
500 {
501 currentChildPrefix = childPrefix;
502 rightmost = rightmostCandidate;
503 }
504 }
505 else
506 {
507 // get prefix which is one component longer than Interest name
508 const Name& childPrefix = (*rightmostCandidate)->getName().getPrefix(interest.getName().size() + 1);
509 NFD_LOG_DEBUG("Child prefix" << childPrefix);
510
511 if ( currentChildPrefix.empty() || (childPrefix != currentChildPrefix) )
512 {
513 currentChildPrefix = childPrefix;
514 rightmost = rightmostCandidate;
515 }
516 }
517 }
518 }
519 }
520 else
521 break;
522 }
523 }
524
525 if (rightmost != startingPoint)
526 {
527 return &(*rightmost)->getData();
528 }
529
530 if (hasRightmostSelector) // if rightmost was not found, try starting point
531 {
532 bool doesInterestContainDigest = recognizeInterestWithDigest(interest, *startingPoint);
533 bool isInPrefix = false;
534
535 if (doesInterestContainDigest)
536 {
537 isInPrefix = interest.getName().getPrefix(-1).isPrefixOf((*startingPoint)->getName());
538 }
539 else
540 {
541 isInPrefix = interest.getName().isPrefixOf((*startingPoint)->getName());
542 }
543
544 if (isInPrefix)
545 {
546 if (doesComplyWithSelectors(interest, *startingPoint))
547 {
548 return &(*startingPoint)->getData();
549 }
550 }
551 }
552
553 return 0;
554}
555
556bool
557Cs::doesComplyWithSelectors(const Interest& interest, shared_ptr<cs::Entry> entry) const
558{
559 NFD_LOG_INFO("doesComplyWithSelectors()");
560
561 /// \todo The following detection is not correct
562 /// 1. If data name ends with 32-octet component doesn't mean that this component is digest
563 /// 2. Only min/max selectors (both 0) can be specified, all other selectors do not make sense
564 /// for interests with digest (though not sure if we need to enforce this)
565 bool doesInterestContainDigest = recognizeInterestWithDigest(interest, entry);
566 if ( doesInterestContainDigest )
567 {
568 const ndn::name::Component& last = interest.getName().get(-1);
569 const ndn::ConstBufferPtr& digest = entry->getDigest();
570
571 BOOST_ASSERT(digest->size() == last.value_size());
572 BOOST_ASSERT(digest->size() == ndn::crypto::SHA256_DIGEST_SIZE);
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700573
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800574 if (std::memcmp(digest->buf(), last.value(), ndn::crypto::SHA256_DIGEST_SIZE) != 0)
575 {
576 NFD_LOG_DEBUG("violates implicit digest");
577 return false;
578 }
579 }
580
581 if ( !doesInterestContainDigest )
582 {
583 if (interest.getMinSuffixComponents() >= 0)
584 {
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700585 size_t minDataNameLength = interest.getName().size() + interest.getMinSuffixComponents();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800586
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700587 bool isSatisfied = (minDataNameLength <= entry->getName().size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800588 if ( !isSatisfied )
589 {
590 NFD_LOG_DEBUG("violates minComponents");
591 return false;
592 }
593 }
594
595 if (interest.getMaxSuffixComponents() >= 0)
596 {
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700597 size_t maxDataNameLength = interest.getName().size() + interest.getMaxSuffixComponents();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800598
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700599 bool isSatisfied = (maxDataNameLength >= entry->getName().size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800600 if ( !isSatisfied )
601 {
602 NFD_LOG_DEBUG("violates maxComponents");
603 return false;
604 }
605 }
606 }
607
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -0700608 if (interest.getMustBeFresh() && entry->getStaleTime() < time::steady_clock::now())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800609 {
610 NFD_LOG_DEBUG("violates mustBeFresh");
611 return false;
612 }
613
614 if ( doesInterestContainDigest )
615 {
616 const ndn::name::Component& lastComponent = entry->getName().get(-1);
617
618 if ( !lastComponent.empty() )
619 {
620 if (interest.getExclude().isExcluded(lastComponent))
621 {
622 NFD_LOG_DEBUG("violates exclusion");
623 return false;
624 }
625 }
626 }
627 else
628 {
629 if (entry->getName().size() >= interest.getName().size() + 1)
630 {
631 const ndn::name::Component& nextComponent = entry->getName().get(interest.getName().size());
632
633 if ( !nextComponent.empty() )
634 {
635 if (interest.getExclude().isExcluded(nextComponent))
636 {
637 NFD_LOG_DEBUG("violates exclusion");
638 return false;
639 }
640 }
641 }
642 }
643
644
645 NFD_LOG_DEBUG("complies!");
646 return true;
647}
648
649bool
650Cs::recognizeInterestWithDigest(const Interest& interest, shared_ptr<cs::Entry> entry) const
651{
652 // only when min selector is not specified or specified with value of 0
653 // and Interest's name length is exactly the length of the name of CS entry
654 if (interest.getMinSuffixComponents() <= 0 &&
655 interest.getName().size() == (entry->getName().size()))
656 {
657 const ndn::name::Component& last = interest.getName().get(-1);
658 if (last.value_size() == ndn::crypto::SHA256_DIGEST_SIZE)
659 {
660 NFD_LOG_DEBUG("digest recognized");
661 return true;
662 }
663 }
664
665 return false;
666}
667
668void
669Cs::erase(const Name& exactName)
670{
671 NFD_LOG_INFO("insert() " << exactName);
672 NFD_LOG_DEBUG("SkipList size " << size());
673
674 bool isIterated = false;
675 SkipListLayer::iterator updateTable[SKIPLIST_MAX_LAYERS];
676 SkipList::reverse_iterator topLayer = m_skipList.rbegin();
677 SkipListLayer::iterator head = (*topLayer)->begin();
678
679 if ( !(*topLayer)->empty() )
680 {
681 //start from the upper layer towards bottom
682 int layer = m_skipList.size() - 1;
683 for (SkipList::reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
684 {
685 //if we didn't do any iterations on the higher layers, start from the begin() again
686 if ( !isIterated )
687 head = (*rit)->begin();
688
689 updateTable[layer] = head;
690
691 if (head != (*rit)->end())
692 {
693 // it can happen when begin() contains the element we want to remove
694 if ( !isIterated && ((*head)->getName() == exactName) )
695 {
696 eraseFromSkipList(*head);
697 return;
698 }
699 else
700 {
701 SkipListLayer::iterator it = head;
702
703 while ((*it)->getName() < exactName)
704 {
705 head = it;
706 updateTable[layer] = it;
707 isIterated = true;
708
709 ++it;
710 if ( it == (*rit)->end() )
711 break;
712 }
713 }
714 }
715
716 if (layer > 0)
717 head = (*head)->getIterators().find(layer - 1)->second; // move HEAD to the lower layer
718
719 layer--;
720 }
721 }
722 else
723 {
724 return;
725 }
726
727 head = updateTable[0];
728 ++head; // look at the next slot to check if it contains the item we want to remove
729
730 bool isCsEmpty = (size() == 0);
731 bool isInBoundaries = (head != (*m_skipList.begin())->end());
732 bool isNameIdentical = false;
733 if (!isCsEmpty && isInBoundaries)
734 {
735 NFD_LOG_DEBUG("Identical? " << (*head)->getName());
736 isNameIdentical = (*head)->getName() == exactName;
737 }
738
739 if (isNameIdentical)
740 {
741 NFD_LOG_DEBUG("Found target " << (*head)->getName());
742 eraseFromSkipList(*head);
743 }
744
745 printSkipList();
746}
747
748void
749Cs::printSkipList() const
750{
751 NFD_LOG_INFO("print()");
752 //start from the upper layer towards bottom
753 int layer = m_skipList.size() - 1;
754 for (SkipList::const_reverse_iterator rit = m_skipList.rbegin(); rit != m_skipList.rend(); ++rit)
755 {
756 for (SkipListLayer::iterator it = (*rit)->begin(); it != (*rit)->end(); ++it)
757 {
758 NFD_LOG_DEBUG("Layer " << layer << " " << (*it)->getName());
759 }
760 layer--;
761 }
762}
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700763
Alexander Afanasyev18bbf812014-01-29 01:40:23 -0800764} //namespace nfd