有任何问题请联系我:zhangtiey@gmail.com
LevelDB是LSM最有名的实现系统。网上介绍的文章不少, 本文主要用于我自己的理解和备忘录,我将用具体的实例来介绍LevelDB的读写过程,希望能让读者更加清楚其细节是如何实现的。
总体来说,LevelDB是LSM+SkipList来实现的。具体来说,memtable是SkipList, sstable是LSM。SkipList的结构如下图所示:
SkipList是一个有序的list。如上图例子中,key依照字母排序。既然是一个list,那么只要找到对应位置后,插入新的元素只需要一个操作即可,即断开原来的链表,插入新的元素即可。SkipList每个节点,除了其基本的元素外,还包括了额外的几个元素(具体几个可以当参数来设置)。那么查询的效率为O(logN),具体证明可以见原始paper。
上面说了,对于插入而言,找到新的位置后,插入的效率为O(1),那么总的插入效率自然和查询效率一直,即也是O(logN). 对SkipList的简要介绍到此结束。
LevelDB的在内存中的数据结构就是SkipList。如上图所示,只不过除了key之外,每个还包括了对应的value。例如NodeA,其key是A1001,value是一个字符串xiaoming。LevelDB在内存中的数据结构称之为memtable和immutable,其实都是SkipList,只不过memtable到了一定程度就是只读的了,就变成了immutable。那么新来的写入和更新操作都要新启一个memtable来进行。这样的话memtable和immutable就可能含有相同的key。查找的时候是先从memtable开始找,如果找到了就返回,找不到再找immutable,因此就算memtable和immutable有两个一样的key,那么因为memtable是先被找到,并且memtable含有的数据是最新的,因此返回也是最新的。
当immutable到达一定数量的时候,就要被置换到磁盘上,如上图所示的Level0,其每一个文件都是immutable置换过来的。注意,这个过程没有Merge,就是把内存中的数据挪到磁盘上(我们不是数据的创造者,我们只是数据的搬运工)。上文我们提到,memtable和immutable是有可能有相同key的,也就是说immutable之间也可能有相同的key。所以Level0中的文件是有可能有相同的key的。因此当查询的时候,如果需要查询Level0,就需要查询多个文件,然后比较最后的结果,选择最新的。当然也可以做些优化,我们暂时不提。
当Level0中的文件数量达到一定的时候,就要进行真正的Merge。如果有相同的key,merge的时候要把老的数据去掉,因此从Level1开始,sstable文件之间不会出现相同的key。所以如果能定位到一个文件含有要查询的key,那么这一层就不用再去查询别的文件了。