关于ceph 客户端的flatten操作
@一只小江 你好,想跟你请教个问题:
看了你关于客户端流程的分析,收益很大,谢谢你的分享。
我想请教你关于在客户端的rbd flatten操作的相关事宜,在rbd flatten操作的时候,会将重合数据重新写入新的image,我加日志后,发现其会以4M的块向相应的oid写数据。但这些数据从哪里来,一直没有追踪到,通过自已添加的log看,大致判断可能是读出来的,但依旧不能确定。且自己对读流程不是很清晰,不明白读到数据后的回调机制。
麻烦您能帮我解惑,不吝赐教!谢谢您。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
引用来自“百草权舆”的评论
@一只小江
你好,谢谢你在百忙之中能回帮复我的问题。
关于flatten操作,根据你的给的启示,我对其具体的流程又做了具体的调查和分析,如你所说,其通过状态转换来实现具体的功能,设计相当的精妙。
但还有一些小的细节需要和你探讨,望不吝赐教。
1flatten操作可以分为三次操作,写-读-写, 第一次写只是空数据,未有相关的动作,只是进入了初始状态,在写动作的异步回调函数中(should_complete)状态转变,且发送读请求,读请求的完成回调后,收集读到的数据置于,然后发起第三次写请求,将相应的数据 写到osd。
第三次的写请求,由谁发起的呢?或者说是谁的回调呢?
最后,真心谢谢你的上次回答。
@一只小江
你好,谢谢你在百忙之中能回帮复我的问题。
关于flatten操作,根据你的给的启示,我对其具体的流程又做了具体的调查和分析,如你所说,其通过状态转换来实现具体的功能,设计相当的精妙。
但还有一些小的细节需要和你探讨,望不吝赐教。
1flatten操作可以分为三次操作,写-读-写, 第一次写只是空数据,未有相关的动作,只是进入了初始状态,在写动作的异步回调函数中(should_complete)状态转变,且发送读请求,读请求的完成回调后,收集读到的数据置于,然后发起第三次写请求,将相应的数据 写到osd。
第三次的写请求,由谁发起的呢?或者说是谁的回调呢?
最后,真心谢谢你的上次回答。
感谢你的回复。 还有一个小问题需要请教。 关于flatten的操作,我们知道,第一次是一个空的写请求,第二次是一个读请求,第三次将第二次的读请求获取的数据发送一个写请求。 但我们从代码可以看到,第二次读请求是获取所有ovelap数据,但第三部分只是针对某一个objectid的写请求,这两个部分难道 不应该是读一个具体的overlap中object id的数据,再将其写到新的objectid中吗?
这部分代码当初确实看过,但是现在也想不起来那么详细的细节了。
1. 首先需要说明一下child_image的写入原理。原始parent_image经过快照snap。然后在根据snap创建clone。这里clone后的child_image是没有真正的将parent_image数据拷贝到child_image中(一开始时,一丁点数据都没拷贝)。直到child_image要写入数据时,假如写child_image的object_x中的一部分数据data_new(data_new的数据小于等于4M),则会先从parent_image读出object_x的数据data_old(data_old包含了object的大小,默认是4M)。这时把data_new覆盖到data_old上形成最新的data,再将这个data写入child_image中。
2.flatten的操作的原理同child_image的写入原理是一样。flatten操作会将parent与child重合的object统计出来set_object,然后向child_image的set_object中的每一个object发送一个写请求,这个写请求的size为0 data_new(0M),对于child_image的写入原理上面说了,这时出先从parent中读取对应的object的数据data_old(4M),然后再合并data_new与data_old,合并仍然是4M的data。再将这个data写入到child_image。
原理就是上述讲的内容,具体的代码可参考AioWrite req。
调用关系,最重要的生成一个
do_flatten()
flatten_with_progress()
librbd::flatten()
async_flatten()
AsyncFlattenRequest::send()
throttle->start_ops()
start_next_op()
AsyncFlattenObjectContext ::send()
AioWrite *req = new AioWrite()
req->send()
req有一个继承的类叫做AbstractWrite,这个类里边定义很重要的回调函数should_complete(),这个就是child_image写入操作的各个阶段,根据不同阶段会有不同的处理,这里包括了读取parent_image数据,合并数据date_new 与 data_old,合并后的数据写入child_image的各个阶段。
AioWrite ---> AbstractWrite
AbstractWrite::should_complete()
flatten这部分代码写的很妙,值得去细细看,然后学会这些程序设计的思想。