ceph源码分析之读写操作流程(2)

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

ceph源码分析之读写操作流程(2)

上一篇介绍了ceph存储在上两层的消息逻辑,这一篇主要介绍一下读写操作在底两层的流程。下图是上一篇消息流程的一个总结。上在ceph中,读写操作由于分布式存储的原因,故走了不同流程。

对于读操作而言:

1.客户端直接计算出存储数据所属于的主osd,直接给主osd 上发送消息。

2.主osd收到消息后,可以调用Filestore直接读取处在底层文件系统中的主pg里面的内容然后返回给客户端。具体调用函数在ReplicatedPG::do_osd_ops中实现。读操作代码流程如图:如我们之前说的,当确定读操作为主osd的消息时(CEPH_MSG_OSD_OP类型),会调用到ReplicatePG::do_osd_op函数,该函数对类型做进一步判断,当发现为读类型(CEPH_OSD_OP_READ)时,会调用FileStore中的函数对磁盘上数据进行读。

[cpp] view plain copy int ReplicatedPG::do_osd_ops(OpContext *ctx, vector<OSDOp>& ops) { ……

switch (op.op) { …… case

CEPH_OSD_OP_READ: ++ctx->num_read; { // read into a buffer bufferlist

bl; int r = osd->store->read(coll, soid, op.extent.offset, op.extent.length, bl); // 调用FileStore::read从底层文件系统读

取……} case

CEPH_OSD_OP_WRITE:

++ctx->num_write; { ……//写操作只是做准备工作,并不实际的

写} ……} } FileStore::read 函数是底层具体的实现,会通过调用系统函数

如::open,::pread,::close等函数来完成具体的操作。[cpp] view plain copy int FileStore::read( coll_t cid, const ghobject_t& oid, uint64_t offset, size_t len, bufferlist& bl, bool allow_eio) { ……

int r = lfn_open(cid, oid, false, &fd); ……

got = safe_pread(**fd, bptr.c_str(), len, offset);

//FileStore::safe_pread中调用了::pread ……

lfn_close(fd); ……} 而对于写操作而言,由于要保证数据写入的同步性就会复杂很多:

1.首先客户端会将数据发送给主osd,

2.主osd同样要先进行写操作预处理,完成后它要发送写消息给其他的从osd,让他们对副本pg进行更改,

3.从osd通过FileJournal完成写操作到Journal中后发送消息

告诉主osd说完成,进入5

4.当主osd收到所有的从osd完成写操作的消息后,会通过FileJournal完成自身的写操作到Journal中。完成后会通知客户端,已经完成了写操作。

5.主osd,从osd的线程开始工作调用Filestore将Journal中的数据写入到底层文件系统中。在介绍写操作的流程前,需要先介绍一下ceph中的callback函数。

Context类定义在src/include文件中,该类是一个回调函数类的抽象类,继承它的类只要在子类实现它的finish函数,在finish函数调用自己需要回调的函数,就可以完成回调。

[cpp] view plain copy class Context { Context(const Context& other); const Context&

operator=(const Context& other); protected:

virtual void finish(int r) = 0; public: Context() {} virtual ~Context() {} // we want a virtual destructor!!! virtual void complete(int r) { finish(r); delete this; } }; Finisher类是在src/common中定义的一个专门查看操作是否结束的一个类。在这个类里面拥有一个线程finisher_thread和一个类型为Context指针的队列finisher_queue。当一个操作线程完成自己的操作后,会将Context类型对象送入队列。此时finisher_thread线程循环监

视着自己的finisher_queue队列,当发现了有新进入的Context时,会调用这个Context::complete函数,这个函数则会调用到Context子类自己实现的finish函数。来处理操作完成后的后续工作。

[cpp] view plain copy class Finisher { CephContext

*cct; …… vector<Context*>

finisher_queue; …… void

*finisher_thread_entry(); struct FinisherThread : public Thread { Finisher *fin;

FinisherThread(Finisher *f) : fin(f) {} void* entry() { return (void*)fin->finisher_thread_entry(); } } finisher_thread; …… } void

*Finisher::finisher_thread_entry() { ……

while(!finisher_stop){ while(!finisher_queue.empty( )){ ……

vector<Context*> ls

ls.swap(finisher_queue); for

(vector<Context*>::iterator p = ls.begin();

p != ls.end(); ++p) { if (*p) { //这里面调用Context子类实现的finish函数

相关文档
最新文档