table: MeasurementsAccessor for strategy

refs #1276

Change-Id: Idec8f615c726f51612236a55a7532fabeb81a32d
diff --git a/daemon/common.hpp b/daemon/common.hpp
index af4a9fd..b5203c3 100644
--- a/daemon/common.hpp
+++ b/daemon/common.hpp
@@ -39,6 +39,8 @@
 #include <sstream>
 #include <istream>
 #include <fstream>
+#include <algorithm>
+#include <numeric>
 
 #include "core/logger.hpp"
 
diff --git a/daemon/fw/forwarder.cpp b/daemon/fw/forwarder.cpp
index 6ab6fd4..8f6f015 100644
--- a/daemon/fw/forwarder.cpp
+++ b/daemon/fw/forwarder.cpp
@@ -17,6 +17,7 @@
 Forwarder::Forwarder(boost::asio::io_service& ioService)
   : m_scheduler(ioService)
   , m_lastFaceId(0)
+  , m_measurements(ioService)
 {
   m_strategy = make_shared<fw::BestRouteStrategy>(boost::ref(*this));
 }
diff --git a/daemon/fw/forwarder.hpp b/daemon/fw/forwarder.hpp
index ae9fb6a..6da99c7 100644
--- a/daemon/fw/forwarder.hpp
+++ b/daemon/fw/forwarder.hpp
@@ -13,6 +13,7 @@
 #include "table/fib.hpp"
 #include "table/pit.hpp"
 #include "table/cs.hpp"
+#include "table/measurements.hpp"
 #include "strategy.hpp"
 
 namespace nfd {
@@ -49,6 +50,9 @@
   
   Cs&
   getCs();
+  
+  Measurements&
+  getMeasurements();
 
   shared_ptr<Face>
   getFace(FaceId id);
@@ -117,9 +121,10 @@
   FaceId m_lastFaceId;
   std::map<FaceId, shared_ptr<Face> > m_faces;
   
-  Fib m_fib;
-  Pit m_pit;
-  Cs  m_cs;
+  Fib          m_fib;
+  Pit          m_pit;
+  Cs           m_cs;
+  Measurements m_measurements;
   /// the active strategy (only one strategy in mock)
   shared_ptr<fw::Strategy> m_strategy;
   
@@ -147,6 +152,12 @@
   return m_cs;
 }
 
+inline Measurements&
+Forwarder::getMeasurements()
+{
+  return m_measurements;
+}
+
 } // namespace nfd
 
 #endif // NFD_FW_FORWARDER_HPP
diff --git a/daemon/fw/strategy.cpp b/daemon/fw/strategy.cpp
index 14e4cbe..078ef22 100644
--- a/daemon/fw/strategy.cpp
+++ b/daemon/fw/strategy.cpp
@@ -15,6 +15,7 @@
 
 Strategy::Strategy(Forwarder& forwarder)
   : m_forwarder(forwarder)
+  , m_measurements(m_forwarder.getMeasurements(), m_forwarder.getFib(), this)
 {
 }
 
diff --git a/daemon/fw/strategy.hpp b/daemon/fw/strategy.hpp
index 1ecbfc9..311af93 100644
--- a/daemon/fw/strategy.hpp
+++ b/daemon/fw/strategy.hpp
@@ -8,16 +8,13 @@
 #define NFD_FW_STRATEGY_HPP
 
 #include "face/face.hpp"
+#include "table/fib-entry.hpp"
+#include "table/pit-entry.hpp"
+#include "table/measurements-accessor.hpp"
 
 namespace nfd {
 
 class Forwarder;
-namespace fib {
-class Entry;
-}
-namespace pit {
-class Entry;
-}
 
 namespace fw {
 
@@ -29,10 +26,10 @@
 public:
   explicit
   Strategy(Forwarder& forwarder);
-  
+
   virtual
   ~Strategy();
-  
+
 public: // triggers
   /** \brief trigger after Interest is received
    *
@@ -53,7 +50,7 @@
                        const Interest& interest,
                        shared_ptr<fib::Entry> fibEntry,
                        shared_ptr<pit::Entry> pitEntry) =0;
-  
+
   /** \brief trigger before PIT entry is satisfied
    *
    *  In this base class this method does nothing.
@@ -61,7 +58,7 @@
   virtual void
   beforeSatisfyPendingInterest(shared_ptr<pit::Entry> pitEntry,
                                const Face& inFace, const Data& data);
-  
+
   /** \brief trigger before PIT entry expires
    *
    *  PIT entry expires when InterestLifetime has elapsed for all InRecords,
@@ -73,7 +70,7 @@
    */
   virtual void
   beforeExpirePendingInterest(shared_ptr<pit::Entry> pitEntry);
-  
+
 //  /** \brief trigger after FIB entry is being inserted
 //   *         and becomes managed by this strategy
 //   *
@@ -81,14 +78,14 @@
 //   */
 //  virtual void
 //  afterAddFibEntry(shared_ptr<fib::Entry> fibEntry);
-//  
+//
 //  /** \brief trigger after FIB entry being managed by this strategy is updated
 //   *
 //   *  In this base class this method does nothing.
 //   */
 //  virtual void
 //  afterUpdateFibEntry(shared_ptr<fib::Entry> fibEntry);
-//  
+//
 //  /** \brief trigger before FIB entry ceises to be managed by this strategy
 //   *         or is being deleted
 //   *
@@ -96,13 +93,13 @@
 //   */
 //  virtual void
 //  beforeRemoveFibEntry(shared_ptr<fib::Entry> fibEntry);
-  
+
 protected: // actions
   /// send Interest to outFace
   VIRTUAL_WITH_TESTS void
   sendInterest(shared_ptr<pit::Entry> pitEntry,
                     shared_ptr<Face> outFace);
-  
+
   /** \brief decide that a pending Interest cannot be forwarded
    *
    *  This shall not be called if the pending Interest has been
@@ -110,15 +107,27 @@
    */
   VIRTUAL_WITH_TESTS void
   rebuffPendingInterest(shared_ptr<pit::Entry> pitEntry);
-  
+
+protected: // accessors
+  MeasurementsAccessor&
+  getMeasurements();
+
 private:
   /** \brief reference to the forwarder
    *
    *  Triggers can access forwarder indirectly via actions.
    */
   Forwarder& m_forwarder;
+
+  MeasurementsAccessor m_measurements;
 };
 
+inline MeasurementsAccessor&
+Strategy::getMeasurements()
+{
+  return m_measurements;
+}
+
 } // namespace fw
 } // namespace nfd
 
diff --git a/daemon/table/fib-entry.cpp b/daemon/table/fib-entry.cpp
index 5b64e6b..61b9827 100644
--- a/daemon/table/fib-entry.cpp
+++ b/daemon/table/fib-entry.cpp
@@ -5,7 +5,6 @@
  */
 
 #include "fib-entry.hpp"
-#include <algorithm>
 
 namespace nfd {
 namespace fib {
@@ -62,6 +61,12 @@
   std::sort(m_nextHops.begin(), m_nextHops.end(), &compare_NextHop_cost);
 }
 
+void
+Entry::setStrategy(shared_ptr<fw::Strategy> strategy)
+{
+  m_strategy = strategy;
+}
+
 
 } // namespace fib
 } // namespace nfd
diff --git a/daemon/table/fib-entry.hpp b/daemon/table/fib-entry.hpp
index 40098ee..6adddd8 100644
--- a/daemon/table/fib-entry.hpp
+++ b/daemon/table/fib-entry.hpp
@@ -10,6 +10,11 @@
 #include "fib-nexthop.hpp"
 
 namespace nfd {
+
+namespace fw {
+class Strategy;
+}
+
 namespace fib {
 
 /** \class NextHopList
@@ -46,6 +51,12 @@
   /// removes a nexthop
   void
   removeNextHop(shared_ptr<Face> face);
+  
+  const fw::Strategy&
+  getStrategy() const;
+  
+  void
+  setStrategy(shared_ptr<fw::Strategy> strategy);
 
 private:
   /// sorts the nexthop list
@@ -55,6 +66,7 @@
 private:
   Name m_prefix;
   NextHopList m_nextHops;
+  shared_ptr<fw::Strategy> m_strategy;
 };
 
 
@@ -70,6 +82,12 @@
   return m_nextHops;
 }
 
+inline const fw::Strategy&
+Entry::getStrategy() const
+{
+  BOOST_ASSERT(static_cast<bool>(m_strategy));
+  return *m_strategy;
+}
 
 } // namespace fib
 } // namespace nfd
diff --git a/daemon/table/fib.cpp b/daemon/table/fib.cpp
index 7a3295a..481df77 100644
--- a/daemon/table/fib.cpp
+++ b/daemon/table/fib.cpp
@@ -5,8 +5,8 @@
  */
 
 #include "fib.hpp"
-#include <algorithm>
-#include <numeric>
+#include "pit-entry.hpp"
+#include "measurements-entry.hpp"
 
 namespace nfd {
 
@@ -61,6 +61,18 @@
 }
 
 shared_ptr<fib::Entry>
+Fib::findLongestPrefixMatch(const pit::Entry& pitEntry) const
+{
+  return this->findLongestPrefixMatch(pitEntry.getName());
+}
+
+shared_ptr<fib::Entry>
+Fib::findLongestPrefixMatch(const measurements::Entry& measurementsEntry) const
+{
+  return this->findLongestPrefixMatch(measurementsEntry.getName());
+}
+
+shared_ptr<fib::Entry>
 Fib::findExactMatch(const Name& prefix) const
 {
   std::list<shared_ptr<fib::Entry> >::const_iterator it =
diff --git a/daemon/table/fib.hpp b/daemon/table/fib.hpp
index 22d5222..2661911 100644
--- a/daemon/table/fib.hpp
+++ b/daemon/table/fib.hpp
@@ -8,6 +8,9 @@
 #define NFD_TABLE_FIB_HPP
 
 #include "fib-entry.hpp"
+#include "pit-entry.hpp"
+#include "measurements-entry.hpp"
+
 namespace nfd {
 
 /** \class Fib
@@ -31,6 +34,14 @@
   shared_ptr<fib::Entry>
   findLongestPrefixMatch(const Name& prefix) const;
 
+  /// performs a longest prefix match
+  shared_ptr<fib::Entry>
+  findLongestPrefixMatch(const pit::Entry& pitEntry) const;
+
+  /// performs a longest prefix match
+  shared_ptr<fib::Entry>
+  findLongestPrefixMatch(const measurements::Entry& measurementsEntry) const;
+
   shared_ptr<fib::Entry>
   findExactMatch(const Name& prefix) const;
 
diff --git a/daemon/table/measurements-accessor.cpp b/daemon/table/measurements-accessor.cpp
new file mode 100644
index 0000000..5a00c18
--- /dev/null
+++ b/daemon/table/measurements-accessor.cpp
@@ -0,0 +1,38 @@
+/* -*- 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 "measurements-accessor.hpp"
+
+namespace nfd {
+
+MeasurementsAccessor::MeasurementsAccessor(Measurements& measurements,
+                                           Fib& fib, fw::Strategy* strategy)
+  : m_measurements(measurements)
+  , m_fib(fib)
+  , m_strategy(strategy)
+{
+}
+
+MeasurementsAccessor::~MeasurementsAccessor()
+{
+}
+
+shared_ptr<measurements::Entry>
+MeasurementsAccessor::filter(const shared_ptr<measurements::Entry>& entry)
+{
+  if (!static_cast<bool>(entry)) {
+    return entry;
+  }
+
+  shared_ptr<fib::Entry> fibEntry = m_fib.findLongestPrefixMatch(*entry);
+  BOOST_ASSERT(static_cast<bool>(fibEntry));
+  if (&fibEntry->getStrategy() == m_strategy) {
+    return entry;
+  }
+  return shared_ptr<measurements::Entry>();
+}
+
+} // namespace nfd
diff --git a/daemon/table/measurements-accessor.hpp b/daemon/table/measurements-accessor.hpp
new file mode 100644
index 0000000..26a6d38
--- /dev/null
+++ b/daemon/table/measurements-accessor.hpp
@@ -0,0 +1,123 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NFD_TABLE_MEASUREMENTS_ACCESSOR_HPP
+#define NFD_TABLE_MEASUREMENTS_ACCESSOR_HPP
+
+#include "measurements.hpp"
+#include "fib.hpp"
+
+namespace nfd {
+
+namespace fw {
+class Strategy;
+}
+
+/** \brief allows Strategy to access portion of Measurements table under its namespace
+ */
+class MeasurementsAccessor : noncopyable
+{
+public:
+  MeasurementsAccessor(Measurements& measurements, Fib& fib, fw::Strategy* strategy);
+
+  ~MeasurementsAccessor();
+
+  /// find or insert a Measurements entry for name
+  shared_ptr<measurements::Entry>
+  get(const Name& name);
+
+  /// find or insert a Measurements entry for fibEntry->getPrefix()
+  shared_ptr<measurements::Entry>
+  get(const fib::Entry& fibEntry);
+
+  /// find or insert a Measurements entry for pitEntry->getName()
+  shared_ptr<measurements::Entry>
+  get(const pit::Entry& pitEntry);
+
+  /** \brief find or insert a Measurements entry for child's parent
+   *
+   *  If child is the root entry, returns null.
+   */
+  shared_ptr<measurements::Entry>
+  getParent(shared_ptr<measurements::Entry> child);
+
+//  /// perform a longest prefix match
+//  shared_ptr<fib::Entry>
+//  findLongestPrefixMatch(const Name& name) const;
+//
+//  /// perform an exact match
+//  shared_ptr<fib::Entry>
+//  findExactMatch(const Name& name) const;
+
+  /** \brief extend lifetime of an entry
+   *
+   *  The entry will be kept until at least now()+lifetime.
+   */
+  void
+  extendLifetime(measurements::Entry& entry, const time::Duration& lifetime);
+
+private:
+  /** \brief perform access control to Measurements entry
+   *
+   *  \return entry if strategy has access to namespace, otherwise 0
+   */
+  shared_ptr<measurements::Entry>
+  filter(const shared_ptr<measurements::Entry>& entry);
+
+private:
+  Measurements& m_measurements;
+  Fib& m_fib;
+  fw::Strategy* m_strategy;
+};
+
+inline shared_ptr<measurements::Entry>
+MeasurementsAccessor::get(const Name& name)
+{
+  return this->filter(m_measurements.get(name));
+}
+
+inline shared_ptr<measurements::Entry>
+MeasurementsAccessor::get(const fib::Entry& fibEntry)
+{
+  if (&fibEntry.getStrategy() == m_strategy) {
+    return m_measurements.get(fibEntry);
+  }
+  return shared_ptr<measurements::Entry>();
+}
+
+inline shared_ptr<measurements::Entry>
+MeasurementsAccessor::get(const pit::Entry& pitEntry)
+{
+  return this->filter(m_measurements.get(pitEntry));
+}
+
+inline shared_ptr<measurements::Entry>
+MeasurementsAccessor::getParent(shared_ptr<measurements::Entry> child)
+{
+  return this->filter(m_measurements.getParent(child));
+}
+
+//inline shared_ptr<fib::Entry>
+//MeasurementsAccessor::findLongestPrefixMatch(const Name& name) const
+//{
+//  return this->filter(m_measurements.findLongestPrefixMatch(name));
+//}
+//
+//inline shared_ptr<fib::Entry>
+//MeasurementsAccessor::findExactMatch(const Name& name) const
+//{
+//  return this->filter(m_measurements.findExactMatch(name));
+//}
+
+inline void
+MeasurementsAccessor::extendLifetime(measurements::Entry& entry, const time::Duration& lifetime)
+{
+  m_measurements.extendLifetime(entry, lifetime);
+}
+
+} // namespace nfd
+
+#endif // NFD_TABLE_MEASUREMENTS_ACCESSOR_HPP
diff --git a/daemon/table/measurements.cpp b/daemon/table/measurements.cpp
index bc5a9d2..705d3f1 100644
--- a/daemon/table/measurements.cpp
+++ b/daemon/table/measurements.cpp
@@ -71,7 +71,7 @@
 //}
 
 void
-Measurements::extendLifetime(measurements::Entry& entry, time::Duration lifetime)
+Measurements::extendLifetime(measurements::Entry& entry, const time::Duration& lifetime)
 {
   std::map<Name, shared_ptr<measurements::Entry> >::iterator it =
       m_table.find(entry.getName());
@@ -83,7 +83,7 @@
 void
 Measurements::extendLifetimeInternal(
     std::map<Name, shared_ptr<measurements::Entry> >::iterator it,
-    time::Duration lifetime)
+    const time::Duration& lifetime)
 {
   shared_ptr<measurements::Entry>& entry = it->second;
 
diff --git a/daemon/table/measurements.hpp b/daemon/table/measurements.hpp
index 2e3a88c..0fa24e0 100644
--- a/daemon/table/measurements.hpp
+++ b/daemon/table/measurements.hpp
@@ -8,17 +8,12 @@
 #define NFD_TABLE_MEASUREMENTS_HPP
 
 #include "measurements-entry.hpp"
+#include "fib-entry.hpp"
+#include "pit-entry.hpp"
 #include "core/time.hpp"
 
 namespace nfd {
 
-namespace fib {
-class Entry;
-}
-namespace pit {
-class Entry;
-}
-
 /** \class Measurement
  *  \brief represents the Measurements table
  */
@@ -62,13 +57,13 @@
    *  The entry will be kept until at least now()+lifetime.
    */
   void
-  extendLifetime(measurements::Entry& entry, time::Duration lifetime);
+  extendLifetime(measurements::Entry& entry, const time::Duration& lifetime);
 
 private:
   void
   extendLifetimeInternal(
     std::map<Name, shared_ptr<measurements::Entry> >::iterator it,
-    time::Duration lifetime);
+    const time::Duration& lifetime);
 
   void
   cleanup(std::map<Name, shared_ptr<measurements::Entry> >::iterator it);
diff --git a/tests/table/measurements-accessor.cpp b/tests/table/measurements-accessor.cpp
new file mode 100644
index 0000000..789d02a
--- /dev/null
+++ b/tests/table/measurements-accessor.cpp
@@ -0,0 +1,89 @@
+/* -*- 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 "table/measurements-accessor.hpp"
+#include "fw/forwarder.hpp"
+
+#include <boost/test/unit_test.hpp>
+
+namespace nfd {
+
+BOOST_AUTO_TEST_SUITE(TableMeasurementsAccessor)
+
+class MeasurementsAccessorTestStrategy : public fw::Strategy
+{
+public:
+  explicit
+  MeasurementsAccessorTestStrategy(Forwarder& forwarder)
+    : Strategy(forwarder)
+  {
+  }
+  
+  virtual
+  ~MeasurementsAccessorTestStrategy()
+  
+  {
+  }
+
+  virtual void
+  afterReceiveInterest(const Face& inFace,
+                       const Interest& interest,
+                       shared_ptr<fib::Entry> fibEntry,
+                       shared_ptr<pit::Entry> pitEntry)
+  {
+    BOOST_ASSERT(false);
+  }
+  
+public: // accessors
+  MeasurementsAccessor&
+  getMeasurements_accessor()
+  {
+    return this->getMeasurements();
+  }
+};
+
+BOOST_AUTO_TEST_CASE(Access)
+{
+  boost::asio::io_service ioService;
+  Forwarder forwarder(ioService);
+  shared_ptr<MeasurementsAccessorTestStrategy> strategy1 =
+    make_shared<MeasurementsAccessorTestStrategy>(boost::ref(forwarder));
+  shared_ptr<MeasurementsAccessorTestStrategy> strategy2 =
+    make_shared<MeasurementsAccessorTestStrategy>(boost::ref(forwarder));
+  
+  Name nameRoot("ndn:/");
+  Name nameA   ("ndn:/A");
+  Name nameAB  ("ndn:/A/B");
+  Name nameABC ("ndn:/A/B/C");
+  Name nameAD  ("ndn:/A/D");
+  
+  Fib& fib = forwarder.getFib();
+  fib.insert(nameRoot).first->setStrategy(strategy1);
+  fib.insert(nameA   ).first->setStrategy(strategy2);
+  fib.insert(nameAB  ).first->setStrategy(strategy1);
+  
+  MeasurementsAccessor& accessor1 = strategy1->getMeasurements_accessor();
+  MeasurementsAccessor& accessor2 = strategy2->getMeasurements_accessor();
+  
+  BOOST_CHECK_EQUAL(static_cast<bool>(accessor1.get(nameRoot)), true);
+  BOOST_CHECK_EQUAL(static_cast<bool>(accessor1.get(nameA   )), false);
+  BOOST_CHECK_EQUAL(static_cast<bool>(accessor1.get(nameAB  )), true);
+  BOOST_CHECK_EQUAL(static_cast<bool>(accessor1.get(nameABC )), true);
+  BOOST_CHECK_EQUAL(static_cast<bool>(accessor1.get(nameAD  )), false);
+  
+  shared_ptr<measurements::Entry> entryRoot = forwarder.getMeasurements().get(nameRoot);
+  BOOST_CHECK_NO_THROW(accessor1.getParent(entryRoot));
+  
+  BOOST_CHECK_EQUAL(static_cast<bool>(accessor2.get(nameRoot)), false);
+  BOOST_CHECK_EQUAL(static_cast<bool>(accessor2.get(nameA   )), true);
+  BOOST_CHECK_EQUAL(static_cast<bool>(accessor2.get(nameAB  )), false);
+  BOOST_CHECK_EQUAL(static_cast<bool>(accessor2.get(nameABC )), false);
+  BOOST_CHECK_EQUAL(static_cast<bool>(accessor2.get(nameAD  )), true);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace nfd