Table相当于.sst文件在内存中的映像,它保存了.sst文件的Index Block数据。
TableCache相当于所有打开的.sst文件在内存中的管理结构,内部采用LRUCache,每个打开的.sst文件在LRUCache中都有一项:map<file_number -> {file, table}>
TableCache相当于所有打开的.sst文件在内存中的管理结构,内部采用LRUCache,每个打开的.sst文件在LRUCache中都有一项:map<file_number -> {file, table}>
static void DeleteEntry(const Slice& key, void* value) { // 删除TableAndFile节点
TableAndFile* tf = reinterpret_cast<TableAndFile*>(value);
delete tf->table;
delete tf->file;
delete tf;
}
static void UnrefEntry(void* arg1, void* arg2) { // 减少handle引用计数
Cache* cache = reinterpret_cast<Cache*>(arg1);
Cache::Handle* h = reinterpret_cast<Cache::Handle*>(arg2);
cache->Release(h);
}
// 构造函数,dbname:数据库, entries:指明了LRUCache中的容量
TableCache::TableCache(const std::string& dbname, const Options* options, int entries)
: env_(options->env), dbname_(dbname), options_(options), cache_(NewLRUCache(entries)) // cache_: 新建一个LRUCache
{
}
TableCache::~TableCache() {
delete cache_;
}
Iterator* TableCache::NewIterator(const ReadOptions& options, // 新建一个.sst文件内存映像(table_, file)
uint64_t file_number,
uint64_t file_size,
Table** tableptr)
{
if (tableptr != NULL) {
*tableptr = NULL;
}
char buf[sizeof(file_number)];
EncodeFixed64(buf, file_number);
Slice key(buf, sizeof(buf));
Cache::Handle* handle = cache_->Lookup(key); // 在LRUCache中查找映像是否存在(根据file_number查找)
if (handle == NULL) {
std::string fname = TableFileName(dbname_, file_number);// 构造.sst文件名
RandomAccessFile* file = NULL;
Table* table = NULL;
Status s = env_->NewRandomAccessFile(fname, &file); // 随机读方式打开文件
if (s.ok()) {
s = Table::Open(*options_, file, file_size, &table);// 解析sstable文件(读取Footer,找到index_block_handle,读取Index Block数据)
}
if (!s.ok()) {
assert(table == NULL);
delete file;
// We do not cache error results so that if the error is transient,
// or somebody repairs the file, we recover automatically.
return NewErrorIterator(s);
}
TableAndFile* tf = new TableAndFile; // 新建一个节点
tf->file = file; // .sst文件打开文件指针
tf->table = table; // .sst文件索引数据内存映像
handle = cache_->Insert(key, tf, 1, &DeleteEntry); // 插入LRUCache(对应释放回调函数)
}
Table* table = reinterpret_cast<TableAndFile*>(cache_->Value(handle))->table;
Iterator* result = table->NewIterator(options);
result->RegisterCleanup(&UnrefEntry, cache_, handle); // 注册一个减少引用计数的函数(用于减少cache_中的handle对应的引用计数)
if (tableptr != NULL) {
*tableptr = table;
}
return result;
}
void TableCache::Evict(uint64_t file_number) {
char buf[sizeof(file_number)];
EncodeFixed64(buf, file_number);
cache_->Erase(Slice(buf, sizeof(buf))); // 从LRUCache中删除对应的key节点,这里为TableAndFile
}
说明介绍的TableBuilder为构造.sst文件的Data Block及Index Block的实现,下面BuildTable是根据Memtable或Immutable Memtable生成一个.sst文件,保存结束后,同时会将其打开,存入TableCache中。
Status BuildTable(const std::string& dbname, // 根据Immutable Memtable或Memtable, 构造一个.sst文件
Env* env, // 文件操作等
const Options& options, // 选项
TableCache* table_cache, // .sst文件内存映像table_cache(包含.sst文件的IndxBlock数据-table_和打开的文件句柄-file)
Iterator* iter, // Immutable Memtable的迭代器
FileMetaData* meta) // manifest记录的.sst文件索引(file_number, smallest_key, max_key)
{
Status s;
meta->file_size = 0;
iter->SeekToFirst();
std::string fname = TableFileName(dbname, meta->number);
if (iter->Valid()) {
WritableFile* file;
s = env->NewWritableFile(fname, &file); // 新建一个可写文件
if (!s.ok()) {
return s;
}
// meta为manifest中对应每个.sst文件的索引项(包括: file_number, smallest_key, max_key)
TableBuilder* builder = new TableBuilder(options, file); // TableBuilder为.sst文件的构造器
meta->smallest.DecodeFrom(iter->key()); // .sst文件的索引项的smallest_key
for (; iter->Valid(); iter->Next()) {
Slice key = iter->key();
meta->largest.DecodeFrom(key); // .sst文件的索引项的max_key
builder->Add(key, iter->value()); // key/value键值对存入.sst(TableBuilder内部构造每个Data Block及IndexBlock索引)
}
// Finish and check for builder errors
if (s.ok()) { // .sst构造成功
s = builder->Finish(); // .sst数据写入文件
if (s.ok()) {
meta->file_size = builder->FileSize(); // .sst文件大小
assert(meta->file_size > 0);
}
} else {
builder->Abandon(); // .sst文件构造失败,放弃
}
delete builder;
// Finish and check for file errors
if (s.ok()) {
s = file->Sync(); // fsync,fdatasync-synchronize a file’s in-core state with storage device
}
if (s.ok()) {
s = file->Close(); // 关闭文件
}
delete file;
file = NULL;
if (s.ok()) {
// Verify that the table is usable
// 新建一个.sst文件内存映像(table_, file)
Iterator* it = table_cache->NewIterator(ReadOptions(),
meta->number,
meta->file_size);
s = it->status();
delete it;
}
}
// Check for input iterator errors
if (!iter->status().ok()) {
s = iter->status();
}
if (s.ok() && meta->file_size > 0) {
// Keep it
} else {
env->DeleteFile(fname);
}
return s;
}