leveldb的write代码初看瞎搞一堆,细看则实为短小精悍。1 Status DBImpl::Write(const WriteOptions& options, WriteBatch* my_batch) {

 2  // -----A begin-------  3   Writer w(&mutex_);  4   w.batch = my_batch;  5   w.sync = options.sync;  6   w.done = false;  7   // -----A end  --------  8 9
10   // -----B begin-------
11   MutexLock l(&mutex_);
12   writers_.push_back(&w);
13   while (!w.done && &w != writers_.front()) {
14     w.cv.Wait();
15   }
16   if (w.done) {
17     return w.status;
18   }
19   // -----B end  -------
20
21   // May temporarily unlock and wait.
22   Status status = MakeRoomForWrite(my_batch == NULL);
23   uint64_t last_sequence = versions_->LastSequence();
24   Writer* last_writer = &w;
25   if (status.ok() && my_batch != NULL) {  // NULL batch is for compactions
26     WriteBatch* updates = BuildBatchGroup(&last_writer);
27     WriteBatchInternal::SetSequence(updates, last_sequence + 1);
28     last_sequence += WriteBatchInternal::Count(updates);
29
30     // Add to log and apply to memtable.  We can release the lock
31     // during this phase since &w is currently responsible for logging
32     // and protects against concurrent loggers and concurrent writes
33     // into mem_.
34     {
35       // -----C begin-------
36       mutex_.Unlock();
37       // -----C end  -------  

      // add batch data to log files
38       status = log_->AddRecord(WriteBatchInternal::Contents(updates));
39       if (status.ok() && options.sync) {
40         status = logfile_->Sync();
41       }
42       if (status.ok()) {
43         status = WriteBatchInternal::InsertInto(updates, mem_);
44       }
45       // -----D begin-------
46       mutex_.Lock();
47       // -----D end  -------
48     }
49     if (updates == tmp_batch_) tmp_batch_->Clear();
50
51     versions_->SetLastSequence(last_sequence);
52   }
53
54   // -----E begin-------
55   while (true) {
56     Writer* ready = writers_.front();
57     writers_.pop_front();
58     if (ready != &w) {
59       ready->status = status;
60       ready->done = true;
61       ready->cv.Signal();
62     }
63     if (ready == last_writer) break;
64   }
65   // -----E end -------
66
67
68   // -----F begin-------
69   // Notify new head of write queue
70   if (!writers_.empty()) {
71     writers_.front()->cv.Signal();
72   }
73   // -----F end-------
74
75   return status;
76 }

   如上,A段代码定义一个Writer w, w的成员包括了batch信息,同时初始化了一个条件变量成员(port::CondVar)

  假设同时有w1, w2, w3, w4, w5, w6 并发请求写入。

  B段代码让竞争到mutex资源的w1获取了锁。添加到writers队列里去,此时队列只有一个w1, 从而其顺利的进行BuildBatchGroup。当运行到c段代码时,mutex互斥锁释放,这时(w2, w3, w4, w5, w6)会竞争锁,由于B段代码中不满足队首条件,均等待并释放锁了。从而队列可能会如(w3, w5, w2, w4).

  继而w1进行log写入和memtable写入,之所以这里在无锁状况下时安全的,因为其它的写操作都不满足队首条件,进而不会进入log和memtable写入阶段。 当w1完成log和memtable写入后,进入d段代码,则mutex又锁住,这时B段代码中队列因为获取不到锁则队列不会修改。

  进入E段代码后,w1被pop出来,由于reader==w, 并且ready==last_writer,所以直接到F段代码,唤醒了此时处于队首的w3.

  w3唤醒时,发现自己是队首,可以顺利的进行进入BuildBatchGroup,在该函数中,遍历了目前所有的队列元素,形成一个update的batch,即将w3, w5, w2, w4合并为一个batch. 并将last_writer置为此时处于队尾的最后一个元素w4,c段代码运行后,因为释放了锁资源,队列可能随着DBImpl::Write的调用而更改,如队列状况可能为(w3, w5, w2, w4, w6, w9, w8).

  C段和D段间的代码将w3, w5, w2, w4整个的batch写入log和memtable. 到E段时,分别对w5, w2, w4进行了一次cond signal.当判断到完w4 == lastwriter时,则退出E段代码。F段则对队首的w6唤醒,从而按上述步骤依次进行下去。

  这样就形成了多个并发write 合并为一个batch写入log和memtable的机制。

转载于:https://www.cnblogs.com/mh1092/p/9936484.html

[LevelDB] 写批处理过程详解相关推荐

  1. Hadoop学习之Mapreduce执行过程详解

    一.MapReduce执行过程 MapReduce运行时,首先通过Map读取HDFS中的数据,然后经过拆分,将每个文件中的每行数据分拆成键值对,最后输出作为Reduce的输入,大体执行流程如下图所示: ...

  2. Android签名机制之---签名验证过程详解

    一.前言 今天是元旦,也是Single Dog的嚎叫之日,只能写博客来祛除寂寞了,今天我们继续来看一下Android中的签名机制的姊妹篇:Android中是如何验证一个Apk的签名.在前一篇文章中我们 ...

  3. Linux开启动过程详解

    Linux开启动过程详解 Linux启动过程 前言: Linux是一种自由和开放源代码的类UNIX操作系统.该操作系统的内核由林纳斯·托瓦兹在1991年10月5日首次发布.在加上用户空间的应用程序之后 ...

  4. 操作系统之多线程编程—读者优先/写者优先详解

    操作系统之进程调度--优先权法和轮转法(附上样例讲解) 操作系统之银行家算法-详解流程及案例数据 操作系统之多线程编程-读者优先/写者优先详解 操作系统之存储管理--FIFO算法和LRU算法 操作系统 ...

  5. Mysql加锁过程详解(2)-关于mysql 幻读理解

    Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...

  6. python属性使用教程_Python对象的属性访问过程详解

    只想回答一个问题: 当编译器要读取obj.field时, 发生了什么? 看似简单的属性访问, 其过程还蛮曲折的. 总共有以下几个step: 1. 如果obj 本身(一个instance )有这个属性, ...

  7. Java web 开发的概念、环境配置、创建项目过程详解(Eclipse)

    Java Web 开发 Java Web 开发概念 搭建过程 详解 在eclipse创建Dynamic Web Project 创建时选择Tomcat的版本 创建项目成功 eclipse环境下如何配置 ...

  8. #转载:杨辉三角形实现过程详解-c语言基础

    杨辉三角形实现过程详解-C语言基础 十一一个人 2018-12-26 06:45:45 6465 收藏 28 最后发布:2018-12-26 06:45:45首发:2018-12-26 06:45:4 ...

  9. U-Boot 之三 U-Boot 源码文件解析及移植过程详解

      在之前的博文 Linux 之八 完整嵌入式 Linux 环境介绍及搭建说明 中我们说了要一步步搭建整个嵌入式 Linux 运行环境.我所使用的硬件平台及整个要搭建的嵌入式 Linux 环境见博文 ...

最新文章

  1. wpf listview mysql_Kivy:使用MySQL的Kivy页面的Listview实现
  2. 不是变量 win10_在win10下安装manim
  3. 【Android】Apk安装和删除
  4. mysql 取 映射数据库中_JAVA与数据库MySQL相连接
  5. python函数结构_PYTHON 之结构体,全局变量,函数参数,lambda编程 等
  6. 数据结构与算法——二叉排序树详解以及代码实现
  7. tdk怎么设置_网站tdk如何正确的设置
  8. python数据挖掘笔记】十八.线性回归及多项式回归分析四个案例分享
  9. 学习OpenCV时 ,添加:#includeopencv2/core/core.hpp等头文件出现无法编译的错误
  10. windows 安装 mysql 5.6
  11. python strip() 方法
  12. python数据框添加一列无列名_Pandas只使用列名创建空数据框
  13. matlab积分超过最大值,MATLAB 定积分上限是变量a,如何求解目标函数关于变量a的最大值?谢谢...
  14. 对话「平衡车之父」:把Solowheel带回中国
  15. 大学计算机云计算与虚拟服务实验,虚拟化与云计算实验报告.doc.pdf
  16. 工控网络安全学习路线
  17. 新一代打包神器parcel简介
  18. web网页制作期末大作业——蓝色的异清轩个人博客(6页) 个人博客模板源码异清轩博客
  19. 什么是ISO?ISO增值的作用
  20. C++环境下部署深度学习模型方案

热门文章

  1. linux mysql 忘记root密码_Linux MySQL忘记root密码解决方案
  2. LeetCode 07. 整数反转
  3. linux监控nginx占用,使用zabbix 2.4 监控nginx
  4. mysql开发问题解决_开发过程中mysql常见问题的解决方法
  5. 公路多孔箱涵设计_【公路常识中篇】公路路基边坡滑坡防护设计和预防
  6. java 实现按规则自增功能_java运算符详解 - osc_74vaali6的个人空间 - OSCHINA - 中文开源技术交流社区...
  7. pat 乙级 1021 个位数统计(C++)
  8. 光端机的几种物理接口类型
  9. 【渝粤教育】国家开放大学2018年春季 8634-22TAndroid智能手机编程 参考试题
  10. 【渝粤题库】陕西师范大学200641高等数学作业(高起专、专升本)