34 #include <ndn-cxx/util/crypto.hpp>
35 #include <ndn-cxx/security/signature-sha256-with-rsa.hpp>
37 #include <boost/random/bernoulli_distribution.hpp>
38 #include <boost/concept/assert.hpp>
39 #include <boost/concept_check.hpp>
40 #include <type_traits>
52 BOOST_CONCEPT_ASSERT((boost::ForwardIterator<Cs::const_iterator>));
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");
59 BOOST_CONCEPT_ASSERT((boost::DefaultConstructible<Cs::const_iterator>));
60 #endif // HAVE_IS_DEFAULT_CONSTRUCTIBLE
63 : m_nMaxPackets(nMaxPackets)
67 m_skipList.push_back(zeroLayer);
69 for (
size_t i = 0; i < m_nMaxPackets; i++)
79 BOOST_ASSERT(m_freeCsEntries.size() == m_nMaxPackets);
81 while (!m_freeCsEntries.empty())
83 delete m_freeCsEntries.front();
84 m_freeCsEntries.pop();
97 size_t oldNMaxPackets = m_nMaxPackets;
98 m_nMaxPackets = nMaxPackets;
100 while (
size() > m_nMaxPackets) {
104 if (m_nMaxPackets >= oldNMaxPackets) {
105 for (
size_t i = oldNMaxPackets; i < m_nMaxPackets; i++) {
110 for (
size_t i = oldNMaxPackets; i > m_nMaxPackets; i--) {
111 delete m_freeCsEntries.front();
112 m_freeCsEntries.pop();
120 return m_nMaxPackets;
124 std::pair<cs::skip_list::Entry*, bool>
125 Cs::insertToSkipList(
const Data& data,
bool isUnsolicited)
127 NFD_LOG_TRACE(
"insertToSkipList() " << data.getFullName() <<
", "
128 <<
"skipList size " <<
size());
130 BOOST_ASSERT(m_cleanupIndex.size() <=
size());
131 BOOST_ASSERT(m_freeCsEntries.size() > 0);
135 m_freeCsEntries.pop();
137 entry->setData(data, isUnsolicited);
139 bool insertInFront =
false;
140 bool isIterated =
false;
141 SkipList::reverse_iterator topLayer = m_skipList.rbegin();
143 SkipListLayer::iterator head = (*topLayer)->begin();
145 if (!(*topLayer)->empty())
148 int layer = m_skipList.size() - 1;
149 for (SkipList::reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
153 head = (*rit)->begin();
155 updateTable[layer] = head;
157 if (head != (*rit)->end())
160 if (!isIterated && ((*head)->getFullName() >= entry->getFullName()))
162 --updateTable[layer];
163 insertInFront =
true;
167 SkipListLayer::iterator it = head;
169 while ((*it)->getFullName() < entry->getFullName())
172 updateTable[layer] = it;
176 if (it == (*rit)->end())
183 head = (*head)->getIterators().find(layer - 1)->second;
190 updateTable[0] = (*topLayer)->begin();
193 head = updateTable[0];
196 bool isCsEmpty = (
size() == 0);
197 bool isInBoundaries = (head != (*m_skipList.begin())->
end());
198 bool isNameIdentical =
false;
199 if (!isCsEmpty && isInBoundaries)
201 isNameIdentical = (*head)->getFullName() == entry->getFullName();
209 (*head)->setData(data, isUnsolicited);
213 m_freeCsEntries.push(entry);
216 return std::make_pair(*head,
false);
221 size_t randomLayer = pickRandomLayer();
223 while (m_skipList.size() < randomLayer + 1)
226 m_skipList.push_back(newLayer);
228 updateTable[(m_skipList.size() - 1)] = newLayer->begin();
232 for (SkipList::iterator i = m_skipList.begin();
233 i != m_skipList.end() && layer <= randomLayer; ++i)
235 if (updateTable[layer] == (*i)->end() && !insertInFront)
237 (*i)->push_back(entry);
238 SkipListLayer::iterator last = (*i)->end();
240 entry->setIterator(layer, last);
244 else if (updateTable[layer] == (*i)->end() && insertInFront)
246 (*i)->push_front(entry);
247 entry->setIterator(layer, (*i)->begin());
254 ++updateTable[layer];
255 SkipListLayer::iterator position = (*i)->insert(updateTable[layer], entry);
256 entry->setIterator(layer, position);
261 return std::make_pair(entry,
true);
275 std::pair<cs::skip_list::Entry*, bool> entry = insertToSkipList(data, isUnsolicited);
278 if (static_cast<bool>(entry.first) && (entry.second ==
true))
280 m_cleanupIndex.push_back(entry.first);
288 Cs::pickRandomLayer()
const
304 if (
size() >= m_nMaxPackets)
311 Cs::eraseFromSkipList(cs::skip_list::Entry* entry)
313 NFD_LOG_TRACE(
"eraseFromSkipList() " << entry->getFullName());
316 bool isErased =
false;
318 const std::map<int, std::list<cs::skip_list::Entry*>::iterator>& iterators = entry->getIterators();
320 if (!iterators.empty())
324 for (SkipList::iterator it = m_skipList.begin(); it != m_skipList.end(); )
326 std::map<int, std::list<cs::skip_list::Entry*>::iterator>::const_iterator i = iterators.find(layer);
328 if (i != iterators.end())
330 (*it)->erase(i->second);
331 entry->removeIterator(layer);
335 if ((layer != 0) && (*it)->empty())
338 it = m_skipList.erase(it);
354 m_freeCsEntries.push(entry);
366 if (!m_cleanupIndex.get<unsolicited>().empty()) {
367 CleanupIndex::index<unsolicited>::type::const_iterator firstSolicited =
368 m_cleanupIndex.get<unsolicited>().upper_bound(
false);
370 if (firstSolicited != m_cleanupIndex.get<unsolicited>().begin()) {
372 BOOST_ASSERT((*firstSolicited)->isUnsolicited());
375 eraseFromSkipList(*firstSolicited);
376 m_cleanupIndex.get<unsolicited>().
erase(firstSolicited);
380 BOOST_ASSERT(!(*m_cleanupIndex.get<unsolicited>().begin())->isUnsolicited());
384 if (!m_cleanupIndex.get<byStaleness>().empty() &&
385 (*m_cleanupIndex.get<byStaleness>().
begin())->getStaleTime() < time::steady_clock::now())
389 eraseFromSkipList(*m_cleanupIndex.get<byStaleness>().begin());
390 m_cleanupIndex.get<byStaleness>().
erase(m_cleanupIndex.get<byStaleness>().begin());
394 if (!m_cleanupIndex.get<byArrival>().empty())
398 eraseFromSkipList(*m_cleanupIndex.get<byArrival>().begin());
399 m_cleanupIndex.get<byArrival>().
erase(m_cleanupIndex.get<byArrival>().begin());
411 bool isIterated =
false;
412 SkipList::const_reverse_iterator topLayer = m_skipList.rbegin();
413 SkipListLayer::iterator head = (*topLayer)->begin();
415 if (!(*topLayer)->empty())
418 int layer = m_skipList.size() - 1;
419 for (SkipList::const_reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
423 head = (*rit)->begin();
425 if (head != (*rit)->end())
428 if (!isIterated && (interest.getName().isPrefixOf((*head)->getFullName())))
442 SkipListLayer::iterator it = head;
444 while ((*it)->getFullName() < interest.getName())
446 NFD_LOG_TRACE((*it)->getFullName() <<
" < " << interest.getName());
451 if (it == (*rit)->end())
459 head = (*head)->getIterators().find(layer - 1)->second;
464 return selectChild(interest, head);
475 Cs::selectChild(
const Interest& interest, SkipListLayer::iterator startingPoint)
const
477 BOOST_ASSERT(startingPoint != (*m_skipList.begin())->
end());
479 if (startingPoint != (*m_skipList.begin())->
begin())
481 BOOST_ASSERT((*startingPoint)->getFullName() < interest.getName());
484 NFD_LOG_TRACE(
"selectChild() " << interest.getChildSelector() <<
" "
485 << (*startingPoint)->getFullName());
487 bool hasLeftmostSelector = (interest.getChildSelector() <= 0);
488 bool hasRightmostSelector = !hasLeftmostSelector;
490 if (hasLeftmostSelector)
492 bool doesInterestContainDigest = recognizeInterestWithDigest(interest, *startingPoint);
493 bool isInPrefix =
false;
495 if (doesInterestContainDigest)
497 isInPrefix = interest.getName().getPrefix(-1).isPrefixOf((*startingPoint)->getFullName());
501 isInPrefix = interest.getName().isPrefixOf((*startingPoint)->getFullName());
506 if (doesComplyWithSelectors(interest, *startingPoint, doesInterestContainDigest))
508 return &(*startingPoint)->getData();
514 SkipListLayer::iterator rightmost = startingPoint;
515 if (startingPoint != (*m_skipList.begin())->
end())
517 SkipListLayer::iterator rightmostCandidate = startingPoint;
518 Name currentChildPrefix(
"");
522 ++rightmostCandidate;
524 bool isInBoundaries = (rightmostCandidate != (*m_skipList.begin())->
end());
525 bool isInPrefix =
false;
526 bool doesInterestContainDigest =
false;
529 doesInterestContainDigest = recognizeInterestWithDigest(interest,
530 *rightmostCandidate);
532 if (doesInterestContainDigest)
534 isInPrefix = interest.getName().getPrefix(-1)
535 .isPrefixOf((*rightmostCandidate)->getFullName());
539 isInPrefix = interest.getName().isPrefixOf((*rightmostCandidate)->getFullName());
545 if (doesComplyWithSelectors(interest, *rightmostCandidate, doesInterestContainDigest))
547 if (hasLeftmostSelector)
549 return &(*rightmostCandidate)->getData();
552 if (hasRightmostSelector)
554 if (doesInterestContainDigest)
558 const Name& childPrefix = (*rightmostCandidate)->getFullName()
559 .getPrefix(interest.getName().size());
562 if (currentChildPrefix.empty() || (childPrefix != currentChildPrefix))
564 currentChildPrefix = childPrefix;
565 rightmost = rightmostCandidate;
571 const Name& childPrefix = (*rightmostCandidate)->getFullName()
572 .getPrefix(interest.getName().size() + 1);
575 if (currentChildPrefix.empty() || (childPrefix != currentChildPrefix))
577 currentChildPrefix = childPrefix;
578 rightmost = rightmostCandidate;
589 if (rightmost != startingPoint)
591 return &(*rightmost)->getData();
594 if (hasRightmostSelector)
596 bool doesInterestContainDigest = recognizeInterestWithDigest(interest, *startingPoint);
597 bool isInPrefix =
false;
599 if (doesInterestContainDigest)
601 isInPrefix = interest.getName().getPrefix(-1).isPrefixOf((*startingPoint)->getFullName());
605 isInPrefix = interest.getName().isPrefixOf((*startingPoint)->getFullName());
610 if (doesComplyWithSelectors(interest, *startingPoint, doesInterestContainDigest))
612 return &(*startingPoint)->getData();
621 Cs::doesComplyWithSelectors(
const Interest& interest,
622 cs::skip_list::Entry* entry,
623 bool doesInterestContainDigest)
const
633 if (doesInterestContainDigest)
635 if (interest.getName().get(-1) != entry->getFullName().get(-1))
642 if (!doesInterestContainDigest)
644 if (interest.getMinSuffixComponents() >= 0)
646 size_t minDataNameLength = interest.getName().size() + interest.getMinSuffixComponents();
648 bool isSatisfied = (minDataNameLength <= entry->getFullName().size());
656 if (interest.getMaxSuffixComponents() >= 0)
658 size_t maxDataNameLength = interest.getName().size() + interest.getMaxSuffixComponents();
660 bool isSatisfied = (maxDataNameLength >= entry->getFullName().size());
669 if (interest.getMustBeFresh() && entry->getStaleTime() < time::steady_clock::now())
675 if (!interest.getPublisherPublicKeyLocator().empty())
677 if (entry->getData().getSignature().getType() == ndn::Signature::Sha256WithRsa)
679 ndn::SignatureSha256WithRsa rsaSignature(entry->getData().getSignature());
680 if (rsaSignature.getKeyLocator() != interest.getPublisherPublicKeyLocator())
693 if (doesInterestContainDigest)
695 const ndn::name::Component& lastComponent = entry->getFullName().get(-1);
697 if (!lastComponent.empty())
699 if (interest.getExclude().isExcluded(lastComponent))
708 if (entry->getFullName().size() >= interest.getName().size() + 1)
710 const ndn::name::Component& nextComponent = entry->getFullName()
711 .get(interest.getName().size());
712 if (!nextComponent.empty())
714 if (interest.getExclude().isExcluded(nextComponent))
728 Cs::recognizeInterestWithDigest(
const Interest& interest, cs::skip_list::Entry* entry)
const
732 if (interest.getMinSuffixComponents() <= 0 &&
733 interest.getName().size() == (entry->getFullName().size()))
735 const ndn::name::Component& last = interest.getName().get(-1);
736 if (last.value_size() == ndn::crypto::SHA256_DIGEST_SIZE)
750 <<
"skipList size " <<
size());
752 bool isIterated =
false;
754 SkipList::reverse_iterator topLayer = m_skipList.rbegin();
755 SkipListLayer::iterator head = (*topLayer)->begin();
757 if (!(*topLayer)->empty())
760 int layer = m_skipList.size() - 1;
761 for (SkipList::reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
765 head = (*rit)->begin();
767 updateTable[layer] = head;
769 if (head != (*rit)->end())
772 if (!isIterated && ((*head)->getFullName() == exactName))
776 eraseFromSkipList(entryToDelete);
778 m_cleanupIndex.remove(entryToDelete);
783 SkipListLayer::iterator it = head;
785 while ((*it)->getFullName() < exactName)
788 updateTable[layer] = it;
792 if (it == (*rit)->end())
799 head = (*head)->getIterators().find(layer - 1)->second;
809 head = updateTable[0];
812 bool isCsEmpty = (
size() == 0);
813 bool isInBoundaries = (head != (*m_skipList.begin())->
end());
814 bool isNameIdentical =
false;
815 if (!isCsEmpty && isInBoundaries)
818 isNameIdentical = (*head)->getFullName() == exactName;
825 eraseFromSkipList(entryToDelete);
827 m_cleanupIndex.remove(entryToDelete);
832 Cs::printSkipList()
const
836 int layer = m_skipList.size() - 1;
837 for (SkipList::const_reverse_iterator rit = m_skipList.rbegin(); rit != m_skipList.rend(); ++rit)
839 for (SkipListLayer::iterator it = (*rit)->begin(); it != (*rit)->end(); ++it)
841 NFD_LOG_TRACE(
"Layer " << layer <<
" " << (*it)->getFullName());
static const double SKIPLIST_PROBABILITY
probability for an entry in layer N to appear also in layer N+1
void erase(const Name &exactName)
deletes CS entry by the exact name
bool evictItem()
removes one Data packet from Content Store based on replacement policy
const_iterator begin() const
returns an iterator pointing to the first CS entry
std::list< cs::skip_list::Entry * > SkipListLayer
const_iterator end() const
returns an iterator referring to the past-the-end CS entry
const Data * find(const Interest &interest) const
finds the best match Data for an Interest
size_t getLimit() const
returns maximum allowed size of Content Store (in packets)
bool insert(const Data &data, bool isUnsolicited=false)
inserts a Data packet This method does not consider the payload of the Data packet.
const Name & getFullName() const
returns the full name (including implicit digest) of the Data packet stored in the CS entry ...
size_t size() const
returns current size of Content Store measured in packets
boost::random::mt19937 & getGlobalRng()
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.
#define NFD_LOG_INIT(name)
#define NFD_LOG_TRACE(expression)
represents an entry in a CS with skip list implementation
void setLimit(size_t nMaxPackets)
sets maximum allowed size of Content Store (in packets)
Cs(size_t nMaxPackets=10)