blob: d976def5088eb00395f1c3d83dc37bb71c2b6ef0 [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>
Alexander Afanasyevc91ebfa2015-01-03 18:09:57 -080038#include <boost/concept/assert.hpp>
39#include <boost/concept_check.hpp>
40#include <type_traits>
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080041
Junxiao Shiaf6569a2014-06-14 00:01:34 -070042/// max skip list layers
43static const size_t SKIPLIST_MAX_LAYERS = 32;
44/// probability for an entry in layer N to appear also in layer N+1
45static const double SKIPLIST_PROBABILITY = 0.25;
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080046
47NFD_LOG_INIT("ContentStore");
Alexander Afanasyevb927a3a2014-01-24 10:41:47 -080048
Alexander Afanasyev18bbf812014-01-29 01:40:23 -080049namespace nfd {
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070050
Alexander Afanasyevc91ebfa2015-01-03 18:09:57 -080051// http://en.cppreference.com/w/cpp/concept/ForwardIterator
52BOOST_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
56static_assert(std::is_default_constructible<Cs::const_iterator>::value,
57 "Cs::const_iterator must be default-constructible");
58#else
59BOOST_CONCEPT_ASSERT((boost::DefaultConstructible<Cs::const_iterator>));
60#endif // HAVE_IS_DEFAULT_CONSTRUCTIBLE
61
Steve DiBenedetto3a4f83d2014-06-02 14:58:54 -060062Cs::Cs(size_t nMaxPackets)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080063 : m_nMaxPackets(nMaxPackets)
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040064 , m_nPackets(0)
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070065{
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080066 SkipListLayer* zeroLayer = new SkipListLayer();
67 m_skipList.push_back(zeroLayer);
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040068
69 for (size_t i = 0; i < m_nMaxPackets; i++)
Alexander Afanasyevc91ebfa2015-01-03 18:09:57 -080070 m_freeCsEntries.push(new cs::skip_list::Entry());
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070071}
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080072
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070073Cs::~Cs()
74{
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040075 // 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 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080086}
87
88size_t
89Cs::size() const
90{
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040091 return m_nPackets; // size of the first layer in a skip list
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080092}
93
94void
95Cs::setLimit(size_t nMaxPackets)
96{
Alexander Afanasyev281b9162014-06-08 10:15:20 +030097 size_t oldNMaxPackets = m_nMaxPackets;
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080098 m_nMaxPackets = nMaxPackets;
99
Alexander Afanasyev281b9162014-06-08 10:15:20 +0300100 while (size() > m_nMaxPackets) {
101 evictItem();
102 }
103
104 if (m_nMaxPackets >= oldNMaxPackets) {
105 for (size_t i = oldNMaxPackets; i < m_nMaxPackets; i++) {
Alexander Afanasyevc91ebfa2015-01-03 18:09:57 -0800106 m_freeCsEntries.push(new cs::skip_list::Entry());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800107 }
Alexander Afanasyev281b9162014-06-08 10:15:20 +0300108 }
109 else {
110 for (size_t i = oldNMaxPackets; i > m_nMaxPackets; i--) {
111 delete m_freeCsEntries.front();
112 m_freeCsEntries.pop();
113 }
114 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800115}
116
117size_t
118Cs::getLimit() const
119{
120 return m_nMaxPackets;
121}
122
123//Reference: "Skip Lists: A Probabilistic Alternative to Balanced Trees" by W.Pugh
Alexander Afanasyevc91ebfa2015-01-03 18:09:57 -0800124std::pair<cs::skip_list::Entry*, bool>
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800125Cs::insertToSkipList(const Data& data, bool isUnsolicited)
126{
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700127 NFD_LOG_TRACE("insertToSkipList() " << data.getFullName() << ", "
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700128 << "skipList size " << size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800129
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400130 BOOST_ASSERT(m_cleanupIndex.size() <= size());
131 BOOST_ASSERT(m_freeCsEntries.size() > 0);
132
133 // take entry for the memory pool
Alexander Afanasyevc91ebfa2015-01-03 18:09:57 -0800134 cs::skip_list::Entry* entry = m_freeCsEntries.front();
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400135 m_freeCsEntries.pop();
136 m_nPackets++;
137 entry->setData(data, isUnsolicited);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800138
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
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400145 if (!(*topLayer)->empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800146 {
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
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400152 if (!isIterated)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800153 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
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700160 if (!isIterated && ((*head)->getFullName() >= entry->getFullName()))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800161 {
162 --updateTable[layer];
163 insertInFront = true;
164 }
165 else
166 {
167 SkipListLayer::iterator it = head;
168
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700169 while ((*it)->getFullName() < entry->getFullName())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800170 {
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 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700201 isNameIdentical = (*head)->getFullName() == entry->getFullName();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800202 }
203
204 //check if this is a duplicate packet
205 if (isNameIdentical)
206 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700207 NFD_LOG_TRACE("Duplicate name (with digest)");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800208
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700209 (*head)->setData(data, isUnsolicited); //updates stale time
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800210
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400211 // new entry not needed, returning to the pool
212 entry->release();
213 m_freeCsEntries.push(entry);
214 m_nPackets--;
215
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800216 return std::make_pair(*head, false);
217 }
218
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700219 NFD_LOG_TRACE("Not a duplicate");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800220
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700221 size_t randomLayer = pickRandomLayer();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800222
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400223 while (m_skipList.size() < randomLayer + 1)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800224 {
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700225 SkipListLayer* newLayer = new SkipListLayer();
226 m_skipList.push_back(newLayer);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800227
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700228 updateTable[(m_skipList.size() - 1)] = newLayer->begin();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800229 }
230
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700231 size_t layer = 0;
232 for (SkipList::iterator i = m_skipList.begin();
233 i != m_skipList.end() && layer <= randomLayer; ++i)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800234 {
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
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700242 NFD_LOG_TRACE("pushback " << &(*last));
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800243 }
244 else if (updateTable[layer] == (*i)->end() && insertInFront)
245 {
246 (*i)->push_front(entry);
247 entry->setIterator(layer, (*i)->begin());
248
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700249 NFD_LOG_TRACE("pushfront ");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800250 }
251 else
252 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700253 NFD_LOG_TRACE("insertafter");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800254 ++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
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800261 return std::make_pair(entry, true);
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700262}
263
264bool
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800265Cs::insert(const Data& data, bool isUnsolicited)
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700266{
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700267 NFD_LOG_TRACE("insert() " << data.getFullName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800268
269 if (isFull())
270 {
271 evictItem();
272 }
273
274 //pointer and insertion status
Alexander Afanasyevc91ebfa2015-01-03 18:09:57 -0800275 std::pair<cs::skip_list::Entry*, bool> entry = insertToSkipList(data, isUnsolicited);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800276
277 //new entry
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400278 if (static_cast<bool>(entry.first) && (entry.second == true))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800279 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400280 m_cleanupIndex.push_back(entry.first);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800281 return true;
282 }
283
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700284 return false;
285}
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800286
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700287size_t
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800288Cs::pickRandomLayer() const
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700289{
Junxiao Shiaf6569a2014-06-14 00:01:34 -0700290 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;
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800296 }
Junxiao Shiaf6569a2014-06-14 00:01:34 -0700297 }
298 return layer;
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800299}
300
301bool
302Cs::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
310bool
Alexander Afanasyevc91ebfa2015-01-03 18:09:57 -0800311Cs::eraseFromSkipList(cs::skip_list::Entry* entry)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800312{
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700313 NFD_LOG_TRACE("eraseFromSkipList() " << entry->getFullName());
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700314 NFD_LOG_TRACE("SkipList size " << size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800315
316 bool isErased = false;
317
Alexander Afanasyevc91ebfa2015-01-03 18:09:57 -0800318 const std::map<int, std::list<cs::skip_list::Entry*>::iterator>& iterators = entry->getIterators();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800319
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400320 if (!iterators.empty())
321 {
322 int layer = 0;
323
324 for (SkipList::iterator it = m_skipList.begin(); it != m_skipList.end(); )
325 {
Alexander Afanasyevc91ebfa2015-01-03 18:09:57 -0800326 std::map<int, std::list<cs::skip_list::Entry*>::iterator>::const_iterator i = iterators.find(layer);
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400327
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 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800348 }
349
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400350 //delete entry;
351 if (isErased)
352 {
353 entry->release();
354 m_freeCsEntries.push(entry);
355 m_nPackets--;
356 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800357
358 return isErased;
359}
360
361bool
362Cs::evictItem()
363{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700364 NFD_LOG_TRACE("evictItem()");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800365
Alexander Afanasyev4cf41702014-10-19 23:46:10 -0400366 if (!m_cleanupIndex.get<unsolicited>().empty()) {
367 CleanupIndex::index<unsolicited>::type::const_iterator firstSolicited =
368 m_cleanupIndex.get<unsolicited>().upper_bound(false);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800369
Alexander Afanasyev4cf41702014-10-19 23:46:10 -0400370 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 }
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400382 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800383
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400384 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");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800388
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400389 eraseFromSkipList(*m_cleanupIndex.get<byStaleness>().begin());
390 m_cleanupIndex.get<byStaleness>().erase(m_cleanupIndex.get<byStaleness>().begin());
391 return true;
392 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800393
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400394 if (!m_cleanupIndex.get<byArrival>().empty())
395 {
396 NFD_LOG_TRACE("Evict from arrival queue");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800397
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400398 eraseFromSkipList(*m_cleanupIndex.get<byArrival>().begin());
399 m_cleanupIndex.get<byArrival>().erase(m_cleanupIndex.get<byArrival>().begin());
400 return true;
401 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800402
403 return false;
404}
405
406const Data*
407Cs::find(const Interest& interest) const
408{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700409 NFD_LOG_TRACE("find() " << interest.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800410
411 bool isIterated = false;
412 SkipList::const_reverse_iterator topLayer = m_skipList.rbegin();
413 SkipListLayer::iterator head = (*topLayer)->begin();
414
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400415 if (!(*topLayer)->empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800416 {
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
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700428 if (!isIterated && (interest.getName().isPrefixOf((*head)->getFullName())))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800429 {
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
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700444 while ((*it)->getFullName() < interest.getName())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800445 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700446 NFD_LOG_TRACE((*it)->getFullName() << " < " << interest.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800447 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 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400463 if (isIterated)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800464 return selectChild(interest, head);
465 }
466
467 layer--;
468 }
469 }
470
Alexander Afanasyevc9765df2014-01-25 19:24:27 -0800471 return 0;
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700472}
473
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800474const Data*
475Cs::selectChild(const Interest& interest, SkipListLayer::iterator startingPoint) const
476{
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400477 BOOST_ASSERT(startingPoint != (*m_skipList.begin())->end());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800478
479 if (startingPoint != (*m_skipList.begin())->begin())
480 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700481 BOOST_ASSERT((*startingPoint)->getFullName() < interest.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800482 }
483
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400484 NFD_LOG_TRACE("selectChild() " << interest.getChildSelector() << " "
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700485 << (*startingPoint)->getFullName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800486
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 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700497 isInPrefix = interest.getName().getPrefix(-1).isPrefixOf((*startingPoint)->getFullName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800498 }
499 else
500 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700501 isInPrefix = interest.getName().isPrefixOf((*startingPoint)->getFullName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800502 }
503
504 if (isInPrefix)
505 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400506 if (doesComplyWithSelectors(interest, *startingPoint, doesInterestContainDigest))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800507 {
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 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400529 doesInterestContainDigest = recognizeInterestWithDigest(interest,
530 *rightmostCandidate);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800531
532 if (doesInterestContainDigest)
533 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400534 isInPrefix = interest.getName().getPrefix(-1)
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700535 .isPrefixOf((*rightmostCandidate)->getFullName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800536 }
537 else
538 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700539 isInPrefix = interest.getName().isPrefixOf((*rightmostCandidate)->getFullName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800540 }
541 }
542
543 if (isInPrefix)
544 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400545 if (doesComplyWithSelectors(interest, *rightmostCandidate, doesInterestContainDigest))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800546 {
547 if (hasLeftmostSelector)
548 {
549 return &(*rightmostCandidate)->getData();
550 }
551
552 if (hasRightmostSelector)
553 {
554 if (doesInterestContainDigest)
555 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400556 // get prefix which is one component longer than Interest name
557 // (without digest)
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700558 const Name& childPrefix = (*rightmostCandidate)->getFullName()
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400559 .getPrefix(interest.getName().size());
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700560 NFD_LOG_TRACE("Child prefix" << childPrefix);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800561
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400562 if (currentChildPrefix.empty() || (childPrefix != currentChildPrefix))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800563 {
564 currentChildPrefix = childPrefix;
565 rightmost = rightmostCandidate;
566 }
567 }
568 else
569 {
570 // get prefix which is one component longer than Interest name
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700571 const Name& childPrefix = (*rightmostCandidate)->getFullName()
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400572 .getPrefix(interest.getName().size() + 1);
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700573 NFD_LOG_TRACE("Child prefix" << childPrefix);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800574
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400575 if (currentChildPrefix.empty() || (childPrefix != currentChildPrefix))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800576 {
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 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700601 isInPrefix = interest.getName().getPrefix(-1).isPrefixOf((*startingPoint)->getFullName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800602 }
603 else
604 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700605 isInPrefix = interest.getName().isPrefixOf((*startingPoint)->getFullName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800606 }
607
608 if (isInPrefix)
609 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400610 if (doesComplyWithSelectors(interest, *startingPoint, doesInterestContainDigest))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800611 {
612 return &(*startingPoint)->getData();
613 }
614 }
615 }
616
617 return 0;
618}
619
620bool
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400621Cs::doesComplyWithSelectors(const Interest& interest,
Alexander Afanasyevc91ebfa2015-01-03 18:09:57 -0800622 cs::skip_list::Entry* entry,
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400623 bool doesInterestContainDigest) const
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800624{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700625 NFD_LOG_TRACE("doesComplyWithSelectors()");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800626
627 /// \todo The following detection is not correct
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700628 /// 1. If Interest name ends with 32-octet component doesn't mean that this component is
629 /// digest
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400630 /// 2. Only min/max selectors (both 0) can be specified, all other selectors do not
631 /// make sense for interests with digest (though not sure if we need to enforce this)
632
633 if (doesInterestContainDigest)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800634 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700635 if (interest.getName().get(-1) != entry->getFullName().get(-1))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800636 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700637 NFD_LOG_TRACE("violates implicit digest");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800638 return false;
639 }
640 }
641
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400642 if (!doesInterestContainDigest)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800643 {
644 if (interest.getMinSuffixComponents() >= 0)
645 {
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700646 size_t minDataNameLength = interest.getName().size() + interest.getMinSuffixComponents();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800647
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700648 bool isSatisfied = (minDataNameLength <= entry->getFullName().size());
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400649 if (!isSatisfied)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800650 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700651 NFD_LOG_TRACE("violates minComponents");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800652 return false;
653 }
654 }
655
656 if (interest.getMaxSuffixComponents() >= 0)
657 {
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700658 size_t maxDataNameLength = interest.getName().size() + interest.getMaxSuffixComponents();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800659
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700660 bool isSatisfied = (maxDataNameLength >= entry->getFullName().size());
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400661 if (!isSatisfied)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800662 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700663 NFD_LOG_TRACE("violates maxComponents");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800664 return false;
665 }
666 }
667 }
668
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -0700669 if (interest.getMustBeFresh() && entry->getStaleTime() < time::steady_clock::now())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800670 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700671 NFD_LOG_TRACE("violates mustBeFresh");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800672 return false;
673 }
674
Ilya Moiseenko9c9231b2014-04-10 11:05:12 -0400675 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
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400693 if (doesInterestContainDigest)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800694 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700695 const ndn::name::Component& lastComponent = entry->getFullName().get(-1);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800696
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400697 if (!lastComponent.empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800698 {
699 if (interest.getExclude().isExcluded(lastComponent))
700 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700701 NFD_LOG_TRACE("violates exclusion");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800702 return false;
703 }
704 }
705 }
706 else
707 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700708 if (entry->getFullName().size() >= interest.getName().size() + 1)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800709 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700710 const ndn::name::Component& nextComponent = entry->getFullName()
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400711 .get(interest.getName().size());
712 if (!nextComponent.empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800713 {
714 if (interest.getExclude().isExcluded(nextComponent))
715 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700716 NFD_LOG_TRACE("violates exclusion");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800717 return false;
718 }
719 }
720 }
721 }
722
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700723 NFD_LOG_TRACE("complies");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800724 return true;
725}
726
727bool
Alexander Afanasyevc91ebfa2015-01-03 18:09:57 -0800728Cs::recognizeInterestWithDigest(const Interest& interest, cs::skip_list::Entry* entry) const
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800729{
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 &&
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700733 interest.getName().size() == (entry->getFullName().size()))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800734 {
735 const ndn::name::Component& last = interest.getName().get(-1);
736 if (last.value_size() == ndn::crypto::SHA256_DIGEST_SIZE)
737 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700738 NFD_LOG_TRACE("digest recognized");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800739 return true;
740 }
741 }
742
743 return false;
744}
745
746void
747Cs::erase(const Name& exactName)
748{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700749 NFD_LOG_TRACE("insert() " << exactName << ", "
750 << "skipList size " << size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800751
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
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400757 if (!(*topLayer)->empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800758 {
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
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400764 if (!isIterated)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800765 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
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700772 if (!isIterated && ((*head)->getFullName() == exactName))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800773 {
Alexander Afanasyevc91ebfa2015-01-03 18:09:57 -0800774 cs::skip_list::Entry* entryToDelete = *head;
Alexander Afanasyev8934c422015-01-05 15:58:46 -0800775 NFD_LOG_TRACE("Found target " << entryToDelete->getFullName());
776 eraseFromSkipList(entryToDelete);
777 // head can become invalid after eraseFromSkipList
778 m_cleanupIndex.remove(entryToDelete);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800779 return;
780 }
781 else
782 {
783 SkipListLayer::iterator it = head;
784
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700785 while ((*it)->getFullName() < exactName)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800786 {
787 head = it;
788 updateTable[layer] = it;
789 isIterated = true;
790
791 ++it;
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400792 if (it == (*rit)->end())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800793 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 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700817 NFD_LOG_TRACE("Identical? " << (*head)->getFullName());
818 isNameIdentical = (*head)->getFullName() == exactName;
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800819 }
820
821 if (isNameIdentical)
822 {
Alexander Afanasyevc91ebfa2015-01-03 18:09:57 -0800823 cs::skip_list::Entry* entryToDelete = *head;
Alexander Afanasyev8934c422015-01-05 15:58:46 -0800824 NFD_LOG_TRACE("Found target " << entryToDelete->getFullName());
825 eraseFromSkipList(entryToDelete);
826 // head can become invalid after eraseFromSkipList
827 m_cleanupIndex.remove(entryToDelete);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800828 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800829}
830
831void
832Cs::printSkipList() const
833{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700834 NFD_LOG_TRACE("print()");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800835 //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 {
Alexander Afanasyev4b3fc862014-06-19 14:57:57 -0700841 NFD_LOG_TRACE("Layer " << layer << " " << (*it)->getFullName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800842 }
843 layer--;
844 }
845}
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700846
Alexander Afanasyev18bbf812014-01-29 01:40:23 -0800847} //namespace nfd