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. 那些年我们一起追过的缓存写法(二)
  2. 自己动手 从android硬件驱动到APP---(1)硬件驱动层
  3. python打开并读取csv文件_!python3中使用使用read_csv( )读取csv文件,文件路径中含有中文,无法读取怎么处理?...
  4. ant中的loading按钮使用
  5. httpservletrequest_HttpServletResponse和HttpServletRequest取值的2个坑你知道吗?
  6. KNN(五)--层次Kmean
  7. 车辆等级、车型分类及carsim内置车辆种类整理
  8. java字体设置框_CSS样式更改——字体设置Font边框Border
  9. Cannot negotiate authentication mechanism svn: Unable to connect to a repository at URL 'svn://gite
  10. win10装debian 双系统_如何安装win10和linux [ubuntu14]双系统
  11. 论文解读:Making Pre-trained Language Models Better Few-shot Learners(LM-BFF)
  12. (poj 2377)Kruskal算法 最大生成树
  13. 微信公众号开发相关问题
  14. 服务器怎么备案?备案时间要多久?
  15. 数据分析利器 —— 列式储存数据库
  16. 电商项目相关面试问题及答案
  17. 信号(进程间的通信方式)
  18. 虚函数、虚表的生成,虚表的修改
  19. 智能体温检测系统解决方案
  20. ultraiso软碟通注册码

热门文章

  1. Linux 系统启动流程图/系统初始化流程图
  2. 安装、启动、配置zookeeper(window版)
  3. python聚类分析成绩反思_机器学习python实践——二分K-means聚类
  4. Leecode 136. 只出现一次的数字
  5. linux下kegg注释软件,KEGG功能注释工具 KofamKOALA 安装与使用
  6. scale和java比较_浅谈java中BigDecimal的equals与compareTo的区别
  7. 长见识:你真的知道C语言里extern quot;Cquot; 的作用吗?
  8. pat 乙级 1026 程序运行时间(C++)
  9. 485通讯转换器产品功能特点介绍
  10. [渝粤教育] 西南科技大学 英语语法1 在线考试复习资料