当我们不再使用 leveldb 时,会将 db 这个对象删除。 那在 db 的析构函数中会做哪些工作?
1 2 3 leveldb::DB *db; ... delete db;
1. db 的析构函数 ·
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 DBImpl::~DBImpl () { mutex_.Lock (); shutting_down_.store (true , std::memory_order_release); while (background_compaction_scheduled_) { background_work_finished_signal_.Wait (); } mutex_.Unlock (); if (db_lock_ != nullptr ) { env_->UnlockFile (db_lock_); } delete versions_; if (mem_ != nullptr ) mem_->Unref (); if (imm_ != nullptr ) imm_->Unref (); delete tmp_batch_; delete log_; delete logfile_; delete table_cache_; if (owns_info_log_) { delete options_.info_log; } if (owns_cache_) { delete options_.block_cache; } }
基本上这个函数都是在做资源释放,包括:
等待 compaction 结束,强制开启 shutting_down_
, 后序 compaction 会监测这个变量,一旦它为 true,就不会 compaction 了。也就是说当前的 memtable 不一定能完全 dump 到下层中。 但是后序重启 Open leveldb 时,可以从 log 文件中恢复。
解文件锁,这个文件锁是用来保证同一时刻只有一个进程可以使用一个 leveldb 数据库。
释放 version_资源
释放 memtable
释放其它资源
2. versions_析构 ·
1 2 3 4 5 6 7 8 VersionSet::~VersionSet () { current_->Unref (); assert (dummy_versions_.next_ == &dummy_versions_); delete descriptor_log_; delete descriptor_file_; }
首先看 current_->Unref ():
1 2 3 4 5 6 7 8 void Version::Unref () { assert (this != &vset_->dummy_versions_); assert (refs_ >= 1 ); --refs_; if (refs_ == 0 ) { delete this ; } }
1. version 析构 ·
接着是当前版本的析够:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Version::~Version () { assert (refs_ == 0 ); prev_->next_ = next_; next_->prev_ = prev_; for (int level = 0 ; level < config::kNumLevels; level++) { for (size_t i = 0 ; i < files_[level].size (); i++) { FileMetaData* f = files_[level][i]; assert (f->refs > 0 ); f->refs--; if (f->refs <= 0 ) { delete f; } } } }
第一步从 versionset 中移除本版本,第二步释放所有 FileMeta 。
3. mem 析构 ·
mem 的析够比较简单了,当引用计数降低到 0 时,自动 delete:
1 2 3 4 5 6 7 8 void Unref () { --refs_; assert (refs_ >= 0 ); if (refs_ <= 0 ) { delete this ; } }
4. 总结 ·
db 对象的删除,基本做的工作就是释放各个环节中设涉及到的资源,如 version,memtable,cache。