/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /** * Copyright (C) 2014 Named Data Networking Project * See COPYING for copyright and distribution information. */ #include "strategy-choice.hpp" #include "core/logger.hpp" #include "fw/strategy.hpp" #include "pit-entry.hpp" #include "measurements-entry.hpp" namespace nfd { using strategy_choice::Entry; using fw::Strategy; NFD_LOG_INIT("StrategyChoice"); StrategyChoice::StrategyChoice(NameTree& nameTree, shared_ptr defaultStrategy) : m_nameTree(nameTree) { this->setDefaultStrategy(defaultStrategy); } bool StrategyChoice::hasStrategy(const Name& strategyName) const { return m_strategyInstances.count(strategyName) > 0; } bool StrategyChoice::install(shared_ptr strategy) { BOOST_ASSERT(static_cast(strategy)); const Name& strategyName = strategy->getName(); if (this->hasStrategy(strategyName)) { NFD_LOG_ERROR("install(" << strategyName << ") duplicate strategyName"); return false; } m_strategyInstances[strategyName] = strategy; return true; } bool StrategyChoice::insert(const Name& prefix, const Name& strategyName) { shared_ptr nameTreeEntry = m_nameTree.lookup(prefix); shared_ptr entry = nameTreeEntry->getStrategyChoiceEntry(); shared_ptr oldStrategy; if (static_cast(entry)) { if (entry->getStrategy().getName() == strategyName) { NFD_LOG_TRACE("insert(" << prefix << "," << strategyName << ") not changing"); return true; } oldStrategy = entry->getStrategy().shared_from_this(); NFD_LOG_TRACE("insert(" << prefix << "," << strategyName << ") " "changing from " << oldStrategy->getName()); } shared_ptr strategy = this->getStrategy(strategyName); if (!static_cast(strategy)) { NFD_LOG_ERROR("insert(" << prefix << "," << strategyName << ") strategy not installed"); return false; } if (!static_cast(entry)) { oldStrategy = this->findEffectiveStrategy(prefix).shared_from_this(); entry = make_shared(prefix); nameTreeEntry->setStrategyChoiceEntry(entry); ++m_nItems; NFD_LOG_TRACE("insert(" << prefix << "," << strategyName << ") new entry"); } this->changeStrategy(entry, oldStrategy, strategy); return true; } void StrategyChoice::erase(const Name& prefix) { BOOST_ASSERT(prefix.size() > 0); shared_ptr nameTreeEntry = m_nameTree.findExactMatch(prefix); if (!static_cast(nameTreeEntry)) { return; } shared_ptr entry = nameTreeEntry->getStrategyChoiceEntry(); if (!static_cast(entry)) { return; } Strategy& oldStrategy = entry->getStrategy(); Strategy& parentStrategy = this->findEffectiveStrategy(prefix.getPrefix(-1)); this->changeStrategy(entry, oldStrategy.shared_from_this(), parentStrategy.shared_from_this()); nameTreeEntry->setStrategyChoiceEntry(shared_ptr()); --m_nItems; } shared_ptr StrategyChoice::get(const Name& prefix) const { shared_ptr nameTreeEntry = m_nameTree.findExactMatch(prefix); if (!static_cast(nameTreeEntry)) { return shared_ptr(); } shared_ptr entry = nameTreeEntry->getStrategyChoiceEntry(); if (!static_cast(entry)) { return shared_ptr(); } return entry->getStrategy().getName().shared_from_this(); } static inline bool predicate_NameTreeEntry_hasStrategyChoiceEntry(const name_tree::Entry& entry) { return static_cast(entry.getStrategyChoiceEntry()); } Strategy& StrategyChoice::findEffectiveStrategy(const Name& prefix) const { shared_ptr nameTreeEntry = m_nameTree.findLongestPrefixMatch(prefix, &predicate_NameTreeEntry_hasStrategyChoiceEntry); BOOST_ASSERT(static_cast(nameTreeEntry)); return nameTreeEntry->getStrategyChoiceEntry()->getStrategy(); } Strategy& StrategyChoice::findEffectiveStrategy(shared_ptr nameTreeEntry) const { shared_ptr entry = nameTreeEntry->getStrategyChoiceEntry(); if (static_cast(entry)) return entry->getStrategy(); nameTreeEntry = m_nameTree.findLongestPrefixMatch(nameTreeEntry, &predicate_NameTreeEntry_hasStrategyChoiceEntry); BOOST_ASSERT(static_cast(nameTreeEntry)); return nameTreeEntry->getStrategyChoiceEntry()->getStrategy(); } Strategy& StrategyChoice::findEffectiveStrategy(const pit::Entry& pitEntry) const { shared_ptr nameTreeEntry = m_nameTree.get(pitEntry); BOOST_ASSERT(static_cast(nameTreeEntry)); return findEffectiveStrategy(nameTreeEntry); } Strategy& StrategyChoice::findEffectiveStrategy(const measurements::Entry& measurementsEntry) const { shared_ptr nameTreeEntry = m_nameTree.get(measurementsEntry); BOOST_ASSERT(static_cast(nameTreeEntry)); return findEffectiveStrategy(nameTreeEntry); } shared_ptr StrategyChoice::getStrategy(const Name& strategyName) { StrategyInstanceTable::iterator it = m_strategyInstances.find(strategyName); return it != m_strategyInstances.end() ? it->second : shared_ptr(); } void StrategyChoice::setDefaultStrategy(shared_ptr strategy) { this->install(strategy); // don't use .insert here, because it will invoke findEffectiveStrategy // which expects an existing root entry shared_ptr nameTreeEntry = m_nameTree.lookup(Name()); shared_ptr entry = make_shared(Name()); nameTreeEntry->setStrategyChoiceEntry(entry); ++m_nItems; NFD_LOG_INFO("Set default strategy " << strategy->getName()); entry->setStrategy(strategy); } /** \brief a predicate that decides whether StrategyInfo should be reset * * StrategyInfo on a NameTree entry needs to be reset, * if its effective strategy is covered by the changing StrategyChoice entry. */ static inline std::pair predicate_nameTreeEntry_needResetStrategyChoice(const name_tree::Entry& nameTreeEntry, const name_tree::Entry& rootEntry) { if (&nameTreeEntry == &rootEntry) { return std::make_pair(true, true); } if (static_cast(nameTreeEntry.getStrategyChoiceEntry())) { return std::make_pair(false, false); } return std::make_pair(true, true); } static inline void clearStrategyInfo_pitFaceRecord(const pit::FaceRecord& pitFaceRecord) { const_cast(pitFaceRecord).clearStrategyInfo(); } static inline void clearStrategyInfo_pitEntry(shared_ptr pitEntry) { pitEntry->clearStrategyInfo(); std::for_each(pitEntry->getInRecords().begin(), pitEntry->getInRecords().end(), &clearStrategyInfo_pitFaceRecord); std::for_each(pitEntry->getOutRecords().begin(), pitEntry->getOutRecords().end(), &clearStrategyInfo_pitFaceRecord); } static inline void clearStrategyInfo(const name_tree::Entry& nameTreeEntry) { NFD_LOG_TRACE("clearStrategyInfo " << nameTreeEntry.getPrefix()); std::for_each(nameTreeEntry.getPitEntries().begin(), nameTreeEntry.getPitEntries().end(), &clearStrategyInfo_pitEntry); if (static_cast(nameTreeEntry.getMeasurementsEntry())) { nameTreeEntry.getMeasurementsEntry()->clearStrategyInfo(); } } void StrategyChoice::changeStrategy(shared_ptr entry, shared_ptr oldStrategy, shared_ptr newStrategy) { entry->setStrategy(newStrategy); if (oldStrategy == newStrategy) { return; } std::for_each(m_nameTree.partialEnumerate(entry->getPrefix(), bind(&predicate_nameTreeEntry_needResetStrategyChoice, _1, boost::cref(*m_nameTree.get(*entry)))), m_nameTree.end(), &clearStrategyInfo); } } // namespace nfd