leveldb源码分析--WriteBatch
从【leveldb源码分析--插入删除流程】和WriteBatch其名我们就很轻易的知道,这个是leveldb内部的一个批量写的结构,在leveldb为了提高插入和删除的效率,在其插入过程中都采用了批量集合相邻的多个具有相同同步设置的写请求以批量的方式进行写入。
其成员变量仅包含了一个 std::string 类型的 rep_变量,其Put和Delete(其实也是插入删除操作,而非删除Put进去的数据,或者你可以将其理解为Put Delete operation的过度简写)都将相应的操作Encode后存入其中。我们来看看其encode的格式
WriteBatch::rep_ := [ sequence: fixed64 | count: fixed32 | data: record[count ]
record := [ kTypeValue | key(varint32 | data) | value(varint32 | data) ]
我们首先看一下WriteBatch内部相关的一些结构和成员
class Handler {
public:
virtual ~Handler();
virtual void Put(const Slice& key, const Slice& value) = ;
virtual void Delete(const Slice& key) = ;
};
Status Iterate(Handler* handler) const;
friend class WriteBatchInternal;
WriteBatchInternal主要是对WriteBatch的内部解码编码的封装,简化WriteBatch的结构。而Handler接口我们可以看到MemTableInserter成为了其一个实现,这个handler是在WriteBatch的内部解码遍历过程中逐个调用Handler对应的Put、Delete到MemTable中。所以再回头分析DBImpl::BuildBatchGroup方法。
// REQUIRES: First writer must have a non-NULL batch
WriteBatch* DBImpl::BuildBatchGroup(Writer** last_writer) {
Writer* first = writers_.front();
WriteBatch* result = first->batch;
size_t size = WriteBatchInternal::ByteSize(first->batch); /* 这里主要是设置每次批量写入的最大的数据量,防止一次插入过多数据导致等待写完成的时间过长 因为从Write的逻辑分析中我们知道只有位于队列首的写线程会去批量组装然后执行真正的插入,
其他的线程都是在等待这个批量写的完成。 */
size_t max_size = << ;
if (size <= (<<)) {
max_size = size + (<<);
} *last_writer = first;
std::deque<Writer*>::iterator iter = writers_.begin();
++iter; // 跳过 "first"
for (; iter != writers_.end(); ++iter) {
Writer* w = *iter;
if (w->sync && !first->sync) {
// 只组合相邻的sync设置相同的操作到一批进行处理.
break;
} if (w->batch != NULL) {
size += WriteBatchInternal::ByteSize(w->batch);
if (size > max_size) {
// 如果总大小超过设置的现在大小,不再继续组装过程,跳出循环执行已组装的请求
break;
} // 第一次进入循环,把tmp_batch_赋给result并把第一个放入其中,后继的都是append到tmp_batch_中
最后return出去进行操作的也是这个tmp_batch_
if (result == first->batch) {
result = tmp_batch_;
assert(WriteBatchInternal::Count(result) == );
WriteBatchInternal::Append(result, first->batch);
}
WriteBatchInternal::Append(result, w->batch);
}
*last_writer = w;
}
return result;
}
接下来对该batch进行操作的是WriteBatchInternal::InsertInto(updates, mem_)这个调用,这就是前面提到的采用了一个Iterator的方式解码遍历操作batch中的数据
Status WriteBatchInternal::InsertInto(const WriteBatch* b,
MemTable* memtable) {
MemTableInserter inserter;
inserter.sequence_ = WriteBatchInternal::Sequence(b);
inserter.mem_ = memtable;
return b->Iterate(&inserter);
}
Status WriteBatch::Iterate(Handler* handler) const {
while (!input.empty()) {
switch (tag) {
case kTypeValue:
handler->Put(key, value);
break;
case kTypeDeletion:
handler->Delete(key);
break;
}
}
return Status::OK();
}
这里我们再回顾一下Write有
while (!w.done && &w != writers_.front()) {
这个语句是说线程一直等待直到当前线程的请求被完成或者请求到队列的最前端,那么为什么leveldb采用了这样的其中一个线程去批量操作而其他线程进行等待的方式呢?我们知道leveldb在实际插入过程中会有一系列的判断,和写日志到磁盘的操作。而首先这些判断都是在保持锁的情形下进行的,这里其实也就注定了只能是串行的;其次对于写磁盘,将多次写合并为一次写入会显著的提高效率,相当于 N * 磁盘寻址时间 + 写入时间总和变为了 一次磁盘寻址时间 + 写入时间总和,即节省了(N - 1)次磁盘寻址时间。
leveldb源码分析--WriteBatch的更多相关文章
- leveldb源码分析--SSTable之block
在SSTable中主要存储数据的地方是data block,block_builder就是这个专门进行block的组织的地方,我们来详细看看其中的内容,其主要有Add,Finish和CurrentSi ...
- leveldb源码分析--Key结构
[注]本文参考了sparkliang的专栏的Leveldb源码分析--3并进行了一定的重组和排版 经过上一篇文章的分析我们队leveldb的插入流程有了一定的认识,而该文设计最多的又是Batch的概念 ...
- Leveldb源码分析--1
coming from http://blog.csdn.net/sparkliang/article/details/8567602 [前言:看了一点oceanbase,没有意志力继续坚持下去了,暂 ...
- leveldb源码分析--日志
我们知道在一个数据库系统中为了保证数据的可靠性,我们都会记录对系统的操作日志.日志的功能就是用来在系统down掉的时候对数据进行恢复,所以日志系统对一个要求可靠性的存储系统是极其重要的.接下来我们分析 ...
- leveldb源码分析之Slice
转自:http://luodw.cc/2015/10/15/leveldb-02/ leveldb和redis这样的优秀开源框架都没有使用C++自带的字符串string,redis自己写了个sds,l ...
- LevelDB源码分析--Cache及Get查找流程
本打算接下来分析version相关的概念,但是在准备的过程中看到了VersionSet的table_cache_这个变量才想起还有这样一个模块尚未分析,经过权衡觉得leveldb的version相对C ...
- leveldb源码分析--SSTable之TableBuilder
上一篇文章讲述了SSTable的格式以后,本文结合源码解析SSTable是如何生成的. void TableBuilder::Add(const Slice& key, const Slice ...
- leveldb源码分析之内存池Arena
转自:http://luodw.cc/2015/10/15/leveldb-04/ 这篇博客主要讲解下leveldb内存池,内存池很多地方都有用到,像linux内核也有个内存池.内存池的存在主要就是减 ...
- LevelDB源码分析-Write
Write LevelDB提供了write和put两个接口进行插入操作,但是put实际上是调用write实现的,所以我在这里只分析write函数: Status DBImpl::Write(const ...
随机推荐
- php如何使用rabbitmq实现发布消息和消费消息(一对多)(tp框架)(第二篇)
一个publisher发布消息 多个个customer接受消息 1:准备工作参照: http://www.cnblogs.com/spicy/p/7886820.html 2,:路由: 3: 方法: ...
- Linux 上安装 Couchbase服务
down: http://www.couchbase.com/downloads/ doc: http://docs.couchbase.com/archive-index/ forums: htt ...
- 浅谈Android Studio中项目结构中project模式的各个文件和文件夹
致敬郭霖,这些知识是从第一行代码第二版中直接码下来的,谢谢他,注意每个条目前是否有. 1..gradle和.idea 这两个目录下放置的都是Android Studio自动生成的一些文件,我们无需关心 ...
- Java的try-catch-finally
Javac语法糖之TryCatchFinally 如下引用文章:https://help.semmle.com/wiki/display/JAVA/Finally+block+may+not+comp ...
- j2ee高级开发技术课程第二周(web请求的整个过程、XML)
博客非原创,只是收集整理了一下网上的一些文章 一.web请求的整个过程 1)把URL分割成几个部分:协议.网络地址.资源路径.其中网络地址指示该连接网络上哪一台计算机,可以是域名或者IP地址,可以包括 ...
- [C语言]声明解析器cdecl修改版
一.写在前面 K&R曾经在书中承认,"C语言声明的语法有时会带来严重的问题.".由于历史原因(BCPL语言只有唯一一个类型——二进制字),C语言声明的语法在各种合理的组合下 ...
- 消除ADB错误“more than one device and emulator”的方法(转)
当我连着手机充电的时候,启动模拟器调试,执行ADB指令时,报错.C:\Users\gaojs>adb shellerror: more than one device and emulatorC ...
- Spring系列之——springboot解析resources.application.properties文件
摘要:本文通过讲解如何解析application.properties属性,介绍了几个注解的运用@Value @ConfigurationProperties @EnableConfiguration ...
- npm saveError ENOENT: no such file or directory
1.报错情况 在执行npm install xxx时,出现如下:npm WARN saveError ENOENT: no such file or directory, open '/nodetes ...
- Dijkstra Java
https://leetcode.com/problems/network-delay-time/ /* Java program to find a Pair which has maximum s ...