LevelDB源码阅读(1)

LevelDB源码阅读(1)

 

 

时间就是杀猪刀,不抓紧学习不行呀。2017年新年第一天,我们就来学习一下LevelDB吧。之所以选它,是因为代码还不算多(1.19版本):

     ...

     51./util/testutil.cc

     63./util/testutil.h

  15805 total

[root@localhost src]#

我们先看看目录结构:


#

Path

Description

1

db

库相关的代码

2

include

头文件

3

port

移植相关的代码

4

table

表相关的代码

5

util

工具函数等

 

我们先看看最主要的DB类,其实就是一个接口,真正的实现实在DBImpl中。DB类定义的主要方法是:Open,Put, Delete, Write, Get, NewIterator, GetSnapshot, ReleaseSnapshot等。我们找一个Open来看看:

Status Open(const Options& options, conststring& dbname, DB** dbptr);

输入参数是打开的选项,数据库的名字以及要传出的数据库指针,而返回的是结果状态。我们来逐个分析一下这几个参数:

Options类主要成员:

#

Name

Description

1

Comparator

用于Key的比较,提供不同的key比较方法还是有必要的。它的主要实现方法就是Compare,比较两个Slice(带长度字符数组)

2

create_if_missing

例如这个标记就是说,如果数据库不存在时候怎么办,是创建一个新的还是报错。

3

… …

一些其他标记,在出问题的时候,确定怎么做的。

4

Env

封装了和环境的交互,环境就是运行时和外界的交互。一般和操作系统的交互,例如:

文件操作

目录操作

线程操作

时间操作

等等,这些操作在不同的操作系统间可能是不同的。

5

Logger

写日志的

6

Cache

数据块的缓存,当然这个Cache可以存储任何的对象指针。

7

CompressionType

压缩类型

8

FilterPolicy

过滤文件用的过滤器,用于判断Key是否在一个文件中。未来可以有更高效的实现,例如布隆过滤器。

 

Status是封装了状态和描述,用于函数一次性返回错误代码以及相关的描述。居然Status也是使用一个字符数组来容纳code和msg的,难道是为了将来序列化方便?还是作者习惯了。

0-3

4

5-…

长度(uint32)

Code(难道代码只有256种?)

代码的描述字符串

 

 

接着我们看一下DB的实现类DBImpl的情况(关键信息):

#

Name

Description

1

TableCache

 

2

Memtable *mem

 

3

Memtable *imm

 

4

WritableFile *logfile

 

5

Logfile number

 

6

Writer * writers

 

7

VersionSet *versions

 

 

 

打开数据库Open:

 

 

写入一个KV(Put):

 

很显然,所有的写都是通过批量方式写入到库中的(单一的KV也是放入Batch中然后再写),估计Batch是一个类似事务的概念,应该是确保一次性的写入吧,并且保证性能比较好。那我们看看WriteBatch是个什么容器:

#

Name

Description

1

Put()

放入一个KV

2

Delete()

删除一个KV

3

Clear()

清除所有的KV

4

string rep_

注意,这里就是所有的容器存储了。难道为了提高内存利用率?居然使用了紧缩的内存实现。所有的KV都按照一定的编码格式放入一个字符数组中了。这个数组的结构如下:

{

      “sequence” : “int64”,

      “count” : “int32”,

      “records” : [

            {

                  “TypeKeyValue” : “int8”,

                  “KeyLength” : “vint”,

                  “KeyData” : “char[]”,

                  “ValueLength” : “vint”,

                  “ValueData” : “char[]”

            },

            {

                  “TypeDeletion” : “int8”,

                  “KeyLength” : “vint”,

                  “KeyData” : “char[]”

            },

      ]

}

注意,上述的vint,实际上是变长的数字,小于127的,占用1byte,大于127的,占用2byte(第一个字节的高位为1),一次类推。这样大部分都是小于127的key,就不用占用太多长度字节了。

 

这么做的好处是,避免了大量的内存分配操作。而且紧密。缺点是引入了编解码的性能损耗

 

这个WriteBatch的数据组装是由一个WriteBatchInternal类的静态方法来实现的,这样WriteBatch就不会混杂有具体的格式实现代码了。未来如果想修改一下数据组织格式,直接写一个WriteBatch就可以了。写入KV的整体流程如下:

 

查询一个KV(Get):


今天先简单浏览一下整个工程,后面我们仔细的检查一下每一个具体的方面。

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
阅读Leveldb码,你可以按照以下步骤进行: 1. 确保你对C++语言有基本的了解。Leveldb是用C++编写的,因此你需要熟悉C++的语法和面向对象编程的概念。 2. 阅读Leveldb的README文件。这个文件提供了关于Leveldb的基本信息,如其用途、功能和性能特征。同时,它还列出了Leveldb的依赖关系,这对于理解码以及构建和运行Leveldb非常重要。 3. 了解Leveldb的核心概念和数据结构。Leveldb是一个高效的键值存储库,它使用了一些关键的数据结构,如有序字符串表(Skip List)和持久化存储。 4. 查看Leveldb的目录结构。Leveldb码包含了一些核心文件和目录,如“db”目录下的文件是Leveldb的核心实现。理解码的组织结构可以帮助你快速找到感兴趣的部分。 5. 阅读核心文件的码。从“db/db_impl.cc”文件开始,这个文件是Leveldb的主要实现。阅读这个文件可以帮助你了解Leveldb如何管理内存、实施并发控制和实现持久化存储。 6. 跟踪函数调用和数据流。了解Leveldb的主要功能是如何通过函数调用进行实现的很重要。你可以使用调试器或添加日志输出来跟踪函数调用和数据流,这有助于你了解代码的执行流程和逻辑。 7. 阅读Leveldb的测试用例。Leveldb码中包含了大量的测试用例,这些用例对于理解Leveldb的不同功能和特性非常有帮助。通过阅读和运行这些测试用例,你可以对Leveldb的行为有更深入的了解。 8. 参考文档和论文。如果你想更深入地了解Leveldb的实现原理和技术细节,可以查阅Leveldb的官方文档或相关的论文。这些文档可以为你提供更详细的信息和背景知识。 最后,要理解Leveldb码并不是一件简单的任务,需要投入大量的时间和精力。所以,建议你在阅读码之前,对C++和数据库原理有一定的了解和经验,同时也要具备耐心和持续学习的精神。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值