blob: 2db556499a442cfbcbda4ea6e8c10494d8d8b838 [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#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"
28
29#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>
40#include <stdexcept>
41
42namespace ndn {
43namespace util {
44
45/** @brief Represents in-memory storage
46 */
47class InMemoryStorage : noncopyable
48{
49public:
50 //multi_index_container to implement storage
51 class byFullName;
52
53 typedef boost::multi_index_container<
54 InMemoryStorageEntry*,
55 boost::multi_index::indexed_by<
56
57 // by Full Name
58 boost::multi_index::ordered_unique<
59 boost::multi_index::tag<byFullName>,
60 boost::multi_index::const_mem_fun<InMemoryStorageEntry, const Name&,
61 &InMemoryStorageEntry::getFullName>,
62 std::less<Name>
63 >
64
65 >
66 > Cache;
67
68 /** @brief Represents a self-defined const_iterator for the in-memory storage
69 *
70 * @note Don't try to instantiate this class directly, use InMemoryStorage::begin() instead.
71 */
72 class const_iterator : public std::iterator<std::input_iterator_tag, const Data>
73 {
74 public:
75 const_iterator(const Data* ptr, const Cache* cache,
76 Cache::index<byFullName>::type::iterator it);
77
78 const_iterator&
79 operator++();
80
81 const_iterator
82 operator++(int);
83
84 const Data&
85 operator*();
86
87 const Data*
88 operator->();
89
90 bool
91 operator==(const const_iterator& rhs);
92
93 bool
94 operator!=(const const_iterator& rhs);
95
96 private:
97 const Data* m_ptr;
98 const Cache* m_cache;
99 Cache::index<byFullName>::type::iterator m_it;
100 };
101
102 /** @brief Represents an error might be thrown during reduce the current capacity of the
103 * in-memory storage through function setCapacity(size_t nMaxPackets).
104 */
105 class Error : public std::runtime_error
106 {
107 public:
108 Error() : std::runtime_error("Cannot reduce the capacity of the in-memory storage!")
109 {
110 }
111 };
112
113 explicit
114 InMemoryStorage(size_t limit = std::numeric_limits<size_t>::max());
115
116 /** @note Please make sure to implement it to free m_freeEntries and evict
117 * all items in the derived class for anybody who wishes to inherit this class
118 */
119 virtual
120 ~InMemoryStorage();
121
122 /** @brief Inserts a Data packet
123 *
124 * @note Packets are considered duplicate if the name with implicit digest matches.
125 * The new Data packet with the identical name, but a different payload
126 * will be placed in the in-memory storage.
127 *
128 * @note It will invoke afterInsert(shared_ptr<InMemoryStorageEntry>).
129 */
130 void
131 insert(const Data& data);
132
133 /** @brief Finds the best match Data for an Interest
134 *
135 * @note It will invoke afterAccess(shared_ptr<InMemoryStorageEntry>).
136 * As currently it is impossible to determine whether a Name contains implicit digest or not,
137 * therefore this find function is not able to locate a packet according to an interest(
138 * including implicit digest) whose name is not the full name of the data matching the
139 * implicit digest.
140 *
141 * @return{ the best match, if any; otherwise a null shared_ptr }
142 */
143 shared_ptr<const Data>
144 find(const Interest& interest);
145
146 /** @brief Finds the best match Data for a Name with or without
147 * the implicit digest.
148 *
149 * If packets with the same name but different digests exist
150 * and the Name supplied is the one without implicit digest, a packet
151 * will be arbitrarily chosen to return.
152 *
153 * @note It will invoke afterAccess(shared_ptr<InMemoryStorageEntry>).
154 *
155 * @return{ the one matched the Name; otherwise a null shared_ptr }
156 */
157 shared_ptr<const Data>
158 find(const Name& name);
159
160 /** @brief Deletes in-memory storage entry by prefix by default.
161 * @param[in] isPrefix If it is clear, the function will only delete the
162 * entry completely matched with the prefix according to canonical ordering.
163 * For this case, user should substitute the prefix with full name.
164 *
165 * @note Please do not use this function directly in any derived class to erase
166 * entry in the cache, use eraseHelper instead.
167 * @note It will invoke beforeErase(shared_ptr<InMemoryStorageEntry>).
168 */
169 void
170 erase(const Name& prefix, const bool isPrefix = true);
171
172 /** @return{ maximum number of packets that can be allowed to store in in-memory storage }
173 */
174 size_t
175 getLimit() const
176 {
177 return m_limit;
178 }
179
180 /** @return{ number of packets stored in in-memory storage }
181 */
182 size_t
183 size() const
184 {
185 return m_nPackets;
186 }
187
188 /** @brief Returns begin iterator of the in-memory storage ordering by
189 * name with digest
190 *
191 * @return{ const_iterator pointing to the beginning of the m_cache }
192 */
193 InMemoryStorage::const_iterator
194 begin() const;
195
196 /** @brief Returns end iterator of the in-memory storage ordering by
197 * name with digest
198 *
199 * @return{ const_iterator pointing to the end of the m_cache }
200 */
201 InMemoryStorage::const_iterator
202 end() const;
203
204PUBLIC_WITH_TESTS_ELSE_PROTECTED:
205 /** @brief Update the entry when the entry is returned by the find() function
206 * according to derived class implemented replacement policy
207 */
208 virtual void
209 afterAccess(InMemoryStorageEntry* entry);
210
211 /** @brief Update the entry or other data structures
212 * after a entry is successfully inserted
213 * according to derived class implemented replacement policy
214 */
215 virtual void
216 afterInsert(InMemoryStorageEntry* entry);
217
218 /** @brief Update the entry or other data structures
219 * before a entry is successfully erased
220 * according to derived class implemented replacement policy
221 */
222 virtual void
223 beforeErase(InMemoryStorageEntry* entry);
224
225 /** @brief Removes one Data packet from in-memory storage based on
226 * derived class implemented replacement policy
227 *
228 * Please do not use this function directly in any derived class to erase
229 * entry in the cache, use eraseHelper instead.
230 * @return{ whether the Data was removed }
231 */
232 virtual bool
233 evictItem() = 0;
234
235PUBLIC_WITH_TESTS_ELSE_PROTECTED:
236 /** @brief sets current capacity of in-memory storage (in packets)
237 */
238 void
239 setCapacity(size_t nMaxPackets);
240
241 /** @brief returns current capacity of in-memory storage (in packets)
242 * @return{ number of packets that can be stored in application cache }
243 */
244 size_t
245 getCapacity() const
246 {
247 return m_capacity;
248 }
249
250 /** @brief returns true if the in-memory storage uses up the current capacity, false otherwise
251 */
252 bool
253 isFull() const
254 {
255 return size() >= m_capacity;
256 }
257
258 /** @brief deletes in-memory storage entries by the Name with implicit digest.
259 *
260 * This is the function one should use to erase entry in the cache
261 * in derived class.
262 * It won't invoke beforeErase(shared_ptr<Entry>).
263 */
264 void
265 eraseImpl(const Name& name);
266
267 /** @brief Prints contents of the in-memory storage
268 */
269 void
270 printCache(std::ostream& os) const;
271
272PUBLIC_WITH_TESTS_ELSE_PRIVATE:
273 /** @brief free in-memory storage entries by an iterator pointing to that entry.
274 */
275 void
276 freeEntry(Cache::index<byFullName>::type::iterator it);
277
278 /** @brief Implements child selector (leftmost, rightmost, undeclared).
279 * Operates on the first layer of a skip list.
280 *
281 * startingPoint must be less than Interest Name.
282 * startingPoint can be equal to Interest Name only
283 * when the item is in the begin() position.
284 *
285 * Iterates toward greater Names, terminates when application cache entry falls out of Interest
286 * prefix. When childSelector = leftmost, returns first application cache entry that satisfies
287 * other selectors. When childSelector = rightmost, it goes till the end, and returns application
288 * cache entry that satisfies other selectors. Returned application cache entry is the leftmost
289 * child of the rightmost child.
290 * @return{ the best match, if any; otherwise 0 }
291 */
292 InMemoryStorageEntry*
293 selectChild(const Interest& interest,
294 Cache::index<byFullName>::type::iterator startingPoint) const;
295
296private:
297 Cache m_cache;
298 /// user defined maximum capacity of the in-memory storage in packets
299 size_t m_limit;
300 /// current capacity of the in-memory storage in packets
301 size_t m_capacity;
302 /// current number of packets in in-memory storage
303 size_t m_nPackets;
304 /// memory pool
305 std::stack<InMemoryStorageEntry*> m_freeEntries;
306};
307
308} // namespace util
309} // namespace ndn
310
311#endif // NDN_UTIL_IN_MEMORY_STORAGE_HPP