fw: pass parameters to Strategy subclass constructors
refs #3868
Change-Id: I1a09e7353c047d548065c4ed669d1f7993676428
diff --git a/daemon/fw/access-strategy.cpp b/daemon/fw/access-strategy.cpp
index df92d1b..3705037 100644
--- a/daemon/fw/access-strategy.cpp
+++ b/daemon/fw/access-strategy.cpp
@@ -34,10 +34,15 @@
NFD_REGISTER_STRATEGY(AccessStrategy);
AccessStrategy::AccessStrategy(Forwarder& forwarder, const Name& name)
- : Strategy(forwarder, name)
+ : Strategy(forwarder)
, m_removeFaceInfoConn(this->beforeRemoveFace.connect(
bind(&AccessStrategy::removeFaceInfo, this, _1)))
{
+ ParsedInstanceName parsed = parseInstanceName(name);
+ if (!parsed.parameters.empty()) {
+ BOOST_THROW_EXCEPTION(std::invalid_argument("AccessStrategy does not accept parameters"));
+ }
+ this->setInstanceName(makeInstanceName(name, getStrategyName()));
}
const Name&
diff --git a/daemon/fw/asf-strategy.cpp b/daemon/fw/asf-strategy.cpp
index cb2bca3..076a3bb 100644
--- a/daemon/fw/asf-strategy.cpp
+++ b/daemon/fw/asf-strategy.cpp
@@ -39,13 +39,18 @@
const time::milliseconds AsfStrategy::RETX_SUPPRESSION_MAX(250);
AsfStrategy::AsfStrategy(Forwarder& forwarder, const Name& name)
- : Strategy(forwarder, name)
+ : Strategy(forwarder)
, m_measurements(getMeasurements())
, m_probing(m_measurements)
, m_retxSuppression(RETX_SUPPRESSION_INITIAL,
RetxSuppressionExponential::DEFAULT_MULTIPLIER,
RETX_SUPPRESSION_MAX)
{
+ ParsedInstanceName parsed = parseInstanceName(name);
+ if (!parsed.parameters.empty()) {
+ BOOST_THROW_EXCEPTION(std::invalid_argument("AsfStrategy does not accept parameters"));
+ }
+ this->setInstanceName(makeInstanceName(name, getStrategyName()));
}
const Name&
diff --git a/daemon/fw/best-route-strategy.cpp b/daemon/fw/best-route-strategy.cpp
index b58ed88..ad70ab6 100644
--- a/daemon/fw/best-route-strategy.cpp
+++ b/daemon/fw/best-route-strategy.cpp
@@ -29,23 +29,14 @@
namespace nfd {
namespace fw {
-NFD_REGISTER_STRATEGY(BestRouteStrategy);
-
-BestRouteStrategy::BestRouteStrategy(Forwarder& forwarder, const Name& name)
- : Strategy(forwarder, name)
+BestRouteStrategyBase::BestRouteStrategyBase(Forwarder& forwarder)
+ : Strategy(forwarder)
{
}
-const Name&
-BestRouteStrategy::getStrategyName()
-{
- static Name strategyName("/localhost/nfd/strategy/best-route/%FD%01");
- return strategyName;
-}
-
void
-BestRouteStrategy::afterReceiveInterest(const Face& inFace, const Interest& interest,
- const shared_ptr<pit::Entry>& pitEntry)
+BestRouteStrategyBase::afterReceiveInterest(const Face& inFace, const Interest& interest,
+ const shared_ptr<pit::Entry>& pitEntry)
{
if (hasPendingOutRecords(*pitEntry)) {
// not a new Interest, don't forward
@@ -67,5 +58,24 @@
this->rejectPendingInterest(pitEntry);
}
+NFD_REGISTER_STRATEGY(BestRouteStrategy);
+
+BestRouteStrategy::BestRouteStrategy(Forwarder& forwarder, const Name& name)
+ : BestRouteStrategyBase(forwarder)
+{
+ ParsedInstanceName parsed = parseInstanceName(name);
+ if (!parsed.parameters.empty()) {
+ BOOST_THROW_EXCEPTION(std::invalid_argument("BestRouteStrategy does not accept parameters"));
+ }
+ this->setInstanceName(makeInstanceName(name, getStrategyName()));
+}
+
+const Name&
+BestRouteStrategy::getStrategyName()
+{
+ static Name strategyName("/localhost/nfd/strategy/best-route/%FD%01");
+ return strategyName;
+}
+
} // namespace fw
} // namespace nfd
diff --git a/daemon/fw/best-route-strategy.hpp b/daemon/fw/best-route-strategy.hpp
index 70d975d..3cef907 100644
--- a/daemon/fw/best-route-strategy.hpp
+++ b/daemon/fw/best-route-strategy.hpp
@@ -31,6 +31,17 @@
namespace nfd {
namespace fw {
+class BestRouteStrategyBase : public Strategy
+{
+public:
+ void
+ afterReceiveInterest(const Face& inFace, const Interest& interest,
+ const shared_ptr<pit::Entry>& pitEntry) override;
+
+protected:
+ BestRouteStrategyBase(Forwarder& forwarder);
+};
+
/** \brief Best Route strategy version 1
*
* This strategy forwards a new Interest to the lowest-cost nexthop
@@ -38,11 +49,11 @@
* Subsequent similar Interests or consumer retransmissions are suppressed
* until after InterestLifetime expiry.
*
- * \deprecated This strategy is superceded by Best Route strategy version 2,
- * which allows consumer retransmissions. This version is kept for
- * comparison purposes and is not recommended for general usage.
+ * \note This strategy is superceded by Best Route strategy version 2,
+ * which allows consumer retransmissions. This version is kept for
+ * comparison purposes and is not recommended for general usage.
*/
-class BestRouteStrategy : public Strategy
+class BestRouteStrategy : public BestRouteStrategyBase
{
public:
explicit
@@ -50,10 +61,6 @@
static const Name&
getStrategyName();
-
- virtual void
- afterReceiveInterest(const Face& inFace, const Interest& interest,
- const shared_ptr<pit::Entry>& pitEntry) override;
};
} // namespace fw
diff --git a/daemon/fw/best-route-strategy2.cpp b/daemon/fw/best-route-strategy2.cpp
index 9b53b4b..0ba94e8 100644
--- a/daemon/fw/best-route-strategy2.cpp
+++ b/daemon/fw/best-route-strategy2.cpp
@@ -37,11 +37,16 @@
const time::milliseconds BestRouteStrategy2::RETX_SUPPRESSION_MAX(250);
BestRouteStrategy2::BestRouteStrategy2(Forwarder& forwarder, const Name& name)
- : Strategy(forwarder, name)
+ : Strategy(forwarder)
, m_retxSuppression(RETX_SUPPRESSION_INITIAL,
RetxSuppressionExponential::DEFAULT_MULTIPLIER,
RETX_SUPPRESSION_MAX)
{
+ ParsedInstanceName parsed = parseInstanceName(name);
+ if (!parsed.parameters.empty()) {
+ BOOST_THROW_EXCEPTION(std::invalid_argument("BestRouteStrategy2 does not accept parameters"));
+ }
+ this->setInstanceName(makeInstanceName(name, getStrategyName()));
}
const Name&
diff --git a/daemon/fw/client-control-strategy.cpp b/daemon/fw/client-control-strategy.cpp
index edb98cd..8c99db2 100644
--- a/daemon/fw/client-control-strategy.cpp
+++ b/daemon/fw/client-control-strategy.cpp
@@ -33,8 +33,16 @@
NFD_REGISTER_STRATEGY(ClientControlStrategy);
ClientControlStrategy::ClientControlStrategy(Forwarder& forwarder, const Name& name)
- : BestRouteStrategy(forwarder, name)
+ : BestRouteStrategyBase(forwarder)
{
+ ParsedInstanceName parsed = parseInstanceName(name);
+ if (!parsed.parameters.empty()) {
+ BOOST_THROW_EXCEPTION(std::invalid_argument("ClientControlStrategy does not accept parameters"));
+ }
+ this->setInstanceName(makeInstanceName(name, getStrategyName()));
+
+ NFD_LOG_WARN("NextHopFaceId field is honored universally and "
+ "it's unnecessary to set client-control strategy.");
}
const Name&
@@ -44,18 +52,5 @@
return strategyName;
}
-void
-ClientControlStrategy::afterReceiveInterest(const Face& inFace, const Interest& interest,
- const shared_ptr<pit::Entry>& pitEntry)
-{
- if (m_isFirstUse) {
- NFD_LOG_WARN("NextHopFaceId field is honored universally and "
- "it's unnecessary to set client-control strategy.");
- m_isFirstUse = false;
- }
-
- this->BestRouteStrategy::afterReceiveInterest(inFace, interest, pitEntry);
-}
-
} // namespace fw
} // namespace nfd
diff --git a/daemon/fw/client-control-strategy.hpp b/daemon/fw/client-control-strategy.hpp
index e18f15b..8d627dd 100644
--- a/daemon/fw/client-control-strategy.hpp
+++ b/daemon/fw/client-control-strategy.hpp
@@ -34,7 +34,7 @@
/** \brief identical to BestRouteStrategy v1, for backwards compatibility
* \deprecated NextHopFaceId field is honored universally and it's unnecessary to set this strategy
*/
-class ClientControlStrategy : public BestRouteStrategy
+class ClientControlStrategy : public BestRouteStrategyBase
{
public:
explicit
@@ -42,13 +42,6 @@
static const Name&
getStrategyName();
-
- virtual void
- afterReceiveInterest(const Face& inFace, const Interest& interest,
- const shared_ptr<pit::Entry>& pitEntry) override;
-
-private:
- bool m_isFirstUse = true;
};
} // namespace fw
diff --git a/daemon/fw/multicast-strategy.cpp b/daemon/fw/multicast-strategy.cpp
index 3248684..7a416e3 100644
--- a/daemon/fw/multicast-strategy.cpp
+++ b/daemon/fw/multicast-strategy.cpp
@@ -32,8 +32,13 @@
NFD_REGISTER_STRATEGY(MulticastStrategy);
MulticastStrategy::MulticastStrategy(Forwarder& forwarder, const Name& name)
- : Strategy(forwarder, name)
+ : Strategy(forwarder)
{
+ ParsedInstanceName parsed = parseInstanceName(name);
+ if (!parsed.parameters.empty()) {
+ BOOST_THROW_EXCEPTION(std::invalid_argument("MulticastStrategy does not accept parameters"));
+ }
+ this->setInstanceName(makeInstanceName(name, getStrategyName()));
}
const Name&
diff --git a/daemon/fw/ncc-strategy.cpp b/daemon/fw/ncc-strategy.cpp
index 0c8b53a..cfc22cb 100644
--- a/daemon/fw/ncc-strategy.cpp
+++ b/daemon/fw/ncc-strategy.cpp
@@ -37,8 +37,13 @@
const time::nanoseconds NccStrategy::MEASUREMENTS_LIFETIME = time::seconds(16);
NccStrategy::NccStrategy(Forwarder& forwarder, const Name& name)
- : Strategy(forwarder, name)
+ : Strategy(forwarder)
{
+ ParsedInstanceName parsed = parseInstanceName(name);
+ if (!parsed.parameters.empty()) {
+ BOOST_THROW_EXCEPTION(std::invalid_argument("NccStrategy does not accept parameters"));
+ }
+ this->setInstanceName(makeInstanceName(name, getStrategyName()));
}
const Name&
diff --git a/daemon/fw/strategy.cpp b/daemon/fw/strategy.cpp
index ae8a17c..3009123 100644
--- a/daemon/fw/strategy.cpp
+++ b/daemon/fw/strategy.cpp
@@ -43,43 +43,51 @@
}
Strategy::Registry::const_iterator
-Strategy::find(const Name& strategyName)
+Strategy::find(const Name& instanceName)
{
const Registry& registry = getRegistry();
+ ParsedInstanceName parsed = parseInstanceName(instanceName);
+
+ ///\todo #3868 accommodate parameters
+ if (parsed.version) {
+ NFD_LOG_TRACE("find " << instanceName <<
+ " strategyName=" << parsed.strategyName << " versioned");
+ ///\todo #3868 if exact version unavailable, choose closest higher version
+ return registry.find(parsed.strategyName);
+ }
+
+ NFD_LOG_TRACE("find " << instanceName <<
+ " strategyName=" << parsed.strategyName << " unversioned");
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;
+ for (auto it = registry.lower_bound(parsed.strategyName);
+ it != registry.end() && parsed.strategyName.isPrefixOf(it->first); ++it) {
+ if (it->first.size() == parsed.strategyName.size() + 1) { // only one extra component: version
+ candidate = it;
}
}
return candidate;
- ///\todo #3868 if exact version unavailable, choose closest higher version
- ///\todo #3868 allow parameter component
}
bool
-Strategy::canCreate(const Name& strategyName)
+Strategy::canCreate(const Name& instanceName)
{
- return Strategy::find(strategyName) != getRegistry().end();
+ return Strategy::find(instanceName) != getRegistry().end();
}
unique_ptr<Strategy>
-Strategy::create(const Name& strategyName, Forwarder& forwarder)
+Strategy::create(const Name& instanceName, Forwarder& forwarder)
{
- auto found = Strategy::find(strategyName);
+ auto found = Strategy::find(instanceName);
if (found == getRegistry().end()) {
- NFD_LOG_DEBUG("create " << strategyName << " not-found");
+ NFD_LOG_DEBUG("create " << instanceName << " 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);
+ unique_ptr<Strategy> instance = found->second(forwarder, instanceName);
+ NFD_LOG_DEBUG("create " << instanceName << " found=" << found->first <<
+ " created=" << instance->getInstanceName());
+ BOOST_ASSERT(!instance->getInstanceName().empty());
+ return instance;
}
std::set<Name>
@@ -91,10 +99,30 @@
return strategyNames;
}
-Strategy::Strategy(Forwarder& forwarder, const Name& name)
+Strategy::ParsedInstanceName
+Strategy::parseInstanceName(const Name& input)
+{
+ for (ssize_t i = input.size() - 1; i > 0; --i) {
+ if (input[i].isVersion()) {
+ return {input.getPrefix(i + 1), input[i].toVersion(), input.getSubName(i + 1)};
+ }
+ }
+ return {input, ndn::nullopt, PartialName()};
+}
+
+Name
+Strategy::makeInstanceName(const Name& input, const Name& strategyName)
+{
+ BOOST_ASSERT(strategyName.at(-1).isVersion());
+
+ bool hasVersion = std::any_of(input.rbegin(), input.rend(),
+ [] (const name::Component& comp) { return comp.isVersion(); });
+ return hasVersion ? input : Name(input).append(strategyName.at(-1));
+}
+
+Strategy::Strategy(Forwarder& forwarder)
: afterAddFace(forwarder.getFaceTable().afterAdd)
, beforeRemoveFace(forwarder.getFaceTable().beforeRemove)
- , m_name(name)
, m_forwarder(forwarder)
, m_measurements(m_forwarder.getMeasurements(), m_forwarder.getStrategyChoice(), *this)
{
diff --git a/daemon/fw/strategy.hpp b/daemon/fw/strategy.hpp
index 187f7fe..c2949b2 100644
--- a/daemon/fw/strategy.hpp
+++ b/daemon/fw/strategy.hpp
@@ -39,7 +39,7 @@
public: // registry
/** \brief register a strategy type
* \tparam S subclass of Strategy
- * \param strategyName versioned strategy name
+ * \param strategyName strategy program name, must contain version
* \note It is permitted to register the same strategy type under multiple names,
* which is useful in tests and for creating aliases.
*/
@@ -47,27 +47,27 @@
static void
registerType(const Name& strategyName = S::getStrategyName())
{
+ BOOST_ASSERT(strategyName.at(-1).isVersion());
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
+ /** \return whether a strategy instance can be created from \p instanceName
+ * \param instanceName strategy instance name, may contain version and 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);
+ canCreate(const Name& instanceName);
- /** \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
+ /** \return a strategy instance created from \p instanceName
+ * \retval nullptr if !canCreate(instanceName)
+ * \throw std::invalid_argument strategy type constructor does not accept
+ * specified version or parameters
*/
static unique_ptr<Strategy>
- create(const Name& strategyName, Forwarder& forwarder);
+ create(const Name& instanceName, Forwarder& forwarder);
/** \return registered versioned strategy names
*/
@@ -76,36 +76,43 @@
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,
- * and should not keep a reference themselves.
- * \param name the strategy Name.
- * It's recommended to include a version number as the last component.
- * \todo #3868 name contains version and parameters as instantiated.
+ * \param forwarder a reference to the forwarder, used to enable actions and accessors.
+ * \note Strategy subclass constructor should not retain a reference to the forwarder.
*/
- Strategy(Forwarder& forwarder, const Name& name);
+ explicit
+ Strategy(Forwarder& forwarder);
virtual
~Strategy();
#ifdef DOXYGEN
- /** \return a name that represents the strategy program
- * \todo #3868 This name contains version as given in code,
- * which may differ from instantiated version.
+ /** \return strategy program name
+ *
+ * The strategy name is defined by the strategy program.
+ * It must end with a version component.
*/
static const Name&
getStrategyName();
#endif
- /** \return a name that represents the strategy program
- * \todo #3868 This name contains version and parameters as instantiated.
+ /** \return strategy instance name
+ *
+ * The instance name is assigned during instantiation.
+ * It contains a version component, and may have extra parameter components.
*/
const Name&
- getName() const
+ getInstanceName() const
{
return m_name;
}
+ DEPRECATED(
+ const Name&
+ getName() const)
+ {
+ return this->getInstanceName();
+ }
+
public: // triggers
/** \brief trigger after Interest is received
*
@@ -249,9 +256,42 @@
return m_forwarder.getFaceTable();
}
-protected: // accessors
- signal::Signal<FaceTable, Face&>& afterAddFace;
- signal::Signal<FaceTable, Face&>& beforeRemoveFace;
+protected: // instance name
+ struct ParsedInstanceName
+ {
+ Name strategyName; ///< strategy name without parameters
+ ndn::optional<uint64_t> version; ///< whether strategyName contains a version component
+ PartialName parameters; ///< parameter components
+ };
+
+ /** \brief parse a strategy instance name
+ * \param input strategy instance name, may contain version and parameters
+ * \throw std::invalid_argument input format is unacceptable
+ */
+ static ParsedInstanceName
+ parseInstanceName(const Name& input);
+
+ /** \brief construct a strategy instance name
+ * \param input strategy instance name, may contain version and parameters
+ * \param strategyName strategy name with version but without parameters;
+ * typically this should be \p getStrategyName()
+ *
+ * If \p input contains a version component, return \p input unchanged.
+ * Otherwise, return \p input plus the version component taken from \p strategyName.
+ * This allows a strategy instance to be constructed with an unversioned name,
+ * but its final instance name should contain the version.
+ */
+ static Name
+ makeInstanceName(const Name& input, const Name& strategyName);
+
+ /** \brief set strategy instance name
+ * \note This must be called by strategy subclass constructor.
+ */
+ void
+ setInstanceName(const Name& name)
+ {
+ m_name = name;
+ }
private: // registry
typedef std::function<unique_ptr<Strategy>(Forwarder& forwarder, const Name& strategyName)> CreateFunc;
@@ -261,7 +301,11 @@
getRegistry();
static Registry::const_iterator
- find(const Name& strategyName);
+ find(const Name& instanceName);
+
+protected: // accessors
+ signal::Signal<FaceTable, Face&>& afterAddFace;
+ signal::Signal<FaceTable, Face&>& beforeRemoveFace;
private: // instance fields
Name m_name;