blob: d294dd64f387e5fe7d29dd7575c84b7ab4ff4964 [file] [log] [blame]
Jiewen Tan99135962014-09-20 02:18:53 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2013-2014 Regents of the University of California.
4 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
22#include "in-memory-storage.hpp"
23#include "in-memory-storage-entry.hpp"
24
25#include "crypto.hpp"
26
27#include "../security/signature-sha256-with-rsa.hpp"
28
29namespace ndn {
30namespace util {
31
32InMemoryStorage::const_iterator::const_iterator(const Data* ptr, const Cache* cache,
33 Cache::index<byFullName>::type::iterator it)
34 : m_ptr(ptr)
35 , m_cache(cache)
36 , m_it(it)
37{
38}
39
40InMemoryStorage::const_iterator&
41InMemoryStorage::const_iterator::operator++()
42{
43 m_it++;
44 if (m_it != m_cache->get<byFullName>().end()) {
45 m_ptr = &((*m_it)->getData());
46 }
47 else {
48 m_ptr = 0;
49 }
50
51 return *this;
52}
53
54InMemoryStorage::const_iterator
55InMemoryStorage::const_iterator::operator++(int)
56{
57 InMemoryStorage::const_iterator i(*this);
58 this->operator++();
59 return i;
60}
61
62const Data&
63InMemoryStorage::const_iterator::operator*()
64{
65 return *m_ptr;
66}
67
68const Data*
69InMemoryStorage::const_iterator::operator->()
70{
71 return m_ptr;
72}
73
74bool
75InMemoryStorage::const_iterator::operator==(const const_iterator& rhs)
76{
77 return m_it == rhs.m_it;
78}
79
80bool
81InMemoryStorage::const_iterator::operator!=(const const_iterator& rhs)
82{
83 return m_it != rhs.m_it;
84}
85
86InMemoryStorage::InMemoryStorage(size_t limit)
87 : m_limit(limit)
88 , m_nPackets(0)
89{
90 // TODO consider a more suitable initial value
91 m_capacity = 10;
92
93 if (limit != std::numeric_limits<size_t>::max() && m_capacity > m_limit) {
94 m_capacity = m_limit;
95 }
96
97 for (size_t i = 0; i < m_capacity; i++) {
98 m_freeEntries.push(new InMemoryStorageEntry());
99 }
100}
101
102InMemoryStorage::~InMemoryStorage()
103{
104 // evict all items from cache
105 Cache::iterator it = m_cache.begin();
106 while (it != m_cache.end()) {
107 freeEntry(it);
108 it++;
109 }
110
111 BOOST_ASSERT(m_freeEntries.size() == m_capacity);
112
113 while (!m_freeEntries.empty()) {
114 delete m_freeEntries.top();
115 m_freeEntries.pop();
116 }
117}
118
119void
120InMemoryStorage::setCapacity(size_t capacity)
121{
122 size_t oldCapacity = m_capacity;
123 m_capacity = capacity;
124
125 if (size() > m_capacity) {
126 ssize_t nAllowedFailures = size() - m_capacity;
127 while (size() > m_capacity) {
128 if (!evictItem() && --nAllowedFailures < 0) {
129 throw Error();
130 }
131 }
132 }
133
134 if (m_capacity >= oldCapacity) {
135 for (size_t i = oldCapacity; i < m_capacity; i++) {
136 m_freeEntries.push(new InMemoryStorageEntry());
137 }
138 }
139 else {
140 for (size_t i = oldCapacity; i > m_capacity; i--) {
141 delete m_freeEntries.top();
142 m_freeEntries.pop();
143 }
144 }
145
146 BOOST_ASSERT(size() + m_freeEntries.size() == m_capacity);
147}
148
149void
150InMemoryStorage::insert(const Data& data)
151{
152 //check if identical Data/Name already exists
153 Cache::index<byFullName>::type::iterator it = m_cache.get<byFullName>().find(data.getFullName());
154 if (it != m_cache.get<byFullName>().end())
155 return;
156
157 //if full, double the capacity
158 bool doesReachLimit = (getLimit() == getCapacity());
159 if (isFull() && !doesReachLimit) {
160 // note: This is incorrect if 2*capacity overflows, but memory should run out before that
161 size_t newCapacity = std::min(2 * getCapacity(), getLimit());
162 setCapacity(newCapacity);
163 }
164
165 //if full and reach limitation of the capacity, employ replacement policy
166 if (isFull() && doesReachLimit) {
167 evictItem();
168 }
169
170 //insert to cache
171 BOOST_ASSERT(m_freeEntries.size() > 0);
172 // take entry for the memory pool
173 InMemoryStorageEntry* entry = m_freeEntries.top();
174 m_freeEntries.pop();
175 m_nPackets++;
176 entry->setData(data);
177 m_cache.insert(entry);
178
179 //let derived class do something with the entry
180 afterInsert(entry);
181}
182
183shared_ptr<const Data>
184InMemoryStorage::find(const Name& name)
185{
186 Cache::index<byFullName>::type::iterator it = m_cache.get<byFullName>().lower_bound(name);
187
188 //if not found, return null
189 if (it == m_cache.get<byFullName>().end()) {
190 return shared_ptr<const Data>();
191 }
192
193 //if the given name is not the prefix of the lower_bound, return null
194 if (!name.isPrefixOf((*it)->getFullName())) {
195 return shared_ptr<const Data>();
196 }
197
198 afterAccess(*it);
199 return ((*it)->getData()).shared_from_this();
200}
201
202shared_ptr<const Data>
203InMemoryStorage::find(const Interest& interest)
204{
205 //if the interest contains implicit digest, it is possible to directly locate a packet.
206 Cache::index<byFullName>::type::iterator it = m_cache.get<byFullName>()
207 .find(interest.getName());
208
209 //if a packet is located by its full name, it must be the packet to return.
210 if (it != m_cache.get<byFullName>().end()) {
211 return ((*it)->getData()).shared_from_this();
212 }
213
214 //if the packet is not discovered by last step, either the packet is not in the storage or
215 //the interest doesn't contains implicit digest.
216 it = m_cache.get<byFullName>().lower_bound(interest.getName());
217
218 if (it == m_cache.get<byFullName>().end()) {
219 return shared_ptr<const Data>();
220 }
221
222
223 //to locate the element that has a just smaller name than the interest's
224 if (it != m_cache.get<byFullName>().begin())
225 it--;
226
227 InMemoryStorageEntry* ret = selectChild(interest, it);
228 if (ret != 0) {
229 //let derived class do something with the entry
230 afterAccess(ret);
231 return ret->getData().shared_from_this();
232 }
233 else {
234 return shared_ptr<const Data>();
235 }
236}
237
238InMemoryStorageEntry*
239InMemoryStorage::selectChild(const Interest& interest,
240 Cache::index<byFullName>::type::iterator startingPoint) const
241{
242 BOOST_ASSERT(startingPoint != m_cache.get<byFullName>().end());
243
244 if (startingPoint != m_cache.get<byFullName>().begin())
245 {
246 BOOST_ASSERT((*startingPoint)->getFullName() < interest.getName());
247 }
248
249 bool hasLeftmostSelector = (interest.getChildSelector() <= 0);
250 bool hasRightmostSelector = !hasLeftmostSelector;
251
252 if (hasLeftmostSelector)
253 {
254 if (interest.matchesData((*startingPoint)->getData()))
255 {
256 return *startingPoint;
257 }
258 }
259
260 //iterate to the right
261 Cache::index<byFullName>::type::iterator rightmost = startingPoint;
262 if (startingPoint != m_cache.get<byFullName>().end())
263 {
264 Cache::index<byFullName>::type::iterator rightmostCandidate = startingPoint;
265 Name currentChildPrefix("");
266
267 while (true)
268 {
269 ++rightmostCandidate;
270
271 bool isInBoundaries = (rightmostCandidate != m_cache.get<byFullName>().end());
272 bool isInPrefix = false;
273 if (isInBoundaries)
274 {
275 isInPrefix = interest.getName().isPrefixOf((*rightmostCandidate)->getFullName());
276 }
277
278 if (isInPrefix)
279 {
280 if (interest.matchesData((*rightmostCandidate)->getData()))
281 {
282 if (hasLeftmostSelector)
283 {
284 return *rightmostCandidate;
285 }
286
287 if (hasRightmostSelector)
288 {
289 // get prefix which is one component longer than Interest name
290 const Name& childPrefix = (*rightmostCandidate)->getFullName()
291 .getPrefix(interest.getName().size() + 1);
292
293 if (currentChildPrefix.empty() || (childPrefix != currentChildPrefix))
294 {
295 currentChildPrefix = childPrefix;
296 rightmost = rightmostCandidate;
297 }
298 }
299 }
300 }
301 else
302 break;
303 }
304 }
305
306 if (rightmost != startingPoint)
307 {
308 return *rightmost;
309 }
310
311 if (hasRightmostSelector) // if rightmost was not found, try starting point
312 {
313 if (interest.matchesData((*startingPoint)->getData()))
314 {
315 return *startingPoint;
316 }
317 }
318
319 return 0;
320}
321
322void
323InMemoryStorage::freeEntry(Cache::index<byFullName>::type::iterator it) {
324 //push the *empty* entry into mem pool
325 (*it)->release();
326 m_freeEntries.push(*it);
327 m_nPackets--;
328 m_cache.get<byFullName>().erase(it);
329}
330
331void
332InMemoryStorage::erase(const Name& prefix, const bool isPrefix)
333{
334 if (isPrefix) {
335 Cache::index<byFullName>::type::iterator it = m_cache.get<byFullName>().lower_bound(prefix);
336
337 if (it == m_cache.get<byFullName>().end())
338 return;
339
340 while (it != m_cache.get<byFullName>().end() && prefix.isPrefixOf((*it)->getName())) {
341 //let derived class do something with the entry
342 beforeErase(*it);
343 freeEntry(it);
344 it++;
345 }
346 }
347 else {
348 Cache::index<byFullName>::type::iterator it = m_cache.get<byFullName>().find(prefix);
349
350 if (it == m_cache.get<byFullName>().end())
351 return;
352
353 //let derived class do something with the entry
354 beforeErase(*it);
355 freeEntry(it);
356 }
357
358 if (m_freeEntries.size() > (2 * size()))
359 setCapacity(getCapacity() / 2);
360}
361
362void
363InMemoryStorage::eraseImpl(const Name& name)
364{
365 Cache::index<byFullName>::type::iterator it = m_cache.get<byFullName>().find(name);
366
367 if (it == m_cache.get<byFullName>().end())
368 return;
369
370 freeEntry(it);
371}
372
373InMemoryStorage::const_iterator
374InMemoryStorage::begin() const
375{
376 Cache::index<byFullName>::type::iterator it = m_cache.get<byFullName>().begin();
377
378 return const_iterator(&((*it)->getData()), &m_cache, it);
379}
380
381InMemoryStorage::const_iterator
382InMemoryStorage::end() const
383{
384 Cache::index<byFullName>::type::iterator it = m_cache.get<byFullName>().end();
385
386 const Data* ptr = NULL;
387
388 return const_iterator(ptr, &m_cache, it);
389}
390
391void
392InMemoryStorage::afterInsert(InMemoryStorageEntry* entry)
393{
394}
395
396void
397InMemoryStorage::beforeErase(InMemoryStorageEntry* entry)
398{
399}
400
401void
402InMemoryStorage::afterAccess(InMemoryStorageEntry* entry)
403{
404}
405
406void
407InMemoryStorage::printCache(std::ostream& os) const
408{
409 //start from the upper layer towards bottom
410 const Cache::index<byFullName>::type& cacheIndex = m_cache.get<byFullName>();
411 for (Cache::index<byFullName>::type::iterator it = cacheIndex.begin();
412 it != cacheIndex.end(); it++)
413 os << (*it)->getFullName() << std::endl;
414}
415
416} // namespace util
417} // namespace ndn