前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >leveldb源码解析--打开数据库

leveldb源码解析--打开数据库

原创
作者头像
小林帮
修改2021-03-22 12:30:34
1.8K0
修改2021-03-22 12:30:34
举报

原理

在分析打开leveldb数据库之前,我们先来讨论一下几个类似的子问题:

  1. 如何恢复一个进程的运行状态?
  2. 如何解决数据索引慢的问题?

主要完成的事项:

  • 构建存储中的MemTable数据结构;
  • 加载SSTable文件查找相关的索引信息;
  • 重放未执行完成的WAL日志;

打开数据库

代码语言:txt
复制
Status DB::Open(const Options& options, const std::string& dbname, DB** dbptr) {
  *dbptr = nullptr;

  DBImpl* impl = new DBImpl(options, dbname);
  impl->mutex_.Lock();
  VersionEdit edit;
  // Recover handles create_if_missing, error_if_exists
  bool save_manifest = false;
  Status s = impl->Recover(&edit, &save_manifest);
  if (s.ok() && impl->mem_ == nullptr) {
    // Create new log and a corresponding memtable.
    uint64_t new_log_number = impl->versions_->NewFileNumber();
    WritableFile* lfile;
    s = options.env->NewWritableFile(LogFileName(dbname, new_log_number),
                                     &lfile);
    if (s.ok()) {
      edit.SetLogNumber(new_log_number);
      impl->logfile_ = lfile;
      impl->logfile_number_ = new_log_number;
      impl->log_ = new log::Writer(lfile);
      impl->mem_ = new MemTable(impl->internal_comparator_);
      impl->mem_->Ref();
    }
  }
  if (s.ok() && save_manifest) {
    edit.SetPrevLogNumber(0);  // No older logs needed after recovery.
    edit.SetLogNumber(impl->logfile_number_);
    s = impl->versions_->LogAndApply(&edit, &impl->mutex_);
  }
  if (s.ok()) {
    impl->RemoveObsoleteFiles();
    impl->MaybeScheduleCompaction();
  }
  impl->mutex_.Unlock();
  if (s.ok()) {
    assert(impl->mem_ != nullptr);
    *dbptr = impl;
  } else {
    delete impl;
  }
  return s;
}

恢复数据库

代码语言:txt
复制
Status DBImpl::Recover(VersionEdit* edit, bool* save_manifest) {
  // 创建数据库目录
  env_->CreateDir(dbname_);
  // 获取文件锁,禁止多个进程同时访问数据库
  Status s = env_->LockFile(LockFileName(dbname_), &db_lock_);

  if (!env_->FileExists(CurrentFileName(dbname_))) {
    if (options_.create_if_missing) {
      // 如CURRENT文件不存在,则初始化数据库文件
      s = NewDB();
    }
  }

  // 加载数据库版本管理信息
  s = versions_->Recover(save_manifest);
  
  SequenceNumber max_sequence(0);

  const uint64_t min_log = versions_->LogNumber();
  const uint64_t prev_log = versions_->PrevLogNumber();
  std::vector<std::string> filenames;
  s = env_->GetChildren(dbname_, &filenames);
  std::set<uint64_t> expected;
  versions_->AddLiveFiles(&expected);
  uint64_t number;
  FileType type;
  std::vector<uint64_t> logs;
  for (size_t i = 0; i < filenames.size(); i++) {
    if (ParseFileName(filenames[i], &number, &type)) {
      expected.erase(number);
      if (type == kLogFile && ((number >= min_log) || (number == prev_log)))
        logs.push_back(number);
    }
  }

  // Recover in the order in which the logs were generated
  std::sort(logs.begin(), logs.end());
  for (size_t i = 0; i < logs.size(); i++) {
    s = RecoverLogFile(logs[i], (i == logs.size() - 1), save_manifest, edit,
                       &max_sequence);

    // The previous incarnation may not have written any MANIFEST
    // records after allocating this log number.  So we manually
    // update the file number allocation counter in VersionSet.
    versions_->MarkFileNumberUsed(logs[i]);
  }

  if (versions_->LastSequence() < max_sequence) {
    versions_->SetLastSequence(max_sequence);
  }

  return Status::OK();
}

初始化数据库文件(第一次创建数据时调用)

代码语言:txt
复制
Status DBImpl::NewDB() {
  VersionEdit new_db;
  // 保存比较器的名称
  new_db.SetComparatorName(user_comparator()->Name());
  // 分配日志文件的编号为0
  new_db.SetLogNumber(0);
  // 设置下一个待分配的文件编号为2(1分配给了MANIFEST文件)
  new_db.SetNextFile(2);
  // 设置上一次的sequence版本号为0
  new_db.SetLastSequence(0);

  const std::string manifest = DescriptorFileName(dbname_, 1);
  WritableFile* file;
  Status s = env_->NewWritableFile(manifest, &file);
  {
    log::Writer log(file);
    std::string record;
    new_db.EncodeTo(&record);
    s = log.AddRecord(record);
    if (s.ok()) {
      s = file->Sync();
    }
  }

  if (s.ok()) {
    // 更新CURRENT文件,保存最新的MANIFEST文件名称
    s = SetCurrentFile(env_, dbname_, 1);
  }
  return s;
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 原理
    • 主要完成的事项:
    • 打开数据库
    • 恢复数据库
    • 初始化数据库文件(第一次创建数据时调用)
    相关产品与服务
    数据库
    云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档