Merge with branch 'simulation'
diff --git a/.gitignore b/.gitignore
index f10621d..7ce2679 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,5 @@
*.pyc
doc/html
.DS_Store
+animation.xml
+.R*
diff --git a/model/sync-app-data-fetch.cc b/ccnx/sync-app-data-fetch.cc
similarity index 100%
rename from model/sync-app-data-fetch.cc
rename to ccnx/sync-app-data-fetch.cc
diff --git a/model/sync-app-data-fetch.h b/ccnx/sync-app-data-fetch.h
similarity index 100%
rename from model/sync-app-data-fetch.h
rename to ccnx/sync-app-data-fetch.h
diff --git a/model/sync-app-data-publish.cc b/ccnx/sync-app-data-publish.cc
similarity index 100%
rename from model/sync-app-data-publish.cc
rename to ccnx/sync-app-data-publish.cc
diff --git a/model/sync-app-data-publish.h b/ccnx/sync-app-data-publish.h
similarity index 100%
rename from model/sync-app-data-publish.h
rename to ccnx/sync-app-data-publish.h
diff --git a/model/sync-app-socket-c.cc b/ccnx/sync-app-socket-c.cc
similarity index 100%
rename from model/sync-app-socket-c.cc
rename to ccnx/sync-app-socket-c.cc
diff --git a/model/sync-app-socket-c.h b/ccnx/sync-app-socket-c.h
similarity index 100%
rename from model/sync-app-socket-c.h
rename to ccnx/sync-app-socket-c.h
diff --git a/model/sync-app-socket.cc b/ccnx/sync-app-socket.cc
similarity index 100%
rename from model/sync-app-socket.cc
rename to ccnx/sync-app-socket.cc
diff --git a/model/sync-app-socket.h b/ccnx/sync-app-socket.h
similarity index 100%
rename from model/sync-app-socket.h
rename to ccnx/sync-app-socket.h
diff --git a/model/sync-ccnx-wrapper.cc b/ccnx/sync-ccnx-wrapper.cc
similarity index 100%
rename from model/sync-ccnx-wrapper.cc
rename to ccnx/sync-ccnx-wrapper.cc
diff --git a/model/sync-ccnx-wrapper.h b/ccnx/sync-ccnx-wrapper.h
similarity index 100%
rename from model/sync-ccnx-wrapper.h
rename to ccnx/sync-ccnx-wrapper.h
diff --git a/model/sync-log.cc b/ccnx/sync-log.cc
similarity index 100%
rename from model/sync-log.cc
rename to ccnx/sync-log.cc
diff --git a/model/sync-log.h b/ccnx/sync-log.h
similarity index 100%
rename from model/sync-log.h
rename to ccnx/sync-log.h
diff --git a/model/sync-logic-event-container.h b/ccnx/sync-logic-event-container.h
similarity index 97%
rename from model/sync-logic-event-container.h
rename to ccnx/sync-logic-event-container.h
index 65c8ab2..ebab72a 100644
--- a/model/sync-logic-event-container.h
+++ b/ccnx/sync-logic-event-container.h
@@ -23,6 +23,8 @@
#ifndef SYNC_LOGIC_EVENT_CONTAINER_H
#define SYNC_LOGIC_EVENT_CONTAINER_H
+#include "sync-event.h"
+
#include <boost/function.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
@@ -40,8 +42,6 @@
namespace Sync
{
-typedef boost::function< void ( ) > Event;
-
struct LogicEvent
{
LogicEvent (const boost::system_time &_time, Event _event, uint32_t _label)
diff --git a/model/sync-scheduler.cc b/ccnx/sync-scheduler.cc
similarity index 90%
rename from model/sync-scheduler.cc
rename to ccnx/sync-scheduler.cc
index 4f9e082..866f742 100644
--- a/model/sync-scheduler.cc
+++ b/ccnx/sync-scheduler.cc
@@ -107,26 +107,18 @@
// cout << "Exited...\n";
}
-
void
-Scheduler::schedule (const boost::system_time &abstime, Event event, uint32_t label)
+Scheduler::schedule (const TimeDuration &reltime, Event event, uint32_t label)
{
{
lock_guard<mutex> lock (m_eventsMutex);
- m_events.insert (LogicEvent (abstime, event, label));
+ m_events.insert (LogicEvent (boost::get_system_time () + reltime, event, label));
}
m_eventsCondition.notify_one ();
m_thread.interrupt (); // interrupt sleep, if currently sleeping
}
void
-Scheduler::schedule (const boost::posix_time::time_duration &reltime, Event event, uint32_t label)
-{
- // cout << reltime << endl;
- schedule (boost::get_system_time () + reltime, event, label);
-}
-
-void
Scheduler::cancel (uint32_t label)
{
{
diff --git a/model/sync-scheduler.h b/ccnx/sync-scheduler.h
similarity index 85%
rename from model/sync-scheduler.h
rename to ccnx/sync-scheduler.h
index 10ef210..155c6ba 100644
--- a/model/sync-scheduler.h
+++ b/ccnx/sync-scheduler.h
@@ -28,6 +28,12 @@
#include "sync-logic-event-container.h"
+#define TIME_SECONDS(number) boost::posix_time::seconds (number)
+#define TIME_MILLISECONDS(number) boost::posix_time::milliseconds(number)
+#define TIME_NOW boost::get_system_time ()
+typedef boost::posix_time::time_duration TimeDuration;
+typedef boost::system_time TimeAbsolute;
+
namespace Sync {
/**
@@ -49,22 +55,13 @@
~Scheduler ();
/**
- * @brief Schedule an event at absolute time 'abstime'
- * @param abstime Absolute time
- * @param event function to be called at the time
- * @param label Label for the event
- */
- void
- schedule (const boost::system_time &abstime, Event event, uint32_t label);
-
- /**
* @brief Schedule an event at relative time 'reltime'
* @param reltime Relative time
* @param event function to be called at the time
* @param label Label for the event
*/
void
- schedule (const boost::posix_time::time_duration &reltime, Event event, uint32_t label);
+ schedule (const TimeDuration &reltime, Event event, uint32_t label);
/**
* @brief Cancel all events for the label
diff --git a/examples/sync-example.cc b/examples/sync-example.cc
index 57bf8b4..38edf4f 100644
--- a/examples/sync-example.cc
+++ b/examples/sync-example.cc
@@ -1,23 +1,139 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-#include "ns3/core-module.h"
-#include "ns3/sync-helper.h"
+#include <ns3/core-module.h>
+#include <ns3/network-module.h>
+#include <ns3/NDNabstraction-module.h>
+#include <ns3/point-to-point-module.h>
+
+#include "sync-logic.h"
+#include "sync-logic-helper.h"
using namespace ns3;
+using namespace Sync;
+NS_LOG_COMPONENT_DEFINE ("SyncExample");
+
+void OnUpdate (const std::string &prefix, const SeqNo &newSeq, const SeqNo &/*oldSeq*/)
+{
+ NS_LOG_LOGIC (Simulator::Now ().ToDouble (Time::S) <<"s\tNode: " << Simulator::GetContext () << ", prefix: " << prefix << ", seqNo: " << newSeq);
+}
+
+void OnRemove (const std::string &prefix)
+{
+ NS_LOG_LOGIC (Simulator::Now ().ToDouble (Time::S) <<"s\tNode: " << Simulator::GetContext () << ", prefix: "<< prefix);
+}
int
main (int argc, char *argv[])
{
- bool verbose = true;
+ Config::SetDefault ("ns3::PointToPointNetDevice::DataRate", StringValue ("1Mbps"));
+ Config::SetDefault ("ns3::PointToPointChannel::Delay", StringValue ("10ms"));
+ Config::SetDefault ("ns3::DropTailQueue::MaxPackets", StringValue ("20"));
+
+ Config::SetDefault ("ns3::CcnxFloodingStrategy::SmartFlooding", StringValue ("false"));
+
+ LogComponentEnable ("SyncExample", LOG_ALL);
+
+ Time finishTime = Seconds (3.0);
CommandLine cmd;
- cmd.AddValue ("verbose", "Tell application to log if true", verbose);
+ cmd.AddValue ("finish", "Finish time", finishTime);
+ cmd.Parse (argc, argv);
- cmd.Parse (argc,argv);
+ // Creating nodes
+ NodeContainer nodes;
+ nodes.Create (11);
- /* ... */
+ // Connecting nodes using two links
+ PointToPointHelper p2p;
+ p2p.Install (nodes.Get (0), nodes.Get (4));
+ p2p.Install (nodes.Get (1), nodes.Get (2));
+ p2p.Install (nodes.Get (1), nodes.Get (4));
+ p2p.Install (nodes.Get (1), nodes.Get (5));
+ p2p.Install (nodes.Get (2), nodes.Get (6));
+ p2p.Install (nodes.Get (2), nodes.Get (7));
+ p2p.Install (nodes.Get (3), nodes.Get (4));
+ p2p.Install (nodes.Get (3), nodes.Get (8));
+ p2p.Install (nodes.Get (4), nodes.Get (5));
+ p2p.Install (nodes.Get (4), nodes.Get (8));
+ p2p.Install (nodes.Get (5), nodes.Get (6));
+ p2p.Install (nodes.Get (5), nodes.Get (9));
+ p2p.Install (nodes.Get (5), nodes.Get (10));
+ p2p.Install (nodes.Get (6), nodes.Get (10));
+ p2p.Install (nodes.Get (7), nodes.Get (10));
+ p2p.Install (nodes.Get (8), nodes.Get (9));
+ p2p.Install (nodes.Get (9), nodes.Get (10));
+ Names::Add ("0", nodes.Get (0));
+ Names::Add ("1", nodes.Get (1));
+ Names::Add ("2", nodes.Get (2));
+ Names::Add ("3", nodes.Get(3));
+ Names::Add ("4", nodes.Get(4));
+ Names::Add ("5", nodes.Get(5));
+ Names::Add ("6", nodes.Get(6));
+ Names::Add ("7", nodes.Get(7));
+ Names::Add ("8", nodes.Get(8));
+ Names::Add ("9", nodes.Get(9));
+ Names::Add ("10", nodes.Get(10));
+
+ // Install CCNx stack on all nodes
+ NS_LOG_INFO ("Installing CCNx stack");
+ CcnxStackHelper ccnxHelper;
+ ccnxHelper.SetForwardingStrategy ("ns3::CcnxFloodingStrategy");
+ ccnxHelper.SetDefaultRoutes (false);
+ ccnxHelper.InstallAll ();
+
+ ccnxHelper.AddRoute ("0", "/sync", 0, 0);
+ ccnxHelper.AddRoute ("1", "/sync", 0, 0);
+ ccnxHelper.AddRoute ("1", "/sync", 1, 0);
+ ccnxHelper.AddRoute ("1", "/sync", 2, 0);
+ ccnxHelper.AddRoute ("2", "/sync", 0, 0);
+ ccnxHelper.AddRoute ("2", "/sync", 1, 0);
+ ccnxHelper.AddRoute ("2", "/sync", 2, 0);
+ ccnxHelper.AddRoute ("3", "/sync", 0, 0);
+ ccnxHelper.AddRoute ("3", "/sync", 1, 0);
+ ccnxHelper.AddRoute ("4", "/sync", 0, 0);
+ ccnxHelper.AddRoute ("4", "/sync", 1, 0);
+ ccnxHelper.AddRoute ("4", "/sync", 2, 0);
+ ccnxHelper.AddRoute ("4", "/sync", 3, 0);
+ ccnxHelper.AddRoute ("4", "/sync", 4, 0);
+ ccnxHelper.AddRoute ("5", "/sync", 0, 0);
+ ccnxHelper.AddRoute ("5", "/sync", 1, 0);
+ ccnxHelper.AddRoute ("5", "/sync", 2, 0);
+ ccnxHelper.AddRoute ("5", "/sync", 3, 0);
+ ccnxHelper.AddRoute ("5", "/sync", 4, 0);
+ ccnxHelper.AddRoute ("6", "/sync", 0, 0);
+ ccnxHelper.AddRoute ("6", "/sync", 1, 0);
+ ccnxHelper.AddRoute ("6", "/sync", 2, 0);
+ ccnxHelper.AddRoute ("7", "/sync", 0, 0);
+ ccnxHelper.AddRoute ("7", "/sync", 1, 0);
+ ccnxHelper.AddRoute ("8", "/sync", 0, 0);
+ ccnxHelper.AddRoute ("8", "/sync", 1, 0);
+ ccnxHelper.AddRoute ("8", "/sync", 2, 0);
+ ccnxHelper.AddRoute ("9", "/sync", 0, 0);
+ ccnxHelper.AddRoute ("9", "/sync", 1, 0);
+ ccnxHelper.AddRoute ("9", "/sync", 2, 0);
+ ccnxHelper.AddRoute ("10", "/sync", 0, 0);
+ ccnxHelper.AddRoute ("10", "/sync", 1, 0);
+ ccnxHelper.AddRoute ("10", "/sync", 2, 0);
+ ccnxHelper.AddRoute ("10", "/sync", 3, 0);
+
+ SyncLogicHelper logicHelper;
+ logicHelper.SetPrefix ("/sync");
+ logicHelper.SetCallbacks (OnUpdate, OnRemove);
+ ApplicationContainer apps = logicHelper.Install (NodeContainer (nodes.Get (0), nodes.Get (1)));
+
+ // one data
+ Simulator::ScheduleWithContext (0, Seconds (0.5), &SyncLogic::addLocalNames, DynamicCast<SyncLogic> (apps.Get (0)), "/0", 1, 1);
+
+ // two producers at the same time
+ Simulator::ScheduleWithContext (0, Seconds (1.001), &SyncLogic::addLocalNames, DynamicCast<SyncLogic> (apps.Get (0)), "/0", 1, 2);
+ Simulator::ScheduleWithContext (1, Seconds (1.001), &SyncLogic::addLocalNames, DynamicCast<SyncLogic> (apps.Get (1)), "/1", 1, 2);
+
+ logicHelper.Install (nodes.Get (2)).
+ Start (Seconds (2.001));
+
+ Simulator::Stop (finishTime);
Simulator::Run ();
Simulator::Destroy ();
return 0;
diff --git a/log4cxx.properties b/log4cxx.properties
index 70f885a..23ff104 100644
--- a/log4cxx.properties
+++ b/log4cxx.properties
@@ -11,10 +11,10 @@
#log4j.appender.A1.layout.ConversionPattern=%d{hh:mm:ss,SSS} %-14t %-14c %m%n
log4j.appender.A1.layout.ConversionPattern=%d{ss,SSS} %-12c %m%n
-log4j.logger.SyncLogic = TRACE
+log4j.logger.SyncLogic = DEBUG
#log4j.logger.SyncInterestTable = TRACE
-# log4j.logger.AppDataFetch = TRACE
-# log4j.logger.Test = TRACE
+#log4j.logger.AppDataFetch = TRACE
+log4j.logger.Test = TRACE
#log4j.logger.bgpparser=TRACE
#log4j.logger.bgpparser.AttributeType=ERROR
#log4j.logger.bgpparser.MRTCommonHeader=ERROR
diff --git a/model/sync-diff-state-container.h b/model/sync-diff-state-container.h
index 6e98aa4..2ae7c59 100644
--- a/model/sync-diff-state-container.h
+++ b/model/sync-diff-state-container.h
@@ -33,36 +33,16 @@
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
// #include <boost/multi_index/random_access_index.hpp>
-// #include <boost/multi_index/member.hpp>
+#include <boost/multi_index/member.hpp>
#include <boost/multi_index/mem_fun.hpp>
namespace mi = boost::multi_index;
namespace Sync {
-struct DigestPtrHash : public std::unary_function<Digest, std::size_t>
-{
- std::size_t
- operator() (DigestConstPtr digest) const
- {
- // std::cout << "digest->getHash: " << digest->getHash () << " (" << *digest << ")" << std::endl;
- return digest->getHash ();
- }
-};
-
-struct DigestPtrEqual : public std::unary_function<Digest, std::size_t>
-{
- bool
- operator() (DigestConstPtr digest1, DigestConstPtr digest2) const
- {
- // std::cout << boost::cref(*digest1) << " == " << boost::cref(*digest2) << " : " << (*digest1 == *digest2) << std::endl;
- return *digest1 == *digest2;
- }
-};
-
-
/// @cond include_hidden
struct sequenced { };
+struct timed { };
/// @endcond
/**
diff --git a/model/sync-digest.h b/model/sync-digest.h
index 8982019..97d2fd4 100644
--- a/model/sync-digest.h
+++ b/model/sync-digest.h
@@ -173,6 +173,26 @@
// return *this;
// }
+struct DigestPtrHash : public std::unary_function<Digest, std::size_t>
+{
+ std::size_t
+ operator() (DigestConstPtr digest) const
+ {
+ // std::cout << "digest->getHash: " << digest->getHash () << " (" << *digest << ")" << std::endl;
+ return digest->getHash ();
+ }
+};
+
+struct DigestPtrEqual : public std::unary_function<Digest, std::size_t>
+{
+ bool
+ operator() (DigestConstPtr digest1, DigestConstPtr digest2) const
+ {
+ // std::cout << boost::cref(*digest1) << " == " << boost::cref(*digest2) << " : " << (*digest1 == *digest2) << std::endl;
+ return *digest1 == *digest2;
+ }
+};
+
} // Sync
diff --git a/model/sync-event.h b/model/sync-event.h
new file mode 100644
index 0000000..7808947
--- /dev/null
+++ b/model/sync-event.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Chaoyi Bian <bcy@pku.edu.cn>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef SYNC_EVENT_H
+#define SYNC_EVENT_H
+
+#include <boost/function.hpp>
+
+namespace Sync
+{
+
+typedef boost::function< void ( ) > Event;
+
+} // Sync
+
+#endif // SYNC_EVENT_H
diff --git a/model/sync-full-state.h b/model/sync-full-state.h
index cff1306..c39ec4f 100644
--- a/model/sync-full-state.h
+++ b/model/sync-full-state.h
@@ -37,6 +37,11 @@
namespace Sync {
+class FullState;
+typedef boost::shared_ptr<FullState> FullStatePtr;
+typedef boost::shared_ptr<FullState> FullStateConstPtr;
+
+
/**
* \ingroup sync
* @brief Cumulative SYNC state
diff --git a/model/sync-interest-container.h b/model/sync-interest-container.h
new file mode 100644
index 0000000..b998b18
--- /dev/null
+++ b/model/sync-interest-container.h
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Chaoyi Bian <bcy@pku.edu.cn>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef SYNC_INTEREST_CONTAINER_H
+#define SYNC_INTEREST_CONTAINER_H
+
+#include "sync-digest.h"
+
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/tag.hpp>
+// #include <boost/multi_index/ordered_index.hpp>
+// #include <boost/multi_index/composite_key.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/multi_index/sequenced_index.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+// #include <boost/multi_index/random_access_index.hpp>
+#include <boost/multi_index/member.hpp>
+#include <boost/multi_index/mem_fun.hpp>
+
+namespace mi = boost::multi_index;
+
+namespace Sync {
+
+struct Interest
+{
+ Interest (DigestConstPtr digest, const std::string &name, bool unknown=false)
+ : m_digest (digest)
+ , m_name (name)
+ , m_time (TIME_NOW)
+ , m_unknown (unknown)
+ {
+ }
+
+ DigestConstPtr m_digest;
+ std::string m_name;
+ TimeAbsolute m_time;
+ bool m_unknown;
+};
+
+/// @cond include_hidden
+struct named { };
+struct hashed;
+struct timed;
+/// @endcond
+
+/**
+ * \ingroup sync
+ * @brief Container for interests (application PIT)
+ */
+struct InterestContainer : public mi::multi_index_container<
+ Interest,
+ mi::indexed_by<
+ mi::hashed_unique<
+ mi::tag<named>,
+ BOOST_MULTI_INDEX_MEMBER(Interest, std::string, m_name)
+ >
+ ,
+
+ mi::hashed_non_unique<
+ mi::tag<hashed>,
+ BOOST_MULTI_INDEX_MEMBER(Interest, DigestConstPtr, m_digest),
+ DigestPtrHash,
+ DigestPtrEqual
+ >
+ ,
+
+ mi::ordered_non_unique<
+ mi::tag<timed>,
+ BOOST_MULTI_INDEX_MEMBER(Interest, TimeAbsolute, m_time)
+ >
+ >
+ >
+{
+};
+
+} // Sync
+
+#endif // SYNC_INTEREST_CONTAINER_H
diff --git a/model/sync-interest-table.cc b/model/sync-interest-table.cc
index 7b9ed35..a05dba3 100644
--- a/model/sync-interest-table.cc
+++ b/model/sync-interest-table.cc
@@ -30,9 +30,10 @@
namespace Sync
{
-SyncInterestTable::SyncInterestTable ()
+SyncInterestTable::SyncInterestTable (TimeDuration lifetime)
+ : m_entryLifetime (lifetime)
{
- m_scheduler.schedule (posix_time::seconds (4),
+ m_scheduler.schedule (TIME_SECONDS (m_checkPeriod),
bind (&SyncInterestTable::expireInterests, this),
0);
}
@@ -41,33 +42,36 @@
{
}
-vector<string>
-SyncInterestTable::fetchAll ()
+Interest
+SyncInterestTable::pop ()
{
expireInterests ();
recursive_mutex::scoped_lock lock (m_mutex);
-
- vector<string> entries;
- for (unordered_map<string, time_t>::iterator it = m_table.begin();
- it != m_table.end();
- ++it)
- {
- entries.push_back(it->first);
- }
- m_table.clear ();
- return entries;
+ if (m_table.size () == 0)
+ BOOST_THROW_EXCEPTION (Error::InterestTableIsEmpty ());
+
+ Interest ret = *m_table.begin ();
+ m_table.erase (m_table.begin ());
+
+ return ret;
}
bool
-SyncInterestTable::insert(const string &interest)
+SyncInterestTable::insert (DigestConstPtr digest, const string &name, bool unknownState/*=false*/)
{
+ bool existent = false;
+
recursive_mutex::scoped_lock lock (m_mutex);
- TableContainer::iterator it = m_table.find (interest);
+ InterestContainer::index<named>::type::iterator it = m_table.get<named> ().find (name);
if (it != m_table.end())
- m_table.erase(it);
- time_t currentTime = time(0);
- m_table.insert (make_pair(interest, currentTime));
+ {
+ existent = true;
+ m_table.erase (it);
+ }
+ m_table.insert (Interest (digest, name, unknownState));
+
+ return existent;
}
uint32_t
@@ -78,42 +82,56 @@
}
bool
-SyncInterestTable::remove (const std::string &interest)
+SyncInterestTable::remove (const string &name)
{
recursive_mutex::scoped_lock lock (m_mutex);
- TableContainer::iterator item = m_table.find (interest);
- if (item != m_table.end ())
+
+ InterestContainer::index<named>::type::iterator item = m_table.get<named> ().find (name);
+ if (item != m_table.get<named> ().end ())
{
- m_table.erase (item);
+ m_table.get<named> ().erase (name);
+ return true;
+ }
+
+ return false;
+}
+
+bool
+SyncInterestTable::remove (DigestConstPtr digest)
+{
+ recursive_mutex::scoped_lock lock (m_mutex);
+ InterestContainer::index<hashed>::type::iterator item = m_table.get<hashed> ().find (digest);
+ if (item != m_table.get<hashed> ().end ())
+ {
+ m_table.get<hashed> ().erase (digest); // erase all records associated with the digest
return true;
}
return false;
}
-
void SyncInterestTable::expireInterests ()
{
recursive_mutex::scoped_lock lock (m_mutex);
uint32_t count = 0;
- time_t currentTime = time(0);
- TableContainer::iterator it = m_table.begin ();
- while (it != m_table.end())
+ TimeAbsolute expireTime = TIME_NOW - m_entryLifetime;
+
+ while (m_table.size () > 0)
{
- time_t timestamp = it->second;
- _LOG_DEBUG ("expireInterests (): " << timestamp << ", " << currentTime);
- if (currentTime - timestamp > m_checkPeriod)
- {
- it = m_table.erase (it);
- count ++;
- }
- else
- ++it;
+ InterestContainer::index<timed>::type::iterator item = m_table.get<timed> ().begin ();
+
+ if (item->m_time < expireTime)
+ {
+ m_table.get<timed> ().erase (item);
+ count ++;
+ }
+ else
+ break;
}
_LOG_DEBUG ("expireInterests (): expired " << count);
- m_scheduler.schedule (posix_time::seconds (4),
+ m_scheduler.schedule (TIME_SECONDS (m_checkPeriod),
bind (&SyncInterestTable::expireInterests, this),
0);
}
diff --git a/model/sync-interest-table.h b/model/sync-interest-table.h
index 16119eb..824d1f9 100644
--- a/model/sync-interest-table.h
+++ b/model/sync-interest-table.h
@@ -22,17 +22,19 @@
#ifndef SYNC_INTEREST_TABLE_H
#define SYNC_INTEREST_TABLE_H
+
#include <string>
#include <vector>
-#include <boost/unordered_map.hpp>
-#include <boost/unordered_set.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/thread.hpp>
#include <ctime>
#include "sync-scheduler.h"
+#include "sync-digest.h"
+#include "sync-interest-container.h"
namespace Sync {
+
/**
* \ingroup sync
* @brief A table to keep unanswered Sync Interest
@@ -42,7 +44,7 @@
class SyncInterestTable
{
public:
- SyncInterestTable ();
+ SyncInterestTable (TimeDuration lifetime);
~SyncInterestTable ();
/**
@@ -50,19 +52,25 @@
* timestamp
*/
bool
- insert (const std::string &interest);
+ insert (DigestConstPtr interest, const std::string &name, bool unknownState=false);
/**
- * @brief Remove interest (e.g., when it was satisfied)
+ * @brief Remove interest by digest (e.g., when it was satisfied)
*/
bool
- remove (const std::string &interest);
+ remove (DigestConstPtr interest);
/**
- * @brief fetch all Interests and clear the table
+ * @brief Remove interest by name (e.g., when it was satisfied)
*/
- std::vector<std::string>
- fetchAll ();
+ bool
+ remove (const std::string &name);
+
+ /**
+ * @brief pop a non-expired Interest from PIT
+ */
+ Interest
+ pop ();
uint32_t
size () const;
@@ -75,15 +83,20 @@
expireInterests ();
private:
- typedef boost::unordered_map<std::string, time_t> TableContainer;
-
- static const int m_checkPeriod = 4;
- TableContainer m_table; // pit entries
+ static const int m_checkPeriod = 4; // seconds
+
+ TimeDuration m_entryLifetime;
+ InterestContainer m_table;
Scheduler m_scheduler;
mutable boost::recursive_mutex m_mutex;
};
+namespace Error {
+struct InterestTableIsEmpty : virtual boost::exception, virtual std::exception { };
+}
+
+
} // Sync
#endif // SYNC_INTEREST_TABLE_H
diff --git a/model/sync-logic.cc b/model/sync-logic.cc
index 6d56764..3bae752 100644
--- a/model/sync-logic.cc
+++ b/model/sync-logic.cc
@@ -20,6 +20,11 @@
* Alexander Afanasyev <alexander.afanasyev@ucla.edu>
*/
+#ifdef NS3_MODULE
+#include <ns3/ccnx-pit.h>
+#include <ns3/ccnx.h>
+#endif
+
#include "sync-logic.h"
#include "sync-diff-leaf.h"
#include "sync-full-leaf.h"
@@ -28,7 +33,6 @@
#include <boost/make_shared.hpp>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
-#include <boost/date_time/posix_time/posix_time.hpp>
#include <vector>
using namespace std;
@@ -36,103 +40,190 @@
INIT_LOGGER ("SyncLogic");
+#ifdef NS3_MODULE
+#define GET_RANDOM(var) var.GetValue ()
+#else
+#define GET_RANDOM(var) var ()
+#endif
+
+#define TIME_SECONDS_WITH_JITTER(sec) \
+ (TIME_SECONDS (sec) + TIME_MILLISECONDS (GET_RANDOM (m_reexpressionJitter)))
+
+#define TIME_MILLISECONDS_WITH_JITTER(ms) \
+ (TIME_MILLISECONDS (ms) + TIME_MILLISECONDS (GET_RANDOM (m_reexpressionJitter)))
+
+
namespace Sync
{
SyncLogic::SyncLogic (const std::string &syncPrefix,
LogicUpdateCallback onUpdate,
LogicRemoveCallback onRemove)
- : m_syncPrefix (syncPrefix)
+ : m_state (new FullState)
+ , m_syncInterestTable (TIME_SECONDS (m_syncInterestReexpress))
+ , m_syncPrefix (syncPrefix)
, m_onUpdate (onUpdate)
, m_onRemove (onRemove)
, m_ccnxHandle(new CcnxWrapper())
+ , m_recoveryRetransmissionInterval (m_defaultRecoveryRetransmitInterval)
+#ifndef NS3_MODULE
, m_randomGenerator (static_cast<unsigned int> (std::time (0)))
- , m_rangeUniformRandom (m_randomGenerator, uniform_int<> (20,80))
-{
-#ifdef _DEBUG
-#ifdef HAVE_LOG4CXX
- // _LOG_FUNCTION (syncPrefix);
- static int id = 0;
- staticModuleLogger = log4cxx::Logger::getLogger ("SyncLogic." + lexical_cast<string> (id));
- id ++;
+ , m_rangeUniformRandom (m_randomGenerator, uniform_int<> (200,1000))
+ , m_reexpressionJitter (m_randomGenerator, uniform_int<> (100,500))
+#else
+ , m_rangeUniformRandom (200,1000)
+ , m_reexpressionJitter (10,500)
#endif
-#endif
+{
+#ifndef NS3_MODULE
+ // In NS3 module these functions are moved to StartApplication method
m_ccnxHandle->setInterestFilter (m_syncPrefix,
bind (&SyncLogic::respondSyncInterest, this, _1));
- m_scheduler.schedule (posix_time::seconds (0),
+ m_scheduler.schedule (TIME_SECONDS (0), // no need to add jitter
bind (&SyncLogic::sendSyncInterest, this),
REEXPRESSING_INTEREST);
+#endif
}
SyncLogic::~SyncLogic ()
{
- // _LOG_FUNCTION (this);
- // cout << "SyncLogic::~SyncLogic ()" << endl;
-
m_ccnxHandle.reset ();
}
+#ifdef NS3_MODULE
void
-SyncLogic::respondSyncInterest (const string &interest)
+SyncLogic::StartApplication ()
{
- _LOG_TRACE ("<< I " << interest);
- //cout << "Respond Sync Interest" << endl;
- string hash = interest.substr(interest.find_last_of("/") + 1);
- // cout << "Received Sync Interest: " << hash << endl;
-
- DigestPtr digest = make_shared<Digest> ();
- try
- {
- istringstream is (hash);
- is >> *digest;
- }
- catch (Error::DigestCalculationError &e)
- {
- // log error. ignoring it for now, later we should log it
- return;
- }
+ m_ccnxHandle->SetNode (GetNode ());
+ m_ccnxHandle->StartApplication ();
- processSyncInterest (digest, interest, false);
+ m_ccnxHandle->setInterestFilter (m_syncPrefix,
+ bind (&SyncLogic::respondSyncInterest, this, _1));
+
+ m_scheduler.schedule (TIME_SECONDS (0), // need to send first interests at exactly the same time
+ bind (&SyncLogic::sendSyncInterest, this),
+ REEXPRESSING_INTEREST);
}
void
-SyncLogic::processSyncInterest (DigestConstPtr digest, const std::string &interestName, bool timedProcessing/*=false*/)
+SyncLogic::StopApplication ()
+{
+ m_ccnxHandle->clearInterestFilter (m_syncPrefix);
+ m_ccnxHandle->StopApplication ();
+ m_scheduler.cancel (REEXPRESSING_INTEREST);
+ m_scheduler.cancel (DELAYED_INTEREST_PROCESSING);
+}
+#endif
+
+/**
+ * Two types of intersts
+ *
+ * Normal name: .../<hash>
+ * Recovery name: .../recovery/<hash>
+ */
+boost::tuple<DigestConstPtr, std::string>
+SyncLogic::convertNameToDigestAndType (const std::string &name)
+{
+ BOOST_ASSERT (name.find (m_syncPrefix) == 0);
+
+ string hash = name.substr (m_syncPrefix.size (), name.size ()-m_syncPrefix.size ());
+ if (hash[0] == '/')
+ hash = hash.substr (1, hash.size ()-1);
+ string interestType = "normal";
+
+ size_t pos = hash.find ('/');
+ if (pos != string::npos)
+ {
+ interestType = hash.substr (0, pos);
+ hash = hash.substr (pos + 1);
+ }
+
+ _LOG_TRACE (hash << ", " << interestType);
+
+ DigestPtr digest = make_shared<Digest> ();
+ istringstream is (hash);
+ is >> *digest;
+
+ return make_tuple (digest, interestType);
+}
+
+void
+SyncLogic::respondSyncInterest (const string &name)
+{
+ try
+ {
+ _LOG_TRACE ("<< I " << name);
+
+ DigestConstPtr digest;
+ string type;
+ tie (digest, type) = convertNameToDigestAndType (name);
+
+ if (type == "normal") // kind of ineffective...
+ {
+ processSyncInterest (name, digest);
+ }
+ else if (type == "recovery")
+ {
+ processSyncRecoveryInterest (name, digest);
+ }
+ }
+ catch (Error::DigestCalculationError &e)
+ {
+ _LOG_TRACE ("Something fishy happened...");
+ // log error. ignoring it for now, later we should log it
+ return ;
+ }
+}
+
+void
+SyncLogic::respondSyncData (const std::string &name, const std::string &dataBuffer)
+{
+ try
+ {
+ _LOG_TRACE ("<< D " << name);
+
+ DigestConstPtr digest;
+ string type;
+ tie (digest, type) = convertNameToDigestAndType (name);
+
+ if (type == "normal")
+ {
+ processSyncData (name, digest, dataBuffer);
+ }
+ else
+ {
+ // timer is always restarted when we schedule recovery
+ m_scheduler.cancel (REEXPRESSING_RECOVERY_INTEREST);
+ processSyncData (name, digest, dataBuffer);
+ }
+ }
+ catch (Error::DigestCalculationError &e)
+ {
+ _LOG_TRACE ("Something fishy happened...");
+ // log error. ignoring it for now, later we should log it
+ return;
+ }
+}
+
+
+void
+SyncLogic::processSyncInterest (const std::string &name, DigestConstPtr digest, bool timedProcessing/*=false*/)
{
recursive_mutex::scoped_lock lock (m_stateMutex);
// Special case when state is not empty and we have received request with zero-root digest
- if (digest->isZero () && !m_state.getDigest()->isZero ())
+ if (digest->isZero () && !m_state->getDigest()->isZero ())
{
- _LOG_TRACE (">> D " << interestName << "/state" << " (zero)");
-
- m_syncInterestTable.remove (interestName + "/state");
- m_ccnxHandle->publishData (interestName + "/state",
- lexical_cast<string> (m_state),
- m_syncResponseFreshness);
- if (m_outstandingInterest == interestName)
- {
- m_scheduler.schedule (posix_time::seconds (0),
- bind (&SyncLogic::sendSyncInterest, this),
- REEXPRESSING_INTEREST);
- }
+ sendSyncData (name, digest, m_state);
return;
}
- if (*m_state.getDigest() == *digest)
+ if (*m_state->getDigest() == *digest)
{
- // cout << interestName << "\n";
- if (digest->isZero ())
- {
- _LOG_TRACE ("processSyncInterest (): Digest is zero, adding /state to PIT");
- m_syncInterestTable.insert (interestName + "/state");
- }
- else
- {
- _LOG_TRACE ("processSyncInterest (): Same state. Adding to PIT");
- m_syncInterestTable.insert (interestName);
- }
+ _LOG_TRACE ("processSyncInterest (): Same state. Adding to PIT");
+ m_syncInterestTable.insert (digest, name, false);
return;
}
@@ -141,82 +232,67 @@
if (stateInDiffLog != m_log.end ())
{
DiffStateConstPtr stateDiff = (*stateInDiffLog)->diff ();
- // string state = lexical_cast<string> (*stateDiff);
- // erase_all (state, "\n");
- // _LOG_TRACE (">> D " << interestName << ", state: " << state);
- // _LOG_DEBUG ("Log size: " << m_log.size ());
- // BOOST_FOREACH (DiffStateConstPtr ds, m_log.get<sequenced> ())
- // {
- // string state = lexical_cast<string> (*ds);
- // erase_all (state, "\n");
- // _LOG_DEBUG (" " << state << ", " << *ds->getDigest ());
- // }
-
- m_syncInterestTable.remove (interestName);
- m_ccnxHandle->publishData (interestName,
- lexical_cast<string> (*stateDiff),
- m_syncResponseFreshness);
- if (m_outstandingInterest == interestName)
- {
- m_scheduler.schedule (posix_time::seconds (0),
- bind (&SyncLogic::sendSyncInterest, this),
- REEXPRESSING_INTEREST);
- }
+ sendSyncData (name, digest, stateDiff);
return;
}
if (!timedProcessing)
{
- m_scheduler.schedule (posix_time::milliseconds (m_rangeUniformRandom ()) /*from 20 to 100ms*/,
- bind (&SyncLogic::processSyncInterest, this, digest, interestName, true),
+ bool exists = m_syncInterestTable.insert (digest, name, true);
+ if (exists) // somebody else replied, so restart random-game timer
+ {
+ _LOG_DEBUG ("Unknown digest, but somebody may have already replied, so restart our timer");
+ m_scheduler.cancel (DELAYED_INTEREST_PROCESSING);
+ }
+
+ uint32_t waitDelay = GET_RANDOM (m_rangeUniformRandom);
+ _LOG_DEBUG ("Digest is not in the log. Schedule processing after small delay: " << waitDelay << "ms");
+
+ m_scheduler.schedule (TIME_MILLISECONDS (waitDelay),
+ bind (&SyncLogic::processSyncInterest, this, name, digest, true),
DELAYED_INTEREST_PROCESSING);
-
}
else
{
- _LOG_TRACE (">> D " << interestName << "/state" << " (timed processing)");
-
- m_syncInterestTable.remove (interestName + "/state");
- m_ccnxHandle->publishData (interestName + "/state",
- lexical_cast<string> (m_state),
- m_syncResponseFreshness);
-
- if (m_outstandingInterest == interestName)
- {
- m_scheduler.schedule (posix_time::seconds (0),
- bind (&SyncLogic::sendSyncInterest, this),
- REEXPRESSING_INTEREST);
- }
+ _LOG_TRACE (" (timed processing)");
+
+ m_recoveryRetransmissionInterval = m_defaultRecoveryRetransmitInterval;
+ sendSyncRecoveryInterests (digest);
}
}
void
-SyncLogic::processSyncData (const string &name, const string &dataBuffer)
+SyncLogic::processSyncData (const std::string &name, DigestConstPtr digest, const string &dataBuffer)
{
- _LOG_TRACE ("<< D " << name);
DiffStatePtr diffLog = make_shared<DiffState> ();
+ bool ownInterestSatisfied = false;
try
{
recursive_mutex::scoped_lock lock (m_stateMutex);
-
- string last = name.substr(name.find_last_of("/") + 1);
- istringstream ss (dataBuffer);
- if (last == "state")
+ m_syncInterestTable.remove (name); // Remove satisfied interest from PIT
+
+ ownInterestSatisfied = (name == m_outstandingInterestName);
+
+ DiffState diff;
+ istringstream ss (dataBuffer);
+ ss >> diff;
+ BOOST_FOREACH (LeafConstPtr leaf, diff.getLeaves().get<ordered>())
{
- FullState full;
- ss >> full;
- BOOST_FOREACH (LeafConstPtr leaf, full.getLeaves()) // order doesn't matter
+ DiffLeafConstPtr diffLeaf = dynamic_pointer_cast<const DiffLeaf> (leaf);
+ BOOST_ASSERT (diffLeaf != 0);
+
+ NameInfoConstPtr info = diffLeaf->getInfo();
+ if (diffLeaf->getOperation() == UPDATE)
{
- NameInfoConstPtr info = leaf->getInfo ();
- SeqNo seq = leaf->getSeq ();
+ SeqNo seq = diffLeaf->getSeq();
bool inserted = false;
bool updated = false;
SeqNo oldSeq;
- tie (inserted, updated, oldSeq) = m_state.update (info, seq);
+ tie (inserted, updated, oldSeq) = m_state->update (info, seq);
if (inserted || updated)
{
@@ -224,44 +300,17 @@
m_onUpdate (info->toString (), seq, oldSeq);
}
}
- }
- else
- {
- DiffState diff;
- ss >> diff;
- BOOST_FOREACH (LeafConstPtr leaf, diff.getLeaves().get<ordered>())
+ else if (diffLeaf->getOperation() == REMOVE)
{
- DiffLeafConstPtr diffLeaf = dynamic_pointer_cast<const DiffLeaf> (leaf);
- BOOST_ASSERT (diffLeaf != 0);
-
- NameInfoConstPtr info = diffLeaf->getInfo();
- if (diffLeaf->getOperation() == UPDATE)
+ if (m_state->remove (info))
{
- SeqNo seq = diffLeaf->getSeq();
-
- bool inserted = false;
- bool updated = false;
- SeqNo oldSeq;
- tie (inserted, updated, oldSeq) = m_state.update (info, seq);
-
- if (inserted || updated)
- {
- diffLog->update (info, seq);
- m_onUpdate (info->toString (), seq, oldSeq);
- }
+ diffLog->remove (info);
+ m_onRemove (info->toString ());
}
- else if (diffLeaf->getOperation() == REMOVE)
- {
- if (m_state.remove (info))
- {
- diffLog->remove (info);
- m_onRemove (info->toString ());
- }
- }
- else
- {
- BOOST_ASSERT (false); // just in case
- }
+ }
+ else
+ {
+ BOOST_ASSERT (false); // just in case
}
}
@@ -269,75 +318,95 @@
}
catch (Error::SyncXmlDecodingFailure &e)
{
+ _LOG_TRACE ("Something really fishy happened during state decoding " <<
+ diagnostic_information (e));
diffLog.reset ();
// don't do anything
}
- // if state has changed, then it is safe to express a new interest
- if (diffLog->getLeaves ().size () > 0)
+ if ((diffLog != 0 && diffLog->getLeaves ().size () > 0) ||
+ ownInterestSatisfied)
{
- m_scheduler.schedule (posix_time::seconds (0),
- bind (&SyncLogic::sendSyncInterest, this),
- REEXPRESSING_INTEREST);
- }
- else
- {
- // should not reexpress the same interest. Need at least wait for data lifetime
- // Otherwise we will get immediate reply from the local daemon and there will be 100% utilization
+ // Do it only if everything went fine and state changed
+
+ // this is kind of wrong
+ // satisfyPendingSyncInterests (diffLog); // if there are interests in PIT, there is a point to satisfy them using new state
+
+ // if state has changed, then it is safe to express a new interest
m_scheduler.cancel (REEXPRESSING_INTEREST);
- // m_scheduler.schedule (posix_time::seconds (0),
- m_scheduler.schedule (posix_time::seconds (m_syncResponseFreshness) + posix_time::milliseconds (1),
+ m_scheduler.schedule (TIME_SECONDS_WITH_JITTER (0),
bind (&SyncLogic::sendSyncInterest, this),
REEXPRESSING_INTEREST);
}
}
void
-SyncLogic::satisfyPendingSyncInterests (DiffStatePtr diffLog)
+SyncLogic::processSyncRecoveryInterest (const std::string &name, DigestConstPtr digest)
{
- vector<string> pis = m_syncInterestTable.fetchAll ();
- if (pis.size () > 0)
+ recursive_mutex::scoped_lock lock (m_stateMutex);
+
+ DiffStateContainer::iterator stateInDiffLog = m_log.find (digest);
+
+ if (stateInDiffLog == m_log.end ())
{
- stringstream ss;
- ss << *diffLog;
- bool satisfiedOwnInterest = false;
-
- for (vector<string>::iterator ii = pis.begin(); ii != pis.end(); ++ii)
- {
- _LOG_TRACE (">> D " << *ii);
- m_ccnxHandle->publishData (*ii, ss.str(), m_syncResponseFreshness);
+ _LOG_TRACE ("Could not find " << *digest << " in digest log");
+ return;
+ }
- {
- recursive_mutex::scoped_lock lock (m_stateMutex);
- // _LOG_DEBUG (*ii << " == " << m_outstandingInterest << " = " << (*ii == m_outstandingInterest));
- satisfiedOwnInterest = satisfiedOwnInterest || (*ii == m_outstandingInterest) || (*ii == (m_outstandingInterest + "/state"));
- }
- }
+ sendSyncData (name, digest, m_state);
+}
- if (satisfiedOwnInterest)
+void
+SyncLogic::satisfyPendingSyncInterests (DiffStateConstPtr diffLog)
+{
+ DiffStatePtr fullStateLog = make_shared<DiffState> ();
+ {
+ recursive_mutex::scoped_lock lock (m_stateMutex);
+ BOOST_FOREACH (LeafConstPtr leaf, m_state->getLeaves ()/*.get<timed> ()*/)
+ {
+ fullStateLog->update (leaf->getInfo (), leaf->getSeq ());
+ /// @todo Impose limit on how many state info should be send out
+ }
+ }
+
+ try
+ {
+ uint32_t counter = 0;
+ while (m_syncInterestTable.size () > 0)
{
- _LOG_DEBUG ("Have satisfied our own interest. Scheduling interest reexpression");
- // we need to reexpress interest only if we satisfied our own interest
- m_scheduler.schedule (posix_time::milliseconds (0),
- bind (&SyncLogic::sendSyncInterest, this),
- REEXPRESSING_INTEREST);
+ Interest interest = m_syncInterestTable.pop ();
+
+ if (!interest.m_unknown)
+ {
+ _LOG_TRACE (">> D " << interest.m_name);
+ sendSyncData (interest.m_name, interest.m_digest, diffLog);
+ }
+ else
+ {
+ _LOG_TRACE (">> D (unknown)" << interest.m_name);
+ sendSyncData (interest.m_name, interest.m_digest, fullStateLog);
+ }
+ counter ++;
}
+ _LOG_DEBUG ("Satisfied " << counter << " pending interests");
+ }
+ catch (Error::InterestTableIsEmpty &e)
+ {
+ // ok. not really an error
}
}
void
SyncLogic::insertToDiffLog (DiffStatePtr diffLog)
{
- //cout << "Process Pending Interests" <<endl;
- diffLog->setDigest (m_state.getDigest());
+ diffLog->setDigest (m_state->getDigest());
if (m_log.size () > 0)
{
m_log.get<sequenced> ().front ()->setNext (diffLog);
}
- m_log.erase (m_state.getDigest()); // remove diff state with the same digest. next pointers are still valid
+ m_log.erase (m_state->getDigest()); // remove diff state with the same digest. next pointers are still valid
/// @todo Optimization
m_log.get<sequenced> ().push_front (diffLog);
- // _LOG_DEBUG (*diffLog->getDigest () << " " << m_log.size ());
}
void
@@ -349,10 +418,12 @@
recursive_mutex::scoped_lock lock (m_stateMutex);
NameInfoConstPtr info = StdNameInfo::FindOrCreate(prefix);
- SeqNo seqN (session, seq);
- m_state.update(info, seqN);
+ _LOG_DEBUG ("addLocalNames (): old state " << *m_state->getDigest ());
- _LOG_DEBUG ("addLocalNames (): new state " << *m_state.getDigest ());
+ SeqNo seqN (session, seq);
+ m_state->update(info, seqN);
+
+ _LOG_DEBUG ("addLocalNames (): new state " << *m_state->getDigest ());
diff = make_shared<DiffState>();
diff->update(info, seqN);
@@ -370,7 +441,7 @@
{
recursive_mutex::scoped_lock lock (m_stateMutex);
NameInfoConstPtr info = StdNameInfo::FindOrCreate(prefix);
- m_state.remove(info);
+ m_state->remove(info);
diff = make_shared<DiffState>();
diff->remove(info);
@@ -387,23 +458,71 @@
ostringstream os;
{
- // cout << "Sending Sync Interest" << endl;
recursive_mutex::scoped_lock lock (m_stateMutex);
- os << m_syncPrefix << "/" << *m_state.getDigest();
-
+ os << m_syncPrefix << "/" << *m_state->getDigest();
+ m_outstandingInterestName = os.str ();
_LOG_TRACE (">> I " << os.str ());
-
- m_outstandingInterest = os.str ();
}
-
- m_ccnxHandle->sendInterest (os.str (),
- bind (&SyncLogic::processSyncData, this, _1, _2));
m_scheduler.cancel (REEXPRESSING_INTEREST);
- m_scheduler.schedule (posix_time::seconds (4),
+ m_scheduler.schedule (TIME_SECONDS_WITH_JITTER (m_syncInterestReexpress),
bind (&SyncLogic::sendSyncInterest, this),
REEXPRESSING_INTEREST);
+
+ m_ccnxHandle->sendInterest (os.str (),
+ bind (&SyncLogic::respondSyncData, this, _1, _2));
}
+void
+SyncLogic::sendSyncRecoveryInterests (DigestConstPtr digest)
+{
+ ostringstream os;
+ os << m_syncPrefix << "/recovery/" << *digest;
+ _LOG_TRACE (">> I " << os.str ());
+
+ TimeDuration nextRetransmission = TIME_MILLISECONDS_WITH_JITTER (m_recoveryRetransmissionInterval);
+ m_recoveryRetransmissionInterval <<= 1;
+
+ m_scheduler.cancel (REEXPRESSING_RECOVERY_INTEREST);
+ if (m_recoveryRetransmissionInterval < 100*1000) // <100 seconds
+ {
+ m_scheduler.schedule (nextRetransmission,
+ bind (&SyncLogic::sendSyncRecoveryInterests, this, digest),
+ REEXPRESSING_RECOVERY_INTEREST);
+ }
+
+ m_ccnxHandle->sendInterest (os.str (),
+ bind (&SyncLogic::respondSyncData, this, _1, _2));
+}
+
+
+void
+SyncLogic::sendSyncData (const std::string &name, DigestConstPtr digest, StateConstPtr state)
+{
+ _LOG_TRACE (">> D " << name);
+ // sending
+ m_ccnxHandle->publishData (name,
+ lexical_cast<string> (*state),
+ m_syncResponseFreshness); // in NS-3 it doesn't have any effect... yet
+
+ // checking if our own interest got satisfied
+ bool satisfiedOwnInterest = false;
+ {
+ recursive_mutex::scoped_lock lock (m_stateMutex);
+ satisfiedOwnInterest = (m_outstandingInterestName == name);
+ }
+
+ if (satisfiedOwnInterest)
+ {
+ _LOG_TRACE ("Satisfied our own Interest. Re-expressing (hopefully with a new digest)");
+
+ m_scheduler.cancel (REEXPRESSING_INTEREST);
+ m_scheduler.schedule (TIME_SECONDS_WITH_JITTER (0),
+ bind (&SyncLogic::sendSyncInterest, this),
+ REEXPRESSING_INTEREST);
+ }
+}
+
+
}
diff --git a/model/sync-logic.h b/model/sync-logic.h
index ad0a208..e205fc0 100644
--- a/model/sync-logic.h
+++ b/model/sync-logic.h
@@ -43,6 +43,11 @@
#endif
#endif
+#ifdef NS3_MODULE
+#include <ns3/application.h>
+#include <ns3/random-variable.h>
+#endif
+
namespace Sync {
/**
@@ -51,6 +56,9 @@
* interests and data)
*/
class SyncLogic
+#ifdef NS3_MODULE
+ : public ns3::Application
+#endif
{
public:
typedef boost::function< void ( const std::string &/*prefix*/, const SeqNo &/*newSeq*/, const SeqNo &/*oldSeq*/ ) > LogicUpdateCallback;
@@ -86,7 +94,7 @@
* @param name the data name
* @param dataBuffer the sync data
*/
- void processSyncData (const std::string &name, const std::string &dataBuffer);
+ void respondSyncData (const std::string &name, const std::string &dataBuffer);
/**
* @brief remove a participant's subtree from the sync tree
@@ -98,29 +106,54 @@
Scheduler &
getScheduler () { return m_scheduler; }
#endif
+
+#ifdef NS3_MODULE
+public:
+ virtual void StartApplication ();
+ virtual void StopApplication ();
+#endif
private:
void
delayedChecksLoop ();
void
- processSyncInterest (DigestConstPtr digest, const std::string &interestname, bool timedProcessing=false);
+ processSyncInterest (const std::string &name,
+ DigestConstPtr digest, bool timedProcessing=false);
+
+ void
+ processSyncData (const std::string &name,
+ DigestConstPtr digest, const std::string &dataBuffer);
void
- sendSyncInterest ();
-
+ processSyncRecoveryInterest (const std::string &name,
+ DigestConstPtr digest);
+
void
insertToDiffLog (DiffStatePtr diff);
void
- satisfyPendingSyncInterests (DiffStatePtr diff);
+ satisfyPendingSyncInterests (DiffStateConstPtr diff);
+ boost::tuple<DigestConstPtr, std::string>
+ convertNameToDigestAndType (const std::string &name);
+
+ void
+ sendSyncInterest ();
+
+ void
+ sendSyncRecoveryInterests (DigestConstPtr digest);
+
+ void
+ sendSyncData (const std::string &name,
+ DigestConstPtr digest, StateConstPtr state);
+
private:
- FullState m_state;
+ FullStatePtr m_state;
DiffStateContainer m_log;
boost::recursive_mutex m_stateMutex;
- std::string m_outstandingInterest;
+ std::string m_outstandingInterestName;
SyncInterestTable m_syncInterestTable;
std::string m_syncPrefix;
@@ -130,22 +163,34 @@
Scheduler m_scheduler;
+#ifndef NS3_MODULE
boost::mt19937 m_randomGenerator;
boost::variate_generator<boost::mt19937&, boost::uniform_int<> > m_rangeUniformRandom;
-
- static const int m_syncResponseFreshness = 2;
+ boost::variate_generator<boost::mt19937&, boost::uniform_int<> > m_reexpressionJitter;
+#else
+ ns3::UniformVariable m_rangeUniformRandom;
+ ns3::UniformVariable m_reexpressionJitter;
+#endif
+ static const int m_unknownDigestStoreTime = 10; // seconds
+#ifdef NS3_MODULE
+ static const int m_syncResponseFreshness = 100; // milliseconds
+ static const int m_syncInterestReexpress = 10; // seconds
+ // don't forget to adjust value in SyncCcnxWrapper
+#else
+ static const int m_syncResponseFreshness = 2000;
+ static const int m_syncInterestReexpress = 4;
+#endif
+
+ static const int m_defaultRecoveryRetransmitInterval = 200; // milliseconds
+ uint32_t m_recoveryRetransmissionInterval; // milliseconds
+
enum EventLabels
{
DELAYED_INTEREST_PROCESSING = 1,
- REEXPRESSING_INTEREST = 2
+ REEXPRESSING_INTEREST = 2,
+ REEXPRESSING_RECOVERY_INTEREST = 3
};
-
-#ifdef _DEBUG
-#ifdef HAVE_LOG4CXX
- log4cxx::LoggerPtr staticModuleLogger;
-#endif
-#endif
};
diff --git a/model/sync-state.h b/model/sync-state.h
index faaad02..826e84d 100644
--- a/model/sync-state.h
+++ b/model/sync-state.h
@@ -34,6 +34,10 @@
*/
namespace Sync {
+class State;
+typedef boost::shared_ptr<State> StatePtr;
+typedef boost::shared_ptr<State> StateConstPtr;
+
/**
* \ingroup sync
* @brief Container for state leaves and definition of the abstract interface to work with State objects
diff --git a/ns3/sync-ccnx-wrapper.cc b/ns3/sync-ccnx-wrapper.cc
new file mode 100644
index 0000000..d0e769a
--- /dev/null
+++ b/ns3/sync-ccnx-wrapper.cc
@@ -0,0 +1,263 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Chaoyi Bian <bcy@pku.edu.cn>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "sync-ccnx-wrapper.h"
+#include "sync-log.h"
+#include <boost/throw_exception.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/lambda/lambda.hpp>
+#include <boost/lambda/bind.hpp>
+
+namespace ll = boost::lambda;
+
+#include "../evaluation/type-tag.h"
+
+#include <ns3/ccnx-name-components.h>
+#include <ns3/ccnx-interest-header.h>
+#include <ns3/ccnx-content-object-header.h>
+#include <ns3/ccnx-face.h>
+#include <ns3/packet.h>
+#include <ns3/ccnx-fib.h>
+
+typedef boost::error_info<struct tag_errmsg, std::string> errmsg_info_str;
+typedef boost::error_info<struct tag_errmsg, int> errmsg_info_int;
+
+using namespace std;
+using namespace boost;
+using namespace ns3;
+
+INIT_LOGGER ("CcnxWrapper");
+
+namespace Sync {
+
+CcnxWrapper::CcnxWrapper()
+ : m_rand (0, std::numeric_limits<uint32_t>::max ())
+{
+}
+
+CcnxWrapper::~CcnxWrapper()
+{
+}
+
+void
+CcnxWrapper::StartApplication ()
+{
+ CcnxApp::StartApplication ();
+}
+
+void
+CcnxWrapper::StopApplication ()
+{
+ CcnxApp::StopApplication ();
+}
+
+int
+CcnxWrapper::publishData (const string &dataName, const string &dataBuffer, int freshness)
+{
+ // NS_LOG_INFO ("Requesting Interest: \n" << interestHeader);
+ _LOG_INFO ("> Data for " << dataName);
+
+ Ptr<CcnxNameComponents> name = Create<CcnxNameComponents> ();
+ istringstream is (dataName);
+ is >> *name;
+
+ static CcnxContentObjectTail trailer;
+
+ CcnxContentObjectHeader data;
+ data.SetName (name);
+ data.SetFreshness (Seconds (freshness));
+
+ Ptr<Packet> packet = Create<Packet> (reinterpret_cast<const uint8_t*> (dataBuffer.c_str ()), dataBuffer.size ());
+ packet->AddPacketTag (CreateObject<TypeTag> (TypeTag::DATA));
+ packet->AddHeader (data);
+ packet->AddTrailer (trailer);
+
+ m_protocolHandler (packet);
+
+ m_transmittedContentObjects (&data, packet, this, m_face);
+
+ return 0;
+}
+
+int CcnxWrapper::sendInterest (const string &strInterest, const DataCallback &dataCallback)
+{
+ // NS_LOG_INFO ("Requesting Interest: \n" << interestHeader);
+ _LOG_INFO ("> Interest for " << strInterest);
+
+ Ptr<CcnxNameComponents> name = Create<CcnxNameComponents> ();
+ istringstream is (strInterest);
+ is >> *name;
+
+ CcnxInterestHeader interestHeader;
+ uint32_t nonce = m_rand.GetValue ();
+ _LOG_DEBUG ("Nonce: " << nonce);
+ interestHeader.SetNonce (nonce);
+ interestHeader.SetName (name);
+ interestHeader.SetInterestLifetime (Seconds (9.9)); // really long-lived interests
+
+ Ptr<Packet> packet = Create<Packet> ();
+ packet->AddPacketTag (CreateObject<TypeTag> (TypeTag::INTEREST));
+ packet->AddHeader (interestHeader);
+
+ // NS_LOG_DEBUG (interestHeader);
+
+ m_protocolHandler (packet);
+
+ m_transmittedInterests (&interestHeader, this, m_face);
+
+ // Record the callback
+ CcnxFilterEntryContainer<DataCallback>::type::iterator entry = m_dataCallbacks.find (*name);
+ if (entry == m_dataCallbacks.end ())
+ {
+ pair<CcnxFilterEntryContainer<DataCallback>::type::iterator, bool> status =
+ m_dataCallbacks.insert (CcnxFilterEntry<DataCallback> (name));
+
+ entry = status.first;
+ }
+ m_dataCallbacks.modify (entry, ll::bind (&CcnxFilterEntry<DataCallback>::AddCallback, ll::_1, dataCallback));
+
+ return 0;
+}
+
+int CcnxWrapper::setInterestFilter (const string &prefix, const InterestCallback &interestCallback)
+{
+ Ptr<CcnxNameComponents> name = Create<CcnxNameComponents> ();
+ istringstream is (prefix);
+ is >> *name;
+
+ CcnxFilterEntryContainer<InterestCallback>::type::iterator entry = m_interestCallbacks.find (*name);
+ if (entry == m_interestCallbacks.end ())
+ {
+ pair<CcnxFilterEntryContainer<InterestCallback>::type::iterator, bool> status =
+ m_interestCallbacks.insert (CcnxFilterEntry<InterestCallback> (name));
+
+ entry = status.first;
+ }
+
+ m_interestCallbacks.modify (entry, ll::bind (&CcnxFilterEntry<InterestCallback>::AddCallback, ll::_1, interestCallback));
+
+ // creating actual face
+
+ Ptr<CcnxFib> fib = GetNode ()->GetObject<CcnxFib> ();
+ CcnxFibEntryContainer::type::iterator fibEntry = fib->Add (*name, m_face, 0);
+
+ // make face green, so it will be used primarily
+ fib->m_fib.modify (fibEntry,
+ ll::bind (&CcnxFibEntry::UpdateStatus,
+ ll::_1, m_face, CcnxFibFaceMetric::NDN_FIB_GREEN));
+
+ return 0;
+}
+
+void
+CcnxWrapper::clearInterestFilter (const std::string &prefix)
+{
+ Ptr<CcnxNameComponents> name = Create<CcnxNameComponents> ();
+ istringstream is (prefix);
+ is >> *name;
+
+ CcnxFilterEntryContainer<InterestCallback>::type::iterator entry = m_interestCallbacks.find (*name);
+ if (entry == m_interestCallbacks.end ())
+ return;
+
+ m_interestCallbacks.modify (entry, ll::bind (&CcnxFilterEntry<InterestCallback>::ClearCallback, ll::_1));
+}
+
+CcnxFilterEntryContainer<CcnxWrapper::InterestCallback>::type::iterator
+CcnxWrapper::InterestCallbackLookup (const ns3::CcnxNameComponents &name)
+{
+ CcnxFilterEntryContainer<InterestCallback>::type::iterator entry = m_interestCallbacks.end ();
+
+ // do the longest prefix match
+ for (size_t componentsCount = name.GetComponents ().size ()+1;
+ componentsCount > 0;
+ componentsCount--)
+ {
+ CcnxNameComponents subPrefix (name.GetSubComponents (componentsCount-1));
+
+ entry = m_interestCallbacks.find (subPrefix);
+ if (entry != m_interestCallbacks.end())
+ return entry;
+ }
+
+ return entry;
+}
+
+CcnxFilterEntryContainer<CcnxWrapper::DataCallback>::type::iterator
+CcnxWrapper::DataCallbackLookup (const ns3::CcnxNameComponents &name)
+{
+ CcnxFilterEntryContainer<DataCallback>::type::iterator entry = m_dataCallbacks.end ();
+
+ // do the longest prefix match
+ for (size_t componentsCount = name.GetComponents ().size ()+1;
+ componentsCount > 0;
+ componentsCount--)
+ {
+ CcnxNameComponents subPrefix (name.GetSubComponents (componentsCount-1));
+
+ entry = m_dataCallbacks.find (subPrefix);
+ if (entry != m_dataCallbacks.end())
+ return entry;
+ }
+
+ return entry;
+}
+
+void
+CcnxWrapper::OnInterest (const Ptr<const CcnxInterestHeader> &interest, Ptr<Packet> packet)
+{
+ CcnxApp::OnInterest (interest, packet);
+
+ CcnxFilterEntryContainer<InterestCallback>::type::iterator entry = InterestCallbackLookup (interest->GetName ());
+ if (entry == m_interestCallbacks.end ())
+ {
+ _LOG_DEBUG ("No Interest callback set");
+ return;
+ }
+
+ entry->m_callback (lexical_cast<string> (interest->GetName ()));
+}
+
+void
+CcnxWrapper::OnContentObject (const Ptr<const CcnxContentObjectHeader> &contentObject,
+ Ptr<Packet> payload)
+{
+ CcnxApp::OnContentObject (contentObject, payload);
+
+ CcnxFilterEntryContainer<DataCallback>::type::iterator entry = DataCallbackLookup (contentObject->GetName ());
+ if (entry == m_dataCallbacks.end ())
+ {
+ _LOG_DEBUG ("No Data callback set");
+ return;
+ }
+
+ ostringstream content;
+ payload->CopyData (&content, payload->GetSize ());
+
+ entry->m_callback (lexical_cast<string> (contentObject->GetName ()), content.str ());
+
+ // i guess it make sense to remove callback when interest is satisfied
+ m_dataCallbacks.erase (entry);
+}
+
+
+}
diff --git a/ns3/sync-ccnx-wrapper.h b/ns3/sync-ccnx-wrapper.h
new file mode 100644
index 0000000..c9ffe27
--- /dev/null
+++ b/ns3/sync-ccnx-wrapper.h
@@ -0,0 +1,195 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Chaoyi Bian <bcy@pku.edu.cn>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef SYNC_CCNX_WRAPPER_H
+#define SYNC_CCNX_WRAPPER_H
+
+#include <boost/exception/all.hpp>
+#include <boost/function.hpp>
+#include <string>
+
+#include <ns3/ptr.h>
+#include <ns3/node.h>
+#include <ns3/random-variable.h>
+#include <ns3/ccnx-app.h>
+#include <ns3/ccnx-name-components.h>
+#include <ns3/ccnx-name-components-hash-helper.h>
+
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/multi_index/mem_fun.hpp>
+
+/**
+ * \defgroup sync SYNC protocol
+ *
+ * Implementation of SYNC protocol
+ */
+namespace Sync {
+
+template<class Callback>
+struct CcnxFilterEntry
+{
+public:
+ CcnxFilterEntry (ns3::Ptr<const ns3::CcnxNameComponents> prefix)
+ : m_prefix (prefix)
+ { }
+
+ const ns3::CcnxNameComponents &
+ GetPrefix () const
+ { return *m_prefix; }
+
+ void
+ AddCallback (Callback callback)
+ {
+ m_callback = callback;
+ }
+
+ void
+ ClearCallback ()
+ {
+ m_callback = 0;
+ }
+
+public:
+ ns3::Ptr<const ns3::CcnxNameComponents> m_prefix; ///< \brief Prefix of the PIT entry
+ Callback m_callback;
+};
+
+
+template<class Callback>
+struct CcnxFilterEntryContainer
+{
+ typedef
+ boost::multi_index::multi_index_container<
+ CcnxFilterEntry<Callback>,
+ boost::multi_index::indexed_by<
+ // indexed by hash
+ boost::multi_index::hashed_unique<
+ boost::multi_index::const_mem_fun< CcnxFilterEntry<Callback>, const ns3::CcnxNameComponents&, &CcnxFilterEntry<Callback>::GetPrefix >,
+ ns3::CcnxPrefixHash
+ >
+ >
+ > type;
+};
+
+
+
+struct CcnxOperationException : virtual boost::exception, virtual std::exception { };
+/**
+ * \ingroup sync
+ * @brief A wrapper for ccnx library; clients of this code do not need to deal
+ * with ccnx library
+ */
+class CcnxWrapper
+ : public ns3::CcnxApp
+{
+public:
+ typedef boost::function<void (std::string, std::string)> DataCallback;
+ typedef boost::function<void (std::string)> InterestCallback;
+
+ /**
+ * @brief initialize the wrapper; a lot of things needs to be done. 1) init
+ * keystore 2) init keylocator 3) start a thread to hold a loop of ccn_run
+ *
+ */
+ CcnxWrapper();
+ ~CcnxWrapper();
+
+ // from CcnxApp
+ /**
+ * @brief Should be called after Node pointer is set to create face and start application
+ */
+ virtual void
+ StartApplication ();
+
+ /**
+ * @brief Stop application
+ */
+ virtual void
+ StopApplication ();
+
+ /**
+ * @brief send Interest; need to grab lock m_mutex first
+ *
+ * @param strInterest the Interest name
+ * @param dataCallback the callback function to deal with the returned data
+ * @return the return code of ccn_express_interest
+ */
+ int
+ sendInterest (const std::string &strInterest, const DataCallback &dataCallback);
+
+ /**
+ * @brief set Interest filter (specify what interest you want to receive)
+ *
+ * @param prefix the prefix of Interest
+ * @param interestCallback the callback function to deal with the returned data
+ * @return the return code of ccn_set_interest_filter
+ */
+ int
+ setInterestFilter (const std::string &prefix, const InterestCallback &interestCallback);
+
+ /**
+ * @brief clear Interest filter
+ * @param prefix the prefix of Interest
+ */
+ void
+ clearInterestFilter (const std::string &prefix);
+
+ /**
+ * @brief publish data and put it to local ccn content store; need to grab
+ * lock m_mutex first
+ *
+ * @param name the name for the data object
+ * @param dataBuffer the data to be published
+ * @param freshness the freshness time for the data object
+ * @return code generated by ccnx library calls, >0 if success
+ */
+ int
+ publishData (const std::string &name, const std::string &dataBuffer, int freshness);
+
+ // from CcnxApp
+ virtual void
+ OnInterest (const ns3::Ptr<const ns3::CcnxInterestHeader> &interest, ns3::Ptr<ns3::Packet> packet);
+
+ virtual void
+ OnContentObject (const ns3::Ptr<const ns3::CcnxContentObjectHeader> &contentObject,
+ ns3::Ptr<ns3::Packet> payload);
+
+private:
+ CcnxFilterEntryContainer<InterestCallback>::type::iterator
+ InterestCallbackLookup (const ns3::CcnxNameComponents &name);
+
+ CcnxFilterEntryContainer<DataCallback>::type::iterator
+ DataCallbackLookup (const ns3::CcnxNameComponents &name);
+
+private:
+ ns3::UniformVariable m_rand; // nonce generator
+
+ CcnxFilterEntryContainer<DataCallback>::type m_dataCallbacks;
+ CcnxFilterEntryContainer<InterestCallback>::type m_interestCallbacks;
+};
+
+typedef boost::shared_ptr<CcnxWrapper> CcnxWrapperPtr;
+
+} // Sync
+
+#endif // SYNC_CCNX_WRAPPER_H
diff --git a/ns3/sync-log.h b/ns3/sync-log.h
new file mode 100644
index 0000000..9da0dc8
--- /dev/null
+++ b/ns3/sync-log.h
@@ -0,0 +1,108 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Chaoyi Bian <bcy@pku.edu.cn>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef SYNC_LOG_H
+#define SYNC_LOG_H
+
+#ifdef NS3_MODULE
+
+#include <ns3/log.h>
+
+#ifdef _DEBUG
+
+#define INIT_LOGGER(name) NS_LOG_COMPONENT_DEFINE(name);
+
+#define _LOG_INFO(x) NS_LOG_INFO(x)
+
+#define _LOG_DEBUG(x) NS_LOG_DEBUG(x)
+
+#define _LOG_TRACE(x) NS_LOG_LOGIC(x)
+
+#define _LOG_FUNCTION(x) NS_LOG_FUNCTION(x)
+
+#define _LOG_FUNCTION_NOARGS NS_LOG_FUNCTION_NOARGS
+
+#else
+
+#define INIT_LOGGER(name)
+#define _LOG_INFO(x)
+#define _LOG_DEBUG(x)
+#define _LOG_TRACE(x)
+#define _LOG_FUNCTION(x)
+#define _LOG_FUNCTION_NOARGS
+
+#endif
+
+#else
+
+#ifdef HAVE_LOG4CXX
+
+#include <log4cxx/logger.h>
+
+#define INIT_LOGGER(name) \
+ static log4cxx::LoggerPtr staticModuleLogger = log4cxx::Logger::getLogger (name);
+
+#define _LOG_INFO(x) \
+ LOG4CXX_INFO(staticModuleLogger, x);
+
+#define _LOG_DEBUG(x) \
+ LOG4CXX_DEBUG(staticModuleLogger, x);
+
+#define _LOG_TRACE(x) \
+ LOG4CXX_TRACE(staticModuleLogger, x);
+
+#define _LOG_FUNCTION(x) \
+ LOG4CXX_TRACE(staticModuleLogger, __FUNCTION__ << "(" << x << ")");
+
+#define _LOG_FUNCTION_NOARGS \
+ LOG4CXX_TRACE(staticModuleLogger, __FUNCTION__ << "()");
+
+void
+INIT_LOGGERS ();
+
+#else
+
+#define INIT_LOGGER(name)
+#define _LOG_FUNCTION(x)
+#define _LOG_FUNCTION_NOARGS
+#define _LOG_TRACE(x)
+#define _LOG_INFO(x)
+#define INIT_LOGGERS(x)
+
+#ifdef _DEBUG
+
+#include <boost/thread/thread.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <iostream>
+
+#define _LOG_DEBUG(x) \
+ std::clog << boost::get_system_time () << " " << boost::this_thread::get_id () << " " << x << endl;
+
+#else
+#define _LOG_DEBUG(x)
+#endif
+
+#endif // HAVE_LOG4CXX
+
+#endif // NS3_MODULE
+
+#endif // SYNC_LOG_H
diff --git a/ns3/sync-logic-helper.cc b/ns3/sync-logic-helper.cc
new file mode 100644
index 0000000..2425ec3
--- /dev/null
+++ b/ns3/sync-logic-helper.cc
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "sync-logic-helper.h"
+#include "sync-logic.h"
+
+#include "ns3/log.h"
+#include "ns3/string.h"
+#include "ns3/names.h"
+
+NS_LOG_COMPONENT_DEFINE ("SyncLogicHelper");
+
+using namespace ns3;
+
+namespace Sync
+{
+
+SyncLogicHelper::SyncLogicHelper ()
+{
+ // m_factory.SetTypeId ("Sync::SyncLogic");
+}
+
+void
+SyncLogicHelper::SetPrefix (const std::string &prefix)
+{
+ m_prefix = prefix;
+}
+
+
+void
+SyncLogicHelper::SetCallbacks (LogicUpdateCallback onUpdate, LogicRemoveCallback onRemove)
+{
+ m_onUpdate = onUpdate;
+ m_onRemove = onRemove;
+}
+
+// void
+// CcnxAppHelper::SetAttribute (std::string name, const AttributeValue &value)
+// {
+// m_factory.Set (name, value);
+// }
+
+ApplicationContainer
+SyncLogicHelper::Install (Ptr<Node> node)
+{
+ return ApplicationContainer (InstallPriv (node));
+}
+
+ApplicationContainer
+SyncLogicHelper::Install (std::string nodeName)
+{
+ Ptr<Node> node = Names::Find<Node> (nodeName);
+ return ApplicationContainer (InstallPriv (node));
+}
+
+ApplicationContainer
+SyncLogicHelper::Install (NodeContainer c)
+{
+ ApplicationContainer apps;
+ for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i)
+ {
+ apps.Add (InstallPriv (*i));
+ }
+
+ return apps;
+}
+
+Ptr<Application>
+SyncLogicHelper::InstallPriv (Ptr<Node> node)
+{
+ Ptr<SyncLogic> app = CreateObject<SyncLogic> ("/sync", m_onUpdate, m_onRemove);
+ node->AddApplication (app);
+
+ return app;
+}
+
+}
diff --git a/ns3/sync-logic-helper.h b/ns3/sync-logic-helper.h
new file mode 100644
index 0000000..20ad746
--- /dev/null
+++ b/ns3/sync-logic-helper.h
@@ -0,0 +1,115 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef SYNC_LOGIC_HELPER_H
+#define SYNC_LOGIC_HELPER_H
+
+#include "ns3/object-factory.h"
+#include "ns3/attribute.h"
+#include "ns3/node-container.h"
+#include "ns3/application-container.h"
+#include "ns3/ptr.h"
+
+#include <boost/function.hpp>
+
+namespace Sync
+{
+
+class SeqNo;
+
+/**
+ * \brief A helper to make it easier to instantiate an ns3::CcnxConsumer Application
+ * on a set of nodes.
+ */
+class SyncLogicHelper
+{
+public:
+ typedef boost::function< void ( const std::string &/*prefix*/, const SeqNo &/*newSeq*/, const SeqNo &/*oldSeq*/ ) > LogicUpdateCallback;
+ typedef boost::function< void ( const std::string &/*prefix*/ ) > LogicRemoveCallback;
+
+ /**
+ * \brief Create an CcnxAppHelper to make it easier to work with CCNx apps
+ *
+ * \param app Class of the application
+ */
+ SyncLogicHelper ();
+
+ /**
+ * @brief Set the sync prefix
+ */
+ void
+ SetPrefix (const std::string &prefix);
+
+ /**
+ * @brief Set onUpdate and onRemove callbacks
+ */
+ void
+ SetCallbacks (LogicUpdateCallback onUpdate, LogicRemoveCallback onRemove);
+
+ /**
+ * Install an ns3::CcnxConsumer on each node of the input container
+ * configured with all the attributes set with SetAttribute.
+ *
+ * \param c NodeContainer of the set of nodes on which an CcnxConsumer
+ * will be installed.
+ * \returns Container of Ptr to the applications installed.
+ */
+ ns3::ApplicationContainer
+ Install (ns3::NodeContainer c);
+
+ /**
+ * Install an ns3::CcnxConsumer on the node configured with all the
+ * attributes set with SetAttribute.
+ *
+ * \param node The node on which an CcnxConsumer will be installed.
+ * \returns Container of Ptr to the applications installed.
+ */
+ ns3::ApplicationContainer
+ Install (ns3::Ptr<ns3::Node> node);
+
+ /**
+ * Install an ns3::CcnxConsumer on the node configured with all the
+ * attributes set with SetAttribute.
+ *
+ * \param nodeName The node on which an CcnxConsumer will be installed.
+ * \returns Container of Ptr to the applications installed.
+ */
+ ns3::ApplicationContainer
+ Install (std::string nodeName);
+
+private:
+ /**
+ * \internal
+ * Install an ns3::CcnxConsumer on the node configured with all the
+ * attributes set with SetAttribute.
+ *
+ * \param node The node on which an CcnxConsumer will be installed.
+ * \returns Ptr to the application installed.
+ */
+ ns3::Ptr<ns3::Application> InstallPriv (ns3::Ptr<ns3::Node> node);
+ std::string m_prefix; // sync prefix
+ LogicUpdateCallback m_onUpdate;
+ LogicRemoveCallback m_onRemove;
+};
+
+} // namespace Sync
+
+#endif // SYNC_LOGIC_HELPER_H
+
diff --git a/model/sync-ns3-name-info.cc b/ns3/sync-ns3-name-info.cc
similarity index 82%
rename from model/sync-ns3-name-info.cc
rename to ns3/sync-ns3-name-info.cc
index b46d1f6..dfd6179 100644
--- a/model/sync-ns3-name-info.cc
+++ b/ns3/sync-ns3-name-info.cc
@@ -35,25 +35,35 @@
namespace Sync {
-
NameInfoConstPtr
Ns3NameInfo::FindOrCreate (ns3::Ptr<const ns3::CcnxNameComponents> name)
{
+ mutex::scoped_lock namesLock (m_namesMutex);
+
+ NameInfoConstPtr ret;
string key = lexical_cast<string> (*name);
-
+
NameMap::iterator item = m_names.find (key);
- if (item == m_names.end ())
+ if (item != m_names.end ())
{
- NameInfoPtr value = NameInfoPtr (new Ns3NameInfo (name));
+ ret = item->second.lock ();
+ BOOST_ASSERT (ret != 0);
+ }
+ else
+ {
+ ret = NameInfoPtr (new Ns3NameInfo (name));
+ weak_ptr<const NameInfo> value (ret);
pair<NameMap::iterator,bool> inserted =
m_names.insert (make_pair (key, value));
+
BOOST_ASSERT (inserted.second); // previous call has to insert value
item = inserted.first;
}
- return item->second;
+ return ret;
}
+
Ns3NameInfo::Ns3NameInfo (ns3::Ptr<const ns3::CcnxNameComponents> name)
: m_name (name)
{
@@ -81,6 +91,19 @@
}
}
+bool
+Ns3NameInfo::operator < (const NameInfo &info) const
+{
+ try
+ {
+ return *m_name < *dynamic_cast<const Ns3NameInfo&> (info).m_name;
+ }
+ catch (...)
+ {
+ return false;
+ }
+}
+
Digest &
operator << (Digest &digest, const ns3::CcnxNameComponents &name)
{
diff --git a/model/sync-ns3-name-info.h b/ns3/sync-ns3-name-info.h
similarity index 96%
rename from model/sync-ns3-name-info.h
rename to ns3/sync-ns3-name-info.h
index 9363665..347ba1a 100644
--- a/model/sync-ns3-name-info.h
+++ b/ns3/sync-ns3-name-info.h
@@ -47,6 +47,9 @@
virtual bool
operator == (const NameInfo &info) const;
+ virtual bool
+ operator < (const NameInfo &info) const;
+
virtual std::string
toString () const;
diff --git a/ns3/sync-scheduler.cc b/ns3/sync-scheduler.cc
new file mode 100644
index 0000000..025eb3e
--- /dev/null
+++ b/ns3/sync-scheduler.cc
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ * Chaoyi Bian <bcy@pku.edu.cn>
+ * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "sync-scheduler.h"
+#include "sync-log.h"
+
+#include "ns3/simulator.h"
+
+using namespace boost;
+using namespace std;
+using namespace ns3;
+
+INIT_LOGGER ("Scheduler");
+
+namespace Sync {
+
+Scheduler::Scheduler ()
+{
+}
+
+Scheduler::~Scheduler ()
+{
+}
+
+void
+Scheduler::eventWrapper (Event event)
+{
+ event ();
+}
+
+void
+Scheduler::schedule (const TimeDuration &reltime, Event event, uint32_t label)
+{
+ _LOG_DEBUG ("Schedule event for " << (Simulator::Now () +reltime).ToDouble (Time::S) << "s for label " << label);
+
+ list< EventId > &eventsForLabel = m_labeledEvents [label];
+ list< EventId >::iterator i = eventsForLabel.begin ();
+ while (i != eventsForLabel.end ())
+ {
+ if (i->IsExpired ())
+ {
+ list< EventId >::iterator next = i;
+ next ++;
+ eventsForLabel.erase (i);
+ i = next;
+ }
+ else
+ i ++;
+ }
+
+ ns3::EventId eventId = ns3::Simulator::Schedule (reltime, Scheduler::eventWrapper, event);
+ eventsForLabel.push_back (eventId);
+}
+
+void
+Scheduler::cancel (uint32_t label)
+{
+ list< EventId > &eventsForLabel = m_labeledEvents [label];
+ _LOG_DEBUG ("Canceling events for label " << label << " (" << eventsForLabel.size () << " events)");
+
+ for (list< EventId >::iterator i = eventsForLabel.begin ();
+ i != eventsForLabel.end ();
+ i++)
+ {
+ i->Cancel ();
+ }
+
+ eventsForLabel.clear ();
+}
+
+
+} // Sync
diff --git a/model/sync-scheduler.h b/ns3/sync-scheduler.h
similarity index 75%
copy from model/sync-scheduler.h
copy to ns3/sync-scheduler.h
index 10ef210..a98f8c1 100644
--- a/model/sync-scheduler.h
+++ b/ns3/sync-scheduler.h
@@ -23,10 +23,19 @@
#ifndef SYNC_SCHEDULER_H
#define SYNC_SCHEDULER_H
-#include <boost/thread/thread.hpp>
-#include <boost/thread/mutex.hpp>
+#include <ns3/nstime.h>
+#include <ns3/event-id.h>
+#include <ns3/simulator.h>
+#include <list>
+#include <map>
-#include "sync-logic-event-container.h"
+#include "sync-event.h"
+
+#define TIME_SECONDS(number) ns3::Seconds(number)
+#define TIME_MILLISECONDS(number) ns3::MilliSeconds(number)
+#define TIME_NOW ns3::Simulator::Now ()
+typedef ns3::Time TimeDuration;
+typedef ns3::Time TimeAbsolute;
namespace Sync {
@@ -54,8 +63,8 @@
* @param event function to be called at the time
* @param label Label for the event
*/
- void
- schedule (const boost::system_time &abstime, Event event, uint32_t label);
+ // void
+ // schedule (const boost::system_time &abstime, Event event, uint32_t label);
/**
* @brief Schedule an event at relative time 'reltime'
@@ -64,7 +73,7 @@
* @param label Label for the event
*/
void
- schedule (const boost::posix_time::time_duration &reltime, Event event, uint32_t label);
+ schedule (const TimeDuration &reltime, Event event, uint32_t label);
/**
* @brief Cancel all events for the label
@@ -73,26 +82,12 @@
void
cancel (uint32_t label);
-#ifdef _DEBUG
- size_t
- getEventsSize ()
- {
- boost::lock_guard<boost::mutex> lock (m_eventsMutex);
- return m_events.size ();
- }
-#endif
-
private:
- void
- threadLoop ();
-
-private:
- EventsContainer m_events;
- boost::condition_variable m_eventsCondition;
- boost::mutex m_eventsMutex;
+ static void
+ eventWrapper (Event event);
- boost::thread m_thread;
- bool m_threadRunning;
+private:
+ std::map< uint32_t, std::list< ns3::EventId > > m_labeledEvents;
};
}
diff --git a/test/test_app_socket.cc b/test/test_app_socket.cc
index e9a87fc..985dac3 100644
--- a/test/test_app_socket.cc
+++ b/test/test_app_socket.cc
@@ -27,9 +27,9 @@
#include <boost/make_shared.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
-#include "../model/sync-log.h"
+#include "sync-log.h"
-#include "../model/sync-app-socket.h"
+#include "sync-app-socket.h"
extern "C" {
#include <unistd.h>
}
diff --git a/test/test_ccnx_wrapper.cc b/test/test_ccnx_wrapper.cc
index ac5150c..6934584 100644
--- a/test/test_ccnx_wrapper.cc
+++ b/test/test_ccnx_wrapper.cc
@@ -26,7 +26,7 @@
#include <boost/make_shared.hpp>
-#include "../model/sync-ccnx-wrapper.h"
+#include "sync-ccnx-wrapper.h"
using namespace Sync;
using namespace std;
diff --git a/test/test_data_fetch_and_publish.cc b/test/test_data_fetch_and_publish.cc
index 0d5417d..157ce7f 100644
--- a/test/test_data_fetch_and_publish.cc
+++ b/test/test_data_fetch_and_publish.cc
@@ -27,9 +27,9 @@
#include <boost/make_shared.hpp>
-#include "../model/sync-ccnx-wrapper.h"
-#include "../model/sync-app-data-fetch.h"
-#include "../model/sync-app-data-publish.h"
+#include "sync-ccnx-wrapper.h"
+#include "sync-app-data-fetch.h"
+#include "sync-app-data-publish.h"
using namespace Sync;
using namespace std;
diff --git a/test/test_digest.cc b/test/test_digest.cc
index 5a0b4de..3cb124e 100644
--- a/test/test_digest.cc
+++ b/test/test_digest.cc
@@ -25,7 +25,7 @@
#include <boost/test/output_test_stream.hpp>
using boost::test_tools::output_test_stream;
-#include "../model/sync-digest.h"
+#include "sync-digest.h"
#include <iostream>
#include <sstream>
diff --git a/test/test_interest_table.cc b/test/test_interest_table.cc
index 6727bcc..34ea00f 100644
--- a/test/test_interest_table.cc
+++ b/test/test_interest_table.cc
@@ -27,7 +27,7 @@
#include <boost/make_shared.hpp>
-#include "../model/sync-interest-table.h"
+#include "sync-interest-table.h"
using namespace Sync;
using namespace std;
diff --git a/test/test_leaf.cc b/test/test_leaf.cc
index 0ba4401..49afcc5 100644
--- a/test/test_leaf.cc
+++ b/test/test_leaf.cc
@@ -26,9 +26,9 @@
#include <boost/make_shared.hpp>
-#include "../model/sync-full-leaf.h"
-#include "../model/sync-diff-leaf.h"
-#include "../model/sync-std-name-info.h"
+#include "sync-full-leaf.h"
+#include "sync-diff-leaf.h"
+#include "sync-std-name-info.h"
using namespace Sync;
using namespace std;
diff --git a/test/test_pit.cc b/test/test_pit.cc
index 7b2c7af..dca697e 100644
--- a/test/test_pit.cc
+++ b/test/test_pit.cc
@@ -27,8 +27,8 @@
#include <boost/make_shared.hpp>
-#include "../model/sync-interest-table.h"
-#include "../model/sync-log.h"
+#include "sync-interest-table.h"
+#include "sync-log.h"
using namespace Sync;
using namespace std;
diff --git a/test/test_scheduler.cc b/test/test_scheduler.cc
index 276fd50..59687e4 100644
--- a/test/test_scheduler.cc
+++ b/test/test_scheduler.cc
@@ -26,8 +26,8 @@
using boost::test_tools::output_test_stream;
#include <boost/make_shared.hpp>
-#include "../model/sync-scheduler.h"
-#include "../model/sync-logic.h"
+#include "sync-scheduler.h"
+#include "sync-logic.h"
using namespace Sync;
using namespace std;
diff --git a/test/test_state.cc b/test/test_state.cc
index 86d4c6f..35fc79c 100644
--- a/test/test_state.cc
+++ b/test/test_state.cc
@@ -30,9 +30,9 @@
#include <boost/make_shared.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
-#include "../model/sync-std-name-info.h"
-#include "../model/sync-full-state.h"
-#include "../model/sync-diff-state.h"
+#include "sync-std-name-info.h"
+#include "sync-full-state.h"
+#include "sync-diff-state.h"
using namespace Sync;
using namespace std;
diff --git a/test/test_sync_logic.cc b/test/test_sync_logic.cc
index 5b36ba8..f6b6808 100644
--- a/test/test_sync_logic.cc
+++ b/test/test_sync_logic.cc
@@ -27,9 +27,9 @@
#include <boost/make_shared.hpp>
-#include "../model/sync-ccnx-wrapper.h"
-#include "../model/sync-logic.h"
-#include "../model/sync-seq-no.h"
+#include "sync-ccnx-wrapper.h"
+#include "sync-logic.h"
+#include "sync-seq-no.h"
using namespace std;
using namespace boost;
diff --git a/waf-tools/ns3.py b/waf-tools/ns3.py
new file mode 100644
index 0000000..8a1f33f
--- /dev/null
+++ b/waf-tools/ns3.py
@@ -0,0 +1,71 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+import waflib
+from waflib.Configure import conf
+from waflib import Utils,Logs,Errors
+
+@conf
+def _print_optional_features(conf):
+ # Write a summary of optional features status
+ print "---- Summary of optional NS-3 features:"
+ Logs.pprint ('RED', "---- Summary of optional NS-3 features:")
+ # for (name, caption, was_enabled, reason_not_enabled) in conf.env['NS3_OPTIONAL_FEATURES']:
+ # if was_enabled:
+ # status = 'enabled'
+ # else:
+ # status = 'not enabled (%s)' % reason_not_enabled
+ # print "%-30s: %s" % (caption, status)
+
+@conf
+def _check_dependencies(conf, required, mandatory):
+ # Logs.pprint ('CYAN', ' + %s' % required)
+ found = []
+
+ libversion = "optimized"
+ if conf.options.ns3_debug:
+ libversion = "debug"
+
+ for module in required:
+ retval = conf.check_cfg(package = 'libns3-dev-%s-%s' % (module, libversion),
+ args='--cflags --libs', mandatory=mandatory,
+ msg="Checking for ns3-%s" % module,
+ uselib_store='NS3_%s' % module.upper())
+ # Logs.pprint ('CYAN', 'NS3_%s' % module.upper())
+ if not retval is None:
+ found.append(module)
+ import copy
+ if not 'NS3_MODULES_FOUND' in conf.env:
+ conf.env['NS3_MODULES_FOUND'] = []
+ conf.env['NS3_MODULES_FOUND'] = conf.env['NS3_MODULES_FOUND'] + copy.copy(found)
+
+def modules_uselib(bld, names):
+ return ['NS3_%s' % name.upper() for name in names] + \
+ ['NS3_LIBRARY_%s' % name.upper() for name in names] + \
+ ['NS3_HEADERS_%s' % name.upper() for name in names]
+
+def modules_found(bld, needed):
+ for module in needed:
+ if not module in bld.env['NS3_MODULES_FOUND']:
+ return False
+ return True
+
+@conf
+def check_modules(conf, modules, mandatory = True):
+ import os
+
+ if not 'NS3_CHECK_MODULE_ONCE' in conf.env:
+ conf.env['NS3_CHECK_MODULE_ONCE'] = ''
+
+ conf.check_cfg(atleast_pkgconfig_version='0.0.0')
+
+ if conf.options.log4cxx:
+ conf.env.append_value('DEFINES', 'NS3_LOG_ENABLE')
+
+ conf._check_dependencies(modules, mandatory)
+ conf._print_optional_features
+
+@conf
+def print_ns3_feature_summary(conf):
+ Logs.pprint ('CYAN', "---- Summary of optional NS-3 features:")
+ conf._print_optional_features
+
diff --git a/wscript b/wscript
index 6a0a629..ce56610 100644
--- a/wscript
+++ b/wscript
@@ -5,16 +5,17 @@
def options(opt):
opt.add_option('--no-debug',action='store_true',default=False,dest='no_debug',help='''Make an optimized build of the library (remove debugging code)''')
- opt.add_option('--log4cxx',action='store_true',default=False,dest='log4cxx',help='''Compile with log4cxx support''')
+ opt.add_option('--log4cxx', action='store_true',default=False,dest='log4cxx',help='''Compile with log4cxx/native NS3 logging support''')
+ opt.add_option('--ns3', action='store_true',default=False,dest='ns3_enable',help='''Compile as NS-3 module''')
+ opt.add_option('--ns3-debug', action='store_true',default=False,dest='ns3_debug',help='''Link against debug NS3 libraries. Optimized version will be used otherwise''')
opt.load('compiler_c')
opt.load('compiler_cxx')
opt.load('boost')
opt.load('doxygen')
- opt.load('ccnx tinyxml', tooldir=["waf-tools"])
+ opt.load('ccnx tinyxml ns3', tooldir=["waf-tools"])
def configure(conf):
conf.load("compiler_cxx")
- conf.env.append_value('CXXFLAGS', ['-O0', '-g3'])
if not conf.check_cfg(package='openssl', args=['--cflags', '--libs'], uselib_store='SSL', mandatory=False):
libcrypto = conf.check_cc(lib='crypto',
@@ -25,40 +26,136 @@
conf.fatal ("Cannot find SSL libraries")
conf.load('boost')
- conf.check_boost(lib='system iostreams test thread')
-
+
+ if conf.options.ns3_enable:
+ conf.load('ns3')
+ conf.define('NS3_MODULE', 1)
+ conf.check_modules(['core', 'network', 'internet'], mandatory = True)
+ conf.check_modules(['NDNabstraction'], mandatory = True)
+ conf.check_modules(['point-to-point'], mandatory = False)
+ conf.check_modules(['point-to-point-layout'], mandatory = False)
+
+ conf.check_boost(lib='system iostreams thread')
+ conf.define ('NS3_LOG_ENABLE', 1)
+ else:
+ conf.check_boost(lib='system iostreams test thread')
+ conf.define ('STANDALONE', 1)
+
+ conf.load ('ccnx')
+ conf.check_ccnx (path=conf.options.ccnx_dir)
+
+ if conf.options.log4cxx:
+ conf.check_cfg(package='liblog4cxx', args=['--cflags', '--libs'], uselib_store='LOG4CXX', mandatory=True)
+
+ if not conf.options.no_debug:
+ conf.define ('_DEBUG', 1)
+ conf.env.append_value('CXXFLAGS', ['-O0', '-g3'])
+ else:
+ conf.env.append_value('CXXFLAGS', ['-O3'])
+
try:
conf.load('doxygen')
except:
pass
- conf.load('ccnx tinyxml')
- conf.check_ccnx (path=conf.options.ccnx_dir)
- conf.check_tinyxml (path=conf.options.ccnx_dir)
-
- conf.define ('STANDALONE', 1)
- if not conf.options.no_debug:
- conf.define ('_DEBUG', 1)
-
- if conf.options.log4cxx:
- conf.check_cfg(package='liblog4cxx', args=['--cflags', '--libs'], uselib_store='LOG4CXX', mandatory=True)
+ conf.load('tinyxml')
+ conf.check_tinyxml ()
def build (bld):
- libsync = bld.shlib (target=APPNAME,
- features=['cxx', 'cxxshlib'],
- source = bld.path.ant_glob(['model/sync-*.cc',
- 'helper/sync-*.cc']),
- use = 'BOOST BOOST_IOSTREAMS BOOST_THREAD SSL TINYXML CCNX')
+ if bld.get_define ("NS3_MODULE"):
+ sync_ns3 = bld.shlib (
+ target = "sync-ns3",
+ features=['cxx', 'cxxshlib'],
+ source = [
+ 'ns3/sync-ccnx-wrapper.cc',
+ 'ns3/sync-ns3-name-info.cc',
+ 'ns3/sync-scheduler.cc',
+ 'ns3/sync-logic-helper.cc',
+
+ # 'model/sync-app-data-fetch.cc',
+ # 'model/sync-app-data-publish.cc',
+ # 'ns3/sync-app.cc',
- # Unit tests
- unittests = bld.program (target="unit-tests",
- source = bld.path.ant_glob(['test/**/*.cc']),
- features=['cxx', 'cxxprogram'],
- use = 'BOOST_TEST sync')
+ 'model/sync-diff-leaf.cc',
+ 'model/sync-diff-state.cc',
+ 'model/sync-digest.cc',
+ 'model/sync-full-leaf.cc',
+ 'model/sync-full-state.cc',
+ 'model/sync-interest-table.cc',
+ 'model/sync-leaf.cc',
+ 'model/sync-logic.cc',
+ 'model/sync-name-info.cc',
+ 'model/sync-seq-no.cc',
+ 'model/sync-state.cc',
+ 'model/sync-std-name-info.cc',
+ ],
+ use = 'BOOST BOOST_IOSTREAMS SSL TINYXML ' + ' '.join (['ns3_'+dep for dep in ['core', 'network', 'internet', 'NDNabstraction']]).upper (),
+ includes = ['model', 'ns3', 'helper'],
+ )
- if bld.get_define ("HAVE_LOG4CXX"):
- libsync.use += ' LOG4CXX'
- unittests.use += ' LOG4CXX'
+ example = bld.program (
+ target = "sync-example",
+ features=['cxx', 'cxxprogram'],
+ source = ['examples/sync-example.cc'],
+ use = 'sync-ns3',
+ includes = ['model', 'ns3', 'helper'],
+ )
+
+ sync_eval = bld.program (
+ target = "sync-eval",
+ features=['cxx', 'cxxprogram'],
+ source = ['evaluation/sync-eval.cc',
+ 'evaluation/standard-muc.cc',
+ 'evaluation/sync-muc.cc',
+ ],
+ use = 'sync-ns3',
+ includes = ['model', 'ns3', 'helper'],
+ )
+ # from waflib import Utils,Logs,Errors
+ # Logs.pprint ('CYAN', program.use)
+
+ else:
+ libsync = bld.shlib (
+ target=APPNAME,
+ features=['cxx', 'cxxshlib'],
+ source = [
+ 'ccnx/sync-ccnx-wrapper.cc',
+ 'ccnx/sync-scheduler.cc',
+ 'ccnx/sync-log.cc',
+ 'ccnx/sync-app-data-fetch.cc',
+ 'ccnx/sync-app-data-publish.cc',
+ 'ccnx/sync-app-socket-c.cc',
+ 'ccnx/sync-app-socket.cc',
+
+ 'model/sync-diff-leaf.cc',
+ 'model/sync-diff-state.cc',
+ 'model/sync-digest.cc',
+ 'model/sync-full-leaf.cc',
+ 'model/sync-full-state.cc',
+ 'model/sync-interest-table.cc',
+ 'model/sync-leaf.cc',
+ 'model/sync-logic.cc',
+ 'model/sync-name-info.cc',
+ 'model/sync-seq-no.cc',
+ 'model/sync-state.cc',
+ 'model/sync-std-name-info.cc',
+ ],
+ use = 'BOOST BOOST_IOSTREAMS BOOST_THREAD SSL TINYXML CCNX',
+ includes = ['model', 'ccnx', 'helper'],
+ )
+
+ # Unit tests
+ unittests = bld.program (
+ target="unit-tests",
+ source = bld.path.ant_glob(['test/**/*.cc']),
+ features=['cxx', 'cxxprogram'],
+ use = 'BOOST_TEST sync',
+ includes = ['model', 'ccnx', 'helper'],
+ )
+
+ if bld.get_define ("HAVE_LOG4CXX"):
+ libsync.use += ' LOG4CXX'
+ unittests.use += ' LOG4CXX'
# doxygen docs
from waflib.Build import BuildContext