blob: aa5db1be6989a4c6b0398b29dfd8865266cd9d90 [file] [log] [blame]
Junxiao Shibb5105f2014-03-03 12:06:45 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Junxiao Shib5888d22014-05-26 07:35:22 -07003 * Copyright (c) 2014, 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
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -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/>.
Junxiao Shiee5a4442014-07-27 17:13:43 -070024 */
Junxiao Shibb5105f2014-03-03 12:06:45 -070025
26#include "strategy-choice.hpp"
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060027#include "core/logger.hpp"
Junxiao Shibb5105f2014-03-03 12:06:45 -070028#include "fw/strategy.hpp"
29#include "pit-entry.hpp"
Junxiao Shi7bb01512014-03-05 21:34:09 -070030#include "measurements-entry.hpp"
Junxiao Shibb5105f2014-03-03 12:06:45 -070031
32namespace nfd {
33
34using strategy_choice::Entry;
35using fw::Strategy;
36
37NFD_LOG_INIT("StrategyChoice");
38
39StrategyChoice::StrategyChoice(NameTree& nameTree, shared_ptr<Strategy> defaultStrategy)
40 : m_nameTree(nameTree)
Junxiao Shib5888d22014-05-26 07:35:22 -070041 , m_nItems(0)
Junxiao Shibb5105f2014-03-03 12:06:45 -070042{
43 this->setDefaultStrategy(defaultStrategy);
44}
45
46bool
47StrategyChoice::hasStrategy(const Name& strategyName) const
48{
49 return m_strategyInstances.count(strategyName) > 0;
50}
51
52bool
53StrategyChoice::install(shared_ptr<Strategy> strategy)
54{
55 BOOST_ASSERT(static_cast<bool>(strategy));
56 const Name& strategyName = strategy->getName();
57
58 if (this->hasStrategy(strategyName)) {
59 NFD_LOG_ERROR("install(" << strategyName << ") duplicate strategyName");
60 return false;
61 }
62
63 m_strategyInstances[strategyName] = strategy;
64 return true;
65}
66
67bool
68StrategyChoice::insert(const Name& prefix, const Name& strategyName)
69{
70 shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.lookup(prefix);
71 shared_ptr<Entry> entry = nameTreeEntry->getStrategyChoiceEntry();
72 shared_ptr<Strategy> oldStrategy;
73
74 if (static_cast<bool>(entry)) {
75 if (entry->getStrategy().getName() == strategyName) {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -070076 NFD_LOG_TRACE("insert(" << prefix << "," << strategyName << ") not changing");
Junxiao Shibb5105f2014-03-03 12:06:45 -070077 return true;
78 }
79 oldStrategy = entry->getStrategy().shared_from_this();
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -070080 NFD_LOG_TRACE("insert(" << prefix << "," << strategyName << ") "
81 "changing from " << oldStrategy->getName());
Junxiao Shibb5105f2014-03-03 12:06:45 -070082 }
83
84 shared_ptr<Strategy> strategy = this->getStrategy(strategyName);
85 if (!static_cast<bool>(strategy)) {
86 NFD_LOG_ERROR("insert(" << prefix << "," << strategyName << ") strategy not installed");
87 return false;
88 }
89
90 if (!static_cast<bool>(entry)) {
91 oldStrategy = this->findEffectiveStrategy(prefix).shared_from_this();
92 entry = make_shared<Entry>(prefix);
93 nameTreeEntry->setStrategyChoiceEntry(entry);
94 ++m_nItems;
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -070095 NFD_LOG_TRACE("insert(" << prefix << "," << strategyName << ") new entry");
Junxiao Shibb5105f2014-03-03 12:06:45 -070096 }
97
98 this->changeStrategy(entry, oldStrategy, strategy);
99 return true;
100}
101
102void
103StrategyChoice::erase(const Name& prefix)
104{
105 BOOST_ASSERT(prefix.size() > 0);
106
107 shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.findExactMatch(prefix);
108 if (!static_cast<bool>(nameTreeEntry)) {
109 return;
110 }
111
112 shared_ptr<Entry> entry = nameTreeEntry->getStrategyChoiceEntry();
113 if (!static_cast<bool>(entry)) {
114 return;
115 }
116
117 Strategy& oldStrategy = entry->getStrategy();
Junxiao Shie349ea12014-03-12 01:32:42 -0700118
119 Strategy& parentStrategy = this->findEffectiveStrategy(prefix.getPrefix(-1));
120 this->changeStrategy(entry, oldStrategy.shared_from_this(), parentStrategy.shared_from_this());
121
Junxiao Shibb5105f2014-03-03 12:06:45 -0700122 nameTreeEntry->setStrategyChoiceEntry(shared_ptr<Entry>());
Junxiao Shiee5a4442014-07-27 17:13:43 -0700123 m_nameTree.eraseEntryIfEmpty(nameTreeEntry);
Junxiao Shibb5105f2014-03-03 12:06:45 -0700124 --m_nItems;
Junxiao Shibb5105f2014-03-03 12:06:45 -0700125}
126
127shared_ptr<const Name>
128StrategyChoice::get(const Name& prefix) const
129{
130 shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.findExactMatch(prefix);
131 if (!static_cast<bool>(nameTreeEntry)) {
132 return shared_ptr<const Name>();
133 }
134
135 shared_ptr<Entry> entry = nameTreeEntry->getStrategyChoiceEntry();
136 if (!static_cast<bool>(entry)) {
137 return shared_ptr<const Name>();
138 }
139
140 return entry->getStrategy().getName().shared_from_this();
141}
142
143static inline bool
144predicate_NameTreeEntry_hasStrategyChoiceEntry(const name_tree::Entry& entry)
145{
146 return static_cast<bool>(entry.getStrategyChoiceEntry());
147}
148
149Strategy&
150StrategyChoice::findEffectiveStrategy(const Name& prefix) const
151{
152 shared_ptr<name_tree::Entry> nameTreeEntry =
153 m_nameTree.findLongestPrefixMatch(prefix, &predicate_NameTreeEntry_hasStrategyChoiceEntry);
154 BOOST_ASSERT(static_cast<bool>(nameTreeEntry));
155 return nameTreeEntry->getStrategyChoiceEntry()->getStrategy();
156}
157
158Strategy&
HangZhangcb4fc832014-03-11 16:57:11 +0800159StrategyChoice::findEffectiveStrategy(shared_ptr<name_tree::Entry> nameTreeEntry) const
160{
161 shared_ptr<strategy_choice::Entry> entry = nameTreeEntry->getStrategyChoiceEntry();
162 if (static_cast<bool>(entry))
163 return entry->getStrategy();
Junxiao Shie349ea12014-03-12 01:32:42 -0700164 nameTreeEntry = m_nameTree.findLongestPrefixMatch(nameTreeEntry,
HangZhangcb4fc832014-03-11 16:57:11 +0800165 &predicate_NameTreeEntry_hasStrategyChoiceEntry);
166 BOOST_ASSERT(static_cast<bool>(nameTreeEntry));
167 return nameTreeEntry->getStrategyChoiceEntry()->getStrategy();
168}
169
170Strategy&
Junxiao Shibb5105f2014-03-03 12:06:45 -0700171StrategyChoice::findEffectiveStrategy(const pit::Entry& pitEntry) const
172{
HangZhangcb4fc832014-03-11 16:57:11 +0800173 shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.get(pitEntry);
174
175 BOOST_ASSERT(static_cast<bool>(nameTreeEntry));
176
177 return findEffectiveStrategy(nameTreeEntry);
Junxiao Shibb5105f2014-03-03 12:06:45 -0700178}
179
Junxiao Shi7bb01512014-03-05 21:34:09 -0700180Strategy&
181StrategyChoice::findEffectiveStrategy(const measurements::Entry& measurementsEntry) const
182{
HangZhangcb4fc832014-03-11 16:57:11 +0800183 shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.get(measurementsEntry);
184
185 BOOST_ASSERT(static_cast<bool>(nameTreeEntry));
186
187 return findEffectiveStrategy(nameTreeEntry);
Junxiao Shi7bb01512014-03-05 21:34:09 -0700188}
189
Junxiao Shibb5105f2014-03-03 12:06:45 -0700190shared_ptr<fw::Strategy>
191StrategyChoice::getStrategy(const Name& strategyName)
192{
193 StrategyInstanceTable::iterator it = m_strategyInstances.find(strategyName);
194 return it != m_strategyInstances.end() ? it->second : shared_ptr<fw::Strategy>();
195}
196
197void
198StrategyChoice::setDefaultStrategy(shared_ptr<Strategy> strategy)
199{
200 this->install(strategy);
201
202 // don't use .insert here, because it will invoke findEffectiveStrategy
203 // which expects an existing root entry
204 shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.lookup(Name());
205 shared_ptr<Entry> entry = make_shared<Entry>(Name());
206 nameTreeEntry->setStrategyChoiceEntry(entry);
207 ++m_nItems;
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700208 NFD_LOG_INFO("Set default strategy " << strategy->getName());
Junxiao Shibb5105f2014-03-03 12:06:45 -0700209
210 entry->setStrategy(strategy);
211}
212
Junxiao Shie349ea12014-03-12 01:32:42 -0700213/** \brief a predicate that decides whether StrategyInfo should be reset
214 *
215 * StrategyInfo on a NameTree entry needs to be reset,
216 * if its effective strategy is covered by the changing StrategyChoice entry.
217 */
218static inline std::pair<bool,bool>
219predicate_nameTreeEntry_needResetStrategyChoice(const name_tree::Entry& nameTreeEntry,
220 const name_tree::Entry& rootEntry)
221{
222 if (&nameTreeEntry == &rootEntry) {
223 return std::make_pair(true, true);
224 }
225 if (static_cast<bool>(nameTreeEntry.getStrategyChoiceEntry())) {
226 return std::make_pair(false, false);
227 }
228 return std::make_pair(true, true);
229}
230
231static inline void
232clearStrategyInfo_pitFaceRecord(const pit::FaceRecord& pitFaceRecord)
233{
234 const_cast<pit::FaceRecord&>(pitFaceRecord).clearStrategyInfo();
235}
236
237static inline void
238clearStrategyInfo_pitEntry(shared_ptr<pit::Entry> pitEntry)
239{
240 pitEntry->clearStrategyInfo();
241 std::for_each(pitEntry->getInRecords().begin(), pitEntry->getInRecords().end(),
242 &clearStrategyInfo_pitFaceRecord);
243 std::for_each(pitEntry->getOutRecords().begin(), pitEntry->getOutRecords().end(),
244 &clearStrategyInfo_pitFaceRecord);
245}
246
247static inline void
248clearStrategyInfo(const name_tree::Entry& nameTreeEntry)
249{
250 NFD_LOG_TRACE("clearStrategyInfo " << nameTreeEntry.getPrefix());
251
252 std::for_each(nameTreeEntry.getPitEntries().begin(), nameTreeEntry.getPitEntries().end(),
253 &clearStrategyInfo_pitEntry);
254 if (static_cast<bool>(nameTreeEntry.getMeasurementsEntry())) {
255 nameTreeEntry.getMeasurementsEntry()->clearStrategyInfo();
256 }
257}
258
Junxiao Shibb5105f2014-03-03 12:06:45 -0700259void
260StrategyChoice::changeStrategy(shared_ptr<strategy_choice::Entry> entry,
261 shared_ptr<fw::Strategy> oldStrategy,
262 shared_ptr<fw::Strategy> newStrategy)
263{
264 entry->setStrategy(newStrategy);
265 if (oldStrategy == newStrategy) {
266 return;
267 }
268
Junxiao Shie349ea12014-03-12 01:32:42 -0700269 std::for_each(m_nameTree.partialEnumerate(entry->getPrefix(),
270 bind(&predicate_nameTreeEntry_needResetStrategyChoice,
Alexander Afanasyevf6980282014-05-13 18:28:40 -0700271 _1, cref(*m_nameTree.get(*entry)))),
Junxiao Shie349ea12014-03-12 01:32:42 -0700272 m_nameTree.end(),
273 &clearStrategyInfo);
Junxiao Shibb5105f2014-03-03 12:06:45 -0700274}
275
Junxiao Shib5888d22014-05-26 07:35:22 -0700276StrategyChoice::const_iterator
277StrategyChoice::begin() const
278{
279 return const_iterator(m_nameTree.fullEnumerate(&predicate_NameTreeEntry_hasStrategyChoiceEntry));
280}
281
Junxiao Shibb5105f2014-03-03 12:06:45 -0700282} // namespace nfd