blob: 874ef520a830461e0bea4ede33519751c45d0441 [file] [log] [blame]
Junxiao Shi0fcb41e2014-01-24 10:29:43 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -07003 * 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
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -08009 *
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -070010 * This file is part of NFD (Named Data Networking Forwarding Daemon).
11 * See AUTHORS.md for complete list of NFD authors and contributors.
12 *
13 * NFD is free software: you can redistribute it and/or modify it under the terms
14 * of the GNU General Public License as published by the Free Software Foundation,
15 * either version 3 of the License, or (at your option) any later version.
16 *
17 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
18 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
19 * PURPOSE. See the GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along with
22 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
23 *
24 * \author Ilya Moiseenko <iliamo@ucla.edu>
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070025 */
26
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070027#include "cs.hpp"
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060028#include "core/logger.hpp"
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080029#include <ndn-cpp-dev/util/crypto.hpp>
30
31#define SKIPLIST_MAX_LAYERS 32
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040032#define SKIPLIST_PROBABILITY 25 // 25% (p = 1/4)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080033
34NFD_LOG_INIT("ContentStore");
Alexander Afanasyevb927a3a2014-01-24 10:41:47 -080035
Alexander Afanasyev18bbf812014-01-29 01:40:23 -080036namespace nfd {
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070037
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080038Cs::Cs(int nMaxPackets)
39 : m_nMaxPackets(nMaxPackets)
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040040 , m_nPackets(0)
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070041{
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080042 SkipListLayer* zeroLayer = new SkipListLayer();
43 m_skipList.push_back(zeroLayer);
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040044
45 for (size_t i = 0; i < m_nMaxPackets; i++)
46 m_freeCsEntries.push(new cs::Entry());
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070047}
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080048
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070049Cs::~Cs()
50{
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040051 // evict all items from CS
52 while (evictItem())
53 ;
54
55 BOOST_ASSERT(m_freeCsEntries.size() == m_nMaxPackets);
56
57 while (!m_freeCsEntries.empty())
58 {
59 delete m_freeCsEntries.front();
60 m_freeCsEntries.pop();
61 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080062}
63
64size_t
65Cs::size() const
66{
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040067 return m_nPackets; // size of the first layer in a skip list
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080068}
69
70void
71Cs::setLimit(size_t nMaxPackets)
72{
73 m_nMaxPackets = nMaxPackets;
74
75 while (isFull())
76 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040077 if (!evictItem())
78 break;
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080079 }
80}
81
82size_t
83Cs::getLimit() const
84{
85 return m_nMaxPackets;
86}
87
88//Reference: "Skip Lists: A Probabilistic Alternative to Balanced Trees" by W.Pugh
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040089std::pair<cs::Entry*, bool>
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080090Cs::insertToSkipList(const Data& data, bool isUnsolicited)
91{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -070092 NFD_LOG_TRACE("insertToSkipList() " << data.getName() << ", "
93 << "skipList size " << size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080094
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040095 BOOST_ASSERT(m_cleanupIndex.size() <= size());
96 BOOST_ASSERT(m_freeCsEntries.size() > 0);
97
98 // take entry for the memory pool
99 cs::Entry* entry = m_freeCsEntries.front();
100 m_freeCsEntries.pop();
101 m_nPackets++;
102 entry->setData(data, isUnsolicited);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800103
104 bool insertInFront = false;
105 bool isIterated = false;
106 SkipList::reverse_iterator topLayer = m_skipList.rbegin();
107 SkipListLayer::iterator updateTable[SKIPLIST_MAX_LAYERS];
108 SkipListLayer::iterator head = (*topLayer)->begin();
109
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400110 if (!(*topLayer)->empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800111 {
112 //start from the upper layer towards bottom
113 int layer = m_skipList.size() - 1;
114 for (SkipList::reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
115 {
116 //if we didn't do any iterations on the higher layers, start from the begin() again
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400117 if (!isIterated)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800118 head = (*rit)->begin();
119
120 updateTable[layer] = head;
121
122 if (head != (*rit)->end())
123 {
124 // it can happen when begin() contains the element in front of which we need to insert
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400125 if (!isIterated && ((*head)->getName() >= entry->getName()))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800126 {
127 --updateTable[layer];
128 insertInFront = true;
129 }
130 else
131 {
132 SkipListLayer::iterator it = head;
133
134 while ((*it)->getName() < entry->getName())
135 {
136 head = it;
137 updateTable[layer] = it;
138 isIterated = true;
139
140 ++it;
141 if (it == (*rit)->end())
142 break;
143 }
144 }
145 }
146
147 if (layer > 0)
148 head = (*head)->getIterators().find(layer - 1)->second; // move HEAD to the lower layer
149
150 layer--;
151 }
152 }
153 else
154 {
155 updateTable[0] = (*topLayer)->begin(); //initialization
156 }
157
158 head = updateTable[0];
159 ++head; // look at the next slot to check if it contains a duplicate
160
161 bool isCsEmpty = (size() == 0);
162 bool isInBoundaries = (head != (*m_skipList.begin())->end());
163 bool isNameIdentical = false;
164 if (!isCsEmpty && isInBoundaries)
165 {
166 isNameIdentical = (*head)->getName() == entry->getName();
167 }
168
169 //check if this is a duplicate packet
170 if (isNameIdentical)
171 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700172 NFD_LOG_TRACE("Duplicate name (with digest)");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800173
Alexander Afanasyev88811622014-04-10 00:00:15 -0700174 (*head)->setData(data, isUnsolicited, entry->getDigest()); //updates stale time
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800175
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400176 // new entry not needed, returning to the pool
177 entry->release();
178 m_freeCsEntries.push(entry);
179 m_nPackets--;
180
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800181 return std::make_pair(*head, false);
182 }
183
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700184 NFD_LOG_TRACE("Not a duplicate");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800185
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700186 size_t randomLayer = pickRandomLayer();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800187
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400188 while (m_skipList.size() < randomLayer + 1)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800189 {
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700190 SkipListLayer* newLayer = new SkipListLayer();
191 m_skipList.push_back(newLayer);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800192
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700193 updateTable[(m_skipList.size() - 1)] = newLayer->begin();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800194 }
195
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700196 size_t layer = 0;
197 for (SkipList::iterator i = m_skipList.begin();
198 i != m_skipList.end() && layer <= randomLayer; ++i)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800199 {
200 if (updateTable[layer] == (*i)->end() && !insertInFront)
201 {
202 (*i)->push_back(entry);
203 SkipListLayer::iterator last = (*i)->end();
204 --last;
205 entry->setIterator(layer, last);
206
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700207 NFD_LOG_TRACE("pushback " << &(*last));
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800208 }
209 else if (updateTable[layer] == (*i)->end() && insertInFront)
210 {
211 (*i)->push_front(entry);
212 entry->setIterator(layer, (*i)->begin());
213
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700214 NFD_LOG_TRACE("pushfront ");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800215 }
216 else
217 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700218 NFD_LOG_TRACE("insertafter");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800219 ++updateTable[layer]; // insert after
220 SkipListLayer::iterator position = (*i)->insert(updateTable[layer], entry);
221 entry->setIterator(layer, position); // save iterator where item was inserted
222 }
223 layer++;
224 }
225
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800226 return std::make_pair(entry, true);
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700227}
228
229bool
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800230Cs::insert(const Data& data, bool isUnsolicited)
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700231{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700232 NFD_LOG_TRACE("insert() " << data.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800233
234 if (isFull())
235 {
236 evictItem();
237 }
238
239 //pointer and insertion status
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400240 std::pair<cs::Entry*, bool> entry = insertToSkipList(data, isUnsolicited);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800241
242 //new entry
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400243 if (static_cast<bool>(entry.first) && (entry.second == true))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800244 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400245 m_cleanupIndex.push_back(entry.first);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800246 return true;
247 }
248
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700249 return false;
250}
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800251
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700252size_t
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800253Cs::pickRandomLayer() const
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700254{
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800255 int layer = -1;
256 int randomValue;
257
258 do
259 {
260 layer++;
261 randomValue = rand() % 100 + 1;
262 }
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400263 while ((randomValue < SKIPLIST_PROBABILITY) && (layer < SKIPLIST_MAX_LAYERS));
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800264
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700265 return static_cast<size_t>(layer);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800266}
267
268bool
269Cs::isFull() const
270{
271 if (size() >= m_nMaxPackets) //size of the first layer vs. max size
272 return true;
273
274 return false;
275}
276
277bool
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400278Cs::eraseFromSkipList(cs::Entry* entry)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800279{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700280 NFD_LOG_TRACE("eraseFromSkipList() " << entry->getName());
281 NFD_LOG_TRACE("SkipList size " << size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800282
283 bool isErased = false;
284
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400285 const std::map<int, std::list<cs::Entry*>::iterator>& iterators = entry->getIterators();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800286
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400287 if (!iterators.empty())
288 {
289 int layer = 0;
290
291 for (SkipList::iterator it = m_skipList.begin(); it != m_skipList.end(); )
292 {
293 std::map<int, std::list<cs::Entry*>::iterator>::const_iterator i = iterators.find(layer);
294
295 if (i != iterators.end())
296 {
297 (*it)->erase(i->second);
298 entry->removeIterator(layer);
299 isErased = true;
300
301 //remove layers that do not contain any elements (starting from the second layer)
302 if ((layer != 0) && (*it)->empty())
303 {
304 delete *it;
305 it = m_skipList.erase(it);
306 }
307 else
308 ++it;
309
310 layer++;
311 }
312 else
313 break;
314 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800315 }
316
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400317 //delete entry;
318 if (isErased)
319 {
320 entry->release();
321 m_freeCsEntries.push(entry);
322 m_nPackets--;
323 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800324
325 return isErased;
326}
327
328bool
329Cs::evictItem()
330{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700331 NFD_LOG_TRACE("evictItem()");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800332
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400333 if (!m_cleanupIndex.get<unsolicited>().empty() &&
334 (*m_cleanupIndex.get<unsolicited>().begin())->isUnsolicited())
335 {
336 NFD_LOG_TRACE("Evict from unsolicited queue");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800337
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400338 eraseFromSkipList(*m_cleanupIndex.get<unsolicited>().begin());
339 m_cleanupIndex.get<unsolicited>().erase(m_cleanupIndex.get<unsolicited>().begin());
340 return true;
341 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800342
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400343 if (!m_cleanupIndex.get<byStaleness>().empty() &&
344 (*m_cleanupIndex.get<byStaleness>().begin())->getStaleTime() < time::steady_clock::now())
345 {
346 NFD_LOG_TRACE("Evict from staleness queue");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800347
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400348 eraseFromSkipList(*m_cleanupIndex.get<byStaleness>().begin());
349 m_cleanupIndex.get<byStaleness>().erase(m_cleanupIndex.get<byStaleness>().begin());
350 return true;
351 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800352
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400353 if (!m_cleanupIndex.get<byArrival>().empty())
354 {
355 NFD_LOG_TRACE("Evict from arrival queue");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800356
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400357 eraseFromSkipList(*m_cleanupIndex.get<byArrival>().begin());
358 m_cleanupIndex.get<byArrival>().erase(m_cleanupIndex.get<byArrival>().begin());
359 return true;
360 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800361
362 return false;
363}
364
365const Data*
366Cs::find(const Interest& interest) const
367{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700368 NFD_LOG_TRACE("find() " << interest.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800369
370 bool isIterated = false;
371 SkipList::const_reverse_iterator topLayer = m_skipList.rbegin();
372 SkipListLayer::iterator head = (*topLayer)->begin();
373
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400374 if (!(*topLayer)->empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800375 {
376 //start from the upper layer towards bottom
377 int layer = m_skipList.size() - 1;
378 for (SkipList::const_reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
379 {
380 //if we didn't do any iterations on the higher layers, start from the begin() again
381 if (!isIterated)
382 head = (*rit)->begin();
383
384 if (head != (*rit)->end())
385 {
386 // it happens when begin() contains the element we want to find
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400387 if (!isIterated && (interest.getName().isPrefixOf((*head)->getName())))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800388 {
389 if (layer > 0)
390 {
391 layer--;
392 continue; // try lower layer
393 }
394 else
395 {
396 isIterated = true;
397 }
398 }
399 else
400 {
401 SkipListLayer::iterator it = head;
402
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400403 while ((*it)->getName() < interest.getName())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800404 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700405 NFD_LOG_TRACE((*it)->getName() << " < " << interest.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800406 head = it;
407 isIterated = true;
408
409 ++it;
410 if (it == (*rit)->end())
411 break;
412 }
413 }
414 }
415
416 if (layer > 0)
417 {
418 head = (*head)->getIterators().find(layer - 1)->second; // move HEAD to the lower layer
419 }
420 else //if we reached the first layer
421 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400422 if (isIterated)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800423 return selectChild(interest, head);
424 }
425
426 layer--;
427 }
428 }
429
Alexander Afanasyevc9765df2014-01-25 19:24:27 -0800430 return 0;
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700431}
432
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800433const Data*
434Cs::selectChild(const Interest& interest, SkipListLayer::iterator startingPoint) const
435{
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400436 BOOST_ASSERT(startingPoint != (*m_skipList.begin())->end());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800437
438 if (startingPoint != (*m_skipList.begin())->begin())
439 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400440 BOOST_ASSERT((*startingPoint)->getName() < interest.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800441 }
442
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400443 NFD_LOG_TRACE("selectChild() " << interest.getChildSelector() << " "
444 << (*startingPoint)->getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800445
446 bool hasLeftmostSelector = (interest.getChildSelector() <= 0);
447 bool hasRightmostSelector = !hasLeftmostSelector;
448
449 if (hasLeftmostSelector)
450 {
451 bool doesInterestContainDigest = recognizeInterestWithDigest(interest, *startingPoint);
452 bool isInPrefix = false;
453
454 if (doesInterestContainDigest)
455 {
456 isInPrefix = interest.getName().getPrefix(-1).isPrefixOf((*startingPoint)->getName());
457 }
458 else
459 {
460 isInPrefix = interest.getName().isPrefixOf((*startingPoint)->getName());
461 }
462
463 if (isInPrefix)
464 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400465 if (doesComplyWithSelectors(interest, *startingPoint, doesInterestContainDigest))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800466 {
467 return &(*startingPoint)->getData();
468 }
469 }
470 }
471
472 //iterate to the right
473 SkipListLayer::iterator rightmost = startingPoint;
474 if (startingPoint != (*m_skipList.begin())->end())
475 {
476 SkipListLayer::iterator rightmostCandidate = startingPoint;
477 Name currentChildPrefix("");
478
479 while (true)
480 {
481 ++rightmostCandidate;
482
483 bool isInBoundaries = (rightmostCandidate != (*m_skipList.begin())->end());
484 bool isInPrefix = false;
485 bool doesInterestContainDigest = false;
486 if (isInBoundaries)
487 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400488 doesInterestContainDigest = recognizeInterestWithDigest(interest,
489 *rightmostCandidate);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800490
491 if (doesInterestContainDigest)
492 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400493 isInPrefix = interest.getName().getPrefix(-1)
494 .isPrefixOf((*rightmostCandidate)->getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800495 }
496 else
497 {
498 isInPrefix = interest.getName().isPrefixOf((*rightmostCandidate)->getName());
499 }
500 }
501
502 if (isInPrefix)
503 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400504 if (doesComplyWithSelectors(interest, *rightmostCandidate, doesInterestContainDigest))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800505 {
506 if (hasLeftmostSelector)
507 {
508 return &(*rightmostCandidate)->getData();
509 }
510
511 if (hasRightmostSelector)
512 {
513 if (doesInterestContainDigest)
514 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400515 // get prefix which is one component longer than Interest name
516 // (without digest)
517 const Name& childPrefix = (*rightmostCandidate)->getName()
518 .getPrefix(interest.getName().size());
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700519 NFD_LOG_TRACE("Child prefix" << childPrefix);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800520
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400521 if (currentChildPrefix.empty() || (childPrefix != currentChildPrefix))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800522 {
523 currentChildPrefix = childPrefix;
524 rightmost = rightmostCandidate;
525 }
526 }
527 else
528 {
529 // get prefix which is one component longer than Interest name
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400530 const Name& childPrefix = (*rightmostCandidate)->getName()
531 .getPrefix(interest.getName().size() + 1);
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700532 NFD_LOG_TRACE("Child prefix" << childPrefix);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800533
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400534 if (currentChildPrefix.empty() || (childPrefix != currentChildPrefix))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800535 {
536 currentChildPrefix = childPrefix;
537 rightmost = rightmostCandidate;
538 }
539 }
540 }
541 }
542 }
543 else
544 break;
545 }
546 }
547
548 if (rightmost != startingPoint)
549 {
550 return &(*rightmost)->getData();
551 }
552
553 if (hasRightmostSelector) // if rightmost was not found, try starting point
554 {
555 bool doesInterestContainDigest = recognizeInterestWithDigest(interest, *startingPoint);
556 bool isInPrefix = false;
557
558 if (doesInterestContainDigest)
559 {
560 isInPrefix = interest.getName().getPrefix(-1).isPrefixOf((*startingPoint)->getName());
561 }
562 else
563 {
564 isInPrefix = interest.getName().isPrefixOf((*startingPoint)->getName());
565 }
566
567 if (isInPrefix)
568 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400569 if (doesComplyWithSelectors(interest, *startingPoint, doesInterestContainDigest))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800570 {
571 return &(*startingPoint)->getData();
572 }
573 }
574 }
575
576 return 0;
577}
578
579bool
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400580Cs::doesComplyWithSelectors(const Interest& interest,
581 cs::Entry* entry,
582 bool doesInterestContainDigest) const
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800583{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700584 NFD_LOG_TRACE("doesComplyWithSelectors()");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800585
586 /// \todo The following detection is not correct
587 /// 1. If data name ends with 32-octet component doesn't mean that this component is digest
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400588 /// 2. Only min/max selectors (both 0) can be specified, all other selectors do not
589 /// make sense for interests with digest (though not sure if we need to enforce this)
590
591 if (doesInterestContainDigest)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800592 {
593 const ndn::name::Component& last = interest.getName().get(-1);
594 const ndn::ConstBufferPtr& digest = entry->getDigest();
595
596 BOOST_ASSERT(digest->size() == last.value_size());
597 BOOST_ASSERT(digest->size() == ndn::crypto::SHA256_DIGEST_SIZE);
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700598
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800599 if (std::memcmp(digest->buf(), last.value(), ndn::crypto::SHA256_DIGEST_SIZE) != 0)
600 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700601 NFD_LOG_TRACE("violates implicit digest");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800602 return false;
603 }
604 }
605
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400606 if (!doesInterestContainDigest)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800607 {
608 if (interest.getMinSuffixComponents() >= 0)
609 {
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700610 size_t minDataNameLength = interest.getName().size() + interest.getMinSuffixComponents();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800611
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700612 bool isSatisfied = (minDataNameLength <= entry->getName().size());
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400613 if (!isSatisfied)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800614 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700615 NFD_LOG_TRACE("violates minComponents");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800616 return false;
617 }
618 }
619
620 if (interest.getMaxSuffixComponents() >= 0)
621 {
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700622 size_t maxDataNameLength = interest.getName().size() + interest.getMaxSuffixComponents();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800623
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700624 bool isSatisfied = (maxDataNameLength >= entry->getName().size());
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400625 if (!isSatisfied)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800626 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700627 NFD_LOG_TRACE("violates maxComponents");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800628 return false;
629 }
630 }
631 }
632
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -0700633 if (interest.getMustBeFresh() && entry->getStaleTime() < time::steady_clock::now())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800634 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700635 NFD_LOG_TRACE("violates mustBeFresh");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800636 return false;
637 }
638
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400639 if (doesInterestContainDigest)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800640 {
641 const ndn::name::Component& lastComponent = entry->getName().get(-1);
642
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400643 if (!lastComponent.empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800644 {
645 if (interest.getExclude().isExcluded(lastComponent))
646 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700647 NFD_LOG_TRACE("violates exclusion");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800648 return false;
649 }
650 }
651 }
652 else
653 {
654 if (entry->getName().size() >= interest.getName().size() + 1)
655 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400656 const ndn::name::Component& nextComponent = entry->getName()
657 .get(interest.getName().size());
658 if (!nextComponent.empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800659 {
660 if (interest.getExclude().isExcluded(nextComponent))
661 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700662 NFD_LOG_TRACE("violates exclusion");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800663 return false;
664 }
665 }
666 }
667 }
668
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700669 NFD_LOG_TRACE("complies");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800670 return true;
671}
672
673bool
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400674Cs::recognizeInterestWithDigest(const Interest& interest, cs::Entry* entry) const
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800675{
676 // only when min selector is not specified or specified with value of 0
677 // and Interest's name length is exactly the length of the name of CS entry
678 if (interest.getMinSuffixComponents() <= 0 &&
679 interest.getName().size() == (entry->getName().size()))
680 {
681 const ndn::name::Component& last = interest.getName().get(-1);
682 if (last.value_size() == ndn::crypto::SHA256_DIGEST_SIZE)
683 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700684 NFD_LOG_TRACE("digest recognized");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800685 return true;
686 }
687 }
688
689 return false;
690}
691
692void
693Cs::erase(const Name& exactName)
694{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700695 NFD_LOG_TRACE("insert() " << exactName << ", "
696 << "skipList size " << size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800697
698 bool isIterated = false;
699 SkipListLayer::iterator updateTable[SKIPLIST_MAX_LAYERS];
700 SkipList::reverse_iterator topLayer = m_skipList.rbegin();
701 SkipListLayer::iterator head = (*topLayer)->begin();
702
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400703 if (!(*topLayer)->empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800704 {
705 //start from the upper layer towards bottom
706 int layer = m_skipList.size() - 1;
707 for (SkipList::reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
708 {
709 //if we didn't do any iterations on the higher layers, start from the begin() again
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400710 if (!isIterated)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800711 head = (*rit)->begin();
712
713 updateTable[layer] = head;
714
715 if (head != (*rit)->end())
716 {
717 // it can happen when begin() contains the element we want to remove
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400718 if (!isIterated && ((*head)->getName() == exactName))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800719 {
720 eraseFromSkipList(*head);
721 return;
722 }
723 else
724 {
725 SkipListLayer::iterator it = head;
726
727 while ((*it)->getName() < exactName)
728 {
729 head = it;
730 updateTable[layer] = it;
731 isIterated = true;
732
733 ++it;
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400734 if (it == (*rit)->end())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800735 break;
736 }
737 }
738 }
739
740 if (layer > 0)
741 head = (*head)->getIterators().find(layer - 1)->second; // move HEAD to the lower layer
742
743 layer--;
744 }
745 }
746 else
747 {
748 return;
749 }
750
751 head = updateTable[0];
752 ++head; // look at the next slot to check if it contains the item we want to remove
753
754 bool isCsEmpty = (size() == 0);
755 bool isInBoundaries = (head != (*m_skipList.begin())->end());
756 bool isNameIdentical = false;
757 if (!isCsEmpty && isInBoundaries)
758 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700759 NFD_LOG_TRACE("Identical? " << (*head)->getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800760 isNameIdentical = (*head)->getName() == exactName;
761 }
762
763 if (isNameIdentical)
764 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700765 NFD_LOG_TRACE("Found target " << (*head)->getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800766 eraseFromSkipList(*head);
767 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800768}
769
770void
771Cs::printSkipList() const
772{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700773 NFD_LOG_TRACE("print()");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800774 //start from the upper layer towards bottom
775 int layer = m_skipList.size() - 1;
776 for (SkipList::const_reverse_iterator rit = m_skipList.rbegin(); rit != m_skipList.rend(); ++rit)
777 {
778 for (SkipListLayer::iterator it = (*rit)->begin(); it != (*rit)->end(); ++it)
779 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700780 NFD_LOG_TRACE("Layer " << layer << " " << (*it)->getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800781 }
782 layer--;
783 }
784}
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700785
Alexander Afanasyev18bbf812014-01-29 01:40:23 -0800786} //namespace nfd