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 ...
随机推荐
- 数据库学习---SQL基础(一)
数据库学习---SQL基础(一) 数据库学习---SQL基础(二) 数据库学习---SQL基础(三) SQL(struct query language)结构化查询语言:一种专门与数据库通信的语言, ...
- 电信固定ip宽带80与8080端口踩坑
本文只是作为记录,避免后面遇到此类问题耗费时间. 实际情况:公司有个固定电信宽带是固定IP的,想把固定IP映射到测试环境ip,实现可以公网通过固定ip访问,内网通过局域网ip访问. 测试环境服务是占用 ...
- spring中获取applicationContext(2)
前几天写web项目的时候,用到了spring mvc. 但是又写bean.我要在代码里面生成,而这个bean里面,又有一些属性是通过spring注入的. 所以,只能通过ApplicationConte ...
- jsp页面查询的数据导出到excel
java导入导出excel操作(jxl) jxl.jar 包下载地址:http://www.andykhan.com/jexcelapi/真实下载地址:http://www.andykhan.com/ ...
- 微信小程序之特殊效果及功能
一.下拉刷新效果 假设页面为index文件,那么代码如下: index.json: { "enablePullDownRefresh": true } index.js: //下拉 ...
- Swift基础语法之变量函数
import Foundation //变量声明使用 //使用 let 来声明常量,使用 var 来声明变量 常量只能为它赋值一次 let name="cuiyw"; var ag ...
- Python调用nmap扫描网段主机信息生成xml
#!/usr/bin/env python # -*- coding: utf_8 -*- # Date: 2015年10月23日 # Author:蔚蓝行 # 博客 http://www.cnblo ...
- CSS3 颜色属性
关键字颜色 red 十六进制颜色 #FF0000 RGB颜色 rgb(255,0,0) 新增的颜色表示方法 RGBa: RGB代表光的三原色,Red.Green和Blue CSS3中可以增加一个值 ...
- java 全自动生成Excel之ExcelUtil篇(上一篇的升级版 [针对实体类对象的遍历赋值])
看了上一篇随笔之后可以对本篇有更好的了解! 使用的poi的jar包依然是上一篇的poi-3.17.jar.... import pojo.UserPojo(上一篇里有,这里就不粘贴了!) 不废话了,直 ...
- An internal error occurred during: "Updating status for Tomcat v7.0 Server at localhost..."
tomcat启动maven工程的时候提示如下错误信息: An internal error occurred during: "Updating status for Tomcat v7.0 ...