cs.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2014-2019, 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.
10  *
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 #include "cs.hpp"
27 #include "common/logger.hpp"
28 #include "core/algorithm.hpp"
29 
30 #include <ndn-cxx/lp/tags.hpp>
31 #include <ndn-cxx/util/concepts.hpp>
32 
33 namespace nfd {
34 namespace cs {
35 
37 
38 NFD_LOG_INIT(ContentStore);
39 
40 static unique_ptr<Policy>
42 {
43  return Policy::create("lru");
44 }
45 
46 Cs::Cs(size_t nMaxPackets)
47 {
48  setPolicyImpl(makeDefaultPolicy());
49  m_policy->setLimit(nMaxPackets);
50 }
51 
52 void
53 Cs::insert(const Data& data, bool isUnsolicited)
54 {
55  if (!m_shouldAdmit || m_policy->getLimit() == 0) {
56  return;
57  }
58  NFD_LOG_DEBUG("insert " << data.getName());
59 
60  // recognize CachePolicy
61  shared_ptr<lp::CachePolicyTag> tag = data.getTag<lp::CachePolicyTag>();
62  if (tag != nullptr) {
63  lp::CachePolicyType policy = tag->get().getPolicy();
64  if (policy == lp::CachePolicyType::NO_CACHE) {
65  return;
66  }
67  }
68 
69  iterator it;
70  bool isNewEntry = false;
71  std::tie(it, isNewEntry) = m_table.emplace(data.shared_from_this(), isUnsolicited);
72  EntryImpl& entry = const_cast<EntryImpl&>(*it);
73 
74  entry.updateStaleTime();
75 
76  if (!isNewEntry) { // existing entry
77  // XXX This doesn't forbid unsolicited Data from refreshing a solicited entry.
78  if (entry.isUnsolicited() && !isUnsolicited) {
79  entry.unsetUnsolicited();
80  }
81 
82  m_policy->afterRefresh(it);
83  }
84  else {
85  m_policy->afterInsert(it);
86  }
87 }
88 
89 void
90 Cs::erase(const Name& prefix, size_t limit, const AfterEraseCallback& cb)
91 {
92  BOOST_ASSERT(static_cast<bool>(cb));
93 
94  iterator first = m_table.lower_bound(prefix);
95  iterator last = m_table.end();
96  if (prefix.size() > 0) {
97  last = m_table.lower_bound(prefix.getSuccessor());
98  }
99 
100  size_t nErased = 0;
101  while (first != last && nErased < limit) {
102  m_policy->beforeErase(first);
103  first = m_table.erase(first);
104  ++nErased;
105  }
106 
107  if (cb) {
108  cb(nErased);
109  }
110 }
111 
112 void
113 Cs::find(const Interest& interest,
114  const HitCallback& hitCallback,
115  const MissCallback& missCallback) const
116 {
117  BOOST_ASSERT(static_cast<bool>(hitCallback));
118  BOOST_ASSERT(static_cast<bool>(missCallback));
119 
120  if (!m_shouldServe || m_policy->getLimit() == 0) {
121  missCallback(interest);
122  return;
123  }
124  const Name& prefix = interest.getName();
125  bool isRightmost = interest.getChildSelector() == 1;
126  NFD_LOG_DEBUG("find " << prefix << (isRightmost ? " R" : " L"));
127 
128  iterator first = m_table.lower_bound(prefix);
129  iterator last = m_table.end();
130  if (prefix.size() > 0) {
131  last = m_table.lower_bound(prefix.getSuccessor());
132  }
133 
134  iterator match = last;
135  if (isRightmost) {
136  match = this->findRightmost(interest, first, last);
137  }
138  else {
139  match = this->findLeftmost(interest, first, last);
140  }
141 
142  if (match == last) {
143  NFD_LOG_DEBUG(" no-match");
144  missCallback(interest);
145  return;
146  }
147  NFD_LOG_DEBUG(" matching " << match->getName());
148  m_policy->beforeUse(match);
149  hitCallback(interest, match->getData());
150 }
151 
152 iterator
153 Cs::findLeftmost(const Interest& interest, iterator first, iterator last) const
154 {
155  return std::find_if(first, last, [&interest] (const auto& entry) { return entry.canSatisfy(interest); });
156 }
157 
158 iterator
159 Cs::findRightmost(const Interest& interest, iterator first, iterator last) const
160 {
161  // Each loop visits a sub-namespace under a prefix one component longer than Interest Name.
162  // If there is a match in that sub-namespace, the leftmost match is returned;
163  // otherwise, loop continues.
164 
165  size_t interestNameLength = interest.getName().size();
166  for (iterator right = last; right != first;) {
167  iterator prev = std::prev(right);
168 
169  // special case: [first,prev] have exact Names
170  if (prev->getName().size() == interestNameLength) {
171  NFD_LOG_TRACE(" find-among-exact " << prev->getName());
172  iterator matchExact = this->findRightmostAmongExact(interest, first, right);
173  return matchExact == right ? last : matchExact;
174  }
175 
176  Name prefix = prev->getName().getPrefix(interestNameLength + 1);
177  iterator left = m_table.lower_bound(prefix);
178 
179  // normal case: [left,right) are under one-component-longer prefix
180  NFD_LOG_TRACE(" find-under-prefix " << prefix);
181  iterator match = this->findLeftmost(interest, left, right);
182  if (match != right) {
183  return match;
184  }
185  right = left;
186  }
187  return last;
188 }
189 
190 iterator
191 Cs::findRightmostAmongExact(const Interest& interest, iterator first, iterator last) const
192 {
193  return find_last_if(first, last, [&interest] (const auto& entry) { return entry.canSatisfy(interest); });
194 }
195 
196 void
197 Cs::dump()
198 {
199  NFD_LOG_DEBUG("dump table");
200  for (const EntryImpl& entry : m_table) {
201  NFD_LOG_TRACE(entry.getFullName());
202  }
203 }
204 
205 void
206 Cs::setPolicy(unique_ptr<Policy> policy)
207 {
208  BOOST_ASSERT(policy != nullptr);
209  BOOST_ASSERT(m_policy != nullptr);
210  size_t limit = m_policy->getLimit();
211  this->setPolicyImpl(std::move(policy));
212  m_policy->setLimit(limit);
213 }
214 
215 void
216 Cs::setPolicyImpl(unique_ptr<Policy> policy)
217 {
218  NFD_LOG_DEBUG("set-policy " << policy->getName());
219  m_policy = std::move(policy);
220  m_beforeEvictConnection = m_policy->beforeEvict.connect([this] (iterator it) {
221  m_table.erase(it);
222  });
223 
224  m_policy->setCs(this);
225  BOOST_ASSERT(m_policy->getCs() == this);
226 }
227 
228 void
230 {
231  if (m_shouldAdmit == shouldAdmit) {
232  return;
233  }
234  m_shouldAdmit = shouldAdmit;
235  NFD_LOG_INFO((shouldAdmit ? "Enabling" : "Disabling") << " Data admittance");
236 }
237 
238 void
240 {
241  if (m_shouldServe == shouldServe) {
242  return;
243  }
244  m_shouldServe = shouldServe;
245  NFD_LOG_INFO((shouldServe ? "Enabling" : "Disabling") << " Data serving");
246 }
247 
248 } // namespace cs
249 } // namespace nfd
void updateStaleTime()
refreshes stale time relative to current time
Definition: cs-entry.cpp:48
It find_last_if(It first, It last, Pred p)
finds the last element satisfying a predicate
Definition: algorithm.hpp:49
static unique_ptr< Policy > makeDefaultPolicy()
Definition: cs.cpp:41
bool shouldServe() const
get CS_ENABLE_SERVE flag
Definition: cs.hpp:143
#define NFD_LOG_TRACE
Definition: logger.hpp:37
void enableAdmit(bool shouldAdmit)
set CS_ENABLE_ADMIT flag
Definition: cs.cpp:229
std::function< void(size_t nErased)> AfterEraseCallback
Definition: cs.hpp:59
static unique_ptr< Policy > create(const std::string &policyName)
Definition: cs-policy.cpp:46
NDN_CXX_ASSERT_FORWARD_ITERATOR(Cs::const_iterator)
Table::const_iterator iterator
Definition: cs-internal.hpp:41
void erase(const Name &prefix, size_t limit, const AfterEraseCallback &cb)
asynchronously erases entries under prefix
Definition: cs.cpp:90
std::function< void(const Interest &)> MissCallback
Definition: cs.hpp:71
Copyright (c) 2014-2015, Regents of the University of California, Arizona Board of Regents...
Definition: algorithm.hpp:32
void insert(const Data &data, bool isUnsolicited=false)
inserts a Data packet
Definition: cs.cpp:53
boost::transform_iterator< EntryFromEntryImpl, iterator, const Entry & > const_iterator
ContentStore iterator (public API)
Definition: cs.hpp:168
void enableServe(bool shouldServe)
set CS_ENABLE_SERVE flag
Definition: cs.cpp:239
void setPolicy(unique_ptr< Policy > policy)
change replacement policy
Definition: cs.cpp:206
an Entry in ContentStore implementation
#define NFD_LOG_INFO
Definition: logger.hpp:39
#define NFD_LOG_DEBUG
Definition: logger.hpp:38
void unsetUnsolicited()
#define NFD_LOG_INIT(name)
Definition: logger.hpp:31
bool isUnsolicited() const
Definition: cs-entry.hpp:73
void find(const Interest &interest, const HitCallback &hitCallback, const MissCallback &missCallback) const
finds the best matching Data packet
Definition: cs.cpp:113
Cs(size_t nMaxPackets=10)
Definition: cs.cpp:46
std::function< void(const Interest &, const Data &)> HitCallback
Definition: cs.hpp:70
bool shouldAdmit() const
get CS_ENABLE_ADMIT flag
Definition: cs.hpp:128