前言
因为我们组要对内容缓存CS部分的代码进行修改,虽然我还是个萌新,对整个NDN框架还没入门,然而还是尝试看了下CS部分的代码。
从今往后,不做特殊声明,约定
- 定义:
<ns-3-folder>
为~/ndnSIM/ns-3
路径 - 定义:
<ndnSIM-folder>
为~/ndnSIM/ns-3/src/ndnSIM
路径 - 定义:
<build-ndnSIM-folder>
为~/ndnSIM/ns-3/build/ns3/ndnSIM
路径
今天要看的代码是:
<ndnSIM-folder>/NFD/daemon/table/cs.hpp
<ndnSIM-folder>/NFD/daemon/table/cs.cpp
<ndnSIM-folder>/NFD/daemon/table/cs-entry.hpp
<ndnSIM-folder>/NFD/daemon/table/cs-entry.cpp
<ndnSIM-folder>/NFD/daemon/table/cs-policy.hpp
<ndnSIM-folder>/NFD/daemon/table/cs-policy.cpp
cs.hpp与cs.cpp
cs.hpp
代码如下(我手动添加了部分注释,并且为了简短性,将部分单行return函数合并为了一行)
class Cs : noncopyable
{
public:
// 构造函数,默认最大存10个包
explicit
Cs(size_t nMaxPackets = 10);
// 识别数据的缓存策略+把data塞进m_table且Fresh data+
// +使用当前FIFO缓存策略处理data在队列中的位置
void
insert(const Data& data, bool isUnsolicited = false);
// 异步擦除前缀名为prefix下的条目,得到擦除的条目数nErased
// 擦除后执行回调函数cb
template<typename AfterEraseCallback>
void
erase(const Name& prefix, size_t limit, AfterEraseCallback&& cb)
{
size_t nErased = eraseImpl(prefix, limit);
cb(nErased);
}
// 用发的interest在CS中最匹配的data包,得到目标对应m_table中的迭代器
// 如果找到,执行回调函数hit,否则执行回调函数miss
template<typename HitCallback, typename MissCallback>
void
find(const Interest& interest, HitCallback&& hit, MissCallback&& miss) const
{
auto match = findImpl(interest);
if (match == m_table.end()) {
miss(interest);
return;
}
hit(interest, match->getData());
}
// 返回m_table的size,即CS储存的条目数
size_t size() const { return m_table.size(); }
public: // configuration
// 返回储存上限
size_t getLimit() const { return m_policy->getLimit(); }
// 设置储存上限
void setLimit(size_t nMaxPackets) { return m_policy->setLimit(nMaxPackets); }
// 获取缓存替换策略
Policy* getPolicy() const { return m_policy.get(); }
// 更改缓存策略(必须size() == 0才能执行)
void setPolicy(unique_ptr<Policy> policy);
// 返回m_shouldAdmit (if false, no Data will be admitted)
bool shouldAdmit() const { return m_shouldAdmit; }
// Set m_shouldAdmit
void enableAdmit(bool shouldAdmit);
// 返回m_shouldServe (if false, all lookups will miss)
bool shouldServe() const { return m_shouldServe; }
// Set m_shouldServe
void enableServe(bool shouldServe);
public: // enumeration
using const_iterator = Table::const_iterator;
// 头尾迭代器,应该不必多说吧,很简单
const_iterator begin() const { return m_table.begin(); }
const_iterator end() const { return m_table.end(); }
private:
// 用Table进行二分查找,获得前缀为prefix的区间
std::pair<const_iterator, const_iterator>
findPrefixRange(const Name& prefix) const;
// 前面的erase函数会调用eraseImpl函数作为具体实现
// 擦除方式是调用findPrefixRange函数获得区间,然后擦掉所有元素
// limit是擦除的上限,超过了就不擦了,不然全擦
size_t
eraseImpl(const Name& prefix, size_t limit);
// 前面的find函数会调用findImpl函数作为具体实现
// 擦除方式是调用findPrefixRange函数获得区间,然后用find_if函数遍历查找
const_iterator
findImpl(const Interest& interest) const;
// 前面的setPolicy函数会调用setPolicyImpl函数作为具体实现
void
setPolicyImpl(unique_ptr<Policy> policy);
PUBLIC_WITH_TESTS_ELSE_PRIVATE: // 测试public,运行时private
void dump(); // 显示m_table里全部内容,仅测试时可用
private:
Table m_table; // 存CS内容的表
unique_ptr<Policy> m_policy; // 存缓存策略
signal::ScopedConnection m_beforeEvictConnection;
bool m_shouldAdmit = true; ///< if false, no Data will be admitted
bool m_shouldServe = true; ///< if false, all lookups will miss
};
cs.cpp的Cs::insert函数详解
整个 cs.hpp
都很简单,对应的函数功能我都给了详细注释。对于 cs.cpp
,我只对 Cs::insert
这一个函数进行一些分析说明,具体说明以注释的形式给出——
void
Cs::insert(const Data& data, bool isUnsolicited)
{
// 如果不Admit或者缓存上限为0,直接返回
if (!m_shouldAdmit || m_policy->getLimit() == 0) {
return;
}
NFD_LOG_DEBUG("insert " << data.getName());
// 尝试取出data的CachePolicyType,如果data没Tag,视为要求缓存
// 如果有Tag,Tag上的Type都说不缓存,那还insert个鬼,直接return吧
shared_ptr<lp::CachePolicyTag> tag = data.getTag<lp::CachePolicyTag>();
if (tag != nullptr) {
lp::CachePolicyType policy = tag->get().getPolicy();
if (policy == lp::CachePolicyType::NO_CACHE) {
return;
}
}
// 尝试把(data, isUnsolicited)压入m_table表
// 压入后把自己在表中的迭代器返回给it(无论是否重复)
// 因为是set类型,所以会调用data的重载operator==分析是否重复
// 如果有重复元素,说明不是NewEntry,isNewEntry=false
const_iterator it;
bool isNewEntry = false;
std::tie(it, isNewEntry) = m_table.emplace(data.shared_from_this(), isUnsolicited);
Entry& entry = const_cast<Entry&>(*it);
// Fresh一下新来的包
entry.updateFreshUntil();
// 善后工作
if (!isNewEntry) { // existing entry
// 刷新新来的包的isUnsolicited
if (entry.isUnsolicited() && !isUnsolicited) {
entry.clearUnsolicited();
}
m_policy->afterRefresh(it);
}
else {
m_policy->afterInsert(it);
}
}
总结
- 类
Cs
就是一个内容缓存器,其中缓存内容都存放在一个m_table
中。 m_table
的类型为Table
,相当于std::set
。因为是集合,所以禁止存在相同元素。std::set
的底层实现用到了红黑树,需要重载operator <
,所以在文件cs-entry.cpp
中Entry
类型重载了<
符号。- 缓存策略由
m_policy
进行维护,其中维护了缓存策略和缓存上限。
cs.hpp
的类 Cs
的数据成员如下——
private:
Table m_table; // 存CS内容的表
unique_ptr<Policy> m_policy; // 存缓存策略
signal::ScopedConnection m_beforeEvictConnection;
bool m_shouldAdmit = true; ///< if false, no Data will be admitted
bool m_shouldServe = true; ///< if false, all lookups will miss
cs-entry.hpp
的类 Entry
的数据成员如下——
private:
shared_ptr<const Data> m_data; // 数据内容
bool m_isUnsolicited; // 未经请求的数据?(PIT里没有就是未经请求的)
time::steady_clock::TimePoint m_freshUntil; // Fresh截止时间
cs-policy.hpp
的类 Policy
的数据成员如下——
private:
std::string m_policyName; // 策略名
size_t m_limit; // 容量
Cs* m_cs; // 指向被维护的Cs的指针