Thread Local Engine

RaftStorage中有read pool和两个write pool, 分别负责storage的读写操作,每个pool中的 每个线程都有自己的RaftKV engine clone为tls engine。

每个线程启动完,在after_start方法中,会调用set_tls_engine设置好自己的TLS_ENGINE_ANY指针。 线程关闭时,会调用destroy_tls_engine清理掉 tls engine. 使用时,用with_tls_engine来使用该指针。

TiKVServer::init_servers初始化时,会创建一些yatp thread pool. TxnScheduler会创建两个 worker pool用来处理Txn command,而Storage和Coprocessor 则有个read_pool,

如果enable了config.pool中的unified_read_pool选项,Storage和coprocessor会共享一个read pool. Unified thread pool 参见pingcap博客 Unified Thread Pool

with_tls_engine

使用with_tls_engine主要有三处,

  1. TxnScheduler在执行事务cmd时,会在worker thread pool,执行read/write cmd.
  2. Storage的正常的batch_get_command, scan等读操作。
  3. Coprocessor的读数据操作。

tls LRUcache

tls engine的作用是,这样每个线程在使用RaftKV时,会优先使用自己线程 tls RaftKv的LruCache,如果cache miss或者cache的数据 stale了才会使用Lock去mutex共享的变量中获取数据,并插入LruCache中。 这样大大的降低了lock使用的概率.

RaftKv中LRUcache主要有两处:

Router::caches

Router给region 的raft peer 发送消息时候(具体方法为Router::check_do),先从Router::caches获取BasicMailbox, 如果cache miss 再加锁去normals中读取BasicMailbox.


#![allow(unused)]
fn main() {
pub struct Router<N: Fsm, C: Fsm, Ns, Cs> {
    normals: Arc<Mutex<HashMap<u64, BasicMailbox<N>>>>,
    caches: Cell<LruCache<u64, BasicMailbox<N>>>,
    //...
}
}

LocalReader::delegate

在读数据时,线程会先在自己的LocalReader::delegates LRUcache中获取delegate(具体方法为LocalReader::get_delegate), 如果cache中没有或者delegate 版本发生了变化,才会去加lock 去store_meta中获取ReadDelegate.


#![allow(unused)]
fn main() {
pub struct LocalReader<C, E>
where
    C: ProposalRouter<E::Snapshot>,
    E: KvEngine,
{
    store_meta: Arc<Mutex<StoreMeta>>,
    delegates: LruCache<u64, Arc<ReadDelegate>>,
}
}

参考文献

  1. Unified Thread Pool | Hackathon 2019 优秀项目介绍