levelDB compaction

compaction 分成两类:
1. minor compaction:

minor compaction,当immemtable写满以后,需要将其落盘成SSTable,这个操作即为minor compaction。

**2. major compaction:**又分成三类
主动compaction:
size compaction:
seek compact:

BackgroundCompaction函数

所有的compaction操作都是由后台线程进行调起的,优先级:minor compaction > size compaction > seek compaction。下面详细介绍后台线程需要运行的函数 (BackgroundCompaction)。

void DBImpl::BackgroundCompaction(){
  mutex_.AssertHeld();

  // minor compaction,即将immemtable中的内容进行落盘
  if (imm_ != nullptr) {
    CompactMemTable();
    return;
  }
}

CompactMemTable 函数

首先详细讲解一下函数CompactMemTable(),该函数的目的是:将immemtable落盘到SStable中,即 minor compaction。

/**
将immemtable落盘到SStable中,即 minor compaction。
**/
void DBImpl::CompactMemTable() {
  ...
  VersionEdit edit;
  // 获取当前磁盘SSTable的最新版本
  Version* base = versions_->current();
  base->Ref();
  // step1: 构造VersionEdit
  Status s = WriteLevel0Table(imm_, &edit, base);
  base->Unref();
  ...
  // Replace immutable memtable with the generated Table
  if (s.ok()) {
    edit.SetPrevLogNumber(0);
    edit.SetLogNumber(logfile_number_);  // Earlier logs no longer needed
    // step2: 构造新的version,并将新version添加到versions_中
    // versionEdit + version = new version
    s = versions_->LogAndApply(&edit, &mutex_);
  }
  ...
}

我的理解,所有的SSTable以文件元信息进行记录,即FileMetaData,而每个version对象中都维护这一系列的FileMetaData。

WriteLevel0Table函数

/**
将imm真实地写入到磁盘中,并构造出对应的文件元信息 meta
然后记录 meta
**/
Status DBImpl::WriteLevel0Table(MemTable* mem, VersionEdit* edit,
                                Version* base) {
  ...
  // 创建一个FileMetaData作为该SSTable句柄,方便之后查找
  // 即记录新SStable的详细信息
  FileMetaData meta;
  meta.number = versions_->NewFileNumber();
  pending_outputs_.insert(meta.number);
  // 取得MemTable的迭代器
  Iterator* iter = mem->NewIterator();
  ... 
  Status s;
  {
    mutex_.Unlock();
    // 将immemtable中的信息写入到磁盘文件中,用meta记录SSTable信息
    s = BuildTable(dbname_, env_, options_, table_cache_, iter, &meta);
    mutex_.Lock();
  }
  ...
  delete iter;
  pending_outputs_.erase(meta.number);

  // Note that if file_size is zero, the file has been deleted and
  // should not be added to the manifest.
  int level = 0;
  if (s.ok() && meta.file_size > 0) {
    // 向SSTable句柄写入所有Key的最小值
    const Slice min_user_key = meta.smallest.user_key();
    // 向SSTable句柄写入所有Key的最大值
    const Slice max_user_key = meta.largest.user_key();
    if (base != nullptr) {
      // 计算新创建的SSTable应该属于哪一层
      level = base->PickLevelForMemTableOutput(min_user_key, max_user_key);
    }
    // 将SSTable文件序列号对应的层,Key等信息写入manifest中
    edit->AddFile(level, meta.number, meta.file_size, meta.smallest,
                  meta.largest);
  }

  CompactionStats stats;
  stats.micros = env_->NowMicros() - start_micros;
  stats.bytes_written = meta.file_size;
  stats_[level].Add(stats);
  return s;
}

// 文件元信息结构
struct FileMetaData {
  FileMetaData() : refs(0), allowed_seeks(1 << 30), file_size(0) {}
  int refs;
  int allowed_seeks;  // Seeks allowed until compaction
  // 元信息,通过该number字段与磁盘中的SSTable进行关联,
  uint64_t number;       // 即 file_number
  uint64_t file_size;    // SStable的大小
  InternalKey smallest;  // Smallest internal key served by table
  InternalKey largest;   // Largest internal key served by table
};

WriteLevel0Table函数操作:

  1. 在当前version下,构建新的文件元信息 meta;
  2. 将mem中的内容,真实地写到磁盘文件中,并与meta进行关联(其实创建文件时,文件名字是基于meta的number字段创建的,e.g. number = 10, 则文件存储为 dbtest/10.ldb,其中dbtest为数据库名称);
  3. 判断该SSTable属于哪一层level;
  4. 基于level和meta 填充 VersionEdit

在这里插入图片描述
图1 FileMetaData与本地SStable之间的关系

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值