原链接
http://blog.csdn.net/carny/article/details/52240828
ceph中的pool有两种类型:replicated pool和erasure pool 这里从rados接口开始跟踪分析一下pool的创建过程 一、rados接口部分 1、rados里创建pool的接口是(librados.cc) int librados::Rados::pool_create(const char *name); int librados::Rados::pool_create(const char *name, uint64_t auid); int librados::Rados::pool_create(const char *name, uint64_t auid, __u8 crush_rule); int librados::Rados::pool_create_async(const char *name, PoolAsyncCompletion *c); int librados::Rados::pool_create_async(const char *name, uint64_t auid, PoolAsyncCompletion *c); int librados::Rados::pool_create_async(const char *name, uint64_t auid, __u8 crush_rule, PoolAsyncCompletion *c); 这些接口最终是会调用librados::RadosClient下的响应接口,比如 int librados::Rados::pool_create(const char *name, uint64_t auid, __u8 crush_rule); 调用的是 int librados::RadosClient::pool_create(string& name, unsigned long long auid, int16_t crush_rule); 这里就以这个接口为例跟踪 2、int librados::RadosClient::pool_create(string& name, unsigned long long auid, int16_t crush_rule) A、先是获取osdmap,获取失败后,则返回 int librados::RadosClient::wait_for_osdmap() 这里面是从radosclient的objecter里读取osdmap,如果没有osdmap,那么会等待objecter获取到osdmap,直到超时(默认一直等OPTION(rados_mon_op_timeout, OPT_DOUBLE, 0)) B、调用reply = objecter->create_pool(name, onfinish, auid, crush_rule); 开始创建pool,并设置了回调函数onfinish C、如果上面的函数调用成功,则会一直等待创建的结果 3、int create_pool(string& name, Context *onfinish, uint64_t auid=0,
int crush_rule=-1);
4、void Objecter::pool_op_submit(PoolOp *op) { // rwlock is locked if (mon_timeout > timespan(0)) { op->ontimeout = timer.add_event(mon_timeout, [this, op]() { pool_op_cancel(op->tid, -ETIMEDOUT); }); } _pool_op_submit(op); } 5、void Objecter::_pool_op_submit(PoolOp *op) 构建与mon通讯的对象,然后发送消息给monitor,请求创建创建pool monc->send_mon_message(m); 消息的类型为CEPH_MSG_POOLOP 二、Monitor消息处理部分 monitor接收消息后,消息处理流程如下 CEPH_MSG_POOLOP是由OSDMonitor处理的 case CEPH_MSG_POOLOP: paxos_service[PAXOS_OSDMAP]->dispatch(op); //这里不应答客户端? break; 1、bool PaxosService::dispatch(MonOpRequestRef op) A、首先会丢弃旧消息 B、确认osdmap是最新的 m->version指的是客户端的osdmap的版本,如果m->version比本地的版本要新,则会通过paxos协议获取最新的osdmap版本 wait_for_readable将当前的操作OP添加到proposal队列里,获取成功后,会通过回调函数重试 C、preprocess_query是查询操作,在这里属于更新操作,所以与这个函数无关,这部分可以先学习paxos的内容 D、更新操作,prepare_update()的实现是bool OSDMonitor::prepare_update(MonOpRequestRef op) 该函数里调用bool OSDMonitor::prepare_pool_op(MonOpRequestRef op) 然后函数里判断是创建pool操作,进一步调用prepare_pool_op_create 2、bool OSDMonitor::prepare_pool_op_create(MonOpRequestRef op) prepare_new_pool函数根据参数,设置crush_ruleset,pg_num,pgp_num,副本数,以及纠删池的条带宽度等 在设置完上面的参数后,会到pending_inc.new_pool_names (OSDMap::Incremental pending_inc;)里查找,是否已经存在相同名字的pool,如果有则返回,不重复创建,否则,创建一个新的pool对象,并添加的pending_inc.new_pool_names里,一遍后续提交,最后为新的pool添加一些参数 在所有参数都设置完成后,需要commit当前的信息到各个monitor节点 wait_for_finished_proposal(op, new OSDMonitor::C_PoolOp(this, op, err, pending_inc.epoch)); 上面的函数将操作压入paxos 的proposal队列,以便提交 在回调函数里,会根据提交结果,应答客户端 3、然后又回到了PaxosService::dispatch(MonOpRequestRef op)函数里, prepare_update(op)根据返回值,决定是否需要触发paxos流程: 4、上面的propose_pending的实现是void PaxosService::propose_pending() void PaxosService::propose_pending()的实现如下 A、创建一个paxos事务 MonitorDBStore::TransactionRef t = paxos->get_pending_transaction(); B、调用encode_pending函数实现序列化,实际上是由void OSDMonitor::encode_pending(MonitorDBStore::TransactionRef t)实现 encode_pending函数里会先拷贝一份当前的osdmap,然后将pending_inc(即OSDMap::Incremental pending_inc;)里的内容应用到拷贝出来的新的osdmap,生成一份新的完整的OSDMap 同时将版本号,和最后提交的序号序列化进入事务里 C、最后应用到paxos里面去 // apply to paxos proposing = true; paxos->queue_pending_finisher(new C_Committed(this)); paxos->trigger_propose(); 这里回调函数C_Committed(this)里会调用void PaxosService::_active() 最终会调用finish_contexts(g_ceph_context, waiting_for_finished_proposal, 0);唤醒创建pool的op操作(在prepare_pool_op_create函数里设置了wait_for_finished_proposal(op, new OSDMonitor::C_PoolOp(this, op, err, pending_inc.epoch));) OSDMonitor::C_PoolOp的回调函数回根据paxos的结果,应答客户端
至此,pool创建流程接收。