[leveldb] 3-Recover数据恢复(1)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/simonyucsdy/article/details/81588073

接上一节的Open操作,DBImpl的Recover接口被调用,它的功能是实现数据库的数据恢复

Code:db/db_impl.cc(279-290)

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

  // Ignore error from CreateDir since the creation of the DB is
  // committed only when the descriptor is created, and this directory
  // may already exist from a previous failed creation attempt.
  env_->CreateDir(dbname_);  //尝试创建目录
  assert(db_lock_ == nullptr);
  Status s = env_->LockFile(LockFileName(dbname_), &db_lock_); //创始对锁文件进行上锁
  if (!s.ok()) {
    return s;
  }

数据库的访问必须是独占的,所以leveldb建立一个FileLock类对象文件,以独占的方式打开,每个实例都要尝试创建/锁定这个文件,如果失败说明有别的实例在使用这个数据库。

理论上来说, 虚函数是完全没有必要的,有些许函数其实是浪费资源。 但是leveldb却到处都是虚函数,一个接口对应一个实现也要用虚函数,模板代替虚函数大法毫无用武之地。

 

网上还有文章指出不应该用虚函数作为库的接口,leveldb再次违反规定,整个对外暴露的db类,全都是虚函数...

继续这个恢复函数

Code:db/db_impl.cc(292-307)

  //没找到当前数据库文件,则新建一个数据库
  if (!env_->FileExists(CurrentFileName(dbname_))) {
    if (options_.create_if_missing) { 
      s = NewDB();
      if (!s.ok()) {
        return s;
      }
    } else {
      return Status::InvalidArgument(
          dbname_, "does not exist (create_if_missing is false)");
    }
  } else {
    if (options_.error_if_exists) {
      return Status::InvalidArgument(
          dbname_, "exists (error_if_exists is true)");
    }
  }

 这里用到了新建数据库操作:

Code:db/db_impl.cc(180-210)

Status DBImpl::NewDB() {
  VersionEdit new_db; // 新的版本
  new_db.SetComparatorName(user_comparator()->Name()); // 防止不同的比较器打开数据库
  new_db.SetLogNumber(0);
  new_db.SetNextFile(2); //文件名后缀
  new_db.SetLastSequence(0);

  const std::string manifest = DescriptorFileName(dbname_, 1); // 描述符名称
  WritableFile* file;
  Status s = env_->NewWritableFile(manifest, &file); // 根据描述符和文件名创建新的可写文件
  if (!s.ok()) {
    return s;
  }
  {
    log::Writer log(file); // 创建了新的可写文件以后就要写一条数据记录
    std::string record;
    new_db.EncodeTo(&record); // 将VersionEdit序列化
    s = log.AddRecord(record); // log增加一条记录并写入硬盘
    if (s.ok()) {
      s = file->Close();
    }
  }
  delete file;
  if (s.ok()) {
    // Make "CURRENT" file that points to the new manifest file.
    s = SetCurrentFile(env_, dbname_, 1); // 
  } else {
    env_->DeleteFile(manifest); //删除文件描述符
  }
  return s;
}

猜你喜欢

转载自blog.csdn.net/simonyucsdy/article/details/81588073