【leveldb】Cache(十七):TableCache

通过上一篇文章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
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值