NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.0: NDN, CCN, CCNx, content centric networks
API Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cs.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
30 #include "cs.hpp"
31 #include "core/logger.hpp"
32 #include "core/random.hpp"
33 
34 #include <ndn-cxx/util/crypto.hpp>
35 #include <ndn-cxx/security/signature-sha256-with-rsa.hpp>
36 
37 #include <boost/random/bernoulli_distribution.hpp>
38 #include <boost/concept/assert.hpp>
39 #include <boost/concept_check.hpp>
40 #include <type_traits>
41 
43 static const size_t SKIPLIST_MAX_LAYERS = 32;
45 static const double SKIPLIST_PROBABILITY = 0.25;
46 
47 NFD_LOG_INIT("ContentStore");
48 
49 namespace nfd {
50 
51 // http://en.cppreference.com/w/cpp/concept/ForwardIterator
52 BOOST_CONCEPT_ASSERT((boost::ForwardIterator<Cs::const_iterator>));
53 // boost::ForwardIterator follows SGI standard http://www.sgi.com/tech/stl/ForwardIterator.html,
54 // which doesn't require DefaultConstructible
55 #ifdef HAVE_IS_DEFAULT_CONSTRUCTIBLE
56 static_assert(std::is_default_constructible<Cs::const_iterator>::value,
57  "Cs::const_iterator must be default-constructible");
58 #else
59 BOOST_CONCEPT_ASSERT((boost::DefaultConstructible<Cs::const_iterator>));
60 #endif // HAVE_IS_DEFAULT_CONSTRUCTIBLE
61 
62 Cs::Cs(size_t nMaxPackets)
63  : m_nMaxPackets(nMaxPackets)
64  , m_nPackets(0)
65 {
66  SkipListLayer* zeroLayer = new SkipListLayer();
67  m_skipList.push_back(zeroLayer);
68 
69  for (size_t i = 0; i < m_nMaxPackets; i++)
70  m_freeCsEntries.push(new cs::skip_list::Entry());
71 }
72 
74 {
75  // evict all items from CS
76  while (evictItem())
77  ;
78 
79  BOOST_ASSERT(m_freeCsEntries.size() == m_nMaxPackets);
80 
81  while (!m_freeCsEntries.empty())
82  {
83  delete m_freeCsEntries.front();
84  m_freeCsEntries.pop();
85  }
86 }
87 
88 size_t
89 Cs::size() const
90 {
91  return m_nPackets; // size of the first layer in a skip list
92 }
93 
94 void
95 Cs::setLimit(size_t nMaxPackets)
96 {
97  size_t oldNMaxPackets = m_nMaxPackets;
98  m_nMaxPackets = nMaxPackets;
99 
100  while (size() > m_nMaxPackets) {
101  evictItem();
102  }
103 
104  if (m_nMaxPackets >= oldNMaxPackets) {
105  for (size_t i = oldNMaxPackets; i < m_nMaxPackets; i++) {
106  m_freeCsEntries.push(new cs::skip_list::Entry());
107  }
108  }
109  else {
110  for (size_t i = oldNMaxPackets; i > m_nMaxPackets; i--) {
111  delete m_freeCsEntries.front();
112  m_freeCsEntries.pop();
113  }
114  }
115 }
116 
117 size_t
119 {
120  return m_nMaxPackets;
121 }
122 
123 //Reference: "Skip Lists: A Probabilistic Alternative to Balanced Trees" by W.Pugh
124 std::pair<cs::skip_list::Entry*, bool>
125 Cs::insertToSkipList(const Data& data, bool isUnsolicited)
126 {
127  NFD_LOG_TRACE("insertToSkipList() " << data.getFullName() << ", "
128  << "skipList size " << size());
129 
130  BOOST_ASSERT(m_cleanupIndex.size() <= size());
131  BOOST_ASSERT(m_freeCsEntries.size() > 0);
132 
133  // take entry for the memory pool
134  cs::skip_list::Entry* entry = m_freeCsEntries.front();
135  m_freeCsEntries.pop();
136  m_nPackets++;
137  entry->setData(data, isUnsolicited);
138 
139  bool insertInFront = false;
140  bool isIterated = false;
141  SkipList::reverse_iterator topLayer = m_skipList.rbegin();
142  SkipListLayer::iterator updateTable[SKIPLIST_MAX_LAYERS];
143  SkipListLayer::iterator head = (*topLayer)->begin();
144 
145  if (!(*topLayer)->empty())
146  {
147  //start from the upper layer towards bottom
148  int layer = m_skipList.size() - 1;
149  for (SkipList::reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
150  {
151  //if we didn't do any iterations on the higher layers, start from the begin() again
152  if (!isIterated)
153  head = (*rit)->begin();
154 
155  updateTable[layer] = head;
156 
157  if (head != (*rit)->end())
158  {
159  // it can happen when begin() contains the element in front of which we need to insert
160  if (!isIterated && ((*head)->getFullName() >= entry->getFullName()))
161  {
162  --updateTable[layer];
163  insertInFront = true;
164  }
165  else
166  {
167  SkipListLayer::iterator it = head;
168 
169  while ((*it)->getFullName() < entry->getFullName())
170  {
171  head = it;
172  updateTable[layer] = it;
173  isIterated = true;
174 
175  ++it;
176  if (it == (*rit)->end())
177  break;
178  }
179  }
180  }
181 
182  if (layer > 0)
183  head = (*head)->getIterators().find(layer - 1)->second; // move HEAD to the lower layer
184 
185  layer--;
186  }
187  }
188  else
189  {
190  updateTable[0] = (*topLayer)->begin(); //initialization
191  }
192 
193  head = updateTable[0];
194  ++head; // look at the next slot to check if it contains a duplicate
195 
196  bool isCsEmpty = (size() == 0);
197  bool isInBoundaries = (head != (*m_skipList.begin())->end());
198  bool isNameIdentical = false;
199  if (!isCsEmpty && isInBoundaries)
200  {
201  isNameIdentical = (*head)->getFullName() == entry->getFullName();
202  }
203 
204  //check if this is a duplicate packet
205  if (isNameIdentical)
206  {
207  NFD_LOG_TRACE("Duplicate name (with digest)");
208 
209  (*head)->setData(data, isUnsolicited); //updates stale time
210 
211  // new entry not needed, returning to the pool
212  entry->release();
213  m_freeCsEntries.push(entry);
214  m_nPackets--;
215 
216  return std::make_pair(*head, false);
217  }
218 
219  NFD_LOG_TRACE("Not a duplicate");
220 
221  size_t randomLayer = pickRandomLayer();
222 
223  while (m_skipList.size() < randomLayer + 1)
224  {
225  SkipListLayer* newLayer = new SkipListLayer();
226  m_skipList.push_back(newLayer);
227 
228  updateTable[(m_skipList.size() - 1)] = newLayer->begin();
229  }
230 
231  size_t layer = 0;
232  for (SkipList::iterator i = m_skipList.begin();
233  i != m_skipList.end() && layer <= randomLayer; ++i)
234  {
235  if (updateTable[layer] == (*i)->end() && !insertInFront)
236  {
237  (*i)->push_back(entry);
238  SkipListLayer::iterator last = (*i)->end();
239  --last;
240  entry->setIterator(layer, last);
241 
242  NFD_LOG_TRACE("pushback " << &(*last));
243  }
244  else if (updateTable[layer] == (*i)->end() && insertInFront)
245  {
246  (*i)->push_front(entry);
247  entry->setIterator(layer, (*i)->begin());
248 
249  NFD_LOG_TRACE("pushfront ");
250  }
251  else
252  {
253  NFD_LOG_TRACE("insertafter");
254  ++updateTable[layer]; // insert after
255  SkipListLayer::iterator position = (*i)->insert(updateTable[layer], entry);
256  entry->setIterator(layer, position); // save iterator where item was inserted
257  }
258  layer++;
259  }
260 
261  return std::make_pair(entry, true);
262 }
263 
264 bool
265 Cs::insert(const Data& data, bool isUnsolicited)
266 {
267  NFD_LOG_TRACE("insert() " << data.getFullName());
268 
269  if (isFull())
270  {
271  evictItem();
272  }
273 
274  //pointer and insertion status
275  std::pair<cs::skip_list::Entry*, bool> entry = insertToSkipList(data, isUnsolicited);
276 
277  //new entry
278  if (static_cast<bool>(entry.first) && (entry.second == true))
279  {
280  m_cleanupIndex.push_back(entry.first);
281  return true;
282  }
283 
284  return false;
285 }
286 
287 size_t
288 Cs::pickRandomLayer() const
289 {
290  static boost::random::bernoulli_distribution<> dist(SKIPLIST_PROBABILITY);
291  // TODO rewrite using geometry_distribution
292  size_t layer;
293  for (layer = 0; layer < SKIPLIST_MAX_LAYERS; ++layer) {
294  if (!dist(getGlobalRng())) {
295  break;
296  }
297  }
298  return layer;
299 }
300 
301 bool
302 Cs::isFull() const
303 {
304  if (size() >= m_nMaxPackets) //size of the first layer vs. max size
305  return true;
306 
307  return false;
308 }
309 
310 bool
311 Cs::eraseFromSkipList(cs::skip_list::Entry* entry)
312 {
313  NFD_LOG_TRACE("eraseFromSkipList() " << entry->getFullName());
314  NFD_LOG_TRACE("SkipList size " << size());
315 
316  bool isErased = false;
317 
318  const std::map<int, std::list<cs::skip_list::Entry*>::iterator>& iterators = entry->getIterators();
319 
320  if (!iterators.empty())
321  {
322  int layer = 0;
323 
324  for (SkipList::iterator it = m_skipList.begin(); it != m_skipList.end(); )
325  {
326  std::map<int, std::list<cs::skip_list::Entry*>::iterator>::const_iterator i = iterators.find(layer);
327 
328  if (i != iterators.end())
329  {
330  (*it)->erase(i->second);
331  entry->removeIterator(layer);
332  isErased = true;
333 
334  //remove layers that do not contain any elements (starting from the second layer)
335  if ((layer != 0) && (*it)->empty())
336  {
337  delete *it;
338  it = m_skipList.erase(it);
339  }
340  else
341  ++it;
342 
343  layer++;
344  }
345  else
346  break;
347  }
348  }
349 
350  //delete entry;
351  if (isErased)
352  {
353  entry->release();
354  m_freeCsEntries.push(entry);
355  m_nPackets--;
356  }
357 
358  return isErased;
359 }
360 
361 bool
363 {
364  NFD_LOG_TRACE("evictItem()");
365 
366  if (!m_cleanupIndex.get<unsolicited>().empty()) {
367  CleanupIndex::index<unsolicited>::type::const_iterator firstSolicited =
368  m_cleanupIndex.get<unsolicited>().upper_bound(false);
369 
370  if (firstSolicited != m_cleanupIndex.get<unsolicited>().begin()) {
371  --firstSolicited;
372  BOOST_ASSERT((*firstSolicited)->isUnsolicited());
373  NFD_LOG_TRACE("Evict from unsolicited queue");
374 
375  eraseFromSkipList(*firstSolicited);
376  m_cleanupIndex.get<unsolicited>().erase(firstSolicited);
377  return true;
378  }
379  else {
380  BOOST_ASSERT(!(*m_cleanupIndex.get<unsolicited>().begin())->isUnsolicited());
381  }
382  }
383 
384  if (!m_cleanupIndex.get<byStaleness>().empty() &&
385  (*m_cleanupIndex.get<byStaleness>().begin())->getStaleTime() < time::steady_clock::now())
386  {
387  NFD_LOG_TRACE("Evict from staleness queue");
388 
389  eraseFromSkipList(*m_cleanupIndex.get<byStaleness>().begin());
390  m_cleanupIndex.get<byStaleness>().erase(m_cleanupIndex.get<byStaleness>().begin());
391  return true;
392  }
393 
394  if (!m_cleanupIndex.get<byArrival>().empty())
395  {
396  NFD_LOG_TRACE("Evict from arrival queue");
397 
398  eraseFromSkipList(*m_cleanupIndex.get<byArrival>().begin());
399  m_cleanupIndex.get<byArrival>().erase(m_cleanupIndex.get<byArrival>().begin());
400  return true;
401  }
402 
403  return false;
404 }
405 
406 const Data*
407 Cs::find(const Interest& interest) const
408 {
409  NFD_LOG_TRACE("find() " << interest.getName());
410 
411  bool isIterated = false;
412  SkipList::const_reverse_iterator topLayer = m_skipList.rbegin();
413  SkipListLayer::iterator head = (*topLayer)->begin();
414 
415  if (!(*topLayer)->empty())
416  {
417  //start from the upper layer towards bottom
418  int layer = m_skipList.size() - 1;
419  for (SkipList::const_reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
420  {
421  //if we didn't do any iterations on the higher layers, start from the begin() again
422  if (!isIterated)
423  head = (*rit)->begin();
424 
425  if (head != (*rit)->end())
426  {
427  // it happens when begin() contains the element we want to find
428  if (!isIterated && (interest.getName().isPrefixOf((*head)->getFullName())))
429  {
430  if (layer > 0)
431  {
432  layer--;
433  continue; // try lower layer
434  }
435  else
436  {
437  isIterated = true;
438  }
439  }
440  else
441  {
442  SkipListLayer::iterator it = head;
443 
444  while ((*it)->getFullName() < interest.getName())
445  {
446  NFD_LOG_TRACE((*it)->getFullName() << " < " << interest.getName());
447  head = it;
448  isIterated = true;
449 
450  ++it;
451  if (it == (*rit)->end())
452  break;
453  }
454  }
455  }
456 
457  if (layer > 0)
458  {
459  head = (*head)->getIterators().find(layer - 1)->second; // move HEAD to the lower layer
460  }
461  else //if we reached the first layer
462  {
463  if (isIterated)
464  return selectChild(interest, head);
465  }
466 
467  layer--;
468  }
469  }
470 
471  return 0;
472 }
473 
474 const Data*
475 Cs::selectChild(const Interest& interest, SkipListLayer::iterator startingPoint) const
476 {
477  BOOST_ASSERT(startingPoint != (*m_skipList.begin())->end());
478 
479  if (startingPoint != (*m_skipList.begin())->begin())
480  {
481  BOOST_ASSERT((*startingPoint)->getFullName() < interest.getName());
482  }
483 
484  NFD_LOG_TRACE("selectChild() " << interest.getChildSelector() << " "
485  << (*startingPoint)->getFullName());
486 
487  bool hasLeftmostSelector = (interest.getChildSelector() <= 0);
488  bool hasRightmostSelector = !hasLeftmostSelector;
489 
490  if (hasLeftmostSelector)
491  {
492  bool doesInterestContainDigest = recognizeInterestWithDigest(interest, *startingPoint);
493  bool isInPrefix = false;
494 
495  if (doesInterestContainDigest)
496  {
497  isInPrefix = interest.getName().getPrefix(-1).isPrefixOf((*startingPoint)->getFullName());
498  }
499  else
500  {
501  isInPrefix = interest.getName().isPrefixOf((*startingPoint)->getFullName());
502  }
503 
504  if (isInPrefix)
505  {
506  if (doesComplyWithSelectors(interest, *startingPoint, doesInterestContainDigest))
507  {
508  return &(*startingPoint)->getData();
509  }
510  }
511  }
512 
513  //iterate to the right
514  SkipListLayer::iterator rightmost = startingPoint;
515  if (startingPoint != (*m_skipList.begin())->end())
516  {
517  SkipListLayer::iterator rightmostCandidate = startingPoint;
518  Name currentChildPrefix("");
519 
520  while (true)
521  {
522  ++rightmostCandidate;
523 
524  bool isInBoundaries = (rightmostCandidate != (*m_skipList.begin())->end());
525  bool isInPrefix = false;
526  bool doesInterestContainDigest = false;
527  if (isInBoundaries)
528  {
529  doesInterestContainDigest = recognizeInterestWithDigest(interest,
530  *rightmostCandidate);
531 
532  if (doesInterestContainDigest)
533  {
534  isInPrefix = interest.getName().getPrefix(-1)
535  .isPrefixOf((*rightmostCandidate)->getFullName());
536  }
537  else
538  {
539  isInPrefix = interest.getName().isPrefixOf((*rightmostCandidate)->getFullName());
540  }
541  }
542 
543  if (isInPrefix)
544  {
545  if (doesComplyWithSelectors(interest, *rightmostCandidate, doesInterestContainDigest))
546  {
547  if (hasLeftmostSelector)
548  {
549  return &(*rightmostCandidate)->getData();
550  }
551 
552  if (hasRightmostSelector)
553  {
554  if (doesInterestContainDigest)
555  {
556  // get prefix which is one component longer than Interest name
557  // (without digest)
558  const Name& childPrefix = (*rightmostCandidate)->getFullName()
559  .getPrefix(interest.getName().size());
560  NFD_LOG_TRACE("Child prefix" << childPrefix);
561 
562  if (currentChildPrefix.empty() || (childPrefix != currentChildPrefix))
563  {
564  currentChildPrefix = childPrefix;
565  rightmost = rightmostCandidate;
566  }
567  }
568  else
569  {
570  // get prefix which is one component longer than Interest name
571  const Name& childPrefix = (*rightmostCandidate)->getFullName()
572  .getPrefix(interest.getName().size() + 1);
573  NFD_LOG_TRACE("Child prefix" << childPrefix);
574 
575  if (currentChildPrefix.empty() || (childPrefix != currentChildPrefix))
576  {
577  currentChildPrefix = childPrefix;
578  rightmost = rightmostCandidate;
579  }
580  }
581  }
582  }
583  }
584  else
585  break;
586  }
587  }
588 
589  if (rightmost != startingPoint)
590  {
591  return &(*rightmost)->getData();
592  }
593 
594  if (hasRightmostSelector) // if rightmost was not found, try starting point
595  {
596  bool doesInterestContainDigest = recognizeInterestWithDigest(interest, *startingPoint);
597  bool isInPrefix = false;
598 
599  if (doesInterestContainDigest)
600  {
601  isInPrefix = interest.getName().getPrefix(-1).isPrefixOf((*startingPoint)->getFullName());
602  }
603  else
604  {
605  isInPrefix = interest.getName().isPrefixOf((*startingPoint)->getFullName());
606  }
607 
608  if (isInPrefix)
609  {
610  if (doesComplyWithSelectors(interest, *startingPoint, doesInterestContainDigest))
611  {
612  return &(*startingPoint)->getData();
613  }
614  }
615  }
616 
617  return 0;
618 }
619 
620 bool
621 Cs::doesComplyWithSelectors(const Interest& interest,
622  cs::skip_list::Entry* entry,
623  bool doesInterestContainDigest) const
624 {
625  NFD_LOG_TRACE("doesComplyWithSelectors()");
626 
632 
633  if (doesInterestContainDigest)
634  {
635  if (interest.getName().get(-1) != entry->getFullName().get(-1))
636  {
637  NFD_LOG_TRACE("violates implicit digest");
638  return false;
639  }
640  }
641 
642  if (!doesInterestContainDigest)
643  {
644  if (interest.getMinSuffixComponents() >= 0)
645  {
646  size_t minDataNameLength = interest.getName().size() + interest.getMinSuffixComponents();
647 
648  bool isSatisfied = (minDataNameLength <= entry->getFullName().size());
649  if (!isSatisfied)
650  {
651  NFD_LOG_TRACE("violates minComponents");
652  return false;
653  }
654  }
655 
656  if (interest.getMaxSuffixComponents() >= 0)
657  {
658  size_t maxDataNameLength = interest.getName().size() + interest.getMaxSuffixComponents();
659 
660  bool isSatisfied = (maxDataNameLength >= entry->getFullName().size());
661  if (!isSatisfied)
662  {
663  NFD_LOG_TRACE("violates maxComponents");
664  return false;
665  }
666  }
667  }
668 
669  if (interest.getMustBeFresh() && entry->getStaleTime() < time::steady_clock::now())
670  {
671  NFD_LOG_TRACE("violates mustBeFresh");
672  return false;
673  }
674 
675  if (!interest.getPublisherPublicKeyLocator().empty())
676  {
677  if (entry->getData().getSignature().getType() == ndn::Signature::Sha256WithRsa)
678  {
679  ndn::SignatureSha256WithRsa rsaSignature(entry->getData().getSignature());
680  if (rsaSignature.getKeyLocator() != interest.getPublisherPublicKeyLocator())
681  {
682  NFD_LOG_TRACE("violates publisher key selector");
683  return false;
684  }
685  }
686  else
687  {
688  NFD_LOG_TRACE("violates publisher key selector");
689  return false;
690  }
691  }
692 
693  if (doesInterestContainDigest)
694  {
695  const ndn::name::Component& lastComponent = entry->getFullName().get(-1);
696 
697  if (!lastComponent.empty())
698  {
699  if (interest.getExclude().isExcluded(lastComponent))
700  {
701  NFD_LOG_TRACE("violates exclusion");
702  return false;
703  }
704  }
705  }
706  else
707  {
708  if (entry->getFullName().size() >= interest.getName().size() + 1)
709  {
710  const ndn::name::Component& nextComponent = entry->getFullName()
711  .get(interest.getName().size());
712  if (!nextComponent.empty())
713  {
714  if (interest.getExclude().isExcluded(nextComponent))
715  {
716  NFD_LOG_TRACE("violates exclusion");
717  return false;
718  }
719  }
720  }
721  }
722 
723  NFD_LOG_TRACE("complies");
724  return true;
725 }
726 
727 bool
728 Cs::recognizeInterestWithDigest(const Interest& interest, cs::skip_list::Entry* entry) const
729 {
730  // only when min selector is not specified or specified with value of 0
731  // and Interest's name length is exactly the length of the name of CS entry
732  if (interest.getMinSuffixComponents() <= 0 &&
733  interest.getName().size() == (entry->getFullName().size()))
734  {
735  const ndn::name::Component& last = interest.getName().get(-1);
736  if (last.value_size() == ndn::crypto::SHA256_DIGEST_SIZE)
737  {
738  NFD_LOG_TRACE("digest recognized");
739  return true;
740  }
741  }
742 
743  return false;
744 }
745 
746 void
747 Cs::erase(const Name& exactName)
748 {
749  NFD_LOG_TRACE("insert() " << exactName << ", "
750  << "skipList size " << size());
751 
752  bool isIterated = false;
753  SkipListLayer::iterator updateTable[SKIPLIST_MAX_LAYERS];
754  SkipList::reverse_iterator topLayer = m_skipList.rbegin();
755  SkipListLayer::iterator head = (*topLayer)->begin();
756 
757  if (!(*topLayer)->empty())
758  {
759  //start from the upper layer towards bottom
760  int layer = m_skipList.size() - 1;
761  for (SkipList::reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
762  {
763  //if we didn't do any iterations on the higher layers, start from the begin() again
764  if (!isIterated)
765  head = (*rit)->begin();
766 
767  updateTable[layer] = head;
768 
769  if (head != (*rit)->end())
770  {
771  // it can happen when begin() contains the element we want to remove
772  if (!isIterated && ((*head)->getFullName() == exactName))
773  {
774  cs::skip_list::Entry* entryToDelete = *head;
775  NFD_LOG_TRACE("Found target " << entryToDelete->getFullName());
776  eraseFromSkipList(entryToDelete);
777  // head can become invalid after eraseFromSkipList
778  m_cleanupIndex.remove(entryToDelete);
779  return;
780  }
781  else
782  {
783  SkipListLayer::iterator it = head;
784 
785  while ((*it)->getFullName() < exactName)
786  {
787  head = it;
788  updateTable[layer] = it;
789  isIterated = true;
790 
791  ++it;
792  if (it == (*rit)->end())
793  break;
794  }
795  }
796  }
797 
798  if (layer > 0)
799  head = (*head)->getIterators().find(layer - 1)->second; // move HEAD to the lower layer
800 
801  layer--;
802  }
803  }
804  else
805  {
806  return;
807  }
808 
809  head = updateTable[0];
810  ++head; // look at the next slot to check if it contains the item we want to remove
811 
812  bool isCsEmpty = (size() == 0);
813  bool isInBoundaries = (head != (*m_skipList.begin())->end());
814  bool isNameIdentical = false;
815  if (!isCsEmpty && isInBoundaries)
816  {
817  NFD_LOG_TRACE("Identical? " << (*head)->getFullName());
818  isNameIdentical = (*head)->getFullName() == exactName;
819  }
820 
821  if (isNameIdentical)
822  {
823  cs::skip_list::Entry* entryToDelete = *head;
824  NFD_LOG_TRACE("Found target " << entryToDelete->getFullName());
825  eraseFromSkipList(entryToDelete);
826  // head can become invalid after eraseFromSkipList
827  m_cleanupIndex.remove(entryToDelete);
828  }
829 }
830 
831 void
832 Cs::printSkipList() const
833 {
834  NFD_LOG_TRACE("print()");
835  //start from the upper layer towards bottom
836  int layer = m_skipList.size() - 1;
837  for (SkipList::const_reverse_iterator rit = m_skipList.rbegin(); rit != m_skipList.rend(); ++rit)
838  {
839  for (SkipListLayer::iterator it = (*rit)->begin(); it != (*rit)->end(); ++it)
840  {
841  NFD_LOG_TRACE("Layer " << layer << " " << (*it)->getFullName());
842  }
843  layer--;
844  }
845 }
846 
847 } //namespace nfd
static const double SKIPLIST_PROBABILITY
probability for an entry in layer N to appear also in layer N+1
Definition: cs.cpp:45
void erase(const Name &exactName)
deletes CS entry by the exact name
Definition: cs.cpp:747
bool evictItem()
removes one Data packet from Content Store based on replacement policy
Definition: cs.cpp:362
const_iterator begin() const
returns an iterator pointing to the first CS entry
Definition: cs.hpp:285
std::list< cs::skip_list::Entry * > SkipListLayer
Definition: cs.hpp:46
const_iterator end() const
returns an iterator referring to the past-the-end CS entry
Definition: cs.hpp:291
const Data * find(const Interest &interest) const
finds the best match Data for an Interest
Definition: cs.cpp:407
~Cs()
Definition: cs.cpp:73
size_t getLimit() const
returns maximum allowed size of Content Store (in packets)
Definition: cs.cpp:118
bool insert(const Data &data, bool isUnsolicited=false)
inserts a Data packet This method does not consider the payload of the Data packet.
Definition: cs.cpp:265
const Name & getFullName() const
returns the full name (including implicit digest) of the Data packet stored in the CS entry ...
Definition: cs-entry.hpp:115
size_t size() const
returns current size of Content Store measured in packets
Definition: cs.cpp:89
boost::random::mt19937 & getGlobalRng()
Definition: random.cpp:33
static const size_t SKIPLIST_MAX_LAYERS
Copyright (c) 2014, Regents of the University of California, Arizona Board of Regents, Colorado State University, University Pierre & Marie Curie, Sorbonne University, Washington University in St.
Definition: cs.cpp:43
#define NFD_LOG_INIT(name)
Definition: logger.hpp:33
#define NFD_LOG_TRACE(expression)
Definition: logger.hpp:35
represents an entry in a CS with skip list implementation
void setLimit(size_t nMaxPackets)
sets maximum allowed size of Content Store (in packets)
Definition: cs.cpp:95
Cs(size_t nMaxPackets=10)
Definition: cs.cpp:62