LevelDB源码分析之十五:table cache
扫描二维码
随时随地手机看文章
阅读本博客可参考:
LevelDB源码分析之十一:cache
LevelDB源码分析之十二:block
LevelDB源码分析之十三:table
由上面这三篇博客可知,LevelDB的Cache分为两种,分别是table cache和block cache。block是table文件内组织数据的单位,也是从持久化存储中读取和写入的单位。
block cache是缓存的block数据。table cache缓存的是table的索引数据,因此通过table cache可以遍历DB所有.sst文件,类似于文件系统中对inode的缓存。
在LevelDB源码分析之十三:table中用到了block_cache,它实际上就是一个NewLRUCache对象,并没有像table_cache一样,专门用一个类TableCache来管理NewLRUCache对象。
下面来简单分析TableCache。
struct TableAndFile { RandomAccessFile* file; Table* table; }; static void DeleteEntry(const Slice& key, void* value) { TableAndFile* tf = reinterpret_cast(value); delete tf->table; delete tf->file; delete tf; } static void UnrefEntry(void* arg1, void* arg2) { Cache* cache = reinterpret_cast(arg1); Cache::Handle* h = reinterpret_cast(arg2); cache->Release(h); } // 从构造函数中可以看出TableCache内部管理的是LRUCache对象 TableCache::TableCache(const std::string& dbname, const Options* options, int entries) : env_(options->env), dbname_(dbname), options_(options), cache_(NewLRUCache(entries)) { } TableCache::~TableCache() { delete cache_; } // 参数file_number是文件编号,file_size是文件大小 // 参数*tableptr指向Table对象,当然必须先判断tableptr是不是NULL // 返回某个.sst文件对应的Table对象的迭代器 Iterator* TableCache::NewIterator(const ReadOptions& options, uint64_t file_number, uint64_t file_size, Table** tableptr) { if (tableptr != NULL) { *tableptr = NULL; } // 将file_number转换为key char buf[sizeof(file_number)]; EncodeFixed64(buf, file_number); Slice key(buf, sizeof(buf)); // 根据key查找指定的文件 Cache::Handle* handle = cache_->Lookup(key); // 如果指定文件不存在,打开文件并添加至缓存 if (handle == NULL) { // 返回新的.sst文件的路径 std::string fname = TableFileName(dbname_, file_number); RandomAccessFile* file = NULL; Table* table = NULL; Status s = env_->NewRandomAccessFile(fname, &file); if (s.ok()) { // 将.sst文件映射到table,Table类用于解析.sst文件 s = Table::Open(*options_, file, file_size, &table); } 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; tf->table = table; // 将tf插入到LRUCache中,占据一个大小的缓存,DeleteEntry是删除结点的回调函数 handle = cache_->Insert(key, tf, 1, &DeleteEntry); } // cache_->Value(handle)用于返回handle结点的value Table* table = reinterpret_cast(cache_->Value(handle))->table; Iterator* result = table->NewIterator(options); result->RegisterCleanup(&UnrefEntry, cache_, handle); if (tableptr != NULL) { *tableptr = table; } return result; } // Evict含义为”驱逐“,当Compaction时,过期的文件将会被移除,此时调用Evict从移除该文件缓存。 void TableCache::Evict(uint64_t file_number) { char buf[sizeof(file_number)]; EncodeFixed64(buf, file_number); // 从LRUCache中删除对应的key结点,不过此时该结点内容为TableAndFile cache_->Erase(Slice(buf, sizeof(buf))); }