Status DBImpl::Write(const WriteOptions& write_options, WriteBatch* my_batch) {
if (my_batch == nullptr) {
return Status::Corruption("Batch is nullptr!");
}
PERF_TIMER_GUARD(write_pre_and_post_process_time);
// WriteThread::Writer是一个写任务的抽象结构,代表了用户的一次写操作。其中的batch字段存有
// 实际需要写入的数据,sync字段指明这个写操作需不需要对事务日志执行fsync/fdatasync操作,而
// disableWAL指明是否需要写事务日志,done字段在该写操作完成时设置,timeout_hint_us指明了
// 这个写操作完成时间期限。
// 最后,in_batch_group的比较有意思。在RocksDB内部,对写入操作做了优化,尽可能地将用户的写入
// 批量处理。这其中使用了一个队列,即write_thread_内部的WriteThread::Writer*队列。在准备写队列头
// 的任务时,会试着用BuildBatchGroup()构建一个批量任务组,将紧跟着队头的其他写操作任务加入
// 到一个BatchGroup,一次性地写入数据库。
WriteThread::Writer w(&mutex_);
w.batch = my_batch;
w.sync = write_options.sync;
w.disableWAL = write_options.disableWAL;
w.in_batch_group = false;
w.done = false;
w.timeout_hint_us = write_options.timeout_hint_us;
uint64_t expiration_time = 0;
bool has_timeout = false;
if (w.timeout_hint_us == 0) {
w.timeout_hint_us = WriteThread::kNoTimeOut;
} else {
expiration_time = env_->NowMicros() + w.timeout_hint_us;
has_timeout = true;
}
if (!write_options.disableWAL) {
RecordTick(stats_, WRITE_WITH_WAL);
}
// ???
WriteContext context;
mutex_.Lock();
if (!write_options.disableWAL) {
default_cf_internal_stats_->AddDBStats(InternalStats::WRITE_WITH_WAL, 1);
}
// 将当前写入任务@w挂入写队列,并在mutex_上睡眠等待。等待直到:
// 1) 写操作设置了超时时间,等待超时。或,
// 2) @w之前的任务都已完成,@w已处于队列头部。或,
// 3) @w这个写任务被别的写线程完成了。
// 第3个条件,任务被别的写线程完成,实际上是被之前的写任务合并进一个
// WriteBatchGroup中去了。此时的@w会被标记成in_batch_group。有意思的是,在EnterWriteThread()
// 里面,如果因为超时唤醒了,发现当前任务in_batch_group为true,则会继续等待,
// 因为它已经被别的线程加入BatchGroup准备写入数据库了。
Status status = write_thread_.EnterWriteThread(&w, expiration_time);
assert(status.ok() || status.IsTimedOut());
if (status.IsTimedOut()) {
mutex_.Unlock();
RecordTick(stats_, WRITE_TIMEDOUT);
return Status::T
RocksDB写入数据过程DBImpl::Write()源代码分析
最新推荐文章于 2023-05-10 10:48:34 发布
本文详细分析了RocksDB的DBImpl::Write()函数,解释了如何处理写入任务,包括同步选项、WriteThread::Writer结构、批处理优化及超时管理。在写操作中,RocksDB尝试将用户写入批量处理以提高效率,并在适当时候触发flush和compaction。
摘要由CSDN通过智能技术生成