CEPH EC覆盖写实现

2017-03-23  本文已影响0人  宋新颖

概述

EC由于需要对原始数据进行编码、解码,覆盖写时必须保证边界对齐。实际情况下客户端发起覆盖写入时传入的offset和length是随机的,因此EC执行时需要先将原始offset和length按stripe进行对齐,读取对齐后对应的数据片段,根据客户传入的新数据对读取的数据进行修改,完成后写入底层,整个流程为read-modify-write(rmw)。

内部实现

使用EC时,ECBackend负责每个pg的EC相关操作。由于覆盖写入经常需要先读取数据,因此在ECBackend中实现了一个cache:ExtenCache,用来管理每个pg已经读到本地内存中的extent,当一次PGTransaction完成后,这些extent会释放掉。

完成一次PGTransaction需要在ECBackend中生成一个Op,在不同阶段,Op位于不同队列中

在上面这些步骤中 EC 完成了 read-modify-write ,下面详细介绍。

为了实现read,ECBackend在每个Op中放入了一个ECTransaction::WritePlan,write_plan 负责记录当前需要写入的extent(WritePlan::will_write)和由于对齐原因需要读取的extent(WritePlan::to_read)。将Op的write_plan 初始化后直接放入了waiting_state队列。计算 write_plan 过程并不复杂,根据用户的PGTransaction信息和目标对象的HashInfo扩展属性即可计算出为了按 stripe 对齐,还需要读取哪些数据。
有了 write_plan 后,就可以查找ExtentCache中是否包含 WritePlan::to_read 中的 extent,对于不在 cache 中的 extent,放入Op::remote_read中,表示需要从各个shard读取的数据(这些数据是stripe对齐的,和用户要写入的数据范围有重叠),而Op::remote_read_result则用来存放最终读取结果。
向各个 shard 发起读请求是通过两个回调类ClientAsyncReadStatusCollectionContext以及两个关键数据结构read_request_tReadOp完成,ECBackend::handle_sub_op_reply时会将结果放在ReadOp::complete中,需要的 shard 读取都完成后,通过ECBackend::complete_read_op()将 shard 的数据解码,最终放入Op::remote_read_result

modify 由ECTransaction::generate_transactions()实现,此函数根据PGTransaction对已经读到的数据进行修改(这些是没按stripe对齐的extent请求),已经 stripe 对齐的 extent 请求只需正常写入即可。最终生成发往每个shard 的ObjectStore::Transaction,返回给调用者一个写入后的最新数据,调用者据此更新cache。

write 动作只是将已经生成好的ObjectStore::Transaction发送给各个shard,写入请求都返回后对cache进行清理,释放掉前面使用过的extent。

上一篇 下一篇

猜你喜欢

热点阅读