leveldb源码学习2-options

简述

本系列第二篇文章,主要讲述基本概念options类,这是leveldb启动时的一些配置,主要是各个配置字段的含义要了解一下,所以本篇文章就采取源码加注释的方式(其实源码的注释就很完善,我就翻译一下)。

include/leveldb/options.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
class Cache;
class Comparator;
class Env;
class FilterPolicy;
class Logger;
class Snapshot;

// leveldb中数据库的内容是保存在一系列的blocks中的,每个block包含一系列KV键值对。
// 每个block的数据在保存前可能会被压缩,压缩方法枚举类如下。
enum CompressionType {
// NOTE: 不要改变已有的值。
kNoCompression = 0x0,
kSnappyCompression = 0x1
};

// 控制数据库行为的选项 (会被传给DB::Open方法)
struct LEVELDB_EXPORT Options {
// 默认构造所有字段。
Options();

// -------------------
// 影响行为的参数。

// 表中keys排序所用的比较器。
// 默认使用字典序。
//
// REQUIRES: 客户端必须保证在这里使用的比较器和之前open相同数据库时所使用的的比较器有相同的名字和完全相同的key顺序。
const Comparator* comparator;

// open时,db目录不存在的时候是否创建。
bool create_if_missing = false;

// open时,db目录已经存在时是否报错
bool error_if_exists = false;

// 如果true,则实现将会对正在处理的数据进行积极检查,
// 并在检测到任何错误时提前停止。这可能会导致无法预料的后果。
bool paranoid_checks = false;

// 使用特定对象来和环境交互,比如读写文件。
// 默认: Env::Default()
Env* env;

// 打印日志的logger。为空的话就存在同目录下的默认文件中。
Logger* info_log = nullptr;

// -------------------
// 影响性能的参数

// 在转换为磁盘上排序的文件之前,要在内存中累积的数据量(由磁盘上未排序的日志支持)。
//
// memtable的最大值,较大的值能够提升性能,尤其在批量加载时。
// 同一时刻最多有两个写buffer会存在在内存中,
// 所以我们可以期待通过调整这个参数来控制内存使用。
// 当然,更大的写buffer也会造成下次数据库open时更长的恢复时间。
size_t write_buffer_size = 4 * 1024 * 1024;


// 数据库能打开文件的最大数量。
// 按照大佬在解析中写的,db中需要打开的文件包括基本的CURRENT/LOG/MANIFEST/LOCK
// sstable一旦打开,就会将index信息加入TableCache,所以把
// max_open_files-10 作为tablecache的最大值
int max_open_files = 1000;

// 传入的block数据的cache管理
// 管理blocks,用户数据被存在一系列blocks中,block也是从磁盘读取数据的单元
// 如果非空,则使用指定的cache管理blocks
// 如果为空,就自动创建并使用一个8MB的内部cache
Cache* block_cache = nullptr;

// 每个块的打包用户数据的大概大小。注意这里的block大小是未压缩前的数据。
// 如果压缩选项被打开的话,从磁盘里读取的数据单元的真实大小可能比该数值小。
// 这个参数可以动态改变。
size_t block_size = 4 * 1024;

// block中对key做前缀压缩的区间长度,这个参数可以动态改变。
// 大多数客户端都不应该使用这个参数。
int block_restart_interval = 16;

// Leveldb在切换一个新文件之前,会将以下字节数导入到一个文件中,也就是文件的最大大小。
// 大多数客户端不需要使用这个参数。但是如果你的文件系统针对大文件效率更高时,可以考虑增大这个值。
// 这样造成的缺点就是更长的压缩时间以及更长的延迟/响应问题。
// 还有一个增大该参数的情况是你正在初始填充大型数据库。
size_t max_file_size = 2 * 1024 * 1024;


// 压缩方法,该参数可动态改变。
// 默认压缩方法:kSnappyCompression,这是一种轻微但快速的压缩方法。
//
// Typical speeds of kSnappyCompression on an Intel(R) Core(TM)2 2.4GHz:
// ~200-500MB/s compression
// ~400-800MB/s decompression
// 注意该压缩方法的速度快过大多数持久化存储的速度,因此可能并没有理由切换成不压缩。
// 即使输入数据是不可压缩的,该方法的实现中也会有效识别并切换到不压缩模式。
CompressionType compression = kSnappyCompression;

// 实验性的参数,如果为真,当一个数据库被打开时,追加到已存在的MANIFEST和日志文件末尾,这可以提高打开速度。
// 默认false。
bool reuse_logs = false;

// 如果非空,使用该过滤策略减少磁盘读取。
// 如果在这里传入NewBloomFilterPolicy() ,很多应用都会受益。
const FilterPolicy* filter_policy = nullptr;
};

// 读操作选项设置
struct LEVELDB_EXPORT ReadOptions {
ReadOptions() = default;

// 如果真,从底层存储读取的所有数据都要根据对应的校验来进行验证。
bool verify_checksums = false;

// 读到的block是否加入内存中的block cache?
// 调用者们可能会喜欢将该字段设置成false来进行批量扫描。
bool fill_cache = true;

// 如果非空,读入指定的snapshot(必须属于正在读取且未被released的BD)
// 若空,使用一个在读取操作开始时状态的隐式快照
const Snapshot* snapshot = nullptr;
};

// 写操作选项设置
struct LEVELDB_EXPORT WriteOptions {
WriteOptions() = default;

// 若真,则在认为写完成之前将从操作系统缓冲区缓存中清除写入。
// 若真,写操作会更慢。
//
// 若假,当机器crash时,一些最近的写会被丢失。注意如果只是进程崩溃,则不会丢失写。
//
// In other words, a DB write with sync==false has similar
// crash semantics as the "write()" system call. A DB write
// with sync==true has similar crash semantics to a "write()"
// system call followed by "fsync()".
//
bool sync = false;
};