rocksdb的缓存在读流程里面的作用

读操作的前期流程

对用户来说,读流程如下:

  DB* db;
  Options options;
  std::string dbname = "/tmp/rocksdb4";
  Status s = DB::Open(options, dbname, &db);
  td::string myValue
  db->Get(ReadOptions(), "a5", &myValue);

内部兜兜转转其实是走到了下面这个方法里(在db_impl.cc里)

Status DBImpl::GetImpl(const ReadOptions& read_options, const Slice& key,
                       GetImplOptions& get_impl_options)

这里面大的流程就是先从mem读,如果没有就去imm读,如果还没有就去sst里面读。
处理从各层sst和缓存里面拿到kv的逻辑就在下面的代码里(实现在version_set.cc):

Version::Get(....)

Version::Get里面会按照L0的sst文件都检查一遍,然后之后的每层只用检查1个sst文件的逻辑进行搜索。
具体对某个sst文件的查询在Version::Get里面的TableCache::Get方法里。
对sst的查询在TableCache::Get里面!可以理解为每次查询某个sst的逻辑都包含了缓存。OK咱们这篇文章的重点就从这里开始。

TableCache::Get

我认为理解一个东西最好的逻辑,就是先假定它不存在,然后看看在没有它的情况整个流程如何运行,然后再去看看加上它都解决了那些问题。
如果咱们去掉所有的缓存逻辑,那么TableCache::Get里面就是两层

1 获取TableReader。
2 调用TableReader的Get方法。

1 获取TableReader

整体逻辑在TableCache::FindTable逻辑里面调用的TableCache::GetTableReader实现。
GetTableReader先通过PosixFileSystem构建了PosixMmapReadableFile,然后构建了RandomAccessFileReader,最终构建了TableReader。
这里有个问题TableReader是啥?它是什么作用?
慢慢说,我们知道一个sst的格式如下:

<beginning_of_file>
[data block 1]
[data block 2]
...
[data block N]
[meta block 1: filter block]                  (see section: "filter" Meta Block)
[meta block 2: stats block]                   (see section: "properties" Meta Block)
[meta block 3: compression dictionary block]  (see section: "compression dictionary" Meta Block)
[meta block 4: range deletion block]          (see section: "range deletion" Meta Block)
...
[meta block K: future extended block]  (we may add more meta blocks in the future)
[metaindex block]
[index block]
[Footer]                               (fixed size; starts at file_size - sizeof(Footer))
<end_of_file>

读取一个sst的时候,就是先读取footer,然后根据footer定位到indeblock和metainde block
然后根据indexblock定位data block
根据meta indexblcok定位各个metablock (上面的结构代码里,包含了4种metablcok)

在BlockBasedTable::Open里面,就是按照如下的顺序解析各个block的。

  // Read in the following order:
  //    1. Footer
  //    2. [metaindex block]
  //    3. [meta block: properties]
  //    4. [meta block: range deletion tombstone]
  //    5. [meta block: compression dictionary]
  //    6. [meta block: index]
  //    7. [meta block: filter]

上面需要几次io?
举个例子,下面的流程就是解析index block的逻辑。

TableCache::GetTableReader
	BlockBasedTableFactory::NewTableReader
		BlockBasedTable::Open
			BlockBasedTable::PrefetchIndexAndFilterBlocks
				BlockBasedTable::CreateIndexReader
					BinarySearchIndexReader::Create
						BlockBasedTable::IndexReaderCommon::ReadIndexBlock
							BlockBasedTable::RetrieveBlock
								ReadBlockFromFile(define at block_based_table_reader.cc)
									BlockFetcher::ReadBlockContents
										BlockFetcher::GetBlockContents

换句话说,TableReader里面持有了一个sst里面的除了datablcok外的所有信息。

2 调用TableReader的Get方法

这里面的逻辑也简单,
1 先去布隆过滤器里面找。如果布隆过滤器说没有,那就肯定没有,直接返回;如果布隆过滤器说有,那就继续找。
2 从indexblock里面找到对应的datablcok,然后在datablcok上构建迭代器(这里需要读磁盘)
3 从datablock的迭代器里面,找到对应的kv。
4 检查kv是否已经删除,是否范围删除等等

缓存的作用

通过代码我们已经知道在TableCache::Get里面大的逻辑就是两个
1 获取TableReader(逻辑在TableCache::FindTable里)
2 调用TableReader的get方法
而TableCache::FindTable里面的逻辑就是如果从缓存里能拿到TableReader就直接返回,拿不到就按照前文的GetTableReader

参考资料

1 关于sst的格式
https://www.jianshu.com/p/d6ce3593a69e
https://www.cnblogs.com/lygin/p/17103522.html

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值