leveldb支持数据的多个版本,可以获取某个版本的快照,遍历或者查找这个版本中的key
class LEVELDB_EXPORT DB {
...
// Return a handle to the current DB state. Iterators created with
// this handle will all observe a stable snapshot of the current DB
// state. The caller must call ReleaseSnapshot(result) when the
// snapshot is no longer needed.
virtual const Snapshot* GetSnapshot() = 0;
// Release a previously acquired snapshot. The caller must not
// use "snapshot" after this call.
virtual void ReleaseSnapshot(const Snapshot* snapshot) = 0;
...
};
同时对某个key更新时,不会直接在原key上更新,而是提交一个版本号更大的record,原版本的key会一直保留,直到在compaction时,低版本的key被merge到高版本的key。
Version
Version保存的是当前版本中的sstable和相关compaction信息。通过引用计数管理生命周期,通过list方式组织。Version封装了在compaction时对sstable的一系列操作。
class Version {
...
VersionSet* vset_; // VersionSet to which this Version belongs
Version* next_; // Next version in linked list
Version* prev_; // Previous version in linked list
int refs_; // Number of live refs to this version
// List of files per level
std::vector<FileMetaData*> files_[config::kNumLevels];
// Next file to compact based on seek stats.
FileMetaData* file_to_compact_;
int file_to_compact_level_;
// Level that should be compacted next and its compaction score.
// Score < 1 means compaction is not strictly needed. These fields
// are initialized by Finalize().
double compaction_score_;
int compaction_level_;
};
VersionEdit
每次compaction之后,会产生一个新的版本,新版本在sstable文件组成上面和老版本上存在差异,这个差异通过VersionEdit表示,老版本通过应用VersionEdit之后,就可以得到新版本。
struct VersionEdit {
typedef std::set<std::pair<int, uint64_t>> DeletedFileSet;
// 比较器名称
std::string comparator_;
// 日志编号,该日志之前的数据均可删除
uint64_t log_number_;
// 已经弃用
uint64_t prev_log_number_;
// 下一个文件编号(ldb、idb、MAINFEST文件共享一个序号空间)
uint64_t next_file_number_;
// 最后的seq_num
SequenceNumber last_sequence_;
//
bool has_comparator_;
bool has_log_number_;
bool has_prev_log_number_;
bool has_next_file_number_;
//
bool has_last_sequence_;
// 记录每一层所对应需要压缩的
std::vector<std::pair<int, InternalKey>> compact_pointers_;
// 相比上次version而言,本次需要删除的文件有哪些
DeletedFileSet deleted_files_;
// 相比上次version而言,本次新增的文件有哪些
std::vector<std::pair<int, FileMetaData>> new_files_;
};
VersionEdit中封装了对上述几个字段的序列化和反序列化。
Manifest
Manifest文件可以看作是VersionEdit的日志,为了快速恢复需要将这些变更持久化到磁盘上。Manifest和WAL使用同样的格式就VersionEdit,一个VersionEdit就是一条record。在DB重启时,通过解析当前Manifest文件,就可以恢复到最新的版本。
VersionSet
通过VersionSet来管理多个Version,整个db只有一个。

class VersionSet {
...
Env* const env_;
const std::string dbname_;
const Options* const options_;
TableCache* const table_cache_;
const InternalKeyComparator icmp_;
uint64_t next_file_number_;
uint64_t manifest_file_number_;
uint64_t last_sequence_;
uint64_t log_number_;
uint64_t prev_log_number_; // 0 or backing store for memtable being compacted
// Opened lazily
WritableFile* descriptor_file_;
log::Writer* descriptor_log_;
Version dummy_versions_; // Head of circular doubly-linked list of versions.
Version* current_; // == dummy_versions_.prev_
// Per-level key at which the next compaction at that level should start.
// Either an empty string, or a valid InternalKey.
std::string compact_pointer_[config::kNumLevels];
...
};