blob: ccbf5a140fc36744934f64ab5a97d4db59e2c1aa [file] [log] [blame]
Junxiao Shi0e42c572014-10-05 20:33:48 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento50a6af32019-02-21 00:04:40 -05002/*
3 * Copyright (c) 2014-2019, Regents of the University of California,
Junxiao Shi9f5b01d2016-08-05 03:54:28 +00004 * 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.
Junxiao Shi0e42c572014-10-05 20:33:48 -070010 *
11 * 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
26#ifndef NFD_DAEMON_TABLE_DEAD_NONCE_LIST_HPP
27#define NFD_DAEMON_TABLE_DEAD_NONCE_LIST_HPP
28
Junxiao Shi9f5b01d2016-08-05 03:54:28 +000029#include "core/common.hpp"
Junxiao Shi0e42c572014-10-05 20:33:48 -070030#include "core/scheduler.hpp"
31
Davide Pesavento50a6af32019-02-21 00:04:40 -050032#include <boost/multi_index_container.hpp>
33#include <boost/multi_index/hashed_index.hpp>
34#include <boost/multi_index/sequenced_index.hpp>
35
Junxiao Shi0e42c572014-10-05 20:33:48 -070036namespace nfd {
37
Davide Pesavento50a6af32019-02-21 00:04:40 -050038/** \brief Represents the Dead Nonce List
Junxiao Shi0e42c572014-10-05 20:33:48 -070039 *
40 * The Dead Nonce List is a global table that supplements PIT for loop detection.
41 * When a Nonce is erased (dead) from PIT entry, the Nonce and the Interest Name is added to
42 * Dead Nonce List, and kept for a duration in which most loops are expected to have occured.
43 *
44 * To reduce memory usage, the Interest Name and Nonce are stored as a 64-bit hash.
45 * There could be false positives (non-looping Interest could be considered looping),
46 * but the probability is small, and the error is recoverable when consumer retransmits
47 * with a different Nonce.
48 *
49 * To reduce memory usage, entries do not have associated timestamps. Instead,
50 * lifetime of entries is controlled by dynamically adjusting the capacity of the container.
51 * At fixed intervals, the MARK, an entry with a special value, is inserted into the container.
52 * The number of MARKs stored in the container reflects the lifetime of entries,
53 * because MARKs are inserted at fixed intervals.
54 */
55class DeadNonceList : noncopyable
56{
57public:
Davide Pesavento50a6af32019-02-21 00:04:40 -050058 /** \brief Constructs the Dead Nonce List
Junxiao Shi0e42c572014-10-05 20:33:48 -070059 * \param lifetime duration of the expected lifetime of each nonce,
60 * must be no less than MIN_LIFETIME.
61 * This should be set to the duration in which most loops would have occured.
62 * A loop cannot be detected if delay of the cycle is greater than lifetime.
63 * \throw std::invalid_argument if lifetime is less than MIN_LIFETIME
64 */
65 explicit
Davide Pesavento50a6af32019-02-21 00:04:40 -050066 DeadNonceList(time::nanoseconds lifetime = DEFAULT_LIFETIME);
Junxiao Shi0e42c572014-10-05 20:33:48 -070067
68 ~DeadNonceList();
69
Davide Pesavento50a6af32019-02-21 00:04:40 -050070 /** \brief Determines if name+nonce exists
Junxiao Shi0e42c572014-10-05 20:33:48 -070071 * \return true if name+nonce exists
72 */
73 bool
74 has(const Name& name, uint32_t nonce) const;
75
Davide Pesavento50a6af32019-02-21 00:04:40 -050076 /** \brief Records name+nonce
Junxiao Shi0e42c572014-10-05 20:33:48 -070077 */
78 void
79 add(const Name& name, uint32_t nonce);
80
81 /** \return number of stored Nonces
82 * \note The return value does not contain non-Nonce entries in the index, if any.
83 */
84 size_t
85 size() const;
86
Junxiao Shia110f262014-10-12 12:35:20 -070087 /** \return expected lifetime
88 */
Davide Pesavento50a6af32019-02-21 00:04:40 -050089 time::nanoseconds
90 getLifetime() const
91 {
92 return m_lifetime;
93 }
Junxiao Shia110f262014-10-12 12:35:20 -070094
Junxiao Shi0e42c572014-10-05 20:33:48 -070095private: // Entry and Index
96 typedef uint64_t Entry;
97
98 static Entry
99 makeEntry(const Name& name, uint32_t nonce);
100
101 typedef boost::multi_index_container<
102 Entry,
103 boost::multi_index::indexed_by<
104 boost::multi_index::sequenced<>,
105 boost::multi_index::hashed_non_unique<
106 boost::multi_index::identity<Entry>
107 >
108 >
109 > Index;
110
111 typedef Index::nth_index<0>::type Queue;
112 typedef Index::nth_index<1>::type Hashtable;
113
114private: // actual lifetime estimation and capacity control
Davide Pesavento50a6af32019-02-21 00:04:40 -0500115 /** \brief Return the number of MARKs in the index
Junxiao Shi0e42c572014-10-05 20:33:48 -0700116 */
117 size_t
118 countMarks() const;
119
Davide Pesavento50a6af32019-02-21 00:04:40 -0500120 /** \brief Add a MARK, then record number of MARKs in m_actualMarkCounts
Junxiao Shi0e42c572014-10-05 20:33:48 -0700121 */
122 void
123 mark();
124
Davide Pesavento50a6af32019-02-21 00:04:40 -0500125 /** \brief Adjust capacity according to m_actualMarkCounts
Junxiao Shi0e42c572014-10-05 20:33:48 -0700126 *
127 * If all counts are above EXPECTED_MARK_COUNT, reduce capacity to m_capacity * CAPACITY_DOWN.
128 * If all counts are below EXPECTED_MARK_COUNT, increase capacity to m_capacity * CAPACITY_UP.
129 */
130 void
131 adjustCapacity();
132
Davide Pesavento50a6af32019-02-21 00:04:40 -0500133 /** \brief Evict some entries if index is over capacity
Junxiao Shi0e42c572014-10-05 20:33:48 -0700134 */
135 void
136 evictEntries();
137
138public:
Davide Pesavento50a6af32019-02-21 00:04:40 -0500139 /// Default entry lifetime
Junxiao Shi0e42c572014-10-05 20:33:48 -0700140 static const time::nanoseconds DEFAULT_LIFETIME;
Davide Pesavento50a6af32019-02-21 00:04:40 -0500141 /// Minimum entry lifetime
Junxiao Shi0e42c572014-10-05 20:33:48 -0700142 static const time::nanoseconds MIN_LIFETIME;
143
144private:
145 time::nanoseconds m_lifetime;
146 Index m_index;
147 Queue& m_queue;
148 Hashtable& m_ht;
149
150PUBLIC_WITH_TESTS_ELSE_PRIVATE: // actual lifetime estimation and capacity control
151
152 // ---- current capacity and hard limits
153
Davide Pesavento50a6af32019-02-21 00:04:40 -0500154 /** \brief Current capacity of index
Junxiao Shi0e42c572014-10-05 20:33:48 -0700155 *
156 * The index size is maintained to be near this capacity.
157 *
158 * The capacity is adjusted so that every Entry is expected to be kept for m_lifetime.
159 * This is achieved by mark() and adjustCapacity().
160 */
161 size_t m_capacity;
162
163 static const size_t INITIAL_CAPACITY;
164
Davide Pesavento50a6af32019-02-21 00:04:40 -0500165 /** \brief Minimum capacity
Junxiao Shi0e42c572014-10-05 20:33:48 -0700166 *
167 * This is to ensure correct algorithm operations.
168 */
169 static const size_t MIN_CAPACITY;
170
Davide Pesavento50a6af32019-02-21 00:04:40 -0500171 /** \brief Maximum capacity
Junxiao Shi0e42c572014-10-05 20:33:48 -0700172 *
173 * This is to limit memory usage.
174 */
175 static const size_t MAX_CAPACITY;
176
177 // ---- actual entry lifetime estimation
178
Davide Pesavento50a6af32019-02-21 00:04:40 -0500179 /** \brief The MARK for capacity
Junxiao Shi0e42c572014-10-05 20:33:48 -0700180 *
181 * The MARK doesn't have a distinct type.
182 * Entry is a hash. The hash function should have non-invertible property,
183 * so it's unlikely for a usual Entry to have collision with the MARK.
184 */
185 static const Entry MARK;
186
Davide Pesavento50a6af32019-02-21 00:04:40 -0500187 /** \brief Expected number of MARKs in the index
Junxiao Shi0e42c572014-10-05 20:33:48 -0700188 */
189 static const size_t EXPECTED_MARK_COUNT;
190
Davide Pesavento50a6af32019-02-21 00:04:40 -0500191 /** \brief Number of MARKs in the index after each MARK insertion
Junxiao Shi0e42c572014-10-05 20:33:48 -0700192 *
Davide Pesavento50a6af32019-02-21 00:04:40 -0500193 * adjustCapacity() uses this to determine whether and how to adjust capcity,
Junxiao Shi0e42c572014-10-05 20:33:48 -0700194 * and then clears this list.
195 */
196 std::multiset<size_t> m_actualMarkCounts;
197
198 time::nanoseconds m_markInterval;
Junxiao Shi0e42c572014-10-05 20:33:48 -0700199 scheduler::EventId m_markEvent;
200
201 // ---- capacity adjustments
202
203 static const double CAPACITY_UP;
Junxiao Shi0e42c572014-10-05 20:33:48 -0700204 static const double CAPACITY_DOWN;
Junxiao Shi0e42c572014-10-05 20:33:48 -0700205 time::nanoseconds m_adjustCapacityInterval;
Junxiao Shi0e42c572014-10-05 20:33:48 -0700206 scheduler::EventId m_adjustCapacityEvent;
207
Davide Pesavento50a6af32019-02-21 00:04:40 -0500208 /// Maximum number of entries to evict at each operation if index is over capacity
Junxiao Shi0e42c572014-10-05 20:33:48 -0700209 static const size_t EVICT_LIMIT;
210};
211
Junxiao Shi0e42c572014-10-05 20:33:48 -0700212} // namespace nfd
213
214#endif // NFD_DAEMON_TABLE_DEAD_NONCE_LIST_HPP