当前位置:网站首页>Leveldb source code analysis -- open the database

Leveldb source code analysis -- open the database

2022-06-24 17:23:00 Xiao Lin Gang

principle

Open in analysis leveldb Before the database , Let's discuss some similar sub problems first :

  1. How to restore the running state of a process ?
  2. How to solve the problem of slow data indexing ?

Main completed items :

  • Build... In storage MemTable data structure ;
  • load SSTable File search related index information ;
  • Replay unfinished WAL journal ;

Open database

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;
}

Recover database

Status DBImpl::Recover(VersionEdit* edit, bool* save_manifest) {
  //  Create database directory 
  env_->CreateDir(dbname_);
  //  Get file lock , Prohibit multiple processes from accessing the database at the same time 
  Status s = env_->LockFile(LockFileName(dbname_), &db_lock_);

  if (!env_->FileExists(CurrentFileName(dbname_))) {
    if (options_.create_if_missing) {
      //  Such as CURRENT file does not exist , Then initialize the database file 
      s = NewDB();
    }
  }

  //  Load database version management information 
  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();
}

Initialize database file ( Called the first time data is created )

Status DBImpl::NewDB() {
  VersionEdit new_db;
  //  Save the name of the comparator 
  new_db.SetComparatorName(user_comparator()->Name());
  //  The assigned log file number is 0
  new_db.SetLogNumber(0);
  //  Set the next document number to be assigned as 2(1 Assigned to the MANIFEST file )
  new_db.SetNextFile(2);
  //  Set last sequence The version number is 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()) {
    //  to update CURRENT file , Keep the latest MANIFEST File name 
    s = SetCurrentFile(env_, dbname_, 1);
  }
  return s;
}
原网站

版权声明
本文为[Xiao Lin Gang]所创,转载请带上原文链接,感谢
https://yzsam.com/2021/03/20210321214122384N.html