美文网首页
从leveldb中学编码技巧(4)

从leveldb中学编码技巧(4)

作者: wangjie_yy | 来源:发表于2019-06-13 16:26 被阅读0次

leveldb的数据以sst文件形式存储在磁盘上,后台有一个常驻线程进行compaction操作。compaction的作用主要是降低存储放大,有效利用磁盘空间。在处理读写请求过程中,以及compaction本身处理过程中,都有可能会触发新一轮的compaction。

compaction主要有两种:

  1. 将memtable中的数据写入到磁盘sst文件中
  2. 将某个level的某个文件合并到更上一层的level中

第一种就是将内存中数据写入到文件,第二种本质上是一个merge外部文件的过程。无论哪种compaction,都会改变当前数据库中的文件,可能会删除或者新增文件。

leveldb使用了一个manifest文件来保存数据库的元信息,其中包括当前有效的文件集合。当处理读请求时,会在当前有效文件集合中查询。同时使用一个CURRENT文件来指向当前的manifest文件。

后台线程进行compaction的过程大概是这样的:

  • 确认compaction的输入是什么,是memtable,还是一些sst文件
  • 确认compaction的输出是什么,基本都是一些sst文件
  • 进行具体读写操作,写入一些新文件,并删除一些不需要的文件
  • 将新的有效文件集合记录在manifest文件中(有可能是新生成的manifest文件)
  • 将CURRENT文件指向新的manifest文件(如果有新manifest文件的话)

这里要说的问题是:如何管理磁盘上的sst文件

随着compaction的进行,sst文件集合在不停变化,会生成一些新的文件,同时也会删除一些旧的文件。 当前最新的有效文件集合记录在manifest文件中,当处理读请求时,总是从当前最新文件中读取数据。但是当在处理快照请求,以及iterator遍历时,可能也会从旧的文件中读取数据。这是因为,快照或者iterator指向的文件可能在compaction中被合并了,生成了新的文件。

leveldb定义了一个Version类,用来表示一个有效的sst文件集合。随着compaction的进行,Version会不断变化,生成新的Version。当前的Version则总是指向当前最新的有效文件集合。相关的一些Class如下定义:

class Version {
public:
    Version();
    ~Version();
    ...
    void Ref();
    void Unref();

private:
    ...
    std::vector<FileMetaData*> files_[config::kNumLevels];
};

class VersionSet {
 public:   
    VersionSet();
    ~VersionSet();
    ...
    
 private:
     
   Version dummy_versions_;  // Head of circular doubly-linked list of versions.
   Version* current_;        // == dummy_versions_.prev_     
};

class VersionEdit {
public:
    VersionEdit();
    ~VersionEdit();
    ...

private:
    ...
    std::vector< std::pair<int, InternalKey> > compact_pointers_;
    DeletedFileSet deleted_files_;
    std::vector< std::pair<int, FileMetaData> > new_files_;    
};

struct FileMetaData {
  int refs;
  int allowed_seeks;          // Seeks allowed until compaction
  uint64_t number;
  uint64_t file_size;         // File size in bytes
  InternalKey smallest;       // Smallest internal key served by table
  InternalKey largest;        // Largest internal key served by table

  FileMetaData() : refs(0), allowed_seeks(1 << 30), file_size(0) { }
};

VersionSet中使用一个Version链表来记录所有的Version,而current则总是指向当前最新的Version。当数据库初始打开时,只有一个current Version以及一个dummy Version。每进行一次compaction,会生成一个新的Version作为current版本并插入到链表中。

每一次compaction都会产生一个VersionEdit实例,其中记录了此次compaction对文件集合的变更:要新加入哪些文件,删除哪些文件等。将VersionEdit作用在当前current Version上,得到最新的Version,并记录在VersionSet中。(将VersionEdit作用在当前current上的实现在VersionSet::LogAndApply()中,这个过程使用了辅助类VersionSet::Builder,代码写的很简洁。使用辅助类是leveldb非常常见的技巧,主要作用是将复杂的逻辑拆解开,让过程变得更清晰,易于阅读和理解)。

Version通过引用计数来管理生命周期,当不再需要某个Version实例时,会在这个实例上调用Unref(),如果发现已经没有对此Version实例的引用时,就会删除Version实例,从而触发Version的析构函数的执行。在析构函数中,并没有直接删除此Version对应的文件,因为同一个文件可能包括在多个Version中。文件也是通过引用计数来管理的,由FileMetaData代表一个sst文件。由在Version的析构函数中,会依次减少其中文件的引用计数,当某个文件的引用计数降为0时,就会删除内存中的FileMetaData实例。也就是,在内存中没有对这个文件的引用了。

在DBImpl::DeleteObsoleteFiles()中,会统计当前前VersionSet中的所有文件,以及磁盘上的所有文件,进行交叉比对,如果发现某个文件存在于磁盘上,而VersionSet中并没有对这个文件的引用。就从磁盘上删除此文件。每次compaction结束后,以及数据库打开时,都会调用DBImpl::DeleteObsoleteFiles()函数来清理一次老旧文件。

总结

如果不用Version,VersionEdit这些类,使用其他的写法,应该也能够实现管理文件和处理变更的功能,但是极有可能代码结构会变得混乱和复杂,难以阅读和理解。leveldb的这种实现,代码结构很很清晰,容易理解它实现的功能,因此也可以降低因为复杂而出错的概率。

相关文章

  • 从leveldb中学编码技巧(4)

    leveldb的数据以sst文件形式存储在磁盘上,后台有一个常驻线程进行compaction操作。compacti...

  • 从leveldb中学编码技巧

    leveldb是一个C++写的kv存储引擎, 作者是google的大神程序员Jeff Dean。leveldb的源...

  • 从leveldb中学编码技巧(6)

    leveldb的运行涉及到很多文件,包括manifest文件,WAL log文件,sst文件,日志文件等,为了方便...

  • 从leveldb中学编码技巧(5)

    在读取一个key的值时,leveldb会按照如下顺序查找这个key: 在memtable中查询 在level0中查...

  • 从leveldb中学编码技巧(2)

    leveldb提供的接口大部分都是线程安全的,包括write。当多个线程并发的调用write时,leveldb会保...

  • 从leveldb学编码技巧(3)

    leveldb中的大部分文件都是用一种类似日志的方式来写数据的,比如和memtable一一对应的log文件,以及m...

  • 以太坊之 Whisper

    主要底层技术 加密 crypto编码 rlp存储 leveldb调用 rpc通讯 p2p 如何拼凑、操作,就是其“...

  • LevelDB varint 变长编码

    定义在coding.h 文件中。 固定长度编码 注意到有注释说指令优化,写了简单代码,测试了下,的确如此。 变长编...

  • 余世维《沟通课》02

    沟通过程: 编码——解码——渠道畅通 怎么讲、怎么听 会讲话、会听 影响编码的4个条件: 技巧、态度、知识(对方是...

  • osd监控埋点指标

    1. WBThrottle 2. filestore 3. leveldb 4. objecter

网友评论

      本文标题:从leveldb中学编码技巧(4)

      本文链接:https://www.haomeiwen.com/subject/gqmsfctx.html