blob: f1bbb0f45915b7ec141ba3f0b3d48da110e2bc2b [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 *
25 * \author Ilya Moiseenko <iliamo@ucla.edu>
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070026 */
27
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070028#include "cs.hpp"
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060029#include "core/logger.hpp"
Junxiao Shiaf6569a2014-06-14 00:01:34 -070030#include "core/random.hpp"
Alexander Afanasyev4a771362014-04-24 21:29:33 -070031#include <ndn-cxx/util/crypto.hpp>
Junxiao Shiaf6569a2014-06-14 00:01:34 -070032#include <ndn-cxx/security/signature-sha256-with-rsa.hpp>
33#include <boost/random/bernoulli_distribution.hpp>
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080034
Junxiao Shiaf6569a2014-06-14 00:01:34 -070035/// max skip list layers
36static const size_t SKIPLIST_MAX_LAYERS = 32;
37/// probability for an entry in layer N to appear also in layer N+1
38static const double SKIPLIST_PROBABILITY = 0.25;
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080039
40NFD_LOG_INIT("ContentStore");
Alexander Afanasyevb927a3a2014-01-24 10:41:47 -080041
Alexander Afanasyev18bbf812014-01-29 01:40:23 -080042namespace nfd {
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070043
Steve DiBenedetto3a4f83d2014-06-02 14:58:54 -060044Cs::Cs(size_t nMaxPackets)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080045 : m_nMaxPackets(nMaxPackets)
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040046 , m_nPackets(0)
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070047{
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080048 SkipListLayer* zeroLayer = new SkipListLayer();
49 m_skipList.push_back(zeroLayer);
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040050
51 for (size_t i = 0; i < m_nMaxPackets; i++)
52 m_freeCsEntries.push(new cs::Entry());
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070053}
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080054
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070055Cs::~Cs()
56{
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040057 // evict all items from CS
58 while (evictItem())
59 ;
60
61 BOOST_ASSERT(m_freeCsEntries.size() == m_nMaxPackets);
62
63 while (!m_freeCsEntries.empty())
64 {
65 delete m_freeCsEntries.front();
66 m_freeCsEntries.pop();
67 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080068}
69
70size_t
71Cs::size() const
72{
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040073 return m_nPackets; // size of the first layer in a skip list
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080074}
75
76void
77Cs::setLimit(size_t nMaxPackets)
78{
Alexander Afanasyev281b9162014-06-08 10:15:20 +030079 size_t oldNMaxPackets = m_nMaxPackets;
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080080 m_nMaxPackets = nMaxPackets;
81
Alexander Afanasyev281b9162014-06-08 10:15:20 +030082 while (size() > m_nMaxPackets) {
83 evictItem();
84 }
85
86 if (m_nMaxPackets >= oldNMaxPackets) {
87 for (size_t i = oldNMaxPackets; i < m_nMaxPackets; i++) {
88 m_freeCsEntries.push(new cs::Entry());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080089 }
Alexander Afanasyev281b9162014-06-08 10:15:20 +030090 }
91 else {
92 for (size_t i = oldNMaxPackets; i > m_nMaxPackets; i--) {
93 delete m_freeCsEntries.front();
94 m_freeCsEntries.pop();
95 }
96 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080097}
98
99size_t
100Cs::getLimit() const
101{
102 return m_nMaxPackets;
103}
104
105//Reference: "Skip Lists: A Probabilistic Alternative to Balanced Trees" by W.Pugh
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400106std::pair<cs::Entry*, bool>
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800107Cs::insertToSkipList(const Data& data, bool isUnsolicited)
108{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700109 NFD_LOG_TRACE("insertToSkipList() " << data.getName() << ", "
110 << "skipList size " << size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800111
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400112 BOOST_ASSERT(m_cleanupIndex.size() <= size());
113 BOOST_ASSERT(m_freeCsEntries.size() > 0);
114
115 // take entry for the memory pool
116 cs::Entry* entry = m_freeCsEntries.front();
117 m_freeCsEntries.pop();
118 m_nPackets++;
119 entry->setData(data, isUnsolicited);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800120
121 bool insertInFront = false;
122 bool isIterated = false;
123 SkipList::reverse_iterator topLayer = m_skipList.rbegin();
124 SkipListLayer::iterator updateTable[SKIPLIST_MAX_LAYERS];
125 SkipListLayer::iterator head = (*topLayer)->begin();
126
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400127 if (!(*topLayer)->empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800128 {
129 //start from the upper layer towards bottom
130 int layer = m_skipList.size() - 1;
131 for (SkipList::reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
132 {
133 //if we didn't do any iterations on the higher layers, start from the begin() again
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400134 if (!isIterated)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800135 head = (*rit)->begin();
136
137 updateTable[layer] = head;
138
139 if (head != (*rit)->end())
140 {
141 // it can happen when begin() contains the element in front of which we need to insert
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400142 if (!isIterated && ((*head)->getName() >= entry->getName()))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800143 {
144 --updateTable[layer];
145 insertInFront = true;
146 }
147 else
148 {
149 SkipListLayer::iterator it = head;
150
151 while ((*it)->getName() < entry->getName())
152 {
153 head = it;
154 updateTable[layer] = it;
155 isIterated = true;
156
157 ++it;
158 if (it == (*rit)->end())
159 break;
160 }
161 }
162 }
163
164 if (layer > 0)
165 head = (*head)->getIterators().find(layer - 1)->second; // move HEAD to the lower layer
166
167 layer--;
168 }
169 }
170 else
171 {
172 updateTable[0] = (*topLayer)->begin(); //initialization
173 }
174
175 head = updateTable[0];
176 ++head; // look at the next slot to check if it contains a duplicate
177
178 bool isCsEmpty = (size() == 0);
179 bool isInBoundaries = (head != (*m_skipList.begin())->end());
180 bool isNameIdentical = false;
181 if (!isCsEmpty && isInBoundaries)
182 {
183 isNameIdentical = (*head)->getName() == entry->getName();
184 }
185
186 //check if this is a duplicate packet
187 if (isNameIdentical)
188 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700189 NFD_LOG_TRACE("Duplicate name (with digest)");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800190
Alexander Afanasyev88811622014-04-10 00:00:15 -0700191 (*head)->setData(data, isUnsolicited, entry->getDigest()); //updates stale time
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800192
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400193 // new entry not needed, returning to the pool
194 entry->release();
195 m_freeCsEntries.push(entry);
196 m_nPackets--;
197
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800198 return std::make_pair(*head, false);
199 }
200
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700201 NFD_LOG_TRACE("Not a duplicate");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800202
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700203 size_t randomLayer = pickRandomLayer();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800204
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400205 while (m_skipList.size() < randomLayer + 1)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800206 {
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700207 SkipListLayer* newLayer = new SkipListLayer();
208 m_skipList.push_back(newLayer);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800209
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700210 updateTable[(m_skipList.size() - 1)] = newLayer->begin();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800211 }
212
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700213 size_t layer = 0;
214 for (SkipList::iterator i = m_skipList.begin();
215 i != m_skipList.end() && layer <= randomLayer; ++i)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800216 {
217 if (updateTable[layer] == (*i)->end() && !insertInFront)
218 {
219 (*i)->push_back(entry);
220 SkipListLayer::iterator last = (*i)->end();
221 --last;
222 entry->setIterator(layer, last);
223
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700224 NFD_LOG_TRACE("pushback " << &(*last));
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800225 }
226 else if (updateTable[layer] == (*i)->end() && insertInFront)
227 {
228 (*i)->push_front(entry);
229 entry->setIterator(layer, (*i)->begin());
230
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700231 NFD_LOG_TRACE("pushfront ");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800232 }
233 else
234 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700235 NFD_LOG_TRACE("insertafter");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800236 ++updateTable[layer]; // insert after
237 SkipListLayer::iterator position = (*i)->insert(updateTable[layer], entry);
238 entry->setIterator(layer, position); // save iterator where item was inserted
239 }
240 layer++;
241 }
242
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800243 return std::make_pair(entry, true);
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700244}
245
246bool
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800247Cs::insert(const Data& data, bool isUnsolicited)
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700248{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700249 NFD_LOG_TRACE("insert() " << data.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800250
251 if (isFull())
252 {
253 evictItem();
254 }
255
256 //pointer and insertion status
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400257 std::pair<cs::Entry*, bool> entry = insertToSkipList(data, isUnsolicited);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800258
259 //new entry
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400260 if (static_cast<bool>(entry.first) && (entry.second == true))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800261 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400262 m_cleanupIndex.push_back(entry.first);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800263 return true;
264 }
265
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700266 return false;
267}
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800268
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700269size_t
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800270Cs::pickRandomLayer() const
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700271{
Junxiao Shiaf6569a2014-06-14 00:01:34 -0700272 static boost::random::bernoulli_distribution<> dist(SKIPLIST_PROBABILITY);
273 // TODO rewrite using geometry_distribution
274 size_t layer;
275 for (layer = 0; layer < SKIPLIST_MAX_LAYERS; ++layer) {
276 if (!dist(getGlobalRng())) {
277 break;
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800278 }
Junxiao Shiaf6569a2014-06-14 00:01:34 -0700279 }
280 return layer;
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800281}
282
283bool
284Cs::isFull() const
285{
286 if (size() >= m_nMaxPackets) //size of the first layer vs. max size
287 return true;
288
289 return false;
290}
291
292bool
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400293Cs::eraseFromSkipList(cs::Entry* entry)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800294{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700295 NFD_LOG_TRACE("eraseFromSkipList() " << entry->getName());
296 NFD_LOG_TRACE("SkipList size " << size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800297
298 bool isErased = false;
299
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400300 const std::map<int, std::list<cs::Entry*>::iterator>& iterators = entry->getIterators();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800301
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400302 if (!iterators.empty())
303 {
304 int layer = 0;
305
306 for (SkipList::iterator it = m_skipList.begin(); it != m_skipList.end(); )
307 {
308 std::map<int, std::list<cs::Entry*>::iterator>::const_iterator i = iterators.find(layer);
309
310 if (i != iterators.end())
311 {
312 (*it)->erase(i->second);
313 entry->removeIterator(layer);
314 isErased = true;
315
316 //remove layers that do not contain any elements (starting from the second layer)
317 if ((layer != 0) && (*it)->empty())
318 {
319 delete *it;
320 it = m_skipList.erase(it);
321 }
322 else
323 ++it;
324
325 layer++;
326 }
327 else
328 break;
329 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800330 }
331
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400332 //delete entry;
333 if (isErased)
334 {
335 entry->release();
336 m_freeCsEntries.push(entry);
337 m_nPackets--;
338 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800339
340 return isErased;
341}
342
343bool
344Cs::evictItem()
345{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700346 NFD_LOG_TRACE("evictItem()");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800347
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400348 if (!m_cleanupIndex.get<unsolicited>().empty() &&
349 (*m_cleanupIndex.get<unsolicited>().begin())->isUnsolicited())
350 {
351 NFD_LOG_TRACE("Evict from unsolicited queue");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800352
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400353 eraseFromSkipList(*m_cleanupIndex.get<unsolicited>().begin());
354 m_cleanupIndex.get<unsolicited>().erase(m_cleanupIndex.get<unsolicited>().begin());
355 return true;
356 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800357
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400358 if (!m_cleanupIndex.get<byStaleness>().empty() &&
359 (*m_cleanupIndex.get<byStaleness>().begin())->getStaleTime() < time::steady_clock::now())
360 {
361 NFD_LOG_TRACE("Evict from staleness queue");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800362
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400363 eraseFromSkipList(*m_cleanupIndex.get<byStaleness>().begin());
364 m_cleanupIndex.get<byStaleness>().erase(m_cleanupIndex.get<byStaleness>().begin());
365 return true;
366 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800367
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400368 if (!m_cleanupIndex.get<byArrival>().empty())
369 {
370 NFD_LOG_TRACE("Evict from arrival queue");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800371
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400372 eraseFromSkipList(*m_cleanupIndex.get<byArrival>().begin());
373 m_cleanupIndex.get<byArrival>().erase(m_cleanupIndex.get<byArrival>().begin());
374 return true;
375 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800376
377 return false;
378}
379
380const Data*
381Cs::find(const Interest& interest) const
382{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700383 NFD_LOG_TRACE("find() " << interest.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800384
385 bool isIterated = false;
386 SkipList::const_reverse_iterator topLayer = m_skipList.rbegin();
387 SkipListLayer::iterator head = (*topLayer)->begin();
388
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400389 if (!(*topLayer)->empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800390 {
391 //start from the upper layer towards bottom
392 int layer = m_skipList.size() - 1;
393 for (SkipList::const_reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
394 {
395 //if we didn't do any iterations on the higher layers, start from the begin() again
396 if (!isIterated)
397 head = (*rit)->begin();
398
399 if (head != (*rit)->end())
400 {
401 // it happens when begin() contains the element we want to find
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400402 if (!isIterated && (interest.getName().isPrefixOf((*head)->getName())))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800403 {
404 if (layer > 0)
405 {
406 layer--;
407 continue; // try lower layer
408 }
409 else
410 {
411 isIterated = true;
412 }
413 }
414 else
415 {
416 SkipListLayer::iterator it = head;
417
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400418 while ((*it)->getName() < interest.getName())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800419 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700420 NFD_LOG_TRACE((*it)->getName() << " < " << interest.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800421 head = it;
422 isIterated = true;
423
424 ++it;
425 if (it == (*rit)->end())
426 break;
427 }
428 }
429 }
430
431 if (layer > 0)
432 {
433 head = (*head)->getIterators().find(layer - 1)->second; // move HEAD to the lower layer
434 }
435 else //if we reached the first layer
436 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400437 if (isIterated)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800438 return selectChild(interest, head);
439 }
440
441 layer--;
442 }
443 }
444
Alexander Afanasyevc9765df2014-01-25 19:24:27 -0800445 return 0;
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700446}
447
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800448const Data*
449Cs::selectChild(const Interest& interest, SkipListLayer::iterator startingPoint) const
450{
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400451 BOOST_ASSERT(startingPoint != (*m_skipList.begin())->end());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800452
453 if (startingPoint != (*m_skipList.begin())->begin())
454 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400455 BOOST_ASSERT((*startingPoint)->getName() < interest.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800456 }
457
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400458 NFD_LOG_TRACE("selectChild() " << interest.getChildSelector() << " "
459 << (*startingPoint)->getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800460
461 bool hasLeftmostSelector = (interest.getChildSelector() <= 0);
462 bool hasRightmostSelector = !hasLeftmostSelector;
463
464 if (hasLeftmostSelector)
465 {
466 bool doesInterestContainDigest = recognizeInterestWithDigest(interest, *startingPoint);
467 bool isInPrefix = false;
468
469 if (doesInterestContainDigest)
470 {
471 isInPrefix = interest.getName().getPrefix(-1).isPrefixOf((*startingPoint)->getName());
472 }
473 else
474 {
475 isInPrefix = interest.getName().isPrefixOf((*startingPoint)->getName());
476 }
477
478 if (isInPrefix)
479 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400480 if (doesComplyWithSelectors(interest, *startingPoint, doesInterestContainDigest))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800481 {
482 return &(*startingPoint)->getData();
483 }
484 }
485 }
486
487 //iterate to the right
488 SkipListLayer::iterator rightmost = startingPoint;
489 if (startingPoint != (*m_skipList.begin())->end())
490 {
491 SkipListLayer::iterator rightmostCandidate = startingPoint;
492 Name currentChildPrefix("");
493
494 while (true)
495 {
496 ++rightmostCandidate;
497
498 bool isInBoundaries = (rightmostCandidate != (*m_skipList.begin())->end());
499 bool isInPrefix = false;
500 bool doesInterestContainDigest = false;
501 if (isInBoundaries)
502 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400503 doesInterestContainDigest = recognizeInterestWithDigest(interest,
504 *rightmostCandidate);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800505
506 if (doesInterestContainDigest)
507 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400508 isInPrefix = interest.getName().getPrefix(-1)
509 .isPrefixOf((*rightmostCandidate)->getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800510 }
511 else
512 {
513 isInPrefix = interest.getName().isPrefixOf((*rightmostCandidate)->getName());
514 }
515 }
516
517 if (isInPrefix)
518 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400519 if (doesComplyWithSelectors(interest, *rightmostCandidate, doesInterestContainDigest))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800520 {
521 if (hasLeftmostSelector)
522 {
523 return &(*rightmostCandidate)->getData();
524 }
525
526 if (hasRightmostSelector)
527 {
528 if (doesInterestContainDigest)
529 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400530 // get prefix which is one component longer than Interest name
531 // (without digest)
532 const Name& childPrefix = (*rightmostCandidate)->getName()
533 .getPrefix(interest.getName().size());
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700534 NFD_LOG_TRACE("Child prefix" << childPrefix);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800535
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400536 if (currentChildPrefix.empty() || (childPrefix != currentChildPrefix))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800537 {
538 currentChildPrefix = childPrefix;
539 rightmost = rightmostCandidate;
540 }
541 }
542 else
543 {
544 // get prefix which is one component longer than Interest name
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400545 const Name& childPrefix = (*rightmostCandidate)->getName()
546 .getPrefix(interest.getName().size() + 1);
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700547 NFD_LOG_TRACE("Child prefix" << childPrefix);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800548
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400549 if (currentChildPrefix.empty() || (childPrefix != currentChildPrefix))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800550 {
551 currentChildPrefix = childPrefix;
552 rightmost = rightmostCandidate;
553 }
554 }
555 }
556 }
557 }
558 else
559 break;
560 }
561 }
562
563 if (rightmost != startingPoint)
564 {
565 return &(*rightmost)->getData();
566 }
567
568 if (hasRightmostSelector) // if rightmost was not found, try starting point
569 {
570 bool doesInterestContainDigest = recognizeInterestWithDigest(interest, *startingPoint);
571 bool isInPrefix = false;
572
573 if (doesInterestContainDigest)
574 {
575 isInPrefix = interest.getName().getPrefix(-1).isPrefixOf((*startingPoint)->getName());
576 }
577 else
578 {
579 isInPrefix = interest.getName().isPrefixOf((*startingPoint)->getName());
580 }
581
582 if (isInPrefix)
583 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400584 if (doesComplyWithSelectors(interest, *startingPoint, doesInterestContainDigest))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800585 {
586 return &(*startingPoint)->getData();
587 }
588 }
589 }
590
591 return 0;
592}
593
594bool
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400595Cs::doesComplyWithSelectors(const Interest& interest,
596 cs::Entry* entry,
597 bool doesInterestContainDigest) const
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800598{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700599 NFD_LOG_TRACE("doesComplyWithSelectors()");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800600
601 /// \todo The following detection is not correct
602 /// 1. If data name ends with 32-octet component doesn't mean that this component is digest
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400603 /// 2. Only min/max selectors (both 0) can be specified, all other selectors do not
604 /// make sense for interests with digest (though not sure if we need to enforce this)
605
606 if (doesInterestContainDigest)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800607 {
608 const ndn::name::Component& last = interest.getName().get(-1);
609 const ndn::ConstBufferPtr& digest = entry->getDigest();
610
611 BOOST_ASSERT(digest->size() == last.value_size());
612 BOOST_ASSERT(digest->size() == ndn::crypto::SHA256_DIGEST_SIZE);
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700613
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800614 if (std::memcmp(digest->buf(), last.value(), ndn::crypto::SHA256_DIGEST_SIZE) != 0)
615 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700616 NFD_LOG_TRACE("violates implicit digest");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800617 return false;
618 }
619 }
620
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400621 if (!doesInterestContainDigest)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800622 {
623 if (interest.getMinSuffixComponents() >= 0)
624 {
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700625 size_t minDataNameLength = interest.getName().size() + interest.getMinSuffixComponents();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800626
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700627 bool isSatisfied = (minDataNameLength <= entry->getName().size());
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400628 if (!isSatisfied)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800629 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700630 NFD_LOG_TRACE("violates minComponents");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800631 return false;
632 }
633 }
634
635 if (interest.getMaxSuffixComponents() >= 0)
636 {
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700637 size_t maxDataNameLength = interest.getName().size() + interest.getMaxSuffixComponents();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800638
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700639 bool isSatisfied = (maxDataNameLength >= entry->getName().size());
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400640 if (!isSatisfied)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800641 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700642 NFD_LOG_TRACE("violates maxComponents");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800643 return false;
644 }
645 }
646 }
647
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -0700648 if (interest.getMustBeFresh() && entry->getStaleTime() < time::steady_clock::now())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800649 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700650 NFD_LOG_TRACE("violates mustBeFresh");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800651 return false;
652 }
653
Ilya Moiseenko9c9231b2014-04-10 11:05:12 -0400654 if (!interest.getPublisherPublicKeyLocator().empty())
655 {
656 if (entry->getData().getSignature().getType() == ndn::Signature::Sha256WithRsa)
657 {
658 ndn::SignatureSha256WithRsa rsaSignature(entry->getData().getSignature());
659 if (rsaSignature.getKeyLocator() != interest.getPublisherPublicKeyLocator())
660 {
661 NFD_LOG_TRACE("violates publisher key selector");
662 return false;
663 }
664 }
665 else
666 {
667 NFD_LOG_TRACE("violates publisher key selector");
668 return false;
669 }
670 }
671
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400672 if (doesInterestContainDigest)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800673 {
674 const ndn::name::Component& lastComponent = entry->getName().get(-1);
675
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400676 if (!lastComponent.empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800677 {
678 if (interest.getExclude().isExcluded(lastComponent))
679 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700680 NFD_LOG_TRACE("violates exclusion");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800681 return false;
682 }
683 }
684 }
685 else
686 {
687 if (entry->getName().size() >= interest.getName().size() + 1)
688 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400689 const ndn::name::Component& nextComponent = entry->getName()
690 .get(interest.getName().size());
691 if (!nextComponent.empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800692 {
693 if (interest.getExclude().isExcluded(nextComponent))
694 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700695 NFD_LOG_TRACE("violates exclusion");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800696 return false;
697 }
698 }
699 }
700 }
701
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700702 NFD_LOG_TRACE("complies");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800703 return true;
704}
705
706bool
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400707Cs::recognizeInterestWithDigest(const Interest& interest, cs::Entry* entry) const
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800708{
709 // only when min selector is not specified or specified with value of 0
710 // and Interest's name length is exactly the length of the name of CS entry
711 if (interest.getMinSuffixComponents() <= 0 &&
712 interest.getName().size() == (entry->getName().size()))
713 {
714 const ndn::name::Component& last = interest.getName().get(-1);
715 if (last.value_size() == ndn::crypto::SHA256_DIGEST_SIZE)
716 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700717 NFD_LOG_TRACE("digest recognized");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800718 return true;
719 }
720 }
721
722 return false;
723}
724
725void
726Cs::erase(const Name& exactName)
727{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700728 NFD_LOG_TRACE("insert() " << exactName << ", "
729 << "skipList size " << size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800730
731 bool isIterated = false;
732 SkipListLayer::iterator updateTable[SKIPLIST_MAX_LAYERS];
733 SkipList::reverse_iterator topLayer = m_skipList.rbegin();
734 SkipListLayer::iterator head = (*topLayer)->begin();
735
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400736 if (!(*topLayer)->empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800737 {
738 //start from the upper layer towards bottom
739 int layer = m_skipList.size() - 1;
740 for (SkipList::reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
741 {
742 //if we didn't do any iterations on the higher layers, start from the begin() again
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400743 if (!isIterated)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800744 head = (*rit)->begin();
745
746 updateTable[layer] = head;
747
748 if (head != (*rit)->end())
749 {
750 // it can happen when begin() contains the element we want to remove
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400751 if (!isIterated && ((*head)->getName() == exactName))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800752 {
753 eraseFromSkipList(*head);
754 return;
755 }
756 else
757 {
758 SkipListLayer::iterator it = head;
759
760 while ((*it)->getName() < exactName)
761 {
762 head = it;
763 updateTable[layer] = it;
764 isIterated = true;
765
766 ++it;
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400767 if (it == (*rit)->end())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800768 break;
769 }
770 }
771 }
772
773 if (layer > 0)
774 head = (*head)->getIterators().find(layer - 1)->second; // move HEAD to the lower layer
775
776 layer--;
777 }
778 }
779 else
780 {
781 return;
782 }
783
784 head = updateTable[0];
785 ++head; // look at the next slot to check if it contains the item we want to remove
786
787 bool isCsEmpty = (size() == 0);
788 bool isInBoundaries = (head != (*m_skipList.begin())->end());
789 bool isNameIdentical = false;
790 if (!isCsEmpty && isInBoundaries)
791 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700792 NFD_LOG_TRACE("Identical? " << (*head)->getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800793 isNameIdentical = (*head)->getName() == exactName;
794 }
795
796 if (isNameIdentical)
797 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700798 NFD_LOG_TRACE("Found target " << (*head)->getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800799 eraseFromSkipList(*head);
800 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800801}
802
803void
804Cs::printSkipList() const
805{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700806 NFD_LOG_TRACE("print()");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800807 //start from the upper layer towards bottom
808 int layer = m_skipList.size() - 1;
809 for (SkipList::const_reverse_iterator rit = m_skipList.rbegin(); rit != m_skipList.rend(); ++rit)
810 {
811 for (SkipListLayer::iterator it = (*rit)->begin(); it != (*rit)->end(); ++it)
812 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700813 NFD_LOG_TRACE("Layer " << layer << " " << (*it)->getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800814 }
815 layer--;
816 }
817}
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700818
Alexander Afanasyev18bbf812014-01-29 01:40:23 -0800819} //namespace nfd