std::vector<FileMetaData*>files_[config::kNumLevels]; // sstable文件列表 // Next fileto compact based on seek stats. 下一个要compact的文件 FileMetaData* file_to_compact_; int file_to_compact_level_; // 下一个应该compact的level和compaction分数. // 分数 < 1 说明compaction并不紧迫. 这些字段在Finalize()中初始化 double compaction_score_; int compaction_level_;可见一个Version就是一个sstable文件集合,以及它管理的compact状态。Version通过Version* prev和*next指针构成了一个Version双向循环链表,表头指针则在VersionSet中(初始都指向自己)。
//=== 第一组,直接来自于DBImple,构造函数传入 Env* const env_; // 操作系统封装 const std::string dbname_; const Options* const options_; TableCache* const table_cache_; // table cache const InternalKeyComparatoricmp_; //=== 第二组,db元信息相关 uint64_t next_file_number_; // log文件编号 uint64_t manifest_file_number_; // manifest文件编号 uint64_t last_sequence_; uint64_t log_number_; // log编号 uint64_t prev_log_number_; // 0 or backingstore for memtable being compacted //=== 第三组,menifest文件相关 WritableFile* descriptor_file_; log::Writer* descriptor_log_; //=== 第四组,版本管理 Version dummy_versions_; // versions双向链表head. Version* current_; // ==dummy_versions_.prev_ // level下一次compaction的开始key,空字符串或者合法的InternalKey std::stringcompact_pointer_[config::kNumLevels];关于版本控制大概了解其Version和VersionEdit的功能和管理范围,详细的函数操作在后面再慢慢揭开。
void Clear(); // 清空信息 void Setxxx(); // 一系列的Set函数,设置信息 // 添加sstable文件信息,要求:DB元信息还没有写入磁盘Manifest文件 // @level:.sst文件层次;@file 文件编号-用作文件名 @size 文件大小 // @smallest, @largest:sst文件包含k/v对的最大最小key void AddFile(int level, uint64_t file, uint64_t file_size, constInternalKey& smallest, const InternalKey& largest) void DeleteFile(int level, uint64_t file) // 从指定的level删除文件 void EncodeTo(std::string* dst) const // 将信息Encode到一个string中 Status DecodeFrom(const Slice& src) // 从Slice中Decode出DB元信息 //===================下面是成员变量,由此可大概窥得DB元信息的内容。 typedef std::set< std::pair<int, uint64_t> > DeletedFileSet; std::string comparator_; // key comparator名字 uint64_t log_number_; // 日志编号 uint64_t prev_log_number_; // 前一个日志编号 uint64_t next_file_number_; // 下一个文件编号 SequenceNumber last_sequence_; // 上一个seq bool has_comparator_; // 是否有comparator bool has_log_number_;// 是否有log_number_ bool has_prev_log_number_;// 是否有prev_log_number_ bool has_next_file_number_;// 是否有next_file_number_ bool has_last_sequence_;// 是否有last_sequence_ std::vector< std::pair<int, InternalKey> >compact_pointers_; // compact点 DeletedFileSet deleted_files_; // 删除文件集合 std::vector< std::pair<int, FileMetaData> > new_files_; // 新文件集合Set系列的函数都很简单,就是根据参数设置相应的信息。
图 9.3-1
其中的数字都是varint存储格式,string都是以varint指明其长度,后面跟实际的字符串内容。
// 设置db项{key, value} virtual Status Put(const WriteOptions& options, const Slice&key, const Slice& value) = 0; // 在db中删除"key",key不存在依然返回成功 virtual Status Delete(const WriteOptions& options, const Slice&key) = 0; // 更新操作 virtual Status Write(const WriteOptions& options, WriteBatch*updates) = 0; // 获取操作,如果db中有”key”项则返回结果,没有就返回Status::IsNotFound() virtual Status Get(const ReadOptions& options, const Slice& key,std::string* value) = 0; // 返回heap分配的iterator,访问db的内容,返回的iterator的位置是invalid的 // 在使用之前,调用者必须先调用Seek。 virtual Iterator* NewIterator(const ReadOptions& options) = 0; // 返回当前db状态的handle,和handle一起创建的Iterator看到的都是 // 当前db状态的稳定快照。不再使用时,应该调用ReleaseSnapshot(result) virtual const Snapshot* GetSnapshot() = 0; // 释放获取的db快照 virtual voidReleaseSnapshot(const Snapshot* snapshot) = 0; // 借此方法DB实现可以展现它们的属性状态. 如果"property" 是合法的, // 设置"*value"为属性的当前状态值并返回true,否则返回false. // 合法属性名包括: // // >"leveldb.num-files-at-level<N>"– 返回level <N>的文件个数, // <N> 是level 数的ASCII 值 (e.g. "0"). // >"leveldb.stats" – 返回描述db内部操作统计的多行string // >"leveldb.sstables" – 返回一个多行string,描述构成db内容的所有sstable virtual bool GetProperty(constSlice& property, std::string* value) = 0; //"sizes[i]"保存的是"[range[i].start.. range[i].limit)"中的key使用的文件空间. // 注:返回的是文件系统的使用空间大概值, // 如果用户数据以10倍压缩,那么返回值就是对应用户数据的1/10 // 结果可能不包含最近写入的数据大小. virtual voidGetApproximateSizes(const Range* range, int n, uint64_t* sizes) = 0; // Compactkey范围[*begin,*end]的底层存储,删除和被覆盖的版本将会被抛弃 // 数据会被重新组织,以减少访问开销 // 注:那些不了解底层实现的用户不应该调用该方法。 //begin==NULL被当作db中所有key之前的key. //end==NULL被当作db中所有key之后的key. // 所以下面的调用将会compact整个db: // db->CompactRange(NULL, NULL); virtual void CompactRange(constSlice* begin, const Slice* end) = 0; // 最后是两个全局函数--删除和修复DB // 要小心,该方法将删除指定db的所有内容 Status DestroyDB(const std::string& name, const Options&options); // 如果db不能打开了,你可能调用该方法尝试纠正尽可能多的数据 // 可能会丢失数据,所以调用时要小心 Status RepairDB(const std::string& dbname, const Options&options);
这里又会设计到几个功能类,如图9.5-1所示。此外还有前面我们讲过的几大组件:操作日志的读写类、内存MemTable类、InternalFilterPolicy类、Internal Key比较类、以及sstable的读取构建类。如图9.5-2所示。
图9.5-1
图9.5-2
这里涉及的类很多,snapshot是内存快照,Version和VersionSet类。
//== 第一组,他们在构造函数中初始化后将不再改变。其中,InternalKeyComparator和InternalFilterPolicy已经分别在Memtable和FilterPolicy中分析过。 Env* const env_; // 环境,封装了系统相关的文件操作、线程等等 const InternalKeyComparatorinternal_comparator_; // key comparator const InternalFilterPolicyinternal_filter_policy_; // filter policy const Options options_; //options_.comparator == &internal_comparator_ bool owns_info_log_; bool owns_cache_; const std::string dbname_; //== 第二组,只有两个。 TableCache* table_cache_; // Table cache,线程安全的 FileLock* db_lock_;// 锁db文件,persistent state,直到leveldb进程结束 //== 第三组,被mutex_包含的状态和成员 port::Mutex mutex_; // 互斥锁 port::AtomicPointershutting_down_; port::CondVar bg_cv_; // 在background work结束时激发 MemTable* mem_; MemTable* imm_; // Memtablebeing compacted port::AtomicPointerhas_imm_; // BGthread 用来检查是否是非NULL的imm_ // 这三个是log相关的 WritableFile* logfile_; // log文件 uint64_t logfile_number_; // log文件编号 log::Writer* log_; // log writer //== 第四组,没有规律 std::deque<Writer*>writers_; // writers队列. WriteBatch* tmp_batch_; SnapshotList snapshots_; //snapshot列表 // Setof table files to protect from deletion because they are // part ofongoing compactions. std::set<uint64_t>pending_outputs_; // 待copact的文件列表,保护以防误删 bool bg_compaction_scheduled_; // 是否有后台compaction在调度或者运行? Status bg_error_; // paranoid mode下是否有后台错误? ManualCompaction*manual_compaction_; // 手动compaction信息 CompactionStatsstats_[config::kNumLevels]; // compaction状态 VersionSet* versions_; // 多版本DB文件,又一个庞然大物