共计 3196 个字符,预计需要花费 8 分钟才能阅读完成。
这篇文章主要介绍 Ceph 中 RGW 是如何向底层 OSD 发送 Message 的,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!
1. Librados 的读写流程
在 src/cls/rgw/cls_rgw_client.cc 可以看到如下函数:
int cls_rgw_lc_set_entry(IoCtx io_ctx, string oid, pair string, int entry)
bufferlist in, out;
cls_rgw_lc_set_entry_op call;
call.entry = entry;
::encode(call, in);
int r = io_ctx.exec(oid, rgw , lc_set_entry , in, out);
return r;
}
继续跟踪 io_ctx.exec() 这个函数调用, 在 src/librados/librados.cc 可以查看到相应的函数实现如下:
int librados::IoCtx::exec(const std::string oid, const char *cls, const char *method,
bufferlist inbl, bufferlist outbl)
object_t obj(oid);
return io_ctx_impl- exec(obj, cls, method, inbl, outbl);
}
继续跟踪 io_ctx_impl- exec() 这个函数调用,在 librados/IoCtxImpl.cc 中看到如下实现:
int librados::IoCtxImpl::exec(const object_t oid,
const char *cls, const char *method,
bufferlist inbl, bufferlist outbl)
::ObjectOperation rd;
prepare_assert_ops(rd);
rd.call(cls, method, inbl);
return operate_read(oid, rd, outbl);
}
rd.call() 此函数将该操作封装成 OSDOp,放入 ObjectOperation 对象的 vector 集合中。在最后的 operate_read(oid, rd, outbl) 函数中发起读写请求操作:
int librados::IoCtxImpl::operate_read(const object_t oid,
::ObjectOperation *o,
bufferlist *pbl,
int flags)
if (!o- size())
return 0;
Mutex mylock( IoCtxImpl::operate_read::mylock
Cond cond;
bool done;
int r;
version_t ver;
Context *onack = new C_SafeCond( mylock, cond, done,
int op = o- ops[0].op.op;
ldout(client- cct, 10) ceph_osd_op_name(op) oid= oid nspace= oloc.nspace dendl;
Objecter::Op *objecter_op = objecter- prepare_read_op(oid, oloc,
*o, snap_seq, pbl, flags,
onack, ver);
lock- Lock();
objecter- op_submit(objecter_op)
;
lock- Unlock();
mylock.Lock();
while (!done)
cond.Wait(mylock);
mylock.Unlock();
ldout(client- cct, 10) Objecter returned from
ceph_osd_op_name(op) r= r dendl;
set_sync_op_version(ver);
return r;
}
需要说明的是 operate_read(oid, rd, outbl) 可以分解为一下三个步骤:
创建一个 Op 实例, 数据结构变成了 Objecter::Op
Objecter::Op *objecter_op = objecter- prepare_read_op(oid, oloc,
*o, snap_seq, pbl, flags,
onack, ver);
操作提交到 objecter 层,操作对象类型变为 Objecter::Op, 函数实现在 osdc/Objecter.cc:
objecter- op_submit(objecter_op)
继续调用 ceph_tid_t Objecter::_op_submit() 函数,函数实现在 osdc/Objecter.cc:省略了部分代码,重点关注 send_op(op)
ceph_tid_t Objecter::_op_submit(Op *op)
// pick tid if we haven t got one yet
if (op- tid == ceph_tid_t(0)) {
ceph_tid_t mytid = ++last_tid;
op- tid = mytid;
}
assert(client_inc = 0);
// pick target
num_homeless_ops++; // initially; recalc_op_target() will decrement if it finds a target
int r = recalc_op_target(op);
bool check_for_latest_map = (r == RECALC_OP_TARGET_POOL_DNE);
............
else if (op- session) { send_op(op);
}
.............
}
这里的 send_op(op) 就是我们要关注的重点了. 从这里开始就会用到网络层提供的各种操作将消息, 也就是这里的 op 发送出去. 这里可以看成是调用网络层的一个起点.
下面的代码就和网络层有关系了。
2. 发送消息的过程。
在网络层中,需要注意的是类 Messenger 是核心的数据结构。同时也是个抽象基类,在 Firefly 版本中,由于网络通信类型只实现了 SimpleMessenger 这一单一类型。在后面,就会看到 SimpleMessenger 是继承自 Messenger 类,很多方法最终都是调用的是 SimpleMessenger(在此也可以体会到多态思想)。首先,看一下 Objecter 类的声明 (其他部分已省略):
class Objecter : public md_config_obs_t {
...........
public:
Messenger *messenger;
........
}
在这个类中声明了 messenger. 从 ceph_tid_t Objecter::_op_submit(Op *op) 中可以看到,最后调用了 send_op() 函数。这个函数末尾:
messenger- send_message(m, op- session- con);
可以看出,需要发送的消息是: m。发送到哪里去呢?通过 **op- session- con** 可以获取到相应的连接。
以上是“Ceph 中 RGW 是如何向底层 OSD 发送 Message 的”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注丸趣 TV 行业资讯频道!