leveldb:数据库recover机制

DBImpl::Recover

把数据库恢复到上次退出的状态,
Recover的基本功能:如果存在表数据,则Load表数据,并对日志进行恢复,否则,根据flag创建新表或者返回错误

Recover的基本流程是:首先是处理创建flag,比如存在就返回失败等等;然后是尝试从已存在的sstable文件恢复db;最后如果发现有大于manifest文件记录的log编号的log文件,则需要回放log(回放的是上一次db关闭时还存在于mem和immem的记录,因为这些记录并没有持久化到磁盘sst文件中),更新db数据。回放期间db可能会dump新的level 0文件,因此需要把db元信息的变动记录到edit中返回

Status DBImpl::Recover(VersionEdit* edit, bool *save_manifest) {
  mutex_.AssertHeld();

  // 创建DB目录,不关注错误
  env_->CreateDir(dbname_);
  // 在DB目录下打开或创建(如果不存在)LOCK文件并锁定它,防止其他进程打开此表
  Status s = env_->LockFile(LockFileName(dbname_), &db_lock_);
  if (!s.ok()) {
    return s;
  }
 //判断CURRENT文件是否存在,current不存在说明数据库不存在
  if (!env_->FileExists(CurrentFileName(dbname_))) {
    //若CURRENT文件不存在,如果options选项设置了create_if_missing,则创建新的db
    if (options_.create_if_missing) {
      s = NewDB();
      if (!s.ok()) {
        return s;
      }
    } else {
    //否则返回db不存在
      return Status::InvalidArgument(
          dbname_, "does not exist (create_if_missing is false)");
    }
  } else {
    if (options_.error_if_exists) {
    //如果数据库存在且设置了error_if_exists,则返回error_if_exists错误
      return Status::InvalidArgument(
          dbname_, "exists (error_if_exists is true)");
    }
  }
 // 如果运行到此,表明数据库已经存在,需要load,第一步是从MANIFEST文件中恢复VersionSet  
  s = versions_->Recover(save_manifest);
  if (!s.ok()) {
    return s;
  }
  SequenceNumber max_sequence(0);

/*尝试从所有比manifest文件中记录的log要新的log文件中恢复(前一个版本可能会添加新的
log文件,却没有记录在manifest中)。这种情况出现在memtable或者immemtable还没来得
及写入sst文件db就挂掉了,因此需要从比manifest文件中记录的log要新的log文件中恢复*/
//prev_log是早前版本level_db使用的机制,现在以及不再使用,这里只是为了兼容
  const uint64_t min_log = versions_->LogNumber();
  const uint64_t prev_log = versions_->PrevLogNumber();
  std::vector<std::string> filenames;
  // 列出目录内的所有文件
  s = env_->GetChildren(dbname_, &filenames);
  if (!s.ok()) {
    return s;
  }
  std::set<uint64_t> expected;
  // 这个函数实质是获取仍然存活(仍然有效)的文件
  versions_->AddLiveFiles(&expected);
  uint64_t number;
  FileType type;
  std::vector<uint64_t> logs;
  //这里先找出所有满足条件的log文件:比manifest文件记录的log编号更新。
  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);
    }
  }
  // 如果这个数组不为空,那么表示有的文件名解析不了,出错!  
  if (!expected.empty()) {
    char b
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值