blob: 34c583e951f11164943c7999d6a2304aebe0706a [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/>.
24 **/
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>());
123 --m_nItems;
Junxiao Shibb5105f2014-03-03 12:06:45 -0700124}
125
126shared_ptr<const Name>
127StrategyChoice::get(const Name& prefix) const
128{
129 shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.findExactMatch(prefix);
130 if (!static_cast<bool>(nameTreeEntry)) {
131 return shared_ptr<const Name>();
132 }
133
134 shared_ptr<Entry> entry = nameTreeEntry->getStrategyChoiceEntry();
135 if (!static_cast<bool>(entry)) {
136 return shared_ptr<const Name>();
137 }
138
139 return entry->getStrategy().getName().shared_from_this();
140}
141
142static inline bool
143predicate_NameTreeEntry_hasStrategyChoiceEntry(const name_tree::Entry& entry)
144{
145 return static_cast<bool>(entry.getStrategyChoiceEntry());
146}
147
148Strategy&
149StrategyChoice::findEffectiveStrategy(const Name& prefix) const
150{
151 shared_ptr<name_tree::Entry> nameTreeEntry =
152 m_nameTree.findLongestPrefixMatch(prefix, &predicate_NameTreeEntry_hasStrategyChoiceEntry);
153 BOOST_ASSERT(static_cast<bool>(nameTreeEntry));
154 return nameTreeEntry->getStrategyChoiceEntry()->getStrategy();
155}
156
157Strategy&
HangZhangcb4fc832014-03-11 16:57:11 +0800158StrategyChoice::findEffectiveStrategy(shared_ptr<name_tree::Entry> nameTreeEntry) const
159{
160 shared_ptr<strategy_choice::Entry> entry = nameTreeEntry->getStrategyChoiceEntry();
161 if (static_cast<bool>(entry))
162 return entry->getStrategy();
Junxiao Shie349ea12014-03-12 01:32:42 -0700163 nameTreeEntry = m_nameTree.findLongestPrefixMatch(nameTreeEntry,
HangZhangcb4fc832014-03-11 16:57:11 +0800164 &predicate_NameTreeEntry_hasStrategyChoiceEntry);
165 BOOST_ASSERT(static_cast<bool>(nameTreeEntry));
166 return nameTreeEntry->getStrategyChoiceEntry()->getStrategy();
167}
168
169Strategy&
Junxiao Shibb5105f2014-03-03 12:06:45 -0700170StrategyChoice::findEffectiveStrategy(const pit::Entry& pitEntry) const
171{
HangZhangcb4fc832014-03-11 16:57:11 +0800172 shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.get(pitEntry);
173
174 BOOST_ASSERT(static_cast<bool>(nameTreeEntry));
175
176 return findEffectiveStrategy(nameTreeEntry);
Junxiao Shibb5105f2014-03-03 12:06:45 -0700177}
178
Junxiao Shi7bb01512014-03-05 21:34:09 -0700179Strategy&
180StrategyChoice::findEffectiveStrategy(const measurements::Entry& measurementsEntry) const
181{
HangZhangcb4fc832014-03-11 16:57:11 +0800182 shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.get(measurementsEntry);
183
184 BOOST_ASSERT(static_cast<bool>(nameTreeEntry));
185
186 return findEffectiveStrategy(nameTreeEntry);
Junxiao Shi7bb01512014-03-05 21:34:09 -0700187}
188
Junxiao Shibb5105f2014-03-03 12:06:45 -0700189shared_ptr<fw::Strategy>
190StrategyChoice::getStrategy(const Name& strategyName)
191{
192 StrategyInstanceTable::iterator it = m_strategyInstances.find(strategyName);
193 return it != m_strategyInstances.end() ? it->second : shared_ptr<fw::Strategy>();
194}
195
196void
197StrategyChoice::setDefaultStrategy(shared_ptr<Strategy> strategy)
198{
199 this->install(strategy);
200
201 // don't use .insert here, because it will invoke findEffectiveStrategy
202 // which expects an existing root entry
203 shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.lookup(Name());
204 shared_ptr<Entry> entry = make_shared<Entry>(Name());
205 nameTreeEntry->setStrategyChoiceEntry(entry);
206 ++m_nItems;
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700207 NFD_LOG_INFO("Set default strategy " << strategy->getName());
Junxiao Shibb5105f2014-03-03 12:06:45 -0700208
209 entry->setStrategy(strategy);
210}
211
Junxiao Shie349ea12014-03-12 01:32:42 -0700212/** \brief a predicate that decides whether StrategyInfo should be reset
213 *
214 * StrategyInfo on a NameTree entry needs to be reset,
215 * if its effective strategy is covered by the changing StrategyChoice entry.
216 */
217static inline std::pair<bool,bool>
218predicate_nameTreeEntry_needResetStrategyChoice(const name_tree::Entry& nameTreeEntry,
219 const name_tree::Entry& rootEntry)
220{
221 if (&nameTreeEntry == &rootEntry) {
222 return std::make_pair(true, true);
223 }
224 if (static_cast<bool>(nameTreeEntry.getStrategyChoiceEntry())) {
225 return std::make_pair(false, false);
226 }
227 return std::make_pair(true, true);
228}
229
230static inline void
231clearStrategyInfo_pitFaceRecord(const pit::FaceRecord& pitFaceRecord)
232{
233 const_cast<pit::FaceRecord&>(pitFaceRecord).clearStrategyInfo();
234}
235
236static inline void
237clearStrategyInfo_pitEntry(shared_ptr<pit::Entry> pitEntry)
238{
239 pitEntry->clearStrategyInfo();
240 std::for_each(pitEntry->getInRecords().begin(), pitEntry->getInRecords().end(),
241 &clearStrategyInfo_pitFaceRecord);
242 std::for_each(pitEntry->getOutRecords().begin(), pitEntry->getOutRecords().end(),
243 &clearStrategyInfo_pitFaceRecord);
244}
245
246static inline void
247clearStrategyInfo(const name_tree::Entry& nameTreeEntry)
248{
249 NFD_LOG_TRACE("clearStrategyInfo " << nameTreeEntry.getPrefix());
250
251 std::for_each(nameTreeEntry.getPitEntries().begin(), nameTreeEntry.getPitEntries().end(),
252 &clearStrategyInfo_pitEntry);
253 if (static_cast<bool>(nameTreeEntry.getMeasurementsEntry())) {
254 nameTreeEntry.getMeasurementsEntry()->clearStrategyInfo();
255 }
256}
257
Junxiao Shibb5105f2014-03-03 12:06:45 -0700258void
259StrategyChoice::changeStrategy(shared_ptr<strategy_choice::Entry> entry,
260 shared_ptr<fw::Strategy> oldStrategy,
261 shared_ptr<fw::Strategy> newStrategy)
262{
263 entry->setStrategy(newStrategy);
264 if (oldStrategy == newStrategy) {
265 return;
266 }
267
Junxiao Shie349ea12014-03-12 01:32:42 -0700268 std::for_each(m_nameTree.partialEnumerate(entry->getPrefix(),
269 bind(&predicate_nameTreeEntry_needResetStrategyChoice,
Alexander Afanasyevf6980282014-05-13 18:28:40 -0700270 _1, cref(*m_nameTree.get(*entry)))),
Junxiao Shie349ea12014-03-12 01:32:42 -0700271 m_nameTree.end(),
272 &clearStrategyInfo);
Junxiao Shibb5105f2014-03-03 12:06:45 -0700273}
274
Junxiao Shib5888d22014-05-26 07:35:22 -0700275StrategyChoice::const_iterator
276StrategyChoice::begin() const
277{
278 return const_iterator(m_nameTree.fullEnumerate(&predicate_NameTreeEntry_hasStrategyChoiceEntry));
279}
280
Junxiao Shibb5105f2014-03-03 12:06:45 -0700281} // namespace nfd