More than code

More Than Code
The efficiency of your iteration of reading, practicing and thinking decides your understanding of the world.
  1. 首页
  2. rocksdb
  3. 正文

RocksDB WAL概览

2023年4月16日 733点热度 0人点赞 0条评论

WAL

简单看一下RocksDB的WAL

SyncWAL

接口处有一个叫SyncWAL的函数,作用是把当前的日志同步到盘上。

相关的数据结构有一个deque<LogWriterNumber>,以及一个锁叫做log_write_mutex_。

其中LogWriterNumber中保存了log filter number,log writer,一个标识当前日志正在进行Sync的标记,以及pre_sync_size,代表在调用Sync之前的已经写入当前日志的数据大小,这里注释是说这个值会被记录在Manifest中,也就是说RocksDB会记录每个日志都有哪些数据被刷到了盘中(具体目的还不清楚)。

SyncWAL中会取出当前MemTable的LogFileNumber,如果当前有日志正在进行Sync,判断的标记就是LogWriterNumber中的getting_sync,就会睡在一个CV上等待唤醒。

然后会把所有小于刚才记录的log file number的日志都调用PrepareForSync,表示当前日志正在进行Sync,并记录每个日志已经写入的数据量,即pre_sync_size。

然后把所有需要同步的日志都调用SyncWithoutFlush,表示不会写入数据(写入PageCache),只会调用Sync。这里调WithoutFlush的含义我也不是很懂,感觉一把刷下去就好了。。可能是有什么feature上的兼容吧。

刷完以后可能会同步一下原数据,这里调的是FsyncWithDirOptions,猜测就是创建新的文件后就需要Sync一下Dir。

结束后会调MarkLogsSynced,里面会判断下,如果一个日志已经全部都Sync了,就会把他从刚才的deque中移除,否则的话就会调用FinishSync,标记Sync已经结束,等待下一轮的Sync。

如果打开了track_and_verify_wals_in_manifest就会把刚才的变更记录到Manifest中,注释中说到他的用处就是用来及时发现Corruption。

如果要记录已经Sync的WAL的话,会调用ApplyWALToManifest来把这个VersionEdit记录下来。

写链路上的WAL

上面看SyncWAL的时候遇到了几个问题,结合一些实现可以找到对应的答案。之所以会有SyncWAL这个接口是因为RocksDB提供一个配置叫need log sync,表示每次写WAL是否需要同步到盘上。在need log sync为false的时候,一般配合SyncWAL的调用使用。

而之所以要区分Flush和Sync,是因为RocksDB也提供一个选项叫manual wal flush,默认是关闭的。在写入WAL的时候,如果打开了manual wal flush,就会放弃调用Flush,而是等待用户手动调用FlushWAL。

在主链路的PreprocessWrite中,会和SyncWAL做类似的逻辑,即调用PrepareForSync,其目的注释中也有写,是为了防止并发的SyncWAL的调用。不过防止并发的Sync调用的目的目前还没太想明白,应该只是为了记录已经Sync的数据大小。

然后Leader会调用WriteToWAL,里面会做MergeBatch,将本次Batch写入到LogWriter中,并调用Sync。

在WAL写完后,同样有一个和SyncWAL类似的处理逻辑,就是调用MarkLogsSynced,这里会调用FinishSync,并且在配置打开的时候,会将Sync的日志信息记录到Manifest中。

SwitchWAL

在PreprocessWrite的时候,如果目前log的长度超过了阈值,就会调用SwitchWAL。只有在CF的数量大于1的时候才会调用SwitchWAL。

里面有个option叫atomic flush,说的是在没开WAL的时候,如果也希望多个CF的写入是原子的,就需要打开这个选项,和主链路无关先不细看。

这里会尝试对若干个CF调用SwitchMemTable,选择CF的条件是CF的LogNumber小于oldest_alive_log(这里感觉是需要联动看的)。

调用SwitchMemTable就会尝试打开一个新的LogWriter,并添加到上面提到的std::deque<LogWriterNumber>这个结构中。并且会对这些CF调用FlushRequested,表示需要Flush L0。

在SwitchMemTable的时候,只有在最新的LogWriter中有新的写入的时候,才会做添加一个新的LogWriter。表示的是一个LogWriter不能记录同一个CF多个不同MemTable的写入。(同样理由还得再想想)

CreateWAL

CreateWAL实际上是在SwitchMemTable内部调用的,即在需要创建新的LogWriter的时候,就会调用CreateWAL。这里主要是看一下,除了SwitchWAL会调用SwitchMemTable,还有哪些地方会调用。

在写入MemTable的时候,比如MemTable的Add,会调用UpdateFlushState,如果MemTable过大,会将flush_state_置为FLUSH_REQUESTED。

在WriteBatch写入MemTable的时候,会调用CheckMemTableFull,如果当前MemTable是ShouldScheduleFlush,就会将flush_state_ CAS为FLUSH_SCHEDULED,并将当前的CF传给flush_scheduler

在Preprocess的时候会判断,如果flush_scheduler_非空的话,就会调用ScheduleFlushes,里面则会Switch掉所有非空的MemTable。

还有一种情况就是在Preprocess的时候,会判断write_buffer_manager->ShouldFlush,里面会判断memtable的内存占用是否过大,过大的话会调用HandleWriteBufferManagerFlush,同样是和ScheduleFlushes类似的逻辑,Switch掉所有非空的MemTable。

标签: 暂无
最后更新:2023年4月16日

sheep

think again

点赞
< 上一篇

文章评论

取消回复

COPYRIGHT © 2021 heavensheep.xyz. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS