文章目录
本文选取了ceph中的几处代码进行分析,旨在读懂代码的基础之上,提炼出关键知识点和思想进行学习。
1. MDSContext::vec
目标代码
class MDSContext : public Context
{
public:
template<template<typename> class A>
using vec_alloc = std::vector<MDSContext*, A<MDSContext*>>;
using vec = vec_alloc<std::allocator>;
};
关键词
- Template template parameter(模板模板参数)
- alias templates(模板别名)
语法分析
在分析这段代码之前,先来看两个更简单的例子:
template<class T>
struct Alloc
{
// 实现自己的内存分配器
};
template<class T>
using Vec = std::vector<T, Alloc<T>>;
int main()
{
Vec<int> as;
return 0;
}
template<class T>
struct Base
{
int val;
};
//没什么实际意义,只是为了说明用法
template<class T>
using A = Base<T>;
int main()
{
Base<int> inst1;
A<int> inst2;
return 0;
}
以上两个例子,就是C++11新增的特性——模板别名,通过using语句为复杂的模板格式起一个简单的别名,极大的简化后续使用时的书写复杂度。
而这里的MDSContext::vec要比以上两个例子更复杂些,一是有模板嵌套,二是两次别名,但其实原理还是一样的,拆开来看就可以了。具体分析直接见下方代码注释吧:
class MDSContext
{
public:
template<template<typename> class A> // A是一个模板,就这么简单
// 用std::alocator来实例化vec_alloc,即vec_alloc<std::allocator>,allocator即替换A来进行实例化
using vec_alloc = std::vector<MDSContext*, A<MDSContext*>>;
using vec = vec_alloc<std::allocator>;
// 上面的最后一个using其实就是最后一步的彻底特例化了,如果去除这步,手动传参也是可以的
template<template<typename> class A>
using vec_alloc = std::vector<MDSContext*, A<MDSContext*>>;
// 一句话总结,其实就是定义了std::vector<MDSContext*, std::allocator<MDSContext*>>的别名
};
int main()
{
// 等价的定义,第一种写法最简单
MDSContext::vec a;
MDSContext::vec_alloc<std::allocator> b;
std::vector<MDSContext*, std::allocator<MDSContext*>> c;
return 0;
}
用法就是如上面所示,借此部分代码学习了模板别名的知识点,但是对于这部分的代码,以我目前的认知来看是没看出有什么好处的,因为这段代码绕了一圈,其实vec就是vector<MDSContext*>,第一个using允许用户自定义allocator,但是第二个using又显示使用了std::allocator,这还有什么意义呢?把本来泛型的东西又给特例化了,MDSContext::vec相比vector<MDSContext*>的并没有更简单,而且可读性也差了很多。后面再看有没有新的理解吧。
2. C_IO_Wrapper
目标代码
下面这段代码做了什么?
Context *fin = new C_IO_Wrapper(this, new C_MDS_BootStart(this, MDS_BOOT_INITIAL));
bool const ready = objecter->wait_for_map(
mdsmap->get_last_failure_osd_epoch(),
fin);
其中类的继承体系如下:
graph BT
MDSContext-->Context
tmp[MDSHolder<MDSIOContextBase>]-->MDSContext
MDSIOContext-->tmp
C_IO_Wrapper-->MDSIOContext
MDSInternalContext-->tmp
C_MDS_BootStart-->MDSInternalContext
为了省去再去翻代码,这里直接把相关类定义的源码列出来了。
/*
* Context - abstract callback class
*/
class Context {
Context(const Context& other);
const Context& operator=(const Context& other);
protected:
virtual void finish(int r) = 0;
// variant of finish that is safe to call "synchronously." override should
// return true.
virtual bool sync_finish(int r) {
return false;
}
public:
Context() {
}
virtual ~Context() {
} // we want a virtual destructor!!!
virtual void complete(int r) {
finish(r);
delete this;
}
virtual bool sync_complete(int r) {
if (sync_finish(r)) {
delete this;
return true;
}
return false;
}
};
/**
* Completion which has access to a reference to the global MDS instance.
*
* This class exists so that Context subclasses can provide the MDS pointer
* from a pointer they already had, e.g. MDCache or Locker, rather than
* necessarily having to carry around an extra MDS* pointer.
*/
class MDSContext : public Context
{
public:
template<template<typename> class A>
using vec_alloc = std::vector<MDSContext*, A<MDSContext*>>;
using vec = vec_alloc<std::allocator>;
template<template<typename> class A>
using que_alloc = std::deque<MDSContext*, A<MDSContext*>>;
using que = que_alloc<std::allocator>;
void complete(int r) override;
virtual MDSRank *get_mds() = 0;
};
void MDSContext::complete(int r)

本文深入分析了Ceph中MDSContext::vec、C_IO_Wrapper及MDSGatherBuilder的代码实现,详细解读了模板别名、回调机制及gather构建器的工作原理。
最低0.47元/天 解锁文章
442

被折叠的 条评论
为什么被折叠?



