Tag: ceph 12.2.4
BlueStore transaction相关结构
BlueStore事务状态转换
OSD层IO保序处理
ShardedOpWQ内部存在一组ShardData,每个ShardData包含队列pqueue、锁sdata_op_ordering_lock;
IO放入时根据pgid哈希映射到某一个shard(保证同一pg映射到同一shard),shard内部通过锁sdata_op_ordering_lock保序;
BlueStore层写操作处理
simple write: 新写 | 对齐写等(非WAL)场景;
deferred write: 需要写WAL场景;
- simple write
1)数据写块设备(新block); 2)更新元数据(k/v);
事务状态转换
写新block:
STATE_PREPARE -> STATE_AIO_WAIT -> STATE_IO_DONE -> STATE_KV_QUEUED;
更新元数据(k/v):
STATE_KV_QUEUED -> STATE_KV_SUBMITTED -> STATE_KV_DONE -> STATE_FINISHING -> STATE_DONE;
线程情况
线程池osd_op_tp设置状态STATE_PREPARE、STATE_AIO_WAIT,提交IO待回调;
线程aio_thread回调处理,设置状态STATE_IO_DONE、STATE_KV_QUEUED;
线程kv_sync_thread提交k/v事务,设置状态STATE_KV_SUBMITTED;
线程kv_finalize_thread设置状态STATE_KV_DONE、STATE_FINISHING、STATE_DONE;
若步骤1完成后发生异常,原先数据未被破坏且元数据并未更新,本次更新数据不可见;
更新元数据,针对同一对象的操作需保序执行;
// 方法:void BlueStore::_txc_finish_io(TransContext *txc)
while (p != osr->q.begin()) {
--p;
// osr内部列表q中元素p(TransContext)之前是否都已完成IO
if (p->state < TransContext::STATE_IO_DONE) {
return;
}
if (p->state > TransContext::STATE_IO_DONE) {
++p;
break;
}
}
do {
_txc_state_proc(&*p++); // 放入kv_queue
} while (p != osr->q.end() && p->state == TransContext::STATE_IO_DONE);
更新元数据完成,_txc_state_proc执行事务状态STATE_KV_SUBMITTED分支,调用_txc_committed_kv进入队列待回调,其后数据可读/已提交;
- deferred write
数据和元数据写WAL(k/v, PREFIX_DEFERRED),其后数据可读/已提交,后续将数据写入块设备;
事务状态转换
写WAL:
STATE_PREPARE -> STATE_IO_DONE -> STATE_KV_QUEUED -> STATE_KV_SUBMITTED -> STATE_KV_DONE -> STATE_DEFERRED_QUEUED;
写数据:
STATE_DEFERRED_QUEUED -> STATE_DEFERRED_CLEANUP -> STATE_FINISHING -> STATE_DONE;
线程情况
线程池osd_op_tp设置状态STATE_PREPARE、STATE_IO_DONE和STATE_KVQUEUED,WAL写请求在k/v队列排队,待kv_sync_thread提交k/v日志,设置状态STATE_KV_SUBMITTED;
线程kv_finalize_thread设置状态STATE_KV_DONE和STATE_DEFERRED_QUEUED,生成写数据deferredbatch事务(dbh)并提交IO请求,待回调;
线程aio_thread回调处理,设置状态STATE_DEFERRED_CLEANUP ;
线程kv_sync_thread清理对应k/v日志;
线程kv_finalize_thread设置状态STATE_FINISHING、STATE_DONE;
异常情况,可通过WAL回放(_deferred_replay);
若数据未写入块设备前,读取该对象,等待pending aio下刷完成再读取;
数据写块设备时如何保序,IO事务OpSequencer进入队列deferred_queue,
_deferred_submit_unlock方法中将deferred_pending、deferred_running两者进行交换,准备aio结构,aio_submit一次性提交txc,完成后进行下一次提交。
另外,simple write和deferred write之间如何保序写kv,事务按序进入OpSequencer q_list_t(_txc_create),simple wirte完成数据写入后,_txc_finish_io将自身事务状态置为STATE_IO_DONE,deferred write调用_txc_finish_io状态直接从STATE_PREPARE转换为STATE_IO_DONE,OpSequencer内部列表本事务之前所有事务都已完成IO,事务按序放入kv_queue,待_kv_sync_thread处理。