blob: f750b61dad3b6ba7a359c9ee62a39301161f3b8e [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"
Alexander Afanasyev4a771362014-04-24 21:29:33 -070029#include <ndn-cxx/util/crypto.hpp>
30#include "ndn-cxx/security/signature-sha256-with-rsa.hpp"
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080031
32#define SKIPLIST_MAX_LAYERS 32
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040033#define SKIPLIST_PROBABILITY 25 // 25% (p = 1/4)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080034
35NFD_LOG_INIT("ContentStore");
Alexander Afanasyevb927a3a2014-01-24 10:41:47 -080036
Alexander Afanasyev18bbf812014-01-29 01:40:23 -080037namespace nfd {
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070038
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080039Cs::Cs(int nMaxPackets)
40 : m_nMaxPackets(nMaxPackets)
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040041 , m_nPackets(0)
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070042{
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080043 SkipListLayer* zeroLayer = new SkipListLayer();
44 m_skipList.push_back(zeroLayer);
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040045
46 for (size_t i = 0; i < m_nMaxPackets; i++)
47 m_freeCsEntries.push(new cs::Entry());
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070048}
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080049
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070050Cs::~Cs()
51{
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040052 // evict all items from CS
53 while (evictItem())
54 ;
55
56 BOOST_ASSERT(m_freeCsEntries.size() == m_nMaxPackets);
57
58 while (!m_freeCsEntries.empty())
59 {
60 delete m_freeCsEntries.front();
61 m_freeCsEntries.pop();
62 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080063}
64
65size_t
66Cs::size() const
67{
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040068 return m_nPackets; // size of the first layer in a skip list
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080069}
70
71void
72Cs::setLimit(size_t nMaxPackets)
73{
Alexander Afanasyev281b9162014-06-08 10:15:20 +030074 size_t oldNMaxPackets = m_nMaxPackets;
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080075 m_nMaxPackets = nMaxPackets;
76
Alexander Afanasyev281b9162014-06-08 10:15:20 +030077 while (size() > m_nMaxPackets) {
78 evictItem();
79 }
80
81 if (m_nMaxPackets >= oldNMaxPackets) {
82 for (size_t i = oldNMaxPackets; i < m_nMaxPackets; i++) {
83 m_freeCsEntries.push(new cs::Entry());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080084 }
Alexander Afanasyev281b9162014-06-08 10:15:20 +030085 }
86 else {
87 for (size_t i = oldNMaxPackets; i > m_nMaxPackets; i--) {
88 delete m_freeCsEntries.front();
89 m_freeCsEntries.pop();
90 }
91 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080092}
93
94size_t
95Cs::getLimit() const
96{
97 return m_nMaxPackets;
98}
99
100//Reference: "Skip Lists: A Probabilistic Alternative to Balanced Trees" by W.Pugh
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400101std::pair<cs::Entry*, bool>
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800102Cs::insertToSkipList(const Data& data, bool isUnsolicited)
103{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700104 NFD_LOG_TRACE("insertToSkipList() " << data.getName() << ", "
105 << "skipList size " << size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800106
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400107 BOOST_ASSERT(m_cleanupIndex.size() <= size());
108 BOOST_ASSERT(m_freeCsEntries.size() > 0);
109
110 // take entry for the memory pool
111 cs::Entry* entry = m_freeCsEntries.front();
112 m_freeCsEntries.pop();
113 m_nPackets++;
114 entry->setData(data, isUnsolicited);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800115
116 bool insertInFront = false;
117 bool isIterated = false;
118 SkipList::reverse_iterator topLayer = m_skipList.rbegin();
119 SkipListLayer::iterator updateTable[SKIPLIST_MAX_LAYERS];
120 SkipListLayer::iterator head = (*topLayer)->begin();
121
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400122 if (!(*topLayer)->empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800123 {
124 //start from the upper layer towards bottom
125 int layer = m_skipList.size() - 1;
126 for (SkipList::reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
127 {
128 //if we didn't do any iterations on the higher layers, start from the begin() again
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400129 if (!isIterated)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800130 head = (*rit)->begin();
131
132 updateTable[layer] = head;
133
134 if (head != (*rit)->end())
135 {
136 // it can happen when begin() contains the element in front of which we need to insert
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400137 if (!isIterated && ((*head)->getName() >= entry->getName()))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800138 {
139 --updateTable[layer];
140 insertInFront = true;
141 }
142 else
143 {
144 SkipListLayer::iterator it = head;
145
146 while ((*it)->getName() < entry->getName())
147 {
148 head = it;
149 updateTable[layer] = it;
150 isIterated = true;
151
152 ++it;
153 if (it == (*rit)->end())
154 break;
155 }
156 }
157 }
158
159 if (layer > 0)
160 head = (*head)->getIterators().find(layer - 1)->second; // move HEAD to the lower layer
161
162 layer--;
163 }
164 }
165 else
166 {
167 updateTable[0] = (*topLayer)->begin(); //initialization
168 }
169
170 head = updateTable[0];
171 ++head; // look at the next slot to check if it contains a duplicate
172
173 bool isCsEmpty = (size() == 0);
174 bool isInBoundaries = (head != (*m_skipList.begin())->end());
175 bool isNameIdentical = false;
176 if (!isCsEmpty && isInBoundaries)
177 {
178 isNameIdentical = (*head)->getName() == entry->getName();
179 }
180
181 //check if this is a duplicate packet
182 if (isNameIdentical)
183 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700184 NFD_LOG_TRACE("Duplicate name (with digest)");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800185
Alexander Afanasyev88811622014-04-10 00:00:15 -0700186 (*head)->setData(data, isUnsolicited, entry->getDigest()); //updates stale time
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800187
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400188 // new entry not needed, returning to the pool
189 entry->release();
190 m_freeCsEntries.push(entry);
191 m_nPackets--;
192
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800193 return std::make_pair(*head, false);
194 }
195
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700196 NFD_LOG_TRACE("Not a duplicate");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800197
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700198 size_t randomLayer = pickRandomLayer();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800199
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400200 while (m_skipList.size() < randomLayer + 1)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800201 {
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700202 SkipListLayer* newLayer = new SkipListLayer();
203 m_skipList.push_back(newLayer);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800204
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700205 updateTable[(m_skipList.size() - 1)] = newLayer->begin();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800206 }
207
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700208 size_t layer = 0;
209 for (SkipList::iterator i = m_skipList.begin();
210 i != m_skipList.end() && layer <= randomLayer; ++i)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800211 {
212 if (updateTable[layer] == (*i)->end() && !insertInFront)
213 {
214 (*i)->push_back(entry);
215 SkipListLayer::iterator last = (*i)->end();
216 --last;
217 entry->setIterator(layer, last);
218
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700219 NFD_LOG_TRACE("pushback " << &(*last));
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800220 }
221 else if (updateTable[layer] == (*i)->end() && insertInFront)
222 {
223 (*i)->push_front(entry);
224 entry->setIterator(layer, (*i)->begin());
225
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700226 NFD_LOG_TRACE("pushfront ");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800227 }
228 else
229 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700230 NFD_LOG_TRACE("insertafter");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800231 ++updateTable[layer]; // insert after
232 SkipListLayer::iterator position = (*i)->insert(updateTable[layer], entry);
233 entry->setIterator(layer, position); // save iterator where item was inserted
234 }
235 layer++;
236 }
237
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800238 return std::make_pair(entry, true);
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700239}
240
241bool
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800242Cs::insert(const Data& data, bool isUnsolicited)
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700243{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700244 NFD_LOG_TRACE("insert() " << data.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800245
246 if (isFull())
247 {
248 evictItem();
249 }
250
251 //pointer and insertion status
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400252 std::pair<cs::Entry*, bool> entry = insertToSkipList(data, isUnsolicited);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800253
254 //new entry
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400255 if (static_cast<bool>(entry.first) && (entry.second == true))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800256 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400257 m_cleanupIndex.push_back(entry.first);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800258 return true;
259 }
260
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700261 return false;
262}
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800263
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700264size_t
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800265Cs::pickRandomLayer() const
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700266{
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800267 int layer = -1;
268 int randomValue;
269
270 do
271 {
272 layer++;
273 randomValue = rand() % 100 + 1;
274 }
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400275 while ((randomValue < SKIPLIST_PROBABILITY) && (layer < SKIPLIST_MAX_LAYERS));
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800276
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700277 return static_cast<size_t>(layer);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800278}
279
280bool
281Cs::isFull() const
282{
283 if (size() >= m_nMaxPackets) //size of the first layer vs. max size
284 return true;
285
286 return false;
287}
288
289bool
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400290Cs::eraseFromSkipList(cs::Entry* entry)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800291{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700292 NFD_LOG_TRACE("eraseFromSkipList() " << entry->getName());
293 NFD_LOG_TRACE("SkipList size " << size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800294
295 bool isErased = false;
296
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400297 const std::map<int, std::list<cs::Entry*>::iterator>& iterators = entry->getIterators();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800298
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400299 if (!iterators.empty())
300 {
301 int layer = 0;
302
303 for (SkipList::iterator it = m_skipList.begin(); it != m_skipList.end(); )
304 {
305 std::map<int, std::list<cs::Entry*>::iterator>::const_iterator i = iterators.find(layer);
306
307 if (i != iterators.end())
308 {
309 (*it)->erase(i->second);
310 entry->removeIterator(layer);
311 isErased = true;
312
313 //remove layers that do not contain any elements (starting from the second layer)
314 if ((layer != 0) && (*it)->empty())
315 {
316 delete *it;
317 it = m_skipList.erase(it);
318 }
319 else
320 ++it;
321
322 layer++;
323 }
324 else
325 break;
326 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800327 }
328
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400329 //delete entry;
330 if (isErased)
331 {
332 entry->release();
333 m_freeCsEntries.push(entry);
334 m_nPackets--;
335 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800336
337 return isErased;
338}
339
340bool
341Cs::evictItem()
342{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700343 NFD_LOG_TRACE("evictItem()");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800344
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400345 if (!m_cleanupIndex.get<unsolicited>().empty() &&
346 (*m_cleanupIndex.get<unsolicited>().begin())->isUnsolicited())
347 {
348 NFD_LOG_TRACE("Evict from unsolicited queue");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800349
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400350 eraseFromSkipList(*m_cleanupIndex.get<unsolicited>().begin());
351 m_cleanupIndex.get<unsolicited>().erase(m_cleanupIndex.get<unsolicited>().begin());
352 return true;
353 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800354
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400355 if (!m_cleanupIndex.get<byStaleness>().empty() &&
356 (*m_cleanupIndex.get<byStaleness>().begin())->getStaleTime() < time::steady_clock::now())
357 {
358 NFD_LOG_TRACE("Evict from staleness queue");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800359
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400360 eraseFromSkipList(*m_cleanupIndex.get<byStaleness>().begin());
361 m_cleanupIndex.get<byStaleness>().erase(m_cleanupIndex.get<byStaleness>().begin());
362 return true;
363 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800364
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400365 if (!m_cleanupIndex.get<byArrival>().empty())
366 {
367 NFD_LOG_TRACE("Evict from arrival queue");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800368
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400369 eraseFromSkipList(*m_cleanupIndex.get<byArrival>().begin());
370 m_cleanupIndex.get<byArrival>().erase(m_cleanupIndex.get<byArrival>().begin());
371 return true;
372 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800373
374 return false;
375}
376
377const Data*
378Cs::find(const Interest& interest) const
379{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700380 NFD_LOG_TRACE("find() " << interest.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800381
382 bool isIterated = false;
383 SkipList::const_reverse_iterator topLayer = m_skipList.rbegin();
384 SkipListLayer::iterator head = (*topLayer)->begin();
385
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400386 if (!(*topLayer)->empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800387 {
388 //start from the upper layer towards bottom
389 int layer = m_skipList.size() - 1;
390 for (SkipList::const_reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
391 {
392 //if we didn't do any iterations on the higher layers, start from the begin() again
393 if (!isIterated)
394 head = (*rit)->begin();
395
396 if (head != (*rit)->end())
397 {
398 // it happens when begin() contains the element we want to find
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400399 if (!isIterated && (interest.getName().isPrefixOf((*head)->getName())))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800400 {
401 if (layer > 0)
402 {
403 layer--;
404 continue; // try lower layer
405 }
406 else
407 {
408 isIterated = true;
409 }
410 }
411 else
412 {
413 SkipListLayer::iterator it = head;
414
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400415 while ((*it)->getName() < interest.getName())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800416 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700417 NFD_LOG_TRACE((*it)->getName() << " < " << interest.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800418 head = it;
419 isIterated = true;
420
421 ++it;
422 if (it == (*rit)->end())
423 break;
424 }
425 }
426 }
427
428 if (layer > 0)
429 {
430 head = (*head)->getIterators().find(layer - 1)->second; // move HEAD to the lower layer
431 }
432 else //if we reached the first layer
433 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400434 if (isIterated)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800435 return selectChild(interest, head);
436 }
437
438 layer--;
439 }
440 }
441
Alexander Afanasyevc9765df2014-01-25 19:24:27 -0800442 return 0;
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700443}
444
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800445const Data*
446Cs::selectChild(const Interest& interest, SkipListLayer::iterator startingPoint) const
447{
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400448 BOOST_ASSERT(startingPoint != (*m_skipList.begin())->end());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800449
450 if (startingPoint != (*m_skipList.begin())->begin())
451 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400452 BOOST_ASSERT((*startingPoint)->getName() < interest.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800453 }
454
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400455 NFD_LOG_TRACE("selectChild() " << interest.getChildSelector() << " "
456 << (*startingPoint)->getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800457
458 bool hasLeftmostSelector = (interest.getChildSelector() <= 0);
459 bool hasRightmostSelector = !hasLeftmostSelector;
460
461 if (hasLeftmostSelector)
462 {
463 bool doesInterestContainDigest = recognizeInterestWithDigest(interest, *startingPoint);
464 bool isInPrefix = false;
465
466 if (doesInterestContainDigest)
467 {
468 isInPrefix = interest.getName().getPrefix(-1).isPrefixOf((*startingPoint)->getName());
469 }
470 else
471 {
472 isInPrefix = interest.getName().isPrefixOf((*startingPoint)->getName());
473 }
474
475 if (isInPrefix)
476 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400477 if (doesComplyWithSelectors(interest, *startingPoint, doesInterestContainDigest))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800478 {
479 return &(*startingPoint)->getData();
480 }
481 }
482 }
483
484 //iterate to the right
485 SkipListLayer::iterator rightmost = startingPoint;
486 if (startingPoint != (*m_skipList.begin())->end())
487 {
488 SkipListLayer::iterator rightmostCandidate = startingPoint;
489 Name currentChildPrefix("");
490
491 while (true)
492 {
493 ++rightmostCandidate;
494
495 bool isInBoundaries = (rightmostCandidate != (*m_skipList.begin())->end());
496 bool isInPrefix = false;
497 bool doesInterestContainDigest = false;
498 if (isInBoundaries)
499 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400500 doesInterestContainDigest = recognizeInterestWithDigest(interest,
501 *rightmostCandidate);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800502
503 if (doesInterestContainDigest)
504 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400505 isInPrefix = interest.getName().getPrefix(-1)
506 .isPrefixOf((*rightmostCandidate)->getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800507 }
508 else
509 {
510 isInPrefix = interest.getName().isPrefixOf((*rightmostCandidate)->getName());
511 }
512 }
513
514 if (isInPrefix)
515 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400516 if (doesComplyWithSelectors(interest, *rightmostCandidate, doesInterestContainDigest))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800517 {
518 if (hasLeftmostSelector)
519 {
520 return &(*rightmostCandidate)->getData();
521 }
522
523 if (hasRightmostSelector)
524 {
525 if (doesInterestContainDigest)
526 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400527 // get prefix which is one component longer than Interest name
528 // (without digest)
529 const Name& childPrefix = (*rightmostCandidate)->getName()
530 .getPrefix(interest.getName().size());
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700531 NFD_LOG_TRACE("Child prefix" << childPrefix);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800532
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400533 if (currentChildPrefix.empty() || (childPrefix != currentChildPrefix))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800534 {
535 currentChildPrefix = childPrefix;
536 rightmost = rightmostCandidate;
537 }
538 }
539 else
540 {
541 // get prefix which is one component longer than Interest name
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400542 const Name& childPrefix = (*rightmostCandidate)->getName()
543 .getPrefix(interest.getName().size() + 1);
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700544 NFD_LOG_TRACE("Child prefix" << childPrefix);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800545
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400546 if (currentChildPrefix.empty() || (childPrefix != currentChildPrefix))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800547 {
548 currentChildPrefix = childPrefix;
549 rightmost = rightmostCandidate;
550 }
551 }
552 }
553 }
554 }
555 else
556 break;
557 }
558 }
559
560 if (rightmost != startingPoint)
561 {
562 return &(*rightmost)->getData();
563 }
564
565 if (hasRightmostSelector) // if rightmost was not found, try starting point
566 {
567 bool doesInterestContainDigest = recognizeInterestWithDigest(interest, *startingPoint);
568 bool isInPrefix = false;
569
570 if (doesInterestContainDigest)
571 {
572 isInPrefix = interest.getName().getPrefix(-1).isPrefixOf((*startingPoint)->getName());
573 }
574 else
575 {
576 isInPrefix = interest.getName().isPrefixOf((*startingPoint)->getName());
577 }
578
579 if (isInPrefix)
580 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400581 if (doesComplyWithSelectors(interest, *startingPoint, doesInterestContainDigest))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800582 {
583 return &(*startingPoint)->getData();
584 }
585 }
586 }
587
588 return 0;
589}
590
591bool
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400592Cs::doesComplyWithSelectors(const Interest& interest,
593 cs::Entry* entry,
594 bool doesInterestContainDigest) const
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800595{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700596 NFD_LOG_TRACE("doesComplyWithSelectors()");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800597
598 /// \todo The following detection is not correct
599 /// 1. If data name ends with 32-octet component doesn't mean that this component is digest
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400600 /// 2. Only min/max selectors (both 0) can be specified, all other selectors do not
601 /// make sense for interests with digest (though not sure if we need to enforce this)
602
603 if (doesInterestContainDigest)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800604 {
605 const ndn::name::Component& last = interest.getName().get(-1);
606 const ndn::ConstBufferPtr& digest = entry->getDigest();
607
608 BOOST_ASSERT(digest->size() == last.value_size());
609 BOOST_ASSERT(digest->size() == ndn::crypto::SHA256_DIGEST_SIZE);
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700610
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800611 if (std::memcmp(digest->buf(), last.value(), ndn::crypto::SHA256_DIGEST_SIZE) != 0)
612 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700613 NFD_LOG_TRACE("violates implicit digest");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800614 return false;
615 }
616 }
617
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400618 if (!doesInterestContainDigest)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800619 {
620 if (interest.getMinSuffixComponents() >= 0)
621 {
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700622 size_t minDataNameLength = interest.getName().size() + interest.getMinSuffixComponents();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800623
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700624 bool isSatisfied = (minDataNameLength <= 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 minComponents");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800628 return false;
629 }
630 }
631
632 if (interest.getMaxSuffixComponents() >= 0)
633 {
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700634 size_t maxDataNameLength = interest.getName().size() + interest.getMaxSuffixComponents();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800635
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700636 bool isSatisfied = (maxDataNameLength >= entry->getName().size());
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400637 if (!isSatisfied)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800638 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700639 NFD_LOG_TRACE("violates maxComponents");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800640 return false;
641 }
642 }
643 }
644
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -0700645 if (interest.getMustBeFresh() && entry->getStaleTime() < time::steady_clock::now())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800646 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700647 NFD_LOG_TRACE("violates mustBeFresh");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800648 return false;
649 }
650
Ilya Moiseenko9c9231b2014-04-10 11:05:12 -0400651 if (!interest.getPublisherPublicKeyLocator().empty())
652 {
653 if (entry->getData().getSignature().getType() == ndn::Signature::Sha256WithRsa)
654 {
655 ndn::SignatureSha256WithRsa rsaSignature(entry->getData().getSignature());
656 if (rsaSignature.getKeyLocator() != interest.getPublisherPublicKeyLocator())
657 {
658 NFD_LOG_TRACE("violates publisher key selector");
659 return false;
660 }
661 }
662 else
663 {
664 NFD_LOG_TRACE("violates publisher key selector");
665 return false;
666 }
667 }
668
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400669 if (doesInterestContainDigest)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800670 {
671 const ndn::name::Component& lastComponent = entry->getName().get(-1);
672
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400673 if (!lastComponent.empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800674 {
675 if (interest.getExclude().isExcluded(lastComponent))
676 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700677 NFD_LOG_TRACE("violates exclusion");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800678 return false;
679 }
680 }
681 }
682 else
683 {
684 if (entry->getName().size() >= interest.getName().size() + 1)
685 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400686 const ndn::name::Component& nextComponent = entry->getName()
687 .get(interest.getName().size());
688 if (!nextComponent.empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800689 {
690 if (interest.getExclude().isExcluded(nextComponent))
691 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700692 NFD_LOG_TRACE("violates exclusion");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800693 return false;
694 }
695 }
696 }
697 }
698
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700699 NFD_LOG_TRACE("complies");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800700 return true;
701}
702
703bool
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400704Cs::recognizeInterestWithDigest(const Interest& interest, cs::Entry* entry) const
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800705{
706 // only when min selector is not specified or specified with value of 0
707 // and Interest's name length is exactly the length of the name of CS entry
708 if (interest.getMinSuffixComponents() <= 0 &&
709 interest.getName().size() == (entry->getName().size()))
710 {
711 const ndn::name::Component& last = interest.getName().get(-1);
712 if (last.value_size() == ndn::crypto::SHA256_DIGEST_SIZE)
713 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700714 NFD_LOG_TRACE("digest recognized");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800715 return true;
716 }
717 }
718
719 return false;
720}
721
722void
723Cs::erase(const Name& exactName)
724{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700725 NFD_LOG_TRACE("insert() " << exactName << ", "
726 << "skipList size " << size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800727
728 bool isIterated = false;
729 SkipListLayer::iterator updateTable[SKIPLIST_MAX_LAYERS];
730 SkipList::reverse_iterator topLayer = m_skipList.rbegin();
731 SkipListLayer::iterator head = (*topLayer)->begin();
732
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400733 if (!(*topLayer)->empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800734 {
735 //start from the upper layer towards bottom
736 int layer = m_skipList.size() - 1;
737 for (SkipList::reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
738 {
739 //if we didn't do any iterations on the higher layers, start from the begin() again
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400740 if (!isIterated)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800741 head = (*rit)->begin();
742
743 updateTable[layer] = head;
744
745 if (head != (*rit)->end())
746 {
747 // it can happen when begin() contains the element we want to remove
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400748 if (!isIterated && ((*head)->getName() == exactName))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800749 {
750 eraseFromSkipList(*head);
751 return;
752 }
753 else
754 {
755 SkipListLayer::iterator it = head;
756
757 while ((*it)->getName() < exactName)
758 {
759 head = it;
760 updateTable[layer] = it;
761 isIterated = true;
762
763 ++it;
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400764 if (it == (*rit)->end())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800765 break;
766 }
767 }
768 }
769
770 if (layer > 0)
771 head = (*head)->getIterators().find(layer - 1)->second; // move HEAD to the lower layer
772
773 layer--;
774 }
775 }
776 else
777 {
778 return;
779 }
780
781 head = updateTable[0];
782 ++head; // look at the next slot to check if it contains the item we want to remove
783
784 bool isCsEmpty = (size() == 0);
785 bool isInBoundaries = (head != (*m_skipList.begin())->end());
786 bool isNameIdentical = false;
787 if (!isCsEmpty && isInBoundaries)
788 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700789 NFD_LOG_TRACE("Identical? " << (*head)->getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800790 isNameIdentical = (*head)->getName() == exactName;
791 }
792
793 if (isNameIdentical)
794 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700795 NFD_LOG_TRACE("Found target " << (*head)->getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800796 eraseFromSkipList(*head);
797 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800798}
799
800void
801Cs::printSkipList() const
802{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700803 NFD_LOG_TRACE("print()");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800804 //start from the upper layer towards bottom
805 int layer = m_skipList.size() - 1;
806 for (SkipList::const_reverse_iterator rit = m_skipList.rbegin(); rit != m_skipList.rend(); ++rit)
807 {
808 for (SkipListLayer::iterator it = (*rit)->begin(); it != (*rit)->end(); ++it)
809 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700810 NFD_LOG_TRACE("Layer " << layer << " " << (*it)->getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800811 }
812 layer--;
813 }
814}
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700815
Alexander Afanasyev18bbf812014-01-29 01:40:23 -0800816} //namespace nfd