版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
}