blob: fff84c14fc9d582a4ecd89baf7d663394b08c55d [file] [log] [blame]
Junxiao Shibb5105f2014-03-03 12:06:45 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -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 *
10 * This file is part of NFD (Named Data Networking Forwarding Daemon).
11 * See AUTHORS.md for complete list of NFD authors and contributors.
12 *
13 * NFD is free software: you can redistribute it and/or modify it under the terms
14 * of the GNU General Public License as published by the Free Software Foundation,
15 * either version 3 of the License, or (at your option) any later version.
16 *
17 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
18 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
19 * PURPOSE. See the GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along with
22 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
23 **/
Junxiao Shibb5105f2014-03-03 12:06:45 -070024
25#include "strategy-choice.hpp"
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060026#include "core/logger.hpp"
Junxiao Shibb5105f2014-03-03 12:06:45 -070027#include "fw/strategy.hpp"
28#include "pit-entry.hpp"
Junxiao Shi7bb01512014-03-05 21:34:09 -070029#include "measurements-entry.hpp"
Junxiao Shibb5105f2014-03-03 12:06:45 -070030
31namespace nfd {
32
33using strategy_choice::Entry;
34using fw::Strategy;
35
36NFD_LOG_INIT("StrategyChoice");
37
38StrategyChoice::StrategyChoice(NameTree& nameTree, shared_ptr<Strategy> defaultStrategy)
39 : m_nameTree(nameTree)
40{
41 this->setDefaultStrategy(defaultStrategy);
42}
43
44bool
45StrategyChoice::hasStrategy(const Name& strategyName) const
46{
47 return m_strategyInstances.count(strategyName) > 0;
48}
49
50bool
51StrategyChoice::install(shared_ptr<Strategy> strategy)
52{
53 BOOST_ASSERT(static_cast<bool>(strategy));
54 const Name& strategyName = strategy->getName();
55
56 if (this->hasStrategy(strategyName)) {
57 NFD_LOG_ERROR("install(" << strategyName << ") duplicate strategyName");
58 return false;
59 }
60
61 m_strategyInstances[strategyName] = strategy;
62 return true;
63}
64
65bool
66StrategyChoice::insert(const Name& prefix, const Name& strategyName)
67{
68 shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.lookup(prefix);
69 shared_ptr<Entry> entry = nameTreeEntry->getStrategyChoiceEntry();
70 shared_ptr<Strategy> oldStrategy;
71
72 if (static_cast<bool>(entry)) {
73 if (entry->getStrategy().getName() == strategyName) {
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -070074 NFD_LOG_TRACE("insert(" << prefix << "," << strategyName << ") not changing");
Junxiao Shibb5105f2014-03-03 12:06:45 -070075 return true;
76 }
77 oldStrategy = entry->getStrategy().shared_from_this();
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -070078 NFD_LOG_TRACE("insert(" << prefix << "," << strategyName << ") "
79 "changing from " << oldStrategy->getName());
Junxiao Shibb5105f2014-03-03 12:06:45 -070080 }
81
82 shared_ptr<Strategy> strategy = this->getStrategy(strategyName);
83 if (!static_cast<bool>(strategy)) {
84 NFD_LOG_ERROR("insert(" << prefix << "," << strategyName << ") strategy not installed");
85 return false;
86 }
87
88 if (!static_cast<bool>(entry)) {
89 oldStrategy = this->findEffectiveStrategy(prefix).shared_from_this();
90 entry = make_shared<Entry>(prefix);
91 nameTreeEntry->setStrategyChoiceEntry(entry);
92 ++m_nItems;
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -070093 NFD_LOG_TRACE("insert(" << prefix << "," << strategyName << ") new entry");
Junxiao Shibb5105f2014-03-03 12:06:45 -070094 }
95
96 this->changeStrategy(entry, oldStrategy, strategy);
97 return true;
98}
99
100void
101StrategyChoice::erase(const Name& prefix)
102{
103 BOOST_ASSERT(prefix.size() > 0);
104
105 shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.findExactMatch(prefix);
106 if (!static_cast<bool>(nameTreeEntry)) {
107 return;
108 }
109
110 shared_ptr<Entry> entry = nameTreeEntry->getStrategyChoiceEntry();
111 if (!static_cast<bool>(entry)) {
112 return;
113 }
114
115 Strategy& oldStrategy = entry->getStrategy();
Junxiao Shie349ea12014-03-12 01:32:42 -0700116
117 Strategy& parentStrategy = this->findEffectiveStrategy(prefix.getPrefix(-1));
118 this->changeStrategy(entry, oldStrategy.shared_from_this(), parentStrategy.shared_from_this());
119
Junxiao Shibb5105f2014-03-03 12:06:45 -0700120 nameTreeEntry->setStrategyChoiceEntry(shared_ptr<Entry>());
121 --m_nItems;
Junxiao Shibb5105f2014-03-03 12:06:45 -0700122}
123
124shared_ptr<const Name>
125StrategyChoice::get(const Name& prefix) const
126{
127 shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.findExactMatch(prefix);
128 if (!static_cast<bool>(nameTreeEntry)) {
129 return shared_ptr<const Name>();
130 }
131
132 shared_ptr<Entry> entry = nameTreeEntry->getStrategyChoiceEntry();
133 if (!static_cast<bool>(entry)) {
134 return shared_ptr<const Name>();
135 }
136
137 return entry->getStrategy().getName().shared_from_this();
138}
139
140static inline bool
141predicate_NameTreeEntry_hasStrategyChoiceEntry(const name_tree::Entry& entry)
142{
143 return static_cast<bool>(entry.getStrategyChoiceEntry());
144}
145
146Strategy&
147StrategyChoice::findEffectiveStrategy(const Name& prefix) const
148{
149 shared_ptr<name_tree::Entry> nameTreeEntry =
150 m_nameTree.findLongestPrefixMatch(prefix, &predicate_NameTreeEntry_hasStrategyChoiceEntry);
151 BOOST_ASSERT(static_cast<bool>(nameTreeEntry));
152 return nameTreeEntry->getStrategyChoiceEntry()->getStrategy();
153}
154
155Strategy&
HangZhangcb4fc832014-03-11 16:57:11 +0800156StrategyChoice::findEffectiveStrategy(shared_ptr<name_tree::Entry> nameTreeEntry) const
157{
158 shared_ptr<strategy_choice::Entry> entry = nameTreeEntry->getStrategyChoiceEntry();
159 if (static_cast<bool>(entry))
160 return entry->getStrategy();
Junxiao Shie349ea12014-03-12 01:32:42 -0700161 nameTreeEntry = m_nameTree.findLongestPrefixMatch(nameTreeEntry,
HangZhangcb4fc832014-03-11 16:57:11 +0800162 &predicate_NameTreeEntry_hasStrategyChoiceEntry);
163 BOOST_ASSERT(static_cast<bool>(nameTreeEntry));
164 return nameTreeEntry->getStrategyChoiceEntry()->getStrategy();
165}
166
167Strategy&
Junxiao Shibb5105f2014-03-03 12:06:45 -0700168StrategyChoice::findEffectiveStrategy(const pit::Entry& pitEntry) const
169{
HangZhangcb4fc832014-03-11 16:57:11 +0800170 shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.get(pitEntry);
171
172 BOOST_ASSERT(static_cast<bool>(nameTreeEntry));
173
174 return findEffectiveStrategy(nameTreeEntry);
Junxiao Shibb5105f2014-03-03 12:06:45 -0700175}
176
Junxiao Shi7bb01512014-03-05 21:34:09 -0700177Strategy&
178StrategyChoice::findEffectiveStrategy(const measurements::Entry& measurementsEntry) const
179{
HangZhangcb4fc832014-03-11 16:57:11 +0800180 shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.get(measurementsEntry);
181
182 BOOST_ASSERT(static_cast<bool>(nameTreeEntry));
183
184 return findEffectiveStrategy(nameTreeEntry);
Junxiao Shi7bb01512014-03-05 21:34:09 -0700185}
186
Junxiao Shibb5105f2014-03-03 12:06:45 -0700187shared_ptr<fw::Strategy>
188StrategyChoice::getStrategy(const Name& strategyName)
189{
190 StrategyInstanceTable::iterator it = m_strategyInstances.find(strategyName);
191 return it != m_strategyInstances.end() ? it->second : shared_ptr<fw::Strategy>();
192}
193
194void
195StrategyChoice::setDefaultStrategy(shared_ptr<Strategy> strategy)
196{
197 this->install(strategy);
198
199 // don't use .insert here, because it will invoke findEffectiveStrategy
200 // which expects an existing root entry
201 shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.lookup(Name());
202 shared_ptr<Entry> entry = make_shared<Entry>(Name());
203 nameTreeEntry->setStrategyChoiceEntry(entry);
204 ++m_nItems;
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700205 NFD_LOG_INFO("Set default strategy " << strategy->getName());
Junxiao Shibb5105f2014-03-03 12:06:45 -0700206
207 entry->setStrategy(strategy);
208}
209
Junxiao Shie349ea12014-03-12 01:32:42 -0700210/** \brief a predicate that decides whether StrategyInfo should be reset
211 *
212 * StrategyInfo on a NameTree entry needs to be reset,
213 * if its effective strategy is covered by the changing StrategyChoice entry.
214 */
215static inline std::pair<bool,bool>
216predicate_nameTreeEntry_needResetStrategyChoice(const name_tree::Entry& nameTreeEntry,
217 const name_tree::Entry& rootEntry)
218{
219 if (&nameTreeEntry == &rootEntry) {
220 return std::make_pair(true, true);
221 }
222 if (static_cast<bool>(nameTreeEntry.getStrategyChoiceEntry())) {
223 return std::make_pair(false, false);
224 }
225 return std::make_pair(true, true);
226}
227
228static inline void
229clearStrategyInfo_pitFaceRecord(const pit::FaceRecord& pitFaceRecord)
230{
231 const_cast<pit::FaceRecord&>(pitFaceRecord).clearStrategyInfo();
232}
233
234static inline void
235clearStrategyInfo_pitEntry(shared_ptr<pit::Entry> pitEntry)
236{
237 pitEntry->clearStrategyInfo();
238 std::for_each(pitEntry->getInRecords().begin(), pitEntry->getInRecords().end(),
239 &clearStrategyInfo_pitFaceRecord);
240 std::for_each(pitEntry->getOutRecords().begin(), pitEntry->getOutRecords().end(),
241 &clearStrategyInfo_pitFaceRecord);
242}
243
244static inline void
245clearStrategyInfo(const name_tree::Entry& nameTreeEntry)
246{
247 NFD_LOG_TRACE("clearStrategyInfo " << nameTreeEntry.getPrefix());
248
249 std::for_each(nameTreeEntry.getPitEntries().begin(), nameTreeEntry.getPitEntries().end(),
250 &clearStrategyInfo_pitEntry);
251 if (static_cast<bool>(nameTreeEntry.getMeasurementsEntry())) {
252 nameTreeEntry.getMeasurementsEntry()->clearStrategyInfo();
253 }
254}
255
Junxiao Shibb5105f2014-03-03 12:06:45 -0700256void
257StrategyChoice::changeStrategy(shared_ptr<strategy_choice::Entry> entry,
258 shared_ptr<fw::Strategy> oldStrategy,
259 shared_ptr<fw::Strategy> newStrategy)
260{
261 entry->setStrategy(newStrategy);
262 if (oldStrategy == newStrategy) {
263 return;
264 }
265
Junxiao Shie349ea12014-03-12 01:32:42 -0700266 std::for_each(m_nameTree.partialEnumerate(entry->getPrefix(),
267 bind(&predicate_nameTreeEntry_needResetStrategyChoice,
268 _1, boost::cref(*m_nameTree.get(*entry)))),
269 m_nameTree.end(),
270 &clearStrategyInfo);
Junxiao Shibb5105f2014-03-03 12:06:45 -0700271}
272
273} // namespace nfd