【leveldb】Cache(十七):TableCache

    技术2025-05-15  57

    通过上一篇文章leveldb的Cache整体结构说明, 我们基本上知道了tableCache在整个leveldb中的作用以及上下文类关系,它主要缓存leveldb落地的ldb文件结构在内存中的信息。本篇主要是对代码流程的解读。

    table_cache.h

    namespace leveldb { class Env; class TableCache { public: TableCache(const std::string& dbname, const Options& options, int entries); ~TableCache(); // Return an iterator for the specified file number (the corresponding // file length must be exactly "file_size" bytes). If "tableptr" is // non-null, also sets "*tableptr" to point to the Table object // underlying the returned iterator, or to nullptr if no Table object // underlies the returned iterator. The returned "*tableptr" object is owned // by the cache and should not be deleted, and is valid for as long as the // returned iterator is live. Iterator* NewIterator(const ReadOptions& options, uint64_t file_number, uint64_t file_size, Table** tableptr = nullptr); // If a seek to internal key "k" in specified file finds an entry, // call (*handle_result)(arg, found_key, found_value). Status Get(const ReadOptions& options, uint64_t file_number, uint64_t file_size, const Slice& k, void* arg, void (*handle_result)(void*, const Slice&, const Slice&)); // Evict any entry for the specified file number void Evict(uint64_t file_number); private: Status FindTable(uint64_t file_number, uint64_t file_size, Cache::Handle**); Env* const env_; //环境相关操作信息 const std::string dbname_; //ldb文件名称 const Options& options_; //用户已经系统设置的操作选择 Cache* cache_; //用以缓存ldb的Cache }; } // namespace leveldb

    table_cache.cc

    namespace leveldb { //TableCache中的Value结构 struct TableAndFile { RandomAccessFile* file; Table* table; }; //删除TableCache一条KV记录, //1、删除ldb在内存中的数据; //2、关闭ldb文件句柄。 static void DeleteEntry(const Slice& key, void* value) { TableAndFile* tf = reinterpret_cast<TableAndFile*>(value); delete tf->table; delete tf->file; delete tf; } //这里是解引用TableCache中的一条KV记录 static void UnrefEntry(void* arg1, void* arg2) { Cache* cache = reinterpret_cast<Cache*>(arg1); Cache::Handle* h = reinterpret_cast<Cache::Handle*>(arg2); cache->Release(h); } //构造一个TableCache,则构造过程中 //就根据传入的entries(KV个数)来创建TableCache。 TableCache::TableCache(const std::string& dbname, const Options& options, int entries) : env_(options.env), dbname_(dbname), options_(options), cache_(NewLRUCache(entries)) {} //析构就释放创建的Cache TableCache::~TableCache() { delete cache_; } //查找ldb文件对应的Cache记录。这里要说明下,当前版本是1.22版本。 //落地的存储文件后缀都是.ldb,旧的落地文件后缀是.sst。 //file_number:就是ldb文件名 //file_size:ldb文件大小。 //handle:要返回的ldb对应的Cache实体 //查找流程是: //1、file_number就是key,先去TableCache中查找,若找到则直接返回。 //2、TableCache中未找到,则需要打开此文件,先以后缀.ldb格式打开。 //3、若打开失败,尝试用文件后缀.sst格式打开。 //4、打开文件成功之后要创建Table实体,用于管理ldb文件内容。 //5、将打开的文件插入到TableCache中。 Status TableCache::FindTable(uint64_t file_number, uint64_t file_size, Cache::Handle** handle) { Status s; char buf[sizeof(file_number)]; EncodeFixed64(buf, file_number); Slice key(buf, sizeof(buf)); //去缓存查找 *handle = cache_->Lookup(key); if (*handle == nullptr) { //先以后缀.ldb格式打开 std::string fname = TableFileName(dbname_, file_number); RandomAccessFile* file = nullptr; Table* table = nullptr; s = env_->NewRandomAccessFile(fname, &file); if (!s.ok()) { //尝试以后缀.sst格式打开 std::string old_fname = SSTTableFileName(dbname_, file_number); if (env_->NewRandomAccessFile(old_fname, &file).ok()) { s = Status::OK(); } } if (s.ok()) { //创建Table实体 s = Table::Open(options_, file, file_size, &table); } if (!s.ok()) { assert(table == nullptr); delete file; // We do not cache error results so that if the error is transient, // or somebody repairs the file, we recover automatically. } else { //插入缓存中 TableAndFile* tf = new TableAndFile; tf->file = file; tf->table = table; *handle = cache_->Insert(key, tf, 1, &DeleteEntry); } } return s; } //创建访问ldb文件的迭代器。 //1、先根据文件名找到ldb文件结构; //2、根据找到的ldb结构,对table结构创建一个二层指针迭代器; //3、注册迭代器销毁时的操作函数。 Iterator* TableCache::NewIterator(const ReadOptions& options, uint64_t file_number, uint64_t file_size, Table** tableptr) { if (tableptr != nullptr) { *tableptr = nullptr; } Cache::Handle* handle = nullptr; Status s = FindTable(file_number, file_size, &handle); if (!s.ok()) { return NewErrorIterator(s); } Table* table = reinterpret_cast<TableAndFile*>(cache_->Value(handle))->table; Iterator* result = table->NewIterator(options); result->RegisterCleanup(&UnrefEntry, cache_, handle); if (tableptr != nullptr) { *tableptr = table; } return result; } //此方法就是查找ldb文件中是否存在key,若存在则执行handle_result函数。 //InternalGet()流程如下: //1、先去ldb文件的index_block中查找key对应的block offset; //2、根据block offset去Filter Block(若开启的话)中去查找; //3、若确定存在,则去实际的DataBlock中去读取,同时执行handle_result方法。 Status TableCache::Get(const ReadOptions& options, uint64_t file_number, uint64_t file_size, const Slice& k, void* arg, void (*handle_result)(void*, const Slice&, const Slice&)) { Cache::Handle* handle = nullptr; Status s = FindTable(file_number, file_size, &handle); if (s.ok()) { Table* t = reinterpret_cast<TableAndFile*>(cache_->Value(handle))->table; s = t->InternalGet(options, k, arg, handle_result); cache_->Release(handle); } return s; } //删除ldb文件在tableCache中缓存 void TableCache::Evict(uint64_t file_number) { char buf[sizeof(file_number)]; EncodeFixed64(buf, file_number); cache_->Erase(Slice(buf, sizeof(buf))); } } // namespace leveldb
    Processed: 0.011, SQL: 9