基本原理
- DB中包含一个队列writers_,用来保存写请求。不同线程的写请求会被打包成一个batch,一起写入DB。(我的理解:为什么打包成batch?如果不打包成batch,每一次写请求,都要写预写日志;然而,向磁盘中写的最小单位是页,一个写请求很可能只占用一页中少数空间,打包成batch,可以把多个写请求存在一页中,减少写磁盘的次数)
- 当打包成batch后,需要考虑以下几种情况:
- mem_有足够的空间:直接将batch写入DB。
- mem_空间不足,且imm_不为空,或level0的文件数量达到最大值:此时线程陷入等待,等压缩线程(后台线程)将imm_写到磁盘后,或后台线程执行完压缩操作后,才能唤起该线程。
- mem_空间不足,且imm_为空,且level0的文件数量未达到最大值:此时将mem_赋值给imm_,后台线程开始压缩过程,同时,用户线程将batch写入DB。
用户线程、消息队列、后台线程
- 生产者-消费者模式:用户线程,主动调用Write(),当需要进行压缩时,将需要压缩的消息放入队列,后台线程取出后进行压缩操作。
- 锁协议:所有用户线程、后台线程公用一把锁,串行执行;当用户线程遇到IO操作,或需要阻塞时,让出锁,后台线程可以执行。
用户线程
用户线程逻辑较简单:如果mem_未满,首先将命令写入WALog,然后写入mem_。如果mem_满了,且imm_非空,或者level0满了,则等待。如果mem_满了,imm_为空,则将mem_赋给imm_,向消息队列发送消息,新生成一个mem_,写入数据。
后台线程
后台线程只有一个,阻塞在消息队列上。当消息队列中,出现待执行的任务(一个函数指针和对应参数),后台线程执行这个任务,执行完,再次阻塞在队列上。
待执行的任务,可以是压缩任务。暂时只看了压缩imm_,level1~level6的压缩还没看。