leveldb sstable min max区间搜索源码分析(1)

本文分析了leveldb中基于sstable的min和max属性进行区间搜索的源码实现,探讨了如何利用min-max信息提高查询效率。文章详细解释了Go和Rust两种语言版本的tFile结构及其after、before、overlaps等方法,以及在已排序和未排序的tFiles集合中如何高效查找重叠区间。
摘要由CSDN通过智能技术生成

作者:王东阳

leveldb 中min_max搜索分析

前言
leveldb是一个写性能十分优秀的存储引擎,是典型的LSM树(Log Structured-Merge Tree)实现。LSM树的核心思想是将随机写转化为连续写,从而提升写操作的吞吐能力,整体架构如下:

在这里插入图片描述

虽然在内存中,所有的数据都是按序排列的,但是当多个memetable数据持久化到磁盘后,对应的不同的sstable之间是存在交集的,在读操作时,需要对所有的sstable文件进行遍历,严重影响了读取效率。因此leveldb后台会“定期“整合这些sstable文件,该过程也称为compaction。随着compaction的进行,sstable文件在逻辑上被分成若干层,由内存数据直接dump出来的文件称为level0层文件,后期整合而成的文件为level i层文件,这也是leveldb这个名字的由来。(参考链接)

在leveldb的压缩过程中, 需要向下层搜索和互相重叠的sstable进行合并,如下图所示:

在这里插入图片描述
上层数据如何快速的查询下一层中和当前sstable文件重叠的文件列表呢?由上图可以看出每个sstable中都有一个最小值min和最大值max,表示当前文件所包含key的最大值和最小值,可以当成一个数据区间,Level0层的key区间互相有重叠,剩余其它层中,每一层中的sstable文件,所包含的key区间,互相不重叠,所以对它们排序后,无论是最大值还是最小值都是严格递增的。

除了文件压缩,leveldb在执行查询的过程中,也会利用sstable的min,max的属性信息进行快速查找请求key所在的文件。

本文主要基于leveldb:table.goleveldb_rs:table.rs介绍sstable区间搜索相关接口代码的实现算法。

tFile

Go
文件的结构如下,主要包含文件的描述信息fd,文件中数据的大小size,以及文件中包含key的最小,最小值 (imin,imax). 在本文中,我们只需要关注imin,imax就可以了。

// tFile holds basic information about a table.
type tFile struct {
   
    fd         storage.FileDesc
    seekLeft   int32
    size       int64
    imin, imax internalKey
}

接下来是tFile中的方法,需要注意的是下面的方法中都有一个参数icmp *iComparer ,我们可以理解为一个比较器,用于判断key大小时候使用的。

首先是tFile的after方法,判断给定的key是否在这个文件的后面 ,这个方法我们可以这么理解,在一个水平数轴上,当前tFile的imin,imax对应数轴上的一个区间,判断给定的key是否在这个区间的后面,也就是判断给定ukey是否比当前文件中的最大值imax要大。

after 方法示意图:

          │          │
          │          │         ukey
  ────────▼──────────▼─────────▲───────►
         imin      imax        │
                               │

对应代码如下

// Returns true if given key is after largest key of this table.
func (t *tFile) after(icmp *iComparer, ukey []byte) bool {
   
    return ukey != nil && icmp.uCompare(ukey, t.imax.ukey()) > 0
}

同理,tFile的before方法用来判断给定的ukey是否在在当前文件的前面,也就是判断ukey是否比当前文件中的最小值imin要小。

// Returns true if given key is before smallest key of this table.
func (t *tFile) before(icmp *iComparer, ukey []byte) bool {
   
    return ukey != nil && icmp.uCompare(ukey, t.imin.ukey()) < 0
}

overlaps用来判断指定区间[umin,umax]是否和当前文件的区间[imin,imax]有重叠。我们可以反向来考虑什么情况下两个区间不重叠。

  • tFile区间的最小值imin大于另外一个区间的最大值umax
  • tFile区间的最大值imax小于另外一个区间的最大值umin
overlaps 方法示意图

      │       │
      │       │        umin   umax
  ────▼───────▼──────────▲──────▲───────►
     imin    imax        │ tFile│
                         │      │


                      │      │
       umin    umax   │      │
   ──────▲──────▲─────▼──────▼──────►
         │tFile │    imin   imax
         │      │
// Returns true if given key range overlaps with this table key range.
func (t *tFile) overlaps(icmp *iComparer, umin, umax []byte) bool {
   
    return !t.after(icmp, umin) && !t.before(icmp, umax)
}

Rust
rust代码中tFile的定义如下,跟go中定义非常相似,我们这里也只关注里面的imin,imax就可以。

#[derive(Clone)]
pub struct tFile {
   
    fd: storage::FileDesc,
    seek_left: Arc<atomic::AtomicI32>,
    size: i64,
    imin: internalKey,
    imax: internalKey,
}

接下来是tFile的方法实现,同样所有的方法都有一个参数icmp: &IComparer<T>,用于比较key。 首先是after方法,判断指定ukey是否在当

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值