实际上ndnSIM2.1中已经自带概率缓存的实现了,在自己的配置文件中,加入
ndn::StackHelper ndnHelper;
ndnHelper.SetOldContentStore("ns3::ndn::cs::Probability::Lru","MaxSize","100","CacheProbability","0.5");
就可以设置好一个最大缓存为100,缓存概率为0.5的缓存。
这里记录它是如何实现的,并以另一种方法实现概率缓存。
方法一:利用配置文件直接配置缓存策略
这种方法就是上面所说的方法,在配置文件中调用SetOldContentStore()函数。这里我们要做的是去了解这些策略文件的位置,以及我们怎么去写简单的策略。
在
ns-3/src/ndnSIM/model/cs
中,存放着有关ndnSIM缓存策略的文件。ndnSIM2.1自带四种策略:
1. freshness
2. stats
3. probability
4. nocache
每种策略都有三个文件,拿probability为例,有
- content-store-with-probability.hpp
- content-store-with-probability.cpp
- custom-policies/probability-policy.hpp
如果要写自己的缓存策略,只要仿照这三个文件,再写三个文件,然后在配置文件中调用即可。
这里放上一个简单的MyPro实现,仅仅是将probability的名称改了。
//content-store-with-mypro.hpp
#ifndef NDN_CONTENT_STORE_WITH_MYPRO_H_
#define NDN_CONTENT_STORE_WITH_MYPRO_H_
#include "ns3/ndnSIM/model/ndn-common.hpp"
#include "content-store-impl.hpp"
#include "../../utils/trie/multi-policy.hpp"
#include "custom-policies/mypro-policy.hpp"
#include "ns3/double.h"
#include "ns3/type-id.h"
namespace ns3 {
namespace ndn {
namespace cs {
/**
* @ingroup ndn-cs
* @brief Special content store realization that probabilistically accepts data packet
* into CS (placement policy)
*/
template<class Policy>
class ContentStoreWithMypro
: public ContentStoreImpl<ndnSIM::multi_policy_traits<boost::mpl::
vector2<ndnSIM::mypro_policy_traits,
Policy>>> {
public:
typedef ContentStoreImpl<ndnSIM::multi_policy_traits<boost::mpl::
vector2<ndnSIM::mypro_policy_traits,
Policy>>> super;
typedef typename super::policy_container::template index<0>::type mypro_policy_container;
ContentStoreWithMypro(){};
static TypeId
GetTypeId();
private:
void
SetCacheProbability(double probability)
{
this->getPolicy().template get<mypro_policy_container>().set_probability(probability);
printf("SetCacheProbability:%lf\n", probability);
}
double
GetCacheProbability() const
{
printf("GetCacheProbability:%lf\n", this->getPolicy().template get<mypro_policy_container>().get_probability());
return this->getPolicy().template get<mypro_policy_container>().get_probability();
}
};
//////////////////////////////////////////
////////// Implementation ////////////////
//////////////////////////////////////////
template<class Policy>
TypeId
ContentStoreWithMypro<Policy>::GetTypeId()
{
static TypeId tid =
TypeId(("ns3::ndn::cs::Mypro::" + Policy::GetName()).c_str())
.SetGroupName("Ndn")
.SetParent<super>()
.template AddConstructor<ContentStoreWithMypro<Policy>>()
.AddAttribute("CacheProbability",
"Set probability of caching in ContentStore. "
"If 1, every content is cached. If 0, no content is cached.",
DoubleValue(1.0), //(+)
MakeDoubleAccessor(&ContentStoreWithMypro<Policy>::GetCacheProbability,
&ContentStoreWithMypro<Policy>::SetCacheProbability),
MakeDoubleChecker<double>());
printf("typename:ns3::ndn::cs::Mypro::%s\n",Policy::GetName().c_str());
return tid;
}
} // namespace cs
} // namespace ndn
} // namespace ns3
#endif // NDN_CONTENT_STORE_WITH_PROBABILITY_H_
//content-store-with-mypro.cpp
#include "content-store-with-mypro.hpp"
#include "../../utils/trie/random-policy.hpp"
#include "../../utils/trie/lru-policy.hpp"
#include "../../utils/trie/fifo-policy.hpp"
#include "../../utils/trie/lfu-policy.hpp"
#define NS_OBJECT_ENSURE_REGISTERED_TEMPL(type, templ) \
static struct X##type##templ##RegistrationClass { \
X##type##templ##RegistrationClass() \
{ \
ns3::TypeId tid = type<templ>::GetTypeId(); \
tid.GetParent(); \
} \
} x_##type##templ##RegistrationVariable
namespace ns3 {
namespace ndn {
using namespace ndnSIM;
namespace cs {
// explicit instantiation and registering
/**
* @brief ContentStore with freshness and LRU cache replacement policy
**/
template class ContentStoreWithMypro<lru_policy_traits>;
/**
* @brief ContentStore with freshness and random cache replacement policy
**/
template class ContentStoreWithMypro<random_policy_traits>;
/**
* @brief ContentStore with freshness and FIFO cache replacement policy
**/
template class ContentStoreWithMypro<fifo_policy_traits>;
/**
* @brief ContentStore with freshness and Least Frequently Used (LFU) cache replacement policy
**/
template class ContentStoreWithMypro<lfu_policy_traits>;
NS_OBJECT_ENSURE_REGISTERED_TEMPL(ContentStoreWithMypro, lru_policy_traits);
NS_OBJECT_ENSURE_REGISTERED_TEMPL(ContentStoreWithMypro, random_policy_traits);
NS_OBJECT_ENSURE_REGISTERED_TEMPL(ContentStoreWithMypro, fifo_policy_traits);
NS_OBJECT_ENSURE_REGISTERED_TEMPL(ContentStoreWithMypro, lfu_policy_traits);
#ifdef DOXYGEN
// /**
// * \brief Content Store with freshness implementing LRU cache replacement policy
// */
class Mypro::Lru : public ContentStoreWithMypro<lru_policy_traits> {
};
/**
* \brief Content Store with freshness implementing FIFO cache replacement policy
*/
class Mypro::Fifo : public ContentStoreWithMypro<fifo_policy_traits> {
};
/**
* \brief Content Store with freshness implementing Random cache replacement policy
*/
class Mypro::Random : public ContentStoreWithMypro<random_policy_traits> {
};
/**
* \brief Content Store with freshness implementing Least Frequently Used cache replacement policy
*/
class Mypro::Lfu : public ContentStoreWithMypro<lfu_policy_traits> {
};
#endif
} // namespace cs
} // namespace ndn
} // namespace ns3
custom-policies/mypro-policy.hpp
#ifndef MYPRO_POLICY_H_
#define MYPRO_POLICY_H_
/// @cond include_hidden
#include "ns3/ndnSIM/model/ndn-common.hpp"
#include <boost/intrusive/options.hpp>
#include <boost/intrusive/list.hpp>
#include <ns3/random-variable-stream.h>
namespace ns3 {
namespace ndn {
namespace ndnSIM {
/**
* @brief Traits for freshness policy
*/
struct mypro_policy_traits {
static std::string
GetName()
{
return "MyproImpl";
}
struct policy_hook_type : public boost::intrusive::list_member_hook<> {
};
template<class Container>
struct container_hook {
typedef boost::intrusive::member_hook<Container, policy_hook_type, &Container::policy_hook_>
type;
};
template<class Base, class Container, class Hook>
struct policy {
typedef typename boost::intrusive::list<Container, Hook> policy_container;
class type : public policy_container {
public:
typedef policy policy_base; // to get access to get_freshness methods from outside
typedef Container parent_trie;
type(Base& base)
: base_(base)
, max_size_(100)
, probability_(1.0)
, ns3_rand_(CreateObject<UniformRandomVariable>())
{
}
inline void
update(typename parent_trie::iterator item)
{
}
inline bool
insert(typename parent_trie::iterator item)
{
if (ns3_rand_->GetValue() < probability_) {
policy_container::push_back(*item);
// allow caching
return true;
}
else {
// don't allow caching
return false;
}
}
inline void
lookup(typename parent_trie::iterator item)
{
// do nothing. it's random policy
}
inline void
erase(typename parent_trie::iterator item)
{
policy_container::erase(policy_container::s_iterator_to(*item));
}
inline void
clear()
{
policy_container::clear();
}
inline void
set_max_size(size_t max_size)
{
max_size_ = max_size;
}
inline size_t
get_max_size() const
{
return max_size_;
}
inline void
set_probability(double probability)
{
probability_ = probability;
}
inline double
get_probability() const
{
return probability_;
}
private:
type()
: base_(*((Base*)0)){};
private:
Base& base_;
size_t max_size_;
double probability_;
Ptr<UniformRandomVariable> ns3_rand_;
};
};
};
} // ndnSIM
} // ndn
} // ns3
/// @endcond
#endif // PROBABILITY_POLICY_H
可以看到custom-policies/mypro-policy.hpp
中的insert
函数实现了概率缓存的主要功能。
content-store-with-mypro.hpp
中的GetTypeId中,AddAttribute
是将自己的变量加入到配置中,这样就可以在配置文件中配置这些变量的值了。
在配置文件中的使用:
ndn::StackHelper ndnHelper;
ndnHelper.SetOldContentStore("ns3::ndn::cs::Mypro::Lru","MaxSize","50","CacheProbability","0.5");
方法二:修改底层策略
在ns-3/src/ndnSIM/NFD/daemon/fw
中,存放着ndnSIM转发策略的一些文件。我们要修改的是forwarder.cpp
。
在forwarder.cpp
中,找到onIncomingData
函数,其中有这么一段:
// CS insert
if (m_csFromNdnSim == nullptr)
m_cs.insert(*dataCopyWithoutPacket);
else
m_csFromNdnSim->Add(dataCopyWithoutPacket);
这就是默认的LCE策略,这里的两个变量m_cs
和m_csFromNdnSim
分别是ns-3/src/ndnSIM/NFD/daemon/table
中的cs
和ns-3/src/ndnSIM/model/cs/
中ndn-content-store
的对象,前者是ndnSIM2.0及以后对cs的实现,后者是1.0对cs的实现,这里代码中的CS insert对m_csFromNdnSim
进行了一次判断,主要是看用户用的是哪一个版本的cs实现,然后在用各自的API将数据插入cs中。
在这里实现简单的概率缓存,只要生成一个随机数,然后与预设的阈值进行比较,如果小于阈值就缓存,否则什么都不做。代码如下:
// CS insert
srand(std::time(NULL));
float p = (float)rand()/RAND_MAX;//产生随机数
float propability = 0.5;//阈值的设定
//概率缓存
if(p < propability){
if (m_csFromNdnSim == nullptr)
m_cs.insert(*dataCopyWithoutPacket);
else
m_csFromNdnSim->Add(dataCopyWithoutPacket);
}
else{
}
这种方法就实现了简单的概率缓存,使用时不需要在配置文件中特地的进行策略的修改。
另外,在配置文件中,ndnSIM官网的例子给出的consumer实现都是
ndn::AppHelper consumerHelper("ns3::ndn::ConsumerCbr");
这种方式产生的Interest很难重复,就更不要说缓存命中了。因此我们要将Interest改为齐普夫分布。在配置文件中将上面的代码改为:
ndn::AppHelper consumerHelper("ns3::ndn::ConsumerZipfMandelbrot");
这是ndnSIM自带的实现,至于在某些文章中看到的更细的齐普夫参数,我还不知道在哪里设置,有待进一步研究。