blob: ad666d5c5b1eaa4971dcbda19d931279f54a168c [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"
Alexander Afanasyev4a771362014-04-24 21:29:33 -070030#include <ndn-cxx/util/crypto.hpp>
31#include "ndn-cxx/security/signature-sha256-with-rsa.hpp"
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080032
33#define SKIPLIST_MAX_LAYERS 32
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040034#define SKIPLIST_PROBABILITY 25 // 25% (p = 1/4)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080035
36NFD_LOG_INIT("ContentStore");
Alexander Afanasyevb927a3a2014-01-24 10:41:47 -080037
Alexander Afanasyev18bbf812014-01-29 01:40:23 -080038namespace nfd {
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070039
Steve DiBenedetto3a4f83d2014-06-02 14:58:54 -060040Cs::Cs(size_t nMaxPackets)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080041 : m_nMaxPackets(nMaxPackets)
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040042 , m_nPackets(0)
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070043{
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080044 SkipListLayer* zeroLayer = new SkipListLayer();
45 m_skipList.push_back(zeroLayer);
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040046
47 for (size_t i = 0; i < m_nMaxPackets; i++)
48 m_freeCsEntries.push(new cs::Entry());
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070049}
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080050
Junxiao Shi0fcb41e2014-01-24 10:29:43 -070051Cs::~Cs()
52{
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040053 // evict all items from CS
54 while (evictItem())
55 ;
56
57 BOOST_ASSERT(m_freeCsEntries.size() == m_nMaxPackets);
58
59 while (!m_freeCsEntries.empty())
60 {
61 delete m_freeCsEntries.front();
62 m_freeCsEntries.pop();
63 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080064}
65
66size_t
67Cs::size() const
68{
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -040069 return m_nPackets; // size of the first layer in a skip list
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080070}
71
72void
73Cs::setLimit(size_t nMaxPackets)
74{
Alexander Afanasyev281b9162014-06-08 10:15:20 +030075 size_t oldNMaxPackets = m_nMaxPackets;
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080076 m_nMaxPackets = nMaxPackets;
77
Alexander Afanasyev281b9162014-06-08 10:15:20 +030078 while (size() > m_nMaxPackets) {
79 evictItem();
80 }
81
82 if (m_nMaxPackets >= oldNMaxPackets) {
83 for (size_t i = oldNMaxPackets; i < m_nMaxPackets; i++) {
84 m_freeCsEntries.push(new cs::Entry());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080085 }
Alexander Afanasyev281b9162014-06-08 10:15:20 +030086 }
87 else {
88 for (size_t i = oldNMaxPackets; i > m_nMaxPackets; i--) {
89 delete m_freeCsEntries.front();
90 m_freeCsEntries.pop();
91 }
92 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -080093}
94
95size_t
96Cs::getLimit() const
97{
98 return m_nMaxPackets;
99}
100
101//Reference: "Skip Lists: A Probabilistic Alternative to Balanced Trees" by W.Pugh
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400102std::pair<cs::Entry*, bool>
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800103Cs::insertToSkipList(const Data& data, bool isUnsolicited)
104{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700105 NFD_LOG_TRACE("insertToSkipList() " << data.getName() << ", "
106 << "skipList size " << size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800107
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400108 BOOST_ASSERT(m_cleanupIndex.size() <= size());
109 BOOST_ASSERT(m_freeCsEntries.size() > 0);
110
111 // take entry for the memory pool
112 cs::Entry* entry = m_freeCsEntries.front();
113 m_freeCsEntries.pop();
114 m_nPackets++;
115 entry->setData(data, isUnsolicited);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800116
117 bool insertInFront = false;
118 bool isIterated = false;
119 SkipList::reverse_iterator topLayer = m_skipList.rbegin();
120 SkipListLayer::iterator updateTable[SKIPLIST_MAX_LAYERS];
121 SkipListLayer::iterator head = (*topLayer)->begin();
122
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400123 if (!(*topLayer)->empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800124 {
125 //start from the upper layer towards bottom
126 int layer = m_skipList.size() - 1;
127 for (SkipList::reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
128 {
129 //if we didn't do any iterations on the higher layers, start from the begin() again
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400130 if (!isIterated)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800131 head = (*rit)->begin();
132
133 updateTable[layer] = head;
134
135 if (head != (*rit)->end())
136 {
137 // it can happen when begin() contains the element in front of which we need to insert
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400138 if (!isIterated && ((*head)->getName() >= entry->getName()))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800139 {
140 --updateTable[layer];
141 insertInFront = true;
142 }
143 else
144 {
145 SkipListLayer::iterator it = head;
146
147 while ((*it)->getName() < entry->getName())
148 {
149 head = it;
150 updateTable[layer] = it;
151 isIterated = true;
152
153 ++it;
154 if (it == (*rit)->end())
155 break;
156 }
157 }
158 }
159
160 if (layer > 0)
161 head = (*head)->getIterators().find(layer - 1)->second; // move HEAD to the lower layer
162
163 layer--;
164 }
165 }
166 else
167 {
168 updateTable[0] = (*topLayer)->begin(); //initialization
169 }
170
171 head = updateTable[0];
172 ++head; // look at the next slot to check if it contains a duplicate
173
174 bool isCsEmpty = (size() == 0);
175 bool isInBoundaries = (head != (*m_skipList.begin())->end());
176 bool isNameIdentical = false;
177 if (!isCsEmpty && isInBoundaries)
178 {
179 isNameIdentical = (*head)->getName() == entry->getName();
180 }
181
182 //check if this is a duplicate packet
183 if (isNameIdentical)
184 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700185 NFD_LOG_TRACE("Duplicate name (with digest)");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800186
Alexander Afanasyev88811622014-04-10 00:00:15 -0700187 (*head)->setData(data, isUnsolicited, entry->getDigest()); //updates stale time
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800188
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400189 // new entry not needed, returning to the pool
190 entry->release();
191 m_freeCsEntries.push(entry);
192 m_nPackets--;
193
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800194 return std::make_pair(*head, false);
195 }
196
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700197 NFD_LOG_TRACE("Not a duplicate");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800198
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700199 size_t randomLayer = pickRandomLayer();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800200
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400201 while (m_skipList.size() < randomLayer + 1)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800202 {
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700203 SkipListLayer* newLayer = new SkipListLayer();
204 m_skipList.push_back(newLayer);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800205
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700206 updateTable[(m_skipList.size() - 1)] = newLayer->begin();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800207 }
208
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700209 size_t layer = 0;
210 for (SkipList::iterator i = m_skipList.begin();
211 i != m_skipList.end() && layer <= randomLayer; ++i)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800212 {
213 if (updateTable[layer] == (*i)->end() && !insertInFront)
214 {
215 (*i)->push_back(entry);
216 SkipListLayer::iterator last = (*i)->end();
217 --last;
218 entry->setIterator(layer, last);
219
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700220 NFD_LOG_TRACE("pushback " << &(*last));
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800221 }
222 else if (updateTable[layer] == (*i)->end() && insertInFront)
223 {
224 (*i)->push_front(entry);
225 entry->setIterator(layer, (*i)->begin());
226
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700227 NFD_LOG_TRACE("pushfront ");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800228 }
229 else
230 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700231 NFD_LOG_TRACE("insertafter");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800232 ++updateTable[layer]; // insert after
233 SkipListLayer::iterator position = (*i)->insert(updateTable[layer], entry);
234 entry->setIterator(layer, position); // save iterator where item was inserted
235 }
236 layer++;
237 }
238
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800239 return std::make_pair(entry, true);
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700240}
241
242bool
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800243Cs::insert(const Data& data, bool isUnsolicited)
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700244{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700245 NFD_LOG_TRACE("insert() " << data.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800246
247 if (isFull())
248 {
249 evictItem();
250 }
251
252 //pointer and insertion status
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400253 std::pair<cs::Entry*, bool> entry = insertToSkipList(data, isUnsolicited);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800254
255 //new entry
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400256 if (static_cast<bool>(entry.first) && (entry.second == true))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800257 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400258 m_cleanupIndex.push_back(entry.first);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800259 return true;
260 }
261
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700262 return false;
263}
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800264
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700265size_t
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800266Cs::pickRandomLayer() const
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700267{
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800268 int layer = -1;
269 int randomValue;
270
271 do
272 {
273 layer++;
274 randomValue = rand() % 100 + 1;
275 }
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400276 while ((randomValue < SKIPLIST_PROBABILITY) && (layer < SKIPLIST_MAX_LAYERS));
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800277
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700278 return static_cast<size_t>(layer);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800279}
280
281bool
282Cs::isFull() const
283{
284 if (size() >= m_nMaxPackets) //size of the first layer vs. max size
285 return true;
286
287 return false;
288}
289
290bool
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400291Cs::eraseFromSkipList(cs::Entry* entry)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800292{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700293 NFD_LOG_TRACE("eraseFromSkipList() " << entry->getName());
294 NFD_LOG_TRACE("SkipList size " << size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800295
296 bool isErased = false;
297
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400298 const std::map<int, std::list<cs::Entry*>::iterator>& iterators = entry->getIterators();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800299
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400300 if (!iterators.empty())
301 {
302 int layer = 0;
303
304 for (SkipList::iterator it = m_skipList.begin(); it != m_skipList.end(); )
305 {
306 std::map<int, std::list<cs::Entry*>::iterator>::const_iterator i = iterators.find(layer);
307
308 if (i != iterators.end())
309 {
310 (*it)->erase(i->second);
311 entry->removeIterator(layer);
312 isErased = true;
313
314 //remove layers that do not contain any elements (starting from the second layer)
315 if ((layer != 0) && (*it)->empty())
316 {
317 delete *it;
318 it = m_skipList.erase(it);
319 }
320 else
321 ++it;
322
323 layer++;
324 }
325 else
326 break;
327 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800328 }
329
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400330 //delete entry;
331 if (isErased)
332 {
333 entry->release();
334 m_freeCsEntries.push(entry);
335 m_nPackets--;
336 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800337
338 return isErased;
339}
340
341bool
342Cs::evictItem()
343{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700344 NFD_LOG_TRACE("evictItem()");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800345
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400346 if (!m_cleanupIndex.get<unsolicited>().empty() &&
347 (*m_cleanupIndex.get<unsolicited>().begin())->isUnsolicited())
348 {
349 NFD_LOG_TRACE("Evict from unsolicited queue");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800350
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400351 eraseFromSkipList(*m_cleanupIndex.get<unsolicited>().begin());
352 m_cleanupIndex.get<unsolicited>().erase(m_cleanupIndex.get<unsolicited>().begin());
353 return true;
354 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800355
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400356 if (!m_cleanupIndex.get<byStaleness>().empty() &&
357 (*m_cleanupIndex.get<byStaleness>().begin())->getStaleTime() < time::steady_clock::now())
358 {
359 NFD_LOG_TRACE("Evict from staleness queue");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800360
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400361 eraseFromSkipList(*m_cleanupIndex.get<byStaleness>().begin());
362 m_cleanupIndex.get<byStaleness>().erase(m_cleanupIndex.get<byStaleness>().begin());
363 return true;
364 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800365
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400366 if (!m_cleanupIndex.get<byArrival>().empty())
367 {
368 NFD_LOG_TRACE("Evict from arrival queue");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800369
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400370 eraseFromSkipList(*m_cleanupIndex.get<byArrival>().begin());
371 m_cleanupIndex.get<byArrival>().erase(m_cleanupIndex.get<byArrival>().begin());
372 return true;
373 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800374
375 return false;
376}
377
378const Data*
379Cs::find(const Interest& interest) const
380{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700381 NFD_LOG_TRACE("find() " << interest.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800382
383 bool isIterated = false;
384 SkipList::const_reverse_iterator topLayer = m_skipList.rbegin();
385 SkipListLayer::iterator head = (*topLayer)->begin();
386
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400387 if (!(*topLayer)->empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800388 {
389 //start from the upper layer towards bottom
390 int layer = m_skipList.size() - 1;
391 for (SkipList::const_reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
392 {
393 //if we didn't do any iterations on the higher layers, start from the begin() again
394 if (!isIterated)
395 head = (*rit)->begin();
396
397 if (head != (*rit)->end())
398 {
399 // it happens when begin() contains the element we want to find
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400400 if (!isIterated && (interest.getName().isPrefixOf((*head)->getName())))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800401 {
402 if (layer > 0)
403 {
404 layer--;
405 continue; // try lower layer
406 }
407 else
408 {
409 isIterated = true;
410 }
411 }
412 else
413 {
414 SkipListLayer::iterator it = head;
415
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400416 while ((*it)->getName() < interest.getName())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800417 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700418 NFD_LOG_TRACE((*it)->getName() << " < " << interest.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800419 head = it;
420 isIterated = true;
421
422 ++it;
423 if (it == (*rit)->end())
424 break;
425 }
426 }
427 }
428
429 if (layer > 0)
430 {
431 head = (*head)->getIterators().find(layer - 1)->second; // move HEAD to the lower layer
432 }
433 else //if we reached the first layer
434 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400435 if (isIterated)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800436 return selectChild(interest, head);
437 }
438
439 layer--;
440 }
441 }
442
Alexander Afanasyevc9765df2014-01-25 19:24:27 -0800443 return 0;
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700444}
445
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800446const Data*
447Cs::selectChild(const Interest& interest, SkipListLayer::iterator startingPoint) const
448{
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400449 BOOST_ASSERT(startingPoint != (*m_skipList.begin())->end());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800450
451 if (startingPoint != (*m_skipList.begin())->begin())
452 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400453 BOOST_ASSERT((*startingPoint)->getName() < interest.getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800454 }
455
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400456 NFD_LOG_TRACE("selectChild() " << interest.getChildSelector() << " "
457 << (*startingPoint)->getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800458
459 bool hasLeftmostSelector = (interest.getChildSelector() <= 0);
460 bool hasRightmostSelector = !hasLeftmostSelector;
461
462 if (hasLeftmostSelector)
463 {
464 bool doesInterestContainDigest = recognizeInterestWithDigest(interest, *startingPoint);
465 bool isInPrefix = false;
466
467 if (doesInterestContainDigest)
468 {
469 isInPrefix = interest.getName().getPrefix(-1).isPrefixOf((*startingPoint)->getName());
470 }
471 else
472 {
473 isInPrefix = interest.getName().isPrefixOf((*startingPoint)->getName());
474 }
475
476 if (isInPrefix)
477 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400478 if (doesComplyWithSelectors(interest, *startingPoint, doesInterestContainDigest))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800479 {
480 return &(*startingPoint)->getData();
481 }
482 }
483 }
484
485 //iterate to the right
486 SkipListLayer::iterator rightmost = startingPoint;
487 if (startingPoint != (*m_skipList.begin())->end())
488 {
489 SkipListLayer::iterator rightmostCandidate = startingPoint;
490 Name currentChildPrefix("");
491
492 while (true)
493 {
494 ++rightmostCandidate;
495
496 bool isInBoundaries = (rightmostCandidate != (*m_skipList.begin())->end());
497 bool isInPrefix = false;
498 bool doesInterestContainDigest = false;
499 if (isInBoundaries)
500 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400501 doesInterestContainDigest = recognizeInterestWithDigest(interest,
502 *rightmostCandidate);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800503
504 if (doesInterestContainDigest)
505 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400506 isInPrefix = interest.getName().getPrefix(-1)
507 .isPrefixOf((*rightmostCandidate)->getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800508 }
509 else
510 {
511 isInPrefix = interest.getName().isPrefixOf((*rightmostCandidate)->getName());
512 }
513 }
514
515 if (isInPrefix)
516 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400517 if (doesComplyWithSelectors(interest, *rightmostCandidate, doesInterestContainDigest))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800518 {
519 if (hasLeftmostSelector)
520 {
521 return &(*rightmostCandidate)->getData();
522 }
523
524 if (hasRightmostSelector)
525 {
526 if (doesInterestContainDigest)
527 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400528 // get prefix which is one component longer than Interest name
529 // (without digest)
530 const Name& childPrefix = (*rightmostCandidate)->getName()
531 .getPrefix(interest.getName().size());
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 else
541 {
542 // get prefix which is one component longer than Interest name
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400543 const Name& childPrefix = (*rightmostCandidate)->getName()
544 .getPrefix(interest.getName().size() + 1);
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700545 NFD_LOG_TRACE("Child prefix" << childPrefix);
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800546
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400547 if (currentChildPrefix.empty() || (childPrefix != currentChildPrefix))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800548 {
549 currentChildPrefix = childPrefix;
550 rightmost = rightmostCandidate;
551 }
552 }
553 }
554 }
555 }
556 else
557 break;
558 }
559 }
560
561 if (rightmost != startingPoint)
562 {
563 return &(*rightmost)->getData();
564 }
565
566 if (hasRightmostSelector) // if rightmost was not found, try starting point
567 {
568 bool doesInterestContainDigest = recognizeInterestWithDigest(interest, *startingPoint);
569 bool isInPrefix = false;
570
571 if (doesInterestContainDigest)
572 {
573 isInPrefix = interest.getName().getPrefix(-1).isPrefixOf((*startingPoint)->getName());
574 }
575 else
576 {
577 isInPrefix = interest.getName().isPrefixOf((*startingPoint)->getName());
578 }
579
580 if (isInPrefix)
581 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400582 if (doesComplyWithSelectors(interest, *startingPoint, doesInterestContainDigest))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800583 {
584 return &(*startingPoint)->getData();
585 }
586 }
587 }
588
589 return 0;
590}
591
592bool
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400593Cs::doesComplyWithSelectors(const Interest& interest,
594 cs::Entry* entry,
595 bool doesInterestContainDigest) const
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800596{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700597 NFD_LOG_TRACE("doesComplyWithSelectors()");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800598
599 /// \todo The following detection is not correct
600 /// 1. If data name ends with 32-octet component doesn't mean that this component is digest
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400601 /// 2. Only min/max selectors (both 0) can be specified, all other selectors do not
602 /// make sense for interests with digest (though not sure if we need to enforce this)
603
604 if (doesInterestContainDigest)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800605 {
606 const ndn::name::Component& last = interest.getName().get(-1);
607 const ndn::ConstBufferPtr& digest = entry->getDigest();
608
609 BOOST_ASSERT(digest->size() == last.value_size());
610 BOOST_ASSERT(digest->size() == ndn::crypto::SHA256_DIGEST_SIZE);
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700611
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800612 if (std::memcmp(digest->buf(), last.value(), ndn::crypto::SHA256_DIGEST_SIZE) != 0)
613 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700614 NFD_LOG_TRACE("violates implicit digest");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800615 return false;
616 }
617 }
618
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400619 if (!doesInterestContainDigest)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800620 {
621 if (interest.getMinSuffixComponents() >= 0)
622 {
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700623 size_t minDataNameLength = interest.getName().size() + interest.getMinSuffixComponents();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800624
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700625 bool isSatisfied = (minDataNameLength <= entry->getName().size());
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400626 if (!isSatisfied)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800627 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700628 NFD_LOG_TRACE("violates minComponents");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800629 return false;
630 }
631 }
632
633 if (interest.getMaxSuffixComponents() >= 0)
634 {
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700635 size_t maxDataNameLength = interest.getName().size() + interest.getMaxSuffixComponents();
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800636
Alexander Afanasyevefea8fe2014-03-23 00:00:35 -0700637 bool isSatisfied = (maxDataNameLength >= entry->getName().size());
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400638 if (!isSatisfied)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800639 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700640 NFD_LOG_TRACE("violates maxComponents");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800641 return false;
642 }
643 }
644 }
645
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -0700646 if (interest.getMustBeFresh() && entry->getStaleTime() < time::steady_clock::now())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800647 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700648 NFD_LOG_TRACE("violates mustBeFresh");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800649 return false;
650 }
651
Ilya Moiseenko9c9231b2014-04-10 11:05:12 -0400652 if (!interest.getPublisherPublicKeyLocator().empty())
653 {
654 if (entry->getData().getSignature().getType() == ndn::Signature::Sha256WithRsa)
655 {
656 ndn::SignatureSha256WithRsa rsaSignature(entry->getData().getSignature());
657 if (rsaSignature.getKeyLocator() != interest.getPublisherPublicKeyLocator())
658 {
659 NFD_LOG_TRACE("violates publisher key selector");
660 return false;
661 }
662 }
663 else
664 {
665 NFD_LOG_TRACE("violates publisher key selector");
666 return false;
667 }
668 }
669
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400670 if (doesInterestContainDigest)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800671 {
672 const ndn::name::Component& lastComponent = entry->getName().get(-1);
673
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400674 if (!lastComponent.empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800675 {
676 if (interest.getExclude().isExcluded(lastComponent))
677 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700678 NFD_LOG_TRACE("violates exclusion");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800679 return false;
680 }
681 }
682 }
683 else
684 {
685 if (entry->getName().size() >= interest.getName().size() + 1)
686 {
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400687 const ndn::name::Component& nextComponent = entry->getName()
688 .get(interest.getName().size());
689 if (!nextComponent.empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800690 {
691 if (interest.getExclude().isExcluded(nextComponent))
692 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700693 NFD_LOG_TRACE("violates exclusion");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800694 return false;
695 }
696 }
697 }
698 }
699
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700700 NFD_LOG_TRACE("complies");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800701 return true;
702}
703
704bool
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400705Cs::recognizeInterestWithDigest(const Interest& interest, cs::Entry* entry) const
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800706{
707 // only when min selector is not specified or specified with value of 0
708 // and Interest's name length is exactly the length of the name of CS entry
709 if (interest.getMinSuffixComponents() <= 0 &&
710 interest.getName().size() == (entry->getName().size()))
711 {
712 const ndn::name::Component& last = interest.getName().get(-1);
713 if (last.value_size() == ndn::crypto::SHA256_DIGEST_SIZE)
714 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700715 NFD_LOG_TRACE("digest recognized");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800716 return true;
717 }
718 }
719
720 return false;
721}
722
723void
724Cs::erase(const Name& exactName)
725{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700726 NFD_LOG_TRACE("insert() " << exactName << ", "
727 << "skipList size " << size());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800728
729 bool isIterated = false;
730 SkipListLayer::iterator updateTable[SKIPLIST_MAX_LAYERS];
731 SkipList::reverse_iterator topLayer = m_skipList.rbegin();
732 SkipListLayer::iterator head = (*topLayer)->begin();
733
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400734 if (!(*topLayer)->empty())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800735 {
736 //start from the upper layer towards bottom
737 int layer = m_skipList.size() - 1;
738 for (SkipList::reverse_iterator rit = topLayer; rit != m_skipList.rend(); ++rit)
739 {
740 //if we didn't do any iterations on the higher layers, start from the begin() again
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400741 if (!isIterated)
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800742 head = (*rit)->begin();
743
744 updateTable[layer] = head;
745
746 if (head != (*rit)->end())
747 {
748 // it can happen when begin() contains the element we want to remove
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400749 if (!isIterated && ((*head)->getName() == exactName))
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800750 {
751 eraseFromSkipList(*head);
752 return;
753 }
754 else
755 {
756 SkipListLayer::iterator it = head;
757
758 while ((*it)->getName() < exactName)
759 {
760 head = it;
761 updateTable[layer] = it;
762 isIterated = true;
763
764 ++it;
Ilya Moiseenko96b80bb2014-04-05 20:53:27 -0400765 if (it == (*rit)->end())
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800766 break;
767 }
768 }
769 }
770
771 if (layer > 0)
772 head = (*head)->getIterators().find(layer - 1)->second; // move HEAD to the lower layer
773
774 layer--;
775 }
776 }
777 else
778 {
779 return;
780 }
781
782 head = updateTable[0];
783 ++head; // look at the next slot to check if it contains the item we want to remove
784
785 bool isCsEmpty = (size() == 0);
786 bool isInBoundaries = (head != (*m_skipList.begin())->end());
787 bool isNameIdentical = false;
788 if (!isCsEmpty && isInBoundaries)
789 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700790 NFD_LOG_TRACE("Identical? " << (*head)->getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800791 isNameIdentical = (*head)->getName() == exactName;
792 }
793
794 if (isNameIdentical)
795 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700796 NFD_LOG_TRACE("Found target " << (*head)->getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800797 eraseFromSkipList(*head);
798 }
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800799}
800
801void
802Cs::printSkipList() const
803{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700804 NFD_LOG_TRACE("print()");
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800805 //start from the upper layer towards bottom
806 int layer = m_skipList.size() - 1;
807 for (SkipList::const_reverse_iterator rit = m_skipList.rbegin(); rit != m_skipList.rend(); ++rit)
808 {
809 for (SkipListLayer::iterator it = (*rit)->begin(); it != (*rit)->end(); ++it)
810 {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700811 NFD_LOG_TRACE("Layer " << layer << " " << (*it)->getName());
Ilya Moiseenko76cf77a2014-03-05 14:35:51 -0800812 }
813 layer--;
814 }
815}
Junxiao Shi0fcb41e2014-01-24 10:29:43 -0700816
Alexander Afanasyev18bbf812014-01-29 01:40:23 -0800817} //namespace nfd