[LevelDB] 写批处理过程详解
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] 写批处理过程详解相关推荐
- Hadoop学习之Mapreduce执行过程详解
一.MapReduce执行过程 MapReduce运行时,首先通过Map读取HDFS中的数据,然后经过拆分,将每个文件中的每行数据分拆成键值对,最后输出作为Reduce的输入,大体执行流程如下图所示: ...
- Android签名机制之---签名验证过程详解
一.前言 今天是元旦,也是Single Dog的嚎叫之日,只能写博客来祛除寂寞了,今天我们继续来看一下Android中的签名机制的姊妹篇:Android中是如何验证一个Apk的签名.在前一篇文章中我们 ...
- Linux开启动过程详解
Linux开启动过程详解 Linux启动过程 前言: Linux是一种自由和开放源代码的类UNIX操作系统.该操作系统的内核由林纳斯·托瓦兹在1991年10月5日首次发布.在加上用户空间的应用程序之后 ...
- 操作系统之多线程编程—读者优先/写者优先详解
操作系统之进程调度--优先权法和轮转法(附上样例讲解) 操作系统之银行家算法-详解流程及案例数据 操作系统之多线程编程-读者优先/写者优先详解 操作系统之存储管理--FIFO算法和LRU算法 操作系统 ...
- Mysql加锁过程详解(2)-关于mysql 幻读理解
Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...
- python属性使用教程_Python对象的属性访问过程详解
只想回答一个问题: 当编译器要读取obj.field时, 发生了什么? 看似简单的属性访问, 其过程还蛮曲折的. 总共有以下几个step: 1. 如果obj 本身(一个instance )有这个属性, ...
- Java web 开发的概念、环境配置、创建项目过程详解(Eclipse)
Java Web 开发 Java Web 开发概念 搭建过程 详解 在eclipse创建Dynamic Web Project 创建时选择Tomcat的版本 创建项目成功 eclipse环境下如何配置 ...
- #转载:杨辉三角形实现过程详解-c语言基础
杨辉三角形实现过程详解-C语言基础 十一一个人 2018-12-26 06:45:45 6465 收藏 28 最后发布:2018-12-26 06:45:45首发:2018-12-26 06:45:4 ...
- U-Boot 之三 U-Boot 源码文件解析及移植过程详解
在之前的博文 Linux 之八 完整嵌入式 Linux 环境介绍及搭建说明 中我们说了要一步步搭建整个嵌入式 Linux 运行环境.我所使用的硬件平台及整个要搭建的嵌入式 Linux 环境见博文 ...
最新文章
- 那些年我们一起追过的缓存写法(二)
- 自己动手 从android硬件驱动到APP---(1)硬件驱动层
- python打开并读取csv文件_!python3中使用使用read_csv( )读取csv文件,文件路径中含有中文,无法读取怎么处理?...
- ant中的loading按钮使用
- httpservletrequest_HttpServletResponse和HttpServletRequest取值的2个坑你知道吗?
- KNN(五)--层次Kmean
- 车辆等级、车型分类及carsim内置车辆种类整理
- java字体设置框_CSS样式更改——字体设置Font边框Border
- Cannot negotiate authentication mechanism svn: Unable to connect to a repository at URL 'svn://gite
- win10装debian 双系统_如何安装win10和linux [ubuntu14]双系统
- 论文解读:Making Pre-trained Language Models Better Few-shot Learners(LM-BFF)
- (poj 2377)Kruskal算法 最大生成树
- 微信公众号开发相关问题
- 服务器怎么备案?备案时间要多久?
- 数据分析利器 —— 列式储存数据库
- 电商项目相关面试问题及答案
- 信号(进程间的通信方式)
- 虚函数、虚表的生成,虚表的修改
- 智能体温检测系统解决方案
- ultraiso软碟通注册码
热门文章
- Linux 系统启动流程图/系统初始化流程图
- 安装、启动、配置zookeeper(window版)
- python聚类分析成绩反思_机器学习python实践——二分K-means聚类
- Leecode 136. 只出现一次的数字
- linux下kegg注释软件,KEGG功能注释工具 KofamKOALA 安装与使用
- scale和java比较_浅谈java中BigDecimal的equals与compareTo的区别
- 长见识:你真的知道C语言里extern quot;Cquot; 的作用吗?
- pat 乙级 1026 程序运行时间(C++)
- 485通讯转换器产品功能特点介绍
- [渝粤教育] 西南科技大学 英语语法1 在线考试复习资料