leveldb源码分析四
2017-07-26 00:56
836 查看
前言
之前写了一些东西,整体了解了工程的编译脚本和一个test的工程结构,本来想按部就班,慢慢来解决可是咱们还是直接进入主题,直接啃这个数据库的测试程序,看看到底如何实现,正文
我们直接进入db_test.cpp文件,找到第一个test类。
TEST(DBTest, Empty) { do { ASSERT_TRUE(db_ != NULL); ASSERT_EQ("NOT_FOUND", Get("foo")); } while (ChangeOptions()); }
这个测试其实很简单,就是简单的额测试真实的操作的
db_代理对象是不是为空,和查找一个键值为k
foo的值。这里我们必须要找到初始化的代码,看看如何获取代理对象,并且初始化这个类的。
DBTest() : option_config_(kDefault), env_(new SpecialEnv(Env::Default())) { filter_policy_ = NewBloomFilterPolicy(10); dbname_ = test::TmpDir() + "/db_test"; DestroyDB(dbname_, Options()); db_ = NULL; Reopen(); }
这里我们记住初始化了几个变量,这里暂时不详细介绍,关于
dbname_,这个我们稍微介绍下,具体获取代码如下
virtual Status GetTestDirectory(std::string* result) { const char* env = getenv("TEST_TMPDIR"); if (env && env[0] != '\0') { *result = env; } else { char buf[100]; snprintf(buf, sizeof(buf), "/tmp/leveldbtest-%d", int(geteuid())); *result = buf; } // Directory may already exist CreateDir(*result); return Status::OK(); } static void InitDefaultEnv() { default_env = new PosixEnv; } Env* Env::Default() { pthread_once(&once, InitDefaultEnv); return default_env; } std::string TmpDir() { std::string dir; Status s = Env::Default()->GetTestDirectory(&dir); ASSERT_TRUE(s.ok()) << s.ToString(); return dir; }
这里的
getenv("TEST_TMPDIR")为空,所以基本就是
/tmp/leveldbtest-%d,这里根据uid得到唯一的一个数据库。不过觉得,因为单次,可以删除自己,所以肯定不会重合。
Env::Default()这个其实是防止并发,这里返回时一个
PosixEnv,这是一个类似代理模式的设计,这里就不详细介绍,其实就是为了得到一个唯一的文件目录。
关键是最后三句话,这才是初始化db_的语句,我们好好看看:
Status DestroyDB(const std::string& dbname, const Options& options) { Env* env = options.env; std::vector<std::string> filenames; // Ignore error in case directory does not exist env->GetChildren(dbname, &filenames); if (filenames.empty()) { return Status::OK(); } FileLock* lock; const std::string lockname = LockFileName(dbname); Status result = env->LockFile(lockname, &lock); if (result.ok()) { uint64_t number; FileType type; for (size_t i = 0; i < filenames.size(); i++) { if (ParseFileName(filenames[i], &number, &type) && type != kDBLockFile) { // Lock file will be deleted at end Status del = env->DeleteFile(dbname + "/" + filenames[i]); if (result.ok() && !del.ok()) { result = del; } } } env->UnlockFile(lock); // Ignore error since state is already gone env->DeleteFile(lockname); env->DeleteDir(dbname); // Ignore error in case dir contains other files } return result; }
传入的参数是个Options的结构体。这里保存一个Env::Default()结构。关于这里删除必要的文件,这里加锁防止并发,并且具有保护措施,其实挺好的,这里就不详细介绍,有兴趣的可以自己阅读。
Status TryReopen(Options* options) { delete db_; db_ = NULL; Options opts; if (options != NULL) { opts = *options; } else { opts = CurrentOptions(); opts.create_if_missing = true; } last_options_ = opts; return DB::Open(opts, dbname_, &db_); } Status DB::Open(const Options& options, const std::string& dbname, DB** dbptr) { *dbptr = NULL; //这里是常见一个工作类。 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_ == NULL) { // 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 rec c4f3 overy. edit.SetLogNumber(impl->logfile_number_); s = impl->versions_->LogAndApply(&edit, &impl->mutex_); } if (s.ok()) { impl->DeleteObsoleteFiles(); impl->MaybeScheduleCompaction(); } impl->mutex_.Unlock(); if (s.ok()) { assert(impl->mem_ != NULL); *dbptr = impl; } else { delete impl; } return s; }
这里其实就是调用了
Open函数,这里才是初始化整个数据库的核心地方,这里因为我们还没有存入数据,所以这里仅仅初始化了一个log的文件,但是经过观察 ,貌似还没创建文件,这里就不详细介绍了。
也就是高了一个
DBImpl类,然后就没有然后了。这里初始化基本完成了,还剩下一个最终的问题,
ASSERT_TRUE(db_ != NULL); ASSERT_EQ("NOT_FOUND", Get("foo"));
这里很容易搞懂啦!第一个就不用多说,第二个,我们看下
std::string Get(const std::string& k, const Snapshot* snapshot = NULL) { ReadOptions options; options.snapshot = snapshot; std::string result; Status s = db_->Get(options, k, &result); if (s.IsNotFound()) { result = "NOT_FOUND"; } else if (!s.ok()) { result = s.ToString(); } return result; }
这里我们很容易知道取得当然是空,我们这里不详细介绍获取的内容,因为我们还没阅读添加字段的代码,阅读这里觉得没太大意义。
后记
有是一天,又是半篇,进度总是没自己想的快,不过至少还在前行,希望快速阅读完这个代码,带着问题,去看下书,解决下自己的语法的问题,希望自己快速掌握c++。加油。相关文章推荐
- leveldb源码分析--SSTable之Compaction 详解
- LevelDB源码分析3-Slice.md
- Leveldb源码分析--1
- Leveldb源码分析
- 谷歌LevelDB之源码分析之1______Slice封装
- leveldb源码分析之五
- goleveldb源码分析-key的存储和构成
- Leveldb源码分析--6
- leveldb源码分析--SSTable之block
- levelDB源码分析-Memtable
- Leveldb源码分析--8
- leveldb源码分析 之 入门使用
- Leveldb源码分析--15
- Leveldb源码分析--7
- leveldb源码分析 之 入门使用
- LevelDB源码分析4-Status
- leveldb源码分析
- leveldb源码分析——SSTable构建
- leveldb源码阅读分析笔记
- 【转载】leveldb源码分析—Recover和Repair