fw: refactor Strategy registry
Strategy registry is moved into Strategy class.
Strategy instantiation logic is implemented in Strategy::create.
These are in preparation of supporting Strategy parameters.
refs #3868
Change-Id: If36a08ad25a00a7008a5eccc8cfe4f6c63638676
diff --git a/daemon/fw/forwarder.cpp b/daemon/fw/forwarder.cpp
index 7e0df65..7482cf4 100644
--- a/daemon/fw/forwarder.cpp
+++ b/daemon/fw/forwarder.cpp
@@ -25,8 +25,9 @@
#include "forwarder.hpp"
#include "algorithm.hpp"
-#include "core/logger.hpp"
+#include "best-route-strategy2.hpp"
#include "strategy.hpp"
+#include "core/logger.hpp"
#include "table/cleanup.hpp"
#include <ndn-cxx/lp/tags.hpp>
@@ -34,15 +35,19 @@
NFD_LOG_INIT("Forwarder");
+static Name
+getDefaultStrategyName()
+{
+ return fw::BestRouteStrategy2::STRATEGY_NAME;
+}
+
Forwarder::Forwarder()
: m_unsolicitedDataPolicy(new fw::DefaultUnsolicitedDataPolicy())
, m_fib(m_nameTree)
, m_pit(m_nameTree)
, m_measurements(m_nameTree)
- , m_strategyChoice(m_nameTree, fw::makeDefaultStrategy(*this))
+ , m_strategyChoice(*this)
{
- fw::installStrategies(*this);
-
m_faceTable.afterAdd.connect([this] (Face& face) {
face.afterReceiveInterest.connect(
[this, &face] (const Interest& interest) {
@@ -61,6 +66,9 @@
m_faceTable.beforeRemove.connect([this] (Face& face) {
cleanupOnFaceRemoval(m_nameTree, m_fib, m_pit, face);
});
+
+ m_strategyChoice.setDefaultStrategy(getDefaultStrategyName());
+ m_strategyChoice.installFromRegistry();
}
Forwarder::~Forwarder() = default;
diff --git a/daemon/fw/strategy-registry.cpp b/daemon/fw/strategy-registry.cpp
deleted file mode 100644
index 49a778f..0000000
--- a/daemon/fw/strategy-registry.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2016, Regents of the University of California,
- * Arizona Board of Regents,
- * Colorado State University,
- * University Pierre & Marie Curie, Sorbonne University,
- * Washington University in St. Louis,
- * Beijing Institute of Technology,
- * The University of Memphis.
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon).
- * See AUTHORS.md for complete list of NFD authors and contributors.
- *
- * NFD is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "strategy-registry.hpp"
-#include "best-route-strategy2.hpp"
-
-namespace nfd {
-namespace fw {
-
-unique_ptr<Strategy>
-makeDefaultStrategy(Forwarder& forwarder)
-{
- return make_unique<BestRouteStrategy2>(ref(forwarder));
-}
-
-static std::map<Name, StrategyCreateFunc>&
-getStrategyFactories()
-{
- static std::map<Name, StrategyCreateFunc> strategyFactories;
- return strategyFactories;
-}
-
-void
-registerStrategyImpl(const Name& strategyName, const StrategyCreateFunc& createFunc)
-{
- getStrategyFactories().insert({strategyName, createFunc});
-}
-
-void
-installStrategies(Forwarder& forwarder)
-{
- StrategyChoice& sc = forwarder.getStrategyChoice();
- for (const auto& pair : getStrategyFactories()) {
- if (!sc.hasStrategy(pair.first, true)) {
- sc.install(pair.second(forwarder));
- }
- }
-}
-
-} // namespace fw
-} // namespace nfd
diff --git a/daemon/fw/strategy-registry.hpp b/daemon/fw/strategy-registry.hpp
deleted file mode 100644
index 83e9f73..0000000
--- a/daemon/fw/strategy-registry.hpp
+++ /dev/null
@@ -1,78 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2016, Regents of the University of California,
- * Arizona Board of Regents,
- * Colorado State University,
- * University Pierre & Marie Curie, Sorbonne University,
- * Washington University in St. Louis,
- * Beijing Institute of Technology,
- * The University of Memphis.
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon).
- * See AUTHORS.md for complete list of NFD authors and contributors.
- *
- * NFD is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef NFD_DAEMON_FW_STRATEGY_REGISTRY_HPP
-#define NFD_DAEMON_FW_STRATEGY_REGISTRY_HPP
-
-#include "core/common.hpp"
-
-namespace nfd {
-
-class Forwarder;
-
-namespace fw {
-
-class Strategy;
-
-unique_ptr<Strategy>
-makeDefaultStrategy(Forwarder& forwarder);
-
-void
-installStrategies(Forwarder& forwarder);
-
-
-typedef std::function<unique_ptr<Strategy>(Forwarder&)> StrategyCreateFunc;
-
-void
-registerStrategyImpl(const Name& strategyName, const StrategyCreateFunc& createFunc);
-
-/** \brief registers a strategy to be installed later
- */
-template<typename S>
-void
-registerStrategy()
-{
- registerStrategyImpl(S::STRATEGY_NAME,
- [] (Forwarder& forwarder) { return make_unique<S>(ref(forwarder)); });
-}
-
-/** \brief registers a built-in strategy
- *
- * This macro should appear once in .cpp of each built-in strategy.
- */
-#define NFD_REGISTER_STRATEGY(StrategyType) \
-static class NfdAuto ## StrategyType ## StrategyRegistrationClass \
-{ \
-public: \
- NfdAuto ## StrategyType ## StrategyRegistrationClass() \
- { \
- ::nfd::fw::registerStrategy<StrategyType>(); \
- } \
-} g_nfdAuto ## StrategyType ## StrategyRegistrationVariable
-
-} // namespace fw
-} // namespace nfd
-
-#endif // NFD_DAEMON_FW_STRATEGY_REGISTRY_HPP
diff --git a/daemon/fw/strategy.cpp b/daemon/fw/strategy.cpp
index 218ce44..ae8a17c 100644
--- a/daemon/fw/strategy.cpp
+++ b/daemon/fw/strategy.cpp
@@ -27,12 +27,70 @@
#include "forwarder.hpp"
#include "core/logger.hpp"
#include "core/random.hpp"
+#include <boost/range/adaptor/map.hpp>
+#include <boost/range/algorithm/copy.hpp>
namespace nfd {
namespace fw {
NFD_LOG_INIT("Strategy");
+Strategy::Registry&
+Strategy::getRegistry()
+{
+ static Registry registry;
+ return registry;
+}
+
+Strategy::Registry::const_iterator
+Strategy::find(const Name& strategyName)
+{
+ const Registry& registry = getRegistry();
+ Registry::const_iterator candidate = registry.end();
+ for (auto it = registry.lower_bound(strategyName);
+ it != registry.end() && strategyName.isPrefixOf(it->first); ++it) {
+ switch (it->first.size() - strategyName.size()) {
+ case 0: // exact match
+ return it;
+ case 1: // unversioned strategyName matches versioned strategy
+ candidate = it;
+ break;
+ }
+ }
+ return candidate;
+ ///\todo #3868 if exact version unavailable, choose closest higher version
+ ///\todo #3868 allow parameter component
+}
+
+bool
+Strategy::canCreate(const Name& strategyName)
+{
+ return Strategy::find(strategyName) != getRegistry().end();
+}
+
+unique_ptr<Strategy>
+Strategy::create(const Name& strategyName, Forwarder& forwarder)
+{
+ auto found = Strategy::find(strategyName);
+ if (found == getRegistry().end()) {
+ NFD_LOG_DEBUG("create " << strategyName << " not-found");
+ return nullptr;
+ }
+
+ NFD_LOG_DEBUG("create " << strategyName << " found=" << found->first);
+ ///\todo #3868 pass parameters to strategy constructor
+ return found->second(forwarder, found->first);
+}
+
+std::set<Name>
+Strategy::listRegistered()
+{
+ std::set<Name> strategyNames;
+ boost::copy(getRegistry() | boost::adaptors::map_keys,
+ std::inserter(strategyNames, strategyNames.end()));
+ return strategyNames;
+}
+
Strategy::Strategy(Forwarder& forwarder, const Name& name)
: afterAddFace(forwarder.getFaceTable().afterAdd)
, beforeRemoveFace(forwarder.getFaceTable().beforeRemove)
diff --git a/daemon/fw/strategy.hpp b/daemon/fw/strategy.hpp
index f4ef3b1..0bc8d9e 100644
--- a/daemon/fw/strategy.hpp
+++ b/daemon/fw/strategy.hpp
@@ -27,7 +27,6 @@
#define NFD_DAEMON_FW_STRATEGY_HPP
#include "forwarder.hpp"
-#include "strategy-registry.hpp"
#include "table/measurements-accessor.hpp"
namespace nfd {
@@ -35,9 +34,47 @@
/** \brief represents a forwarding strategy
*/
-class Strategy : public enable_shared_from_this<Strategy>, noncopyable
+class Strategy : noncopyable
{
-public:
+public: // registry
+ /** \brief register a strategy type
+ * \tparam S subclass of Strategy
+ * \param strategyName versioned strategy name
+ * \note It is permitted to register the same strategy type under multiple names,
+ * which is useful in tests and for creating aliases.
+ */
+ template<typename S>
+ static void
+ registerType(const Name& strategyName = S::STRATEGY_NAME)
+ {
+ Registry& registry = getRegistry();
+ BOOST_ASSERT(registry.count(strategyName) == 0);
+ registry[strategyName] = &make_unique<S, Forwarder&, const Name&>;
+ }
+
+ /** \return whether a strategy instance can be created from \p strategyName
+ * \param strategyName strategy name, may contain version
+ * \todo #3868 may contain parameters
+ * \note This function finds a strategy type using same rules as \p create ,
+ * but does not attempt to construct an instance.
+ */
+ static bool
+ canCreate(const Name& strategyName);
+
+ /** \return a strategy instance created from \p strategyName,
+ * \retval nullptr if !canCreate(strategyName)
+ * \todo #3868 throw std::invalid_argument strategy type constructor
+ * does not accept specified version or parameters
+ */
+ static unique_ptr<Strategy>
+ create(const Name& strategyName, Forwarder& forwarder);
+
+ /** \return registered versioned strategy names
+ */
+ static std::set<Name>
+ listRegistered();
+
+public: // constructor, destructor, strategy name
/** \brief construct a strategy instance
* \param forwarder a reference to the Forwarder, used to enable actions and accessors.
* Strategy subclasses should pass this reference,
@@ -205,7 +242,17 @@
signal::Signal<FaceTable, Face&>& afterAddFace;
signal::Signal<FaceTable, Face&>& beforeRemoveFace;
-private:
+private: // registry
+ typedef std::function<unique_ptr<Strategy>(Forwarder& forwarder, const Name& strategyName)> CreateFunc;
+ typedef std::map<Name, CreateFunc> Registry; // indexed by strategy name
+
+ static Registry&
+ getRegistry();
+
+ static Registry::const_iterator
+ find(const Name& strategyName);
+
+private: // instance fields
Name m_name;
/** \brief reference to the forwarder
@@ -220,4 +267,18 @@
} // namespace fw
} // namespace nfd
+/** \brief registers a strategy
+ *
+ * This macro should appear once in .cpp of each strategy.
+ */
+#define NFD_REGISTER_STRATEGY(S) \
+static class NfdAuto ## S ## StrategyRegistrationClass \
+{ \
+public: \
+ NfdAuto ## S ## StrategyRegistrationClass() \
+ { \
+ ::nfd::fw::Strategy::registerType<S>(); \
+ } \
+} g_nfdAuto ## S ## StrategyRegistrationVariable
+
#endif // NFD_DAEMON_FW_STRATEGY_HPP