我们知道在一个数据库系统中为了保证数据的可靠性,我们都会记录对系统的操作日志。日志的功能就是用来在系统down掉的时候对数据进行恢复,所以日志系统对一个要求可靠性的存储系统是极其重要的。接下来我们分析leveldb的日志,首先在leveldb源码目录中有doc/log_format.txt,这个文件详细的描述了leveldb的日志格式:

record :=
checksum: uint32 // crc32c of type and data[] ; little-endian
length: uint16 // little-endian
type: uint8 // One of FULL,FIRST, MIDDLE, LAST
data: uint8[length]

如下图(图片引用):

leveldb在写日志时,对日志文件进行了划分为多个32K的文件块,每次读写日志时都以这样的每个32K为单位。这样进行处理以后leveldb的日志文件的大致组成就可以看做为如下的形式:

那么我们初步描述一下Log的写入情况为:

当要写入一条首先判断当前block中是否足够存放该条日志

S1.如果足够那么直接安装格式写入;

S2.如果不够那么计算出去头以外可以存放多少内容,将内容组装为FIRST的Log typpe写入;然后新取一个块判断是否足够存放剩下的日志数据

while(数据未写完)

S21. 如果足够就组装为LAST的形式写入;

S22. 如果仍然不够就组装为MIDDLE的形式写入

所以就容易理解这里的FULL,FIRST,MIDDLE和LAST了:

FULL:一条完整的日志被写到block

FIRST:一条日志,但是当前block无法完全写入,有部分数据被写到了下一个block,当前block的数据只是日志的开始(第一)部分

MIDDLE:该日志内容是接着前一个block里面的最后一条日志的继续,而且本block还无法完全写完,在下一个block中继续有该条日志的数据

LAST:    之前block的未写完的日志的最后一部分;

另外需要注意的就是根据前面的描述我们可以想象得到一个block在写入一部分数据以后会剩下部分空间,这个空间可能是大于7byte,等于7byte,小于7byte;这里为什么要以7byte为分界呢?日志记录的header(crc|length|type)长度为7,如果超过7就至少可以存一个FISRT的部分日志记录,而等于7就刚好存一个header,少于7就连header都存不了。LOG也正是基于这样的原因,小于7时就补充”\0”,7就存一个空header。我们来看看代码逻辑

Status Writer::AddRecord(const Slice& slice) {
bool begin = true;
// 循环向日志文件写,直到写完为止
do {
const int leftover = kBlockSize - block_offset_;
if (leftover < kHeaderSize) {// 小于 7 byte (header size )填充 0x0
if (leftover > ) {
dest_->Append(Slice("\x00\x00\x00\x00\x00\x00", leftover));
}
block_offset_ = ;
} const size_t avail = kBlockSize - block_offset_ - kHeaderSize;
const size_t fragment_length = (left < avail) ? left : avail; RecordType type;
const bool end = (left == fragment_length);{// 判断本段能否写完
if (begin && end) { // 开始结束都在本block
type = kFullType;
} else if (begin) { // 开始在本block,结束不在
type = kFirstType;
} else if (end) { // 结束在,开始不在
type = kLastType;
} else { // 开始结束都不在本block
type = kMiddleType;
}
// encode 然后再写入文件中
s = EmitPhysicalRecord(type, ptr, fragment_length);
ptr += fragment_length;
left -= fragment_length;
begin = false;
} while (s.ok() && left > );
return s;
}

读日志的代码在log_reader.cc中,代码的逻辑比写负责很多,主要是读入时会需要增加很多错误处理相关的内容,具体的代码不在罗列,理解了日志文件的格式以后的很容易就能读懂。当然同时其异常处理的逻辑也是我们码农们学习的材料,理解一下高手们是如何进行各种错误处理的。

leveldb源码分析--日志的更多相关文章

  1. leveldb源码分析--WriteBatch

    从[leveldb源码分析--插入删除流程]和WriteBatch其名我们就很轻易的知道,这个是leveldb内部的一个批量写的结构,在leveldb为了提高插入和删除的效率,在其插入过程中都采用了批 ...

  2. leveldb源码分析--SSTable之block

    在SSTable中主要存储数据的地方是data block,block_builder就是这个专门进行block的组织的地方,我们来详细看看其中的内容,其主要有Add,Finish和CurrentSi ...

  3. leveldb源码分析--Key结构

    [注]本文参考了sparkliang的专栏的Leveldb源码分析--3并进行了一定的重组和排版 经过上一篇文章的分析我们队leveldb的插入流程有了一定的认识,而该文设计最多的又是Batch的概念 ...

  4. Leveldb源码分析--1

    coming from http://blog.csdn.net/sparkliang/article/details/8567602 [前言:看了一点oceanbase,没有意志力继续坚持下去了,暂 ...

  5. 精尽Spring Boot源码分析 - 日志系统

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  6. leveldb源码分析之Slice

    转自:http://luodw.cc/2015/10/15/leveldb-02/ leveldb和redis这样的优秀开源框架都没有使用C++自带的字符串string,redis自己写了个sds,l ...

  7. LevelDB源码分析--Cache及Get查找流程

    本打算接下来分析version相关的概念,但是在准备的过程中看到了VersionSet的table_cache_这个变量才想起还有这样一个模块尚未分析,经过权衡觉得leveldb的version相对C ...

  8. leveldb源码分析--SSTable之TableBuilder

    上一篇文章讲述了SSTable的格式以后,本文结合源码解析SSTable是如何生成的. void TableBuilder::Add(const Slice& key, const Slice ...

  9. leveldb源码分析之内存池Arena

    转自:http://luodw.cc/2015/10/15/leveldb-04/ 这篇博客主要讲解下leveldb内存池,内存池很多地方都有用到,像linux内核也有个内存池.内存池的存在主要就是减 ...

随机推荐

  1. iOS事件分发

    前段时间项目有一个需求,要在点击闪屏的时候做一些处理,刚接到这个需求觉得很简单啊,在原有的view上加个button或者手势识别啥的,后面实现的时候发现还是有点坑.无论我在闪屏上面加button还是手 ...

  2. 工具-infer,静态代码检测

    1.工具介绍 Infer 是一个静态程序分析工具,可以对 Java.C 和 Objective-C 程序进行分析,此工具是用 OCaml写成的.https://github.com/facebook/ ...

  3. This Gradle plugin requires Studio 3.0 minimum

    从github上下载的项目遇到一个问题:Error:This Gradle plugin requires Studio 3.0 minimum 意思就是说studio版本不高,导入的项目的版本是3. ...

  4. JS 随机排序算法

    https://www.cnblogs.com/getdaydayup/p/6592154.html 使用JS编写一个方法 让数组中的元素每次刷新随机排列 法一: var arr =[1,2,3,4] ...

  5. Java ArrayList 数组之间相互转换

    做研发的朋友都知道,在项目开发中经常会碰到list与数组类型之间的相互转换,本文通过一个简单的例子给大家讲解具有转换过程. package test.test1; import java.util.A ...

  6. linux 安装mysql8.0

    linux下安装mysql8.0 下载mysql $ wget http://mirrors.ustc.edu.cn/mysql-ftp/Downloads/MySQL-8.0/mysql-8.0.4 ...

  7. Mysql密码忘记了怎么办?

    停止mysql: sudo /etc/init.d/MySQL stop(可能有其它的方法,总之停止MySQLd的运行就可以了) 修改mysql的配置文件: 在/etc/mysql/mysql.con ...

  8. Dubbox分布式框架

    一:简介:前身是阿里巴巴的一个开源的项目,后来停止维护,由当当网继续维护,它致力于rpc远程的调度方案.是一个服务框架 二:执行原理图: 节点角色说明: · Provider: 暴露服务的服务提供方. ...

  9. Java-函数式编程(一)初识篇

    开发者使用Java8编写复杂的集合处理算法,只需要简单的代码就能在多喝cpu上高效运行,这就是Lambda表达式的初衷. 提示:函数式编程和语言无关,它是一种思想,任何语言都可以实现函数式编程,区别只 ...

  10. HDU1114(KB12-F DP)

    Piggy-Bank Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total ...