首页 > 其他分享 >mini-lsm通关笔记Week1Day7

mini-lsm通关笔记Week1Day7

时间:2024-09-03 22:15:07浏览次数:4  
标签:mini lsm Week1Day7 len 布隆 let key 过滤器 bloom

Summary

在上一章中,您已经构建了一个具有get/scan/put支持的存储引擎。在本周末,我们将实现SST存储格式的一些简单但重要的优化。欢迎来到Mini-LSM的第1周零食时间!

在本章中,您将:

  • 在SST上实现布隆过滤器,并集成到LSM读路径get中。
  • 以SST块格式实现对key存储的压缩。

要将测试用例复制到启动器代码中并运行它们,

cargo x copy-test --week 1 --day 7
cargo x scheck

Task 1-Bloom Filters

布隆过滤器是维护一组键的概率数据结构。您可以将键添加到布隆过滤器中,并且您可以知道在添加到布隆过滤器中的键集合中,哪些键可能存在/一定不存在。

为了构造布隆过滤器,通常需要有一个散列函数,一个键可以有多个散列。让我们看看下面的例子。假设我们已经有了一些键的哈希,并且布隆过滤器有7位。

【注:如果你想更好的理解布隆过滤器,可以看这里

hash1 = ((character - a) * 13) % 7
hash2 = ((character - a) * 11) % 7
b -> 6 4
c -> 5 1
d -> 4 5
e -> 3 2
g -> 1 3
h -> 0 0

如果我们将b, c, d插入到7位布隆过滤器中,我们将得到:

    bit  0123456
insert b     1 1
insert c  1   1
insert d     11
result   0101111

在探测布隆过滤器时,我们为key生成哈希,并查看是否设置了相应的位。如果它们都设置为true,那么key可能存在于bloom过滤器中。否则,该键一定不存在于布隆过滤器中。

对于e -> 3 2,由于位2位置上的bit位没有设置为true,所以它一定不存在于原始集合中。对于g -> 1 3,由于两个位都被设置为true,它可能存在于集合中,也可能不存在于集合中。对于h -> 0 0,两个位(实际上它是一个位)都没有设置,因此它不应该在原始集合中。

b -> maybe (actual: yes)
c -> maybe (actual: yes)
d -> maybe (actual: yes)
e -> MUST not (actual: no)
g -> maybe (actual: no)
h -> MUST not (actual: no)

还记得在上一章的最后,我们实现了基于key范围的SST过滤。现在,在get读取路径上,我们还可以使用布隆过滤器来忽略不包含用户想要查找的key的SST,从而减少从磁盘读取文件的数量。

在此任务中,您需要修改:

src/table/bloom.rs

在实现中,您将从键散列(是u32数字)构建一个布隆过滤器。对于每个哈希,您需要设置k位。这些位的计算方式如下:

let delta = (h >> 17) | (h << 15); // h is the key hash
for _ in 0..k {
    // TODO: use the hash to set the corresponding bit
    h = h.wrapping_add(delta);
}

我们提供了执行神奇数学的所有框架代码。您只需要实现构建布隆过滤器和探测布隆过滤器的步骤。

参考资料:

https://leveldb-handbook.readthedocs.io/zh/latest/bloomfilter.html#

https://blog.csdn.net/jiaomeng/article/details/1495500

Task 2-Integrate Bloom Filter on the Read Path

在此任务中,您需要修改:

src/table/builder.rs
src/table.rs
src/lsm_storage.rs

对于布隆过滤器编码,您可以将布隆过滤器附加到SST文件的末尾。您需要在文件末尾存储布隆过滤器偏移量,并相应地计算元偏移量。

-----------------------------------------------------------------------------------------------------
|         Block Section         |                            Meta Section                           |
-----------------------------------------------------------------------------------------------------
| data block | ... | data block | metadata | meta block offset | bloom filter | bloom filter offset |
|                               |  varlen  |         u32       |    varlen    |        u32          |
-----------------------------------------------------------------------------------------------------

我们使用farmhash来计算键的哈希值。在构建SST时,您还需要通过使用farmhash::Factory32计算密钥哈希来构建布隆过滤器。您需要在block的元信息中对布隆过滤器进行编码/解码。你可以为你的布隆过滤器选择误报率0.01。根据需要,您可能需要向结构中添加新的字段,而不是在启动器代码中提供的字段。

之后,可以修改get读取路径,根据bloom filter过滤SST。

我们没有对此部分进行集成测试,您需要确保您的实现仍然通过之前的所有章节测试。

本任务就是借助任务1实现的布隆过滤器,优化性能。在SsTableBuilder中添加成员变量key_hashes

SsTableBuilderadd操作中,添加键的hash值:

self.key_hashes.push(farmhash::fingerprint32(key.raw_ref()));

SsTableBuilderbuild操作中,添加完元信息后,再添加编码后的布隆过滤器:

let bloom = Bloom::build_from_key_hashes(
    &self.key_hashes,
    Bloom::bloom_bits_per_key(self.key_hashes.len(), 0.01),
);
let bloom_offset = buf.len();
bloom.encode(&mut buf);
buf.put_u32(bloom_offset as u32);

SsTableopen操作中,先读取解码出布隆过滤器:

let bloom_offset = (&file.read(len - 4, 4)?[..]).get_u32() as u64;
let raw_bloom = file.read(bloom_offset, len - 4 - bloom_offset)?;
let bloom_filter = Bloom::decode(&raw_bloom)?;

LsmStorageInnerscan扫描函数中,使用布隆过滤器优化代码执行效率:

if table.bloom.is_some()
    && !table
        .bloom
        .as_ref()
        .unwrap()
        .may_contain(farmhash::fingerprint32(_key))
{
    continue;
}

Task 3-Key Prefix Encoding + Decoding

在此任务中,您需要修改:

src/block/builder.rs
src/block/iterator.rs

由于SST文件是按顺序存储键的,所以有可能用户存储的是相同前缀的键,我们可以在SST编码中对前缀进行压缩,以节省空间。

我们将当前键与块中的第一个键进行比较。我们按如下方式存储密钥:

key_overlap_len (u16) | rest_key_len (u16) | key (rest_key_len)

key_overlap_len表示块中的第一个key有多少字节相同。例如,如果我们看到一条记录:5|3|LSM,其中块中的第一个key是mini-something,那么我们可以将当前key恢复为mini-LSM

完成编码后,还需要在块迭代器中实现解码。根据需要,您可能需要向结构中添加新字段,而不是在启动器代码中提供的字段。

从数据添加进Block开始,先对BlockBuilderadd函数进行改造。

通过下面函数计算出相同的长度:

fn compute_overlap(first_key: KeySlice, key: KeySlice) -> usize {
    let mut i = 0;
    loop {
        if i >= first_key.len() || i >= key.len() {
            break;
        }
        if first_key.raw_ref()[i] != key.raw_ref()[i] {
            break;
        }
        i += 1;
    }
    i
}

编码结果如下,先写入相同部分的长度,再写入剩下部分的长度,最后写入差异部分的数据:

let overlap = compute_overlap(self.first_key.as_key_slice(), key);
// Encode key overlap.
self.data.put_u16(overlap as u16);
// Encode key length.
self.data.put_u16((key.len() - overlap) as u16);
// Encode key content.
self.data.put(&key.raw_ref()[overlap..]);

再对BlockIterator的解码函数seek_to_index进行改造。

通过下面函数解码出first_key,因为第一个key没有比较的对象,所以相似的长度是02个字节读取后不使用。

impl Block {
    fn get_first_key(&self) -> KeyVec {
        let mut buf = &self.data[..];
        buf.get_u16();
        let key_len = buf.get_u16();
        let key = &buf[..key_len as usize];
        KeyVec::from_vec(key.to_vec())
    }
}

对原来的key的读取进行改造:

let overlap_len = entry.get_u16() as usize;
let key_len = entry.get_u16() as usize;
let key = &entry[..key_len];
self.key.clear();
self.key.append(&self.first_key.raw_ref()[..overlap_len]);
self.key.append(key);

先拼接与first_key相似的部分,再拼接不同的部分。

个人理解:这种编码手段是一种简单且有效的编码手段。但是编码不一定有收益,若没有收益的情况强行使用这种编码方式,反而会带来空间的膨胀。

标签:mini,lsm,Week1Day7,len,布隆,let,key,过滤器,bloom
From: https://www.cnblogs.com/cnyuyang/p/18395556

相关文章

  • minio-docker
    docker-composeversion:"3"services:minio:image:minio/minio:latestcontainer_name:miniorestart:alwaysports:-"9000:9000"-"9090:9090"......
  • MINIO部署
    创建挂载目录mkdir-p/root/dockerData/ivan_minio/启动方式docker-compose方式启动创建docker-compose.yml文件vimdocker-compose.ymlversion:'3'services:minio:image:"quay.io/minio/minio:RELEASE.2022-08-02T23-59-16Z"container_name:mini......
  • MinimumLongestTripG
    https://www.luogu.com.cn/problem/P9981首先显而易见的是第一问的答案用拓扑排序,然后用它的倒序进行DP。我们考虑第二问。首先要保证第一问的情况下才能考虑第二问,于是我们对于所有点按照第一问的答案分层,先按照新加入的边考虑,再按照上一层点的排名考虑,做完这一层后直接对这一......
  • 极速掌握MinIO对象存储:从零部署到实战操作全攻略
    文章目录介绍安装部署安装服务器开放服务使用端口挂载磁盘安装MinIO创建目录下载安装文件设置执行权限目录结构如下所有节点都需要执行上述步骤编写启动脚本使用Console使用JavaApi调用获取永久链接可能报的错误错误1:ispartofrootdrive,willnotbeused错误2:Therequestsig......
  • mini-lsm通关笔记Week1Day6
    项目地址:https://github.com/skyzh/mini-lsm个人实现地址:https://gitee.com/cnyuyang/mini-lsmSummary在本章中,您将:使用L0flush实现LSM写路径。实现逻辑以正确更新LSM状态。要将测试用例复制到启动器代码中并运行它们,cargoxcopy-test--week1--day6cargoxsch......
  • 无魔法利用GPT4o-mini改善网页翻译
    步骤浏览器安装沉浸式翻译插件:https://immersivetranslate.com/进入伊莉思AGI网址:https://agi.ylsap.com/,创建账号并进入个人中心创建并复制APIKEY进入沉浸式翻译插件设置按如下设置展开更多选项https://api.ylsagi.io/tolinks/v2/translators/chat/completions测试......
  • 高密度、高速卡边缘连接器,ME1005610201091、ME1005610203071、ME1005613401311、ME100
    系列概述MiniCoolEdge是一款0.60mm高密度、高速卡边缘连接器,适用于新一代小型系统。这种精细间距解决方案支持多种板对板应用,如直角、夹层/共面,并提供电缆互连选件。这些连接器符合SFF-TA-1002、GenZ、EDSFF和OCPNIC3.0规范。常见应用包括固态驱动器、网络接口卡和......
  • 来了,HelpLook接入GPT4o-mini,OpenAI大动作!如何巧妙运用AI新功能?
    上月,OpenAI推出了其最新人工智能模型——GPT-4oMini。作为当前较为实用的小型模型,GPT-4oMini旨在大幅拓展AI应用领域,同时显著降低开发成本。每百万输入tokens仅需15美分,输出tokens为60美分,远低于先前的GPT-3.5Turbo。HelpLook率先接入GPT-4oMini大模型,为大家带来福利。......
  • [图文直播]基于ZFile和MinIO搭建私有网盘
    前言ZFile以下是ZFile的官网,上面也涉及到了搭建方法https://docs.zfile.vip/install/os-windows此次仅记录本人按照官方的部署方法进行实操验证。下载ibm-semeru-open-jdk_x64_windows_8u372b07_openj9-0.38.0.msizfile-release.jar具体下载地址见上面的官网安装......
  • XtQuant是什么?哪家券商支持miniQMT,XtQuant?
    XtQuant是基于迅投MiniQMT衍生出来的一套完善的Python策略运行框架,对外以Python库的形式提供策略交易所需要的行情和交易相关的API接口。XtQuant运行依赖环境XtQuant目前提供的库包括64位Python 3.6、3.7、3.8、3.9、3.10、3.11、3.12版本,不同版本的Python导入时会......