blob: 0b6e5238c729ba72020816569686e4d168bd0612 [file] [log] [blame]
Jiewen Tan99135962014-09-20 02:18:53 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Junxiao Shi13d85e02017-07-07 07:34:02 +00002/*
3 * Copyright (c) 2013-2017 Regents of the University of California.
Jiewen Tan99135962014-09-20 02:18:53 -07004 *
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#ifndef NDN_UTIL_IN_MEMORY_STORAGE_HPP
23#define NDN_UTIL_IN_MEMORY_STORAGE_HPP
24
25#include "../common.hpp"
26#include "../interest.hpp"
27#include "../data.hpp"
Yingdi Yu404eafd2016-03-06 14:54:25 -080028#include "scheduler.hpp"
Jiewen Tan99135962014-09-20 02:18:53 -070029#include "in-memory-storage-entry.hpp"
30
31#include <boost/multi_index/member.hpp>
32#include <boost/multi_index_container.hpp>
33#include <boost/multi_index/ordered_index.hpp>
34#include <boost/multi_index/sequenced_index.hpp>
35#include <boost/multi_index/identity.hpp>
36#include <boost/multi_index/mem_fun.hpp>
37
38#include <stack>
39#include <iterator>
Jiewen Tan99135962014-09-20 02:18:53 -070040
41namespace ndn {
42namespace util {
43
44/** @brief Represents in-memory storage
45 */
46class InMemoryStorage : noncopyable
47{
48public:
49 //multi_index_container to implement storage
50 class byFullName;
51
52 typedef boost::multi_index_container<
53 InMemoryStorageEntry*,
54 boost::multi_index::indexed_by<
55
56 // by Full Name
57 boost::multi_index::ordered_unique<
58 boost::multi_index::tag<byFullName>,
59 boost::multi_index::const_mem_fun<InMemoryStorageEntry, const Name&,
60 &InMemoryStorageEntry::getFullName>,
61 std::less<Name>
62 >
63
64 >
65 > Cache;
66
67 /** @brief Represents a self-defined const_iterator for the in-memory storage
68 *
69 * @note Don't try to instantiate this class directly, use InMemoryStorage::begin() instead.
70 */
71 class const_iterator : public std::iterator<std::input_iterator_tag, const Data>
72 {
73 public:
74 const_iterator(const Data* ptr, const Cache* cache,
75 Cache::index<byFullName>::type::iterator it);
76
77 const_iterator&
78 operator++();
79
80 const_iterator
81 operator++(int);
82
83 const Data&
84 operator*();
85
86 const Data*
87 operator->();
88
89 bool
90 operator==(const const_iterator& rhs);
91
92 bool
93 operator!=(const const_iterator& rhs);
94
95 private:
96 const Data* m_ptr;
97 const Cache* m_cache;
98 Cache::index<byFullName>::type::iterator m_it;
99 };
100
101 /** @brief Represents an error might be thrown during reduce the current capacity of the
102 * in-memory storage through function setCapacity(size_t nMaxPackets).
103 */
104 class Error : public std::runtime_error
105 {
106 public:
Junxiao Shi13d85e02017-07-07 07:34:02 +0000107 Error()
108 : std::runtime_error("Cannot reduce the capacity of the in-memory storage!")
Jiewen Tan99135962014-09-20 02:18:53 -0700109 {
110 }
111 };
112
Yingdi Yu404eafd2016-03-06 14:54:25 -0800113 /** @brief Create a InMemoryStorage with up to @p limit entries
114 * The InMemoryStorage created through this method will ignore MustBeFresh in interest processing
115 */
Jiewen Tan99135962014-09-20 02:18:53 -0700116 explicit
117 InMemoryStorage(size_t limit = std::numeric_limits<size_t>::max());
118
Yingdi Yu404eafd2016-03-06 14:54:25 -0800119 /** @brief Create a InMemoryStorage with up to @p limit entries
120 * The InMemoryStorage created through this method will handle MustBeFresh in interest processing
121 */
122 explicit
123 InMemoryStorage(boost::asio::io_service& ioService,
124 size_t limit = std::numeric_limits<size_t>::max());
125
Jiewen Tan99135962014-09-20 02:18:53 -0700126 /** @note Please make sure to implement it to free m_freeEntries and evict
127 * all items in the derived class for anybody who wishes to inherit this class
128 */
129 virtual
130 ~InMemoryStorage();
131
132 /** @brief Inserts a Data packet
133 *
Junxiao Shi13d85e02017-07-07 07:34:02 +0000134 * @param data the packet to insert, must be signed and have wire encoding
Yingdi Yu404eafd2016-03-06 14:54:25 -0800135 * @param mustBeFreshProcessingWindow Beyond this time period after the data is inserted, the
136 * data can only be used to answer interest without MustBeFresh selector.
137 *
Jiewen Tan99135962014-09-20 02:18:53 -0700138 * @note Packets are considered duplicate if the name with implicit digest matches.
139 * The new Data packet with the identical name, but a different payload
140 * will be placed in the in-memory storage.
141 *
142 * @note It will invoke afterInsert(shared_ptr<InMemoryStorageEntry>).
143 */
144 void
Yingdi Yu404eafd2016-03-06 14:54:25 -0800145 insert(const Data& data, const time::milliseconds& mustBeFreshProcessingWindow = INFINITE_WINDOW);
Jiewen Tan99135962014-09-20 02:18:53 -0700146
147 /** @brief Finds the best match Data for an Interest
148 *
149 * @note It will invoke afterAccess(shared_ptr<InMemoryStorageEntry>).
150 * As currently it is impossible to determine whether a Name contains implicit digest or not,
151 * therefore this find function is not able to locate a packet according to an interest(
152 * including implicit digest) whose name is not the full name of the data matching the
153 * implicit digest.
154 *
155 * @return{ the best match, if any; otherwise a null shared_ptr }
156 */
157 shared_ptr<const Data>
158 find(const Interest& interest);
159
160 /** @brief Finds the best match Data for a Name with or without
161 * the implicit digest.
162 *
163 * If packets with the same name but different digests exist
164 * and the Name supplied is the one without implicit digest, a packet
165 * will be arbitrarily chosen to return.
166 *
167 * @note It will invoke afterAccess(shared_ptr<InMemoryStorageEntry>).
168 *
169 * @return{ the one matched the Name; otherwise a null shared_ptr }
170 */
171 shared_ptr<const Data>
172 find(const Name& name);
173
174 /** @brief Deletes in-memory storage entry by prefix by default.
Alexander Afanasyevf2a46222015-09-17 18:01:30 -0700175 * @param prefix Exact name of a prefix of the data to remove
176 * @param isPrefix If false, the function will only delete the
Jiewen Tan99135962014-09-20 02:18:53 -0700177 * entry completely matched with the prefix according to canonical ordering.
178 * For this case, user should substitute the prefix with full name.
179 *
180 * @note Please do not use this function directly in any derived class to erase
181 * entry in the cache, use eraseHelper instead.
182 * @note It will invoke beforeErase(shared_ptr<InMemoryStorageEntry>).
183 */
184 void
185 erase(const Name& prefix, const bool isPrefix = true);
186
187 /** @return{ maximum number of packets that can be allowed to store in in-memory storage }
188 */
189 size_t
190 getLimit() const
191 {
192 return m_limit;
193 }
194
195 /** @return{ number of packets stored in in-memory storage }
196 */
197 size_t
198 size() const
199 {
200 return m_nPackets;
201 }
202
203 /** @brief Returns begin iterator of the in-memory storage ordering by
204 * name with digest
205 *
206 * @return{ const_iterator pointing to the beginning of the m_cache }
207 */
208 InMemoryStorage::const_iterator
209 begin() const;
210
211 /** @brief Returns end iterator of the in-memory storage ordering by
212 * name with digest
213 *
214 * @return{ const_iterator pointing to the end of the m_cache }
215 */
216 InMemoryStorage::const_iterator
217 end() const;
218
Junxiao Shi99848502014-10-13 19:22:22 -0700219NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PROTECTED:
Jiewen Tan99135962014-09-20 02:18:53 -0700220 /** @brief Update the entry when the entry is returned by the find() function
221 * according to derived class implemented replacement policy
222 */
223 virtual void
224 afterAccess(InMemoryStorageEntry* entry);
225
226 /** @brief Update the entry or other data structures
227 * after a entry is successfully inserted
228 * according to derived class implemented replacement policy
229 */
230 virtual void
231 afterInsert(InMemoryStorageEntry* entry);
232
233 /** @brief Update the entry or other data structures
234 * before a entry is successfully erased
235 * according to derived class implemented replacement policy
236 */
237 virtual void
238 beforeErase(InMemoryStorageEntry* entry);
239
240 /** @brief Removes one Data packet from in-memory storage based on
241 * derived class implemented replacement policy
242 *
243 * Please do not use this function directly in any derived class to erase
244 * entry in the cache, use eraseHelper instead.
245 * @return{ whether the Data was removed }
246 */
247 virtual bool
248 evictItem() = 0;
249
Junxiao Shi99848502014-10-13 19:22:22 -0700250NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PROTECTED:
Jiewen Tan99135962014-09-20 02:18:53 -0700251 /** @brief sets current capacity of in-memory storage (in packets)
252 */
253 void
254 setCapacity(size_t nMaxPackets);
255
256 /** @brief returns current capacity of in-memory storage (in packets)
257 * @return{ number of packets that can be stored in application cache }
258 */
259 size_t
260 getCapacity() const
261 {
262 return m_capacity;
263 }
264
265 /** @brief returns true if the in-memory storage uses up the current capacity, false otherwise
266 */
267 bool
268 isFull() const
269 {
270 return size() >= m_capacity;
271 }
272
273 /** @brief deletes in-memory storage entries by the Name with implicit digest.
274 *
275 * This is the function one should use to erase entry in the cache
276 * in derived class.
277 * It won't invoke beforeErase(shared_ptr<Entry>).
278 */
279 void
280 eraseImpl(const Name& name);
281
282 /** @brief Prints contents of the in-memory storage
283 */
284 void
285 printCache(std::ostream& os) const;
286
Junxiao Shi99848502014-10-13 19:22:22 -0700287NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
Jiewen Tan99135962014-09-20 02:18:53 -0700288 /** @brief free in-memory storage entries by an iterator pointing to that entry.
Alexander Afanasyev8e131fd2014-12-15 21:31:50 -0800289 @return An iterator pointing to the element that followed the last element erased.
290 */
291 Cache::iterator
292 freeEntry(Cache::iterator it);
Jiewen Tan99135962014-09-20 02:18:53 -0700293
294 /** @brief Implements child selector (leftmost, rightmost, undeclared).
295 * Operates on the first layer of a skip list.
296 *
297 * startingPoint must be less than Interest Name.
298 * startingPoint can be equal to Interest Name only
299 * when the item is in the begin() position.
300 *
301 * Iterates toward greater Names, terminates when application cache entry falls out of Interest
302 * prefix. When childSelector = leftmost, returns first application cache entry that satisfies
303 * other selectors. When childSelector = rightmost, it goes till the end, and returns application
304 * cache entry that satisfies other selectors. Returned application cache entry is the leftmost
305 * child of the rightmost child.
306 * @return{ the best match, if any; otherwise 0 }
307 */
308 InMemoryStorageEntry*
309 selectChild(const Interest& interest,
310 Cache::index<byFullName>::type::iterator startingPoint) const;
311
Yingdi Yu404eafd2016-03-06 14:54:25 -0800312 /** @brief Get the next iterator (include startingPoint) that satisfies MustBeFresh requirement
313 *
314 * @param startingPoint The iterator to start with.
315 * @return The next qualified iterator
316 */
317 Cache::index<byFullName>::type::iterator
318 findNextFresh(Cache::index<byFullName>::type::iterator startingPoint) const;
319
320private:
321 void
322 init();
323
324public:
325 static const time::milliseconds INFINITE_WINDOW;
326
327private:
328 static const time::milliseconds ZERO_WINDOW;
329
Jiewen Tan99135962014-09-20 02:18:53 -0700330private:
331 Cache m_cache;
332 /// user defined maximum capacity of the in-memory storage in packets
333 size_t m_limit;
334 /// current capacity of the in-memory storage in packets
335 size_t m_capacity;
336 /// current number of packets in in-memory storage
337 size_t m_nPackets;
338 /// memory pool
339 std::stack<InMemoryStorageEntry*> m_freeEntries;
Yingdi Yu404eafd2016-03-06 14:54:25 -0800340 /// scheduler
341 unique_ptr<Scheduler> m_scheduler;
Jiewen Tan99135962014-09-20 02:18:53 -0700342};
343
344} // namespace util
345} // namespace ndn
346
347#endif // NDN_UTIL_IN_MEMORY_STORAGE_HPP