1 使用流程
以ceph mds客户端mds_command中对C_GatherBuilder类类的具体使用为例,简单的流程概述为:C_GatherBuilder gather(cct, onfinish); 该类名为Builder,通过该类创建一个Gather(集合) 任务集合实例,通过new_sub方法为该集合实例添加子任务。当所有的子任务完成以后,返回入参的onfinsh指针的complete方法。
extern "C" int ceph_mds_command()
{
C_SaferCond cond;
int r = cmount->get_client()->mds_command(&cond);
if (r != 0) {
goto out;
}
// Wait for completion
r = cond.wait();
int Client::mds_command()
{
//省略前文,直接从这里开始
C_GatherBuilder gather(cct, onfinish); //建立一个堆栈变量gather
for (const auto& target_gid : non_laggy) {
.........
op.on_finish = gather.new_sub(); //给每个异步任务新建一个context类实例。
.........
}
gather.activate(); //激活异步任务。
return 0;
}
2 C_GatherBuilderBase类
typedef C_GatherBase<Context, Context> C_Gather;
typedef C_GatherBuilderBase<Context, C_Gather > C_GatherBuilder;
1 C_GatherBuilderBase 和 C_GatherBase 都是模板类,首先这里, C_GatherBuilderBase的构造函数非常简单,传入一个ceph上下文cct,和一个继承Context的类C_SaferCond的类的指针。
typedef C_GatherBase<Context, Context> C_Gather;
typedef C_GatherBuilderBase<Context, C_Gather > C_GatherBuilder;
template <class ContextType, class GatherType>
class C_GatherBuilderBase
{
public:
C_GatherBuilderBase(CephContext *cct_)
: cct(cct_), c_gather(NULL), finisher(NULL), activated(false)
{
}
C_GatherBuilderBase(CephContext *cct_, ContextType *finisher_)
: cct(cct_), c_gather(NULL), finisher(finisher_), activated(false)
{ //ContextType 是Context, GatherType 是C_Gather
}
ContextType *new_sub() {
if (!c_gather) { //c_gather 成员初始化为NULL,所以调用该函数时候会先构建一个堆内存(new)对象。
c_gather = new GatherType(cct, finisher);//这里调用C_Gather 的构造函数,即GatherType
}
return c_gather->new_sub();
}
3 C_GatherBase 类
C_GatherBase构造函数如下。
typedef C_GatherBase<Context, Context> C_Gather;
template <class ContextType, class ContextInstanceType>
class C_GatherBase {
private:
CephContext *cct;
int result = 0;
ContextType *onfinish;
#ifdef DEBUG_GATHER
std::set<ContextType*> waitfor; //子任务实例 的集合
#endif
int sub_created_count = 0; //子任务计数
int sub_existing_count = 0;//子任务计数
bool activated = false; //任务开始标志
//中间省略部分代码
public:
C_GatherBase(CephContext *cct_, ContextType *onfinish_)
: cct(cct_), onfinish(onfinish_)
{
}
4 new_sub方法
class C_GatherBuilderBase{ //Builder类是个C_Gather实例的构造器,行为透传到C_Gather实例的new_sub方法。
ContextType *new_sub() {
if (!c_gather) {
c_gather = new GatherType(cct, finisher);
}
return c_gather->new_sub();
}
}
class C_GatherBase {
ContextType *new_sub() {
std::lock_guard l{lock};
ceph_assert(activated == false);
sub_created_count++; //
sub_existing_count++;//子任务计数+1
ContextType *s = new C_GatherSub(this); //C_GatherSub类才是真正的子任务单独拥有的回调类。
waitfor.insert(s);
return s;
}
void sub_finish(ContextType* sub, int r) {
lock.lock();
ceph_assert(waitfor.count(sub));
waitfor.erase(sub); //从waitfor中剔除已经完成的子任务
--sub_existing_count; //计数-1
if (r < 0 && result == 0)
result = r;
if ((activated == false) || (sub_existing_count != 0)) {
lock.unlock();
return; //如果还有子任务没完成,只减少计数
}
lock.unlock();
delete_me(); //如果子任务完成且 集合为激活。进入delete_me函数
}
void delete_me() {
if (onfinish) { //这里是所有子任务完成后,使用最开始外部传入的类的complete方法,唤醒C_SafeCond的等待,然后ceph_mds_commmand执行完毕。
onfinish->complete(result);
onfinish = 0;
}
delete this;
}
}
class C_GatherSub : public ContextInstanceType {
C_GatherBase *gather; //比context类多了一个成员变量,gather,即保存全部子任务信息的父类。C_Gather
public:
C_GatherSub(C_GatherBase *g) : gather(g) {}
void complete(int r) override {
Context::complete(r);
}
void finish(int r) override {
gather->sub_finish(this, r); //引用计数-1
gather = 0;
}
~C_GatherSub() override {
if (gather)
gather->sub_finish(this, 0);
}
};
5 总结
extern "C" int ceph_mds_command()
{
C_SaferCond cond;
int r = cmount->get_client()->mds_command(&cond); //执行完毕以后,栈中的GatherBuilder的变量被释放,但是Gather类和 子任务的GatherSub类是new出来的堆变量,等任务完成以后依靠内部delete函数释放内存。
if (r != 0) {
goto out;
}
// Wait for completion
r = cond.wait(); //所有子任务执行完毕返回
int Client::mds_command()
{
//省略前文,直接从这里开始
C_GatherBuilder gather(cct, onfinish); //建立一个堆栈变量gather
for (const auto& target_gid : non_laggy) {
.........
op.on_finish = gather.new_sub(); //给每个异步任务新建一个context类实例。
.........
}
gather.activate(); //激活异步任务。
return 0;
}