分析均基于v6.27.3
。以下流程为了方便理解均经过了简化。
首先,我们通过调用DB::Open
来创建数据库,它返回了一个DB*
。DB::Open
内部调用了DBImpl::Open
,在里面构造了一个DBImpl*
并转换成DB*
返回。所以我们拿到的DB*
其实是DBImpl*
。
然后我们调用DB::Get
来读取数据。DB::Get
是个virtual函数,它被DBImpl::Get
给override了。
DBImpl::Get
里调用了DBImpl::GetImpl
。
DBImpl::GetImpl
中,先调用DBImpl::GetAndRefSuperVersion
拿到thread
local的super version,然后调用MemTable::Get
读取memory
table和immutable memory
table,如果找到了就返回,否则调用Version::Get
继续在sv->current
里查找。
Version::Get
中,首先将key装进GetContext
,然后遍历每个key
range包含这个key的SSTable,把GetContext
作为参数调用TableCache::Get
来查找这个SSTable。如果都没找到就返回not
found。
TableCache::Get
中,调用TableReader::Get
Table默认是BlockBasedTable
,所以这里的TableReader
应该是BlockBasedTable
的reader:
class BlockBasedTable : public TableReader {
BlockBasedTable::Get
中,调用BlockBasedTable::NewIndexIterator
获得block
index的iterator,然后遍历key range包含目标key的data
block。对每个遍历到的data
block,调用BlockBasedTable::NewDataBlockIterator
构造DataBlockIter biter
,然后seek
next在里面查找key。
BlockBasedTable::NewDataBlockIterator
中,调用BlockBasedTable::RetrieveBlock
,将块存入CachableEntry<Block> block
。
BlockBasedTable::RetrieveBlock
中,参数use_cache=true
,所以调用BlockBasedTable::MaybeReadBlockAndLoadToCache
。
BlockBasedTable::MaybeReadBlockAndLoadToCache
中,参数contents=nullptr
,所以调用BlockBasedTable::GetDataBlockFromCache
,如果miss的话就调用BlockFetcher::ReadBlockContents
。
BlockFetcher::ReadBlockContents
中,先尝试从persistent
cache和prefetch
buffer中读取。如果不成功的话,就调用RandomAccessFileReader::Read
从文件中读取。