leveldb学习记录-文件
leveldb的文件命名
当运行一次leveldb来写入数据时,leveldb可能会生成很多个log文件和SSTable文件,而这些文件的命名都是类似的,都是固定前缀+文件编号+固定后缀的。这些文件的名称是调用函数MakeFileName()来生成的。
如上图,运行./db_bench后,输出很多由数字编号的文件。
一般可能会存在以下文件内容:
LOCK
database文件锁,leveldb
通过文件锁来避免同一个db被多次打开操作。调用DB::Open()
时会先获取该文件锁。MANIFEST-XXXXXX
,描述文件。XXXXX => [1, n),以LOG的形式写入VersionEdit
数据。CURRENT
表明当前正在使用哪个MANIFEST
文件LOG
,LOG.old
运行日志文件,当未指定options.info_log
时,默认会将错误日志输出到该文件,每一次DB::Open()
时,会将LOG
重命名为LOG.old
.log
日志文件.ldb
db ssttable 持久化文件,新版本的后缀为.ldb
,老版本后缀为.sst
.dbtmp
变更文件内容,中间过程中的临时文件。
1.文件命名
leveldb中与文件名创建相关的文件放在:
filename :leveldb/db/filename.cc
leveldb/db/filename.h
database中的文件用文件名区分类型,有以下几种类型
1 | enum FileType { |
1) kLogFile 日志文件: [0-9]+.log
leveldb 的写流程是先记 binlog,然后写 sstable,该日志文件即是 binlog。前缀数字为FileNumber。
2) kDBLockFile, lock 文件: LOCK
一个 db 同时只能有一个 db 实例操作,通过对 LOCK 文件加文件锁(flock) 实现主动保护。
3) kTableFile, sstable 文件: [0-9]+.sst
保存数据的 sstable 文件。前缀为 FileNumber。
4) kDescriptorFile, db 元信息文件: MANIFEST-[0-9]+
每当 db 中的状态改变(VersionSet),会将这次改变(VersionEdit) 追加到 descriptor 文件中。后缀数字为 FileNumber。
5) kCurrentFile,: CURRENT
CURRENT 文件中保存当前使用的 descriptor 文件的文件名。
6) kTempFile,临时文件: [0-9]+.dbtmp
对 db 做修复(Repairer)时,会产生临时文件。 前缀为 FileNumber。
7) kInfoLogFile, db 运行时打印日志的文件: LOG
db 运行时,打印的 info 日志保存在 LOG 中。 每次重新运行,如果已经存在 LOG 文件,会先将 LOG文件重名成 LOG.old
文件命名的核心函数为MakeFileName
1 | //返回形如"$dbname/$number.$suffix"的文件名,其中number使用6位数字输出,不足则左边补0,例如 db/000006.log |
由上述代码得知文件名是由dbname+6位number+后缀名组成的。比如db/000010.ldb
(leveldb1.14版本之前后缀名是.sst,1.14版本之后采用.ldb)
1 | std::string LogFileName(const std::string& dbname, uint64_t number) { |
值得注意的是MAINIFEST文件没有像 TableFileName
、SSTTableFileName
、LogFileName
调用MakeFileName函数
1 | std::string DescriptorFileName(const std::string& dbname, uint64_t number) { |
2.生成文件编号
db/version_set.h中保存了多个编号:
1 | uint64_t next_file_number_;//用于生成系统下一个文件的编号 |
1 | file_number = versions_->NewFileNumber();//sstable文件的number |
所以由以上代码可以发现sstable文件和log文件的number都是由version_set中的函数NewFileNumber()获得的,变化的值是next_file_number_
,leveldb中的文件编号都是逐渐递增的。不存在相同编号的.log或.ldb。也就是说不可能出现000003.ldb和000003.log文件的情况。
在versionset的构造函数中,next_file_number_被初始化为2.
1 | VersionSet::VersionSet(const std::string& dbname, |
文件编号1留给Mainifest使用
1 | Status DBImpl::NewDB() { |
Manifest文件记录了leveldb的元信息,包括数据库使用的Comparator名,以及各SSTable文件的管理信息:如Level层数、文件名、最小key和最大key等等。
总结
sstable, log, manifest 的编号都是由 versoinset 中NewFileNumber函数的 next_file_number_变量来指定。