无法打开 元数据 文件 platform.winmd_[LevelDB] 数据库4:日新月异——版本管理

ae69f1280dbe2bc17b4db94bba97441d.png

数据库4:日新月异——版本管理

在说版本管理实现前,有两个问题得先问问自己:

  • 什么是版本?
  • 为什么需要版本管理?

版本其实就是LevelDB数据库的元数据,之前提到过,在MemTable读取不到键时,需要去SSTable读取。SSTable的文件有哪些,每一个文件分别在哪一个Level上面,每个文件里面包含的键的最小值最大值是什么。需要知道这些信息,才可以快速的从SSTable里读取出相应的键的值。而版本就保存了这些信息,让我们通过版本读取SSTable。

那么为什么要版本管理呢? 在数据不断写入后,MemTable写满了,这时候就会转换为Level 0的一个SSTable,或者Level n的一个文件和Level n + 1的多个文件进行Compaction,会转换成Level n + 1的多个文件。这会使SSTable文件数量改变,文件内容改变,也就是版本信息改变了,所以需要管理版本。

那么有一个版本就够了吗?在文件数量和内容改变时,修改当前的版本就行了。但是并不是,假设使用了整个数据库的迭代器,LevelDB在迭代数据库时,是提供了一个一致性的视图,也就是只能看到迭代前的写入,而迭代后的写入是看不到,在实现的时候,迭代器会引用这个版本,以及里面的SSTable,直到迭代结束。如果在迭代过程中,有文件删除了,那么就无法引用到这个文件了,就会出错。所以需要多个版本,有一个版本是当前版本,当新生成版本后,旧的版本如果有被其它线程引用,也需要保留,直到不被引用后,才会被删除,所以一个时刻可能有多个版本存在。

496c4332eaf1ab673918870e6dfce7a8.png

先看看LevelDB的版本管理架构图,可以看到主要用到了4个类:

  • Version标识了一个版本,主要信息是这个版本包含的SSTable信息;
  • VersionSet是一个版本集,里面保存了Version的一个双链表,其中有一个Version是当前版本,因为只有一个实例,还保存了其它的一些全局的元数据,Dummy Version是链表头;
  • VersionEdit保存了要对Version做的修改,在一个Version上应用一个VersionEdit,可以生成一个新的Version
  • Builder是一个帮助类,帮助Version上应用VersionEdit,生成新版本。

版本管理的基本工作流程如下:

  • VersionSet里保存着当前版本,以及被引用的历史版本;
  • 当有Compaction发生时,会将更改的内容写入到一个VersionEdit中;
  • 利用BuilderVersionEdit应用到当前版本上面生成一个新的版本;
  • 将新版本链接到VersionSet的双链表上面;
  • 将新的版本设置为当前版本;
  • 将旧的当前版本Unref,就是引用计数减1。

版本控制中使用了引用计数来管理历史版本:

  • 假设一个没有被访问的数据库,这时候只有一个版本,也就是当前版本v1,它的引用计数是1;
  • 假设有一个迭代器开始访问数据库,这时候它会对当前版本v1 Ref,引用计数变成了2;
  • 其它线程不断写入,导致了Compaction的生成,这时候生成了一个新的版本v2成为了当前版本,引用计数为1,然后对v1 Unref,这时候v1的引用计数为1;
  • 因为v1的引用计数为1,所以不会被删除,迭代器线程还可以继续访问v1;
  • 迭代器结束后,对v1进行Unref,这时候v1的引用计数变为0,就会从链表上删除了,这时候又只剩下v2版本了;
  • 版本里面的SSTable也是采用引用计数来管理的,每个版本引用一个SSTable会Ref,删除版本时会Unref,如果一个SSTable的计数为0,那么这个SSTable就可以被删除了。

接下来讨论版本控制,以及这几个类的实现。

Version

Version标识了一个版本,读取数据库时都需要使用Version里面的版本信息,主要保存的是SSTable的文件信息:

// db/version_edit.h

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

  int refs;
  int allowed_seeks;     // Compaction时会介绍这个字段
  uint64_t number;
  uint64_t file_size;    // 文件大小
  InternalKey smallest;  // 文件里最小的inter
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值