levelDB源码分析-TableCache

       Table相当于.sst文件在内存中的映像,它保存了.sst文件的Index Block数据。
       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;
    }


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值