当前位置: 首页 > news >正文

mini-lsm通关笔记Week2Day7

项目地址:https://github.com/skyzh/mini-lsm

个人实现地址:https://gitee.com/cnyuyang/mini-lsm

在上一章中,您已经构建了一个完整的基于LSM的存储引擎。在本周末,我们将实现存储引擎的一些简单但重要的优化。欢迎来到Mini-LSM的第2周零食时间!

在本章中,您将:

  • 实现批量写入接口。
  • 添加checksum到块、SST元数据、manifest和WAL。

注意:本章没有单元测试。只要你通过了之前的所有测试,并确保校验和在你的文件格式中正确编码,就可以了。

Task 1-Write Batch Interface

在本任务中,我们将通过添加写入批处理API来为本教程的第3周做好准备。您需要修改:

src/lsm_storage.rs

用户向write_batch提供一批要写入数据库的记录。这些记录是WriteBatchRecord<T:AsRef<[u8]>>,因此它可以是Bytes&[u8]Vec<u8>。有两种类型的记录:deleteput。您可以以与您的putdelete函数相同的方式处理它们。

之后,你可以重构你原来的putdelete函数来调用write_batch。

在实现此功能之后,您应该通过前面章节中的所有测试用例。

该任务就是实现write_batch函数,其实就是把之前写在putdelete中的函数,放在一起循环遍历:

pub fn write_batch<T: AsRef<[u8]>>(&self, _batch: &[WriteBatchRecord<T>]) -> Result<()> {for record in _batch {match record {WriteBatchRecord::Del(key) => {// 原来delete中的逻辑...}WriteBatchRecord::Put(key, value) => {// 原来put中的逻辑...}}}Ok(())
}

再修改putdelete的实现,调用该函数:

pub fn put(&self, _key: &[u8], _value: &[u8]) -> Result<()> {self.write_batch(&[WriteBatchRecord::Put(_key, _value)])
}pub fn delete(&self, _key: &[u8]) -> Result<()> {self.write_batch(&[WriteBatchRecord::Del(_key)])
}

Task 2-Block Checksum

在此任务中,当编码SST时,您需要在每个块的末尾添加块校验和。您需要修改:

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

SST的格式将更改为:

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

我们使用crc32作为我们的校验和算法。您可以在构建block块后使用crc32fast::hash生成block块的校验和。

通常,当用户在存储选项中指定目标block块大小时,大小应包括块内容和校验和。例如,如果目标block块大小为4096,校验和占用4字节,则实际block块内容目标大小应为4092。但是,为了避免破坏之前的测试用例,并且为了简单起见,在我们的教程中,我们仍然将使用目标block块大小作为目标内容大小,并简单地在块的末尾附加校验和。

当你读取块时,你应该在read_block函数中校验校验和,以保证读取到正确的存储内容。在实现此功能之后,您应该通过前面章节中的所有测试用例。

如题目要求需要修改SST的格式,在block块数据后存储校验和。读取的时候通过校验和校验数据是否正确。

计算校验和,并存储(src/table/builder.rs):

fn finish_block(&mut self) {...// 计算校验和let checksum = crc32fast::hash(&encoded_block);// 存储数据self.data.append(&mut encoded_block.to_vec());// 尾部附加校验和self.data.put_u32(checksum);
}

读取校验和,并校验(table.rs):

pub fn read_block(&self, block_idx: usize) -> Result<Arc<Block>> {let offset = self.block_meta[block_idx].offset;let offset_end = self.block_meta.get(block_idx + 1).map_or(self.block_meta_offset, |x| x.offset);// block块的长度let block_len = offset_end - offset - 4;// 读取block块以及校验和let block_data_with_chksum: Vec<u8> = self.file.read(offset as u64, (offset_end - offset) as u64)?;// 数据块数据let block_data = &block_data_with_chksum[..block_len];// 校验和let checksum = (&block_data_with_chksum[block_len..]).get_u32();// 校验数据是否正确if checksum != crc32fast::hash(block_data) {bail!("block checksum mismatched");}Ok(Arc::new(Block::decode(block_data)))
}

Task 3-SST Meta Checksum

在此任务中,您需要为布隆过滤器和块元数据添加块校验和:

src/table/builder.rs
src/table.rs
src/bloom.rs
----------------------------------------------------------------------------------------------------------
|                                                Meta Section                                            |
----------------------------------------------------------------------------------------------------------
| no. of block | metadata | checksum | meta block offset | bloom filter | checksum | bloom filter offset |
|     u32      |  varlen  |    u32   |        u32        |    varlen    |    u32   |        u32          |
----------------------------------------------------------------------------------------------------------

您需要在Bloom::codingBloom::decode中的Bloom过滤器的末尾添加校验和。请注意,我们的大多数API采用一个现有的缓冲区,实现将写入该缓冲区,例如,Bloom::code。因此,在写入编码内容之前,应该记录bloom filter开始的偏移量,并且只对bloom filter本身进行校验和,而不是对整个缓冲区进行校验和。

之后,您可以在块元数据的末尾添加校验和。您可能会发现在小节的开头添加一段元数据会很有帮助,这样在解码块元数据时更容易知道在哪里停止。

元数据校验和

编码(table.rs):

pub fn encode_block_meta(block_meta: &[BlockMeta],#[allow(clippy::ptr_arg)] // remove this allow after you finishbuf: &mut Vec<u8>,
) {let original_len = buf.len();buf.put_u32(block_meta.len() as u32);for meta in block_meta {...// 填充Meta数据}// 计算并写入校验和,只计算Meta数据部分buf.put_u32(crc32fast::hash(&buf[original_len + 4..]));
}

解码(table.rs):

pub fn decode_block_meta(mut buf: &[u8]) -> Result<Vec<BlockMeta>> {let num = buf.get_u32();// 计算校验和let checksum = crc32fast::hash(&buf[..buf.remaining() - 4]);let mut block_meta: Vec<BlockMeta> = Vec::with_capacity(num as usize);for i in 0..num {...// 读取Meta数据}// 读取校验和 并 校验读取的和计算的是否相同if buf.get_u32() != checksum {bail!("meta checksum mismatched");}Ok(block_meta)
}

布隆过滤器校验和

编码(bloom.rs):

pub fn encode(&self, buf: &mut Vec<u8>) {let offset = buf.len();... // 编码布隆过滤器// 计算并写入布隆过滤器let checksum = crc32fast::hash(&buf[offset..]);buf.put_u32(checksum);
}

解码(bloom.rs):

pub fn decode(buf: &[u8]) -> Result<Self> {// 读取校验和并校验let checksum = (&buf[buf.len() - 4..buf.len()]).get_u32();if checksum != crc32fast::hash(&buf[..buf.len() - 4]) {bail!("checksum mismatched for bloom filters");}...
}

Task 4-WAL Checksum

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

src/wal.rs

我们将在预写日志中执行每个记录的校验和。为此,您有两个选择:

  • 生成key-value记录的缓冲区,并使用crc32fast::hash一次性计算校验和。
  • 一次写入一个字段(例如,密钥长度,密钥切片),并使用crc32fast:哈希器对每个字段增量计算校验和。

这取决于您的选择,您将需要选择您自己的冒险。只要正确处理大/小端差异,这两种方法都应该产生完全相同的结果。新的WAL编码应该如下所示:

| key_len | key | value_len | value | checksum |

编码(wal.rs),一次写入一个字段(例如,密钥长度,密钥切片),并使用crc32fast:哈希器对每个字段增量计算校验和:

pub fn put(&self, _key: &[u8], _value: &[u8]) -> Result<()> {...let mut hasher = crc32fast::Hasher::new();hasher.write_u16(key_len as u16);...hasher.write(_key);...hasher.write_u16(value_len as u16);...hasher.write(_value);buf.put_u32(hasher.finalize());...
}

解码(wal.rs),就是逆过程:

let mut hasher = crc32fast::Hasher::new();
...
hasher.write_u16(key_len as u16);
...
hasher.write(&key);
...
hasher.write_u16(value_len as u16);
...
hasher.write(&value);
...// 读取并校验
let checksum = rbuf.get_u32();
if hasher.finalize() != checksum {bail!("checksum mismatch");
}

Task 5-Manifest Checksum

最后,让我们在Manifest文件中添加校验和。Manifest类似于WAL,不同的是,我们不存储每条记录的长度。为了使实现更简单,我们现在在记录的开头添加记录长度的标头,并在记录的末尾添加校验和。

新的Manifest格式如下:

| len | JSON record | checksum | len | JSON record | checksum | len | JSON record | checksum |

在实现所有内容之后,您应该通过之前的所有测试用例。本章不提供新的测试用例。

编码(manifest.rs):

pub fn add_record_when_init(&self, record: ManifestRecord) -> Result<()> {...// 序列化数据let mut buf = serde_json::to_vec(&record)?;// 计算校验和let hash = crc32fast::hash(&buf);// 写入数据段长度file.write_all(&(buf.len() as u64).to_be_bytes())?;// 在数据末尾添加校验和buf.put_u32(hash);// 将数据、校验和写入文件file.write_all(&buf)?;file.sync_all()?;Ok(())
}

解码(manifest.rs),就是逆过程:

while buf_ptr.has_remaining() {// 读取长度let len = buf_ptr.get_u64();let slice = &buf_ptr[..len as usize];// 反序列化let json = serde_json::from_slice::<ManifestRecord>(slice)?;buf_ptr.advance(len as usize);// 读取并校验校验和let checksum = buf_ptr.get_u32();if checksum != crc32fast::hash(slice) {bail!("checksum mismatched!");}records.push(json);
}

相关文章:

mini-lsm通关笔记Week2Day7

项目地址&#xff1a;https://github.com/skyzh/mini-lsm 个人实现地址&#xff1a;https://gitee.com/cnyuyang/mini-lsm 在上一章中&#xff0c;您已经构建了一个完整的基于LSM的存储引擎。在本周末&#xff0c;我们将实现存储引擎的一些简单但重要的优化。欢迎来到Mini-LSM的…...

Typora免费使用

一.下载地址 https://typoraio.cn/ 二.修改配置文件 1.找到安装路径下的LicenseIndex.180dd4c7.4da8909c.chunk.js文件 文件路径为:安装路径\resources\page-dist\static\js\LicenseIndex.180dd4c7.4da8909c.chunk.js 将js中的 e.hasActivated"true"e.hasActiva…...

AI驱动的无线定位:基础、标准、最新进展与挑战

1. 论文概述 研究目标:本论文旨在综述AI在无线定位领域的应用,包括其基础理论、标准化进展、最新技术发展,以及面临的挑战和未来研究方向。主要发现: AI/ML 技术已成为提升无线定位精度和鲁棒性的关键手段,特别是在 3GPP 标准的推动下。论文系统性地分析了 AI 在 LOS/NLOS…...

苹果再度砍掉AR眼镜项目?AR真的是伪风口吗?

曾经&#xff0c;AR游戏一度异常火热&#xff0c;宝可梦go让多少人不惜翻墙都要去玩&#xff0c;但是也没过去几年&#xff0c;苹果被曝出再度砍掉了AR眼镜项目&#xff0c;面对着市场的变化&#xff0c;让人不禁想问AR真的是伪风口吗&#xff1f; 一、苹果再度砍掉AR眼镜项目&…...

18 大量数据的异步查询方案

在分布式的应用中分库分表大家都已经熟知了。如果我们的程序中需要做一个模糊查询&#xff0c;那就涉及到跨库搜索的情况&#xff0c;这个时候需要看中间件能不能支持跨库求交集的功能。比如mycat就不支持跨库查询&#xff0c;当然现在mycat也渐渐被摒弃了(没有处理笛卡尔交集的…...

DRM系列八:Drm之DRM_IOCTL_MODE_ADDFB2

本系列文章基于linux 5.15 在上一篇文章DRM系列七&#xff1a;Drm之DRM_IOCTL_MODE_CREATE_DUMB获取buf的handle和pitch之后&#xff0c;接着使用ioctl(fd, DRM_IOCTL_MODE_ADDFB2, &fb_cmd)创建一个新的帧缓冲区对象&#xff08;framebuffer object),并将帧缓冲区对象与显…...

软件测试用例篇

设计测试用例是测试面试的必考题,务必好好学 1. 测试用例 测试用例的概念 测试⽤例&#xff08;Test Case&#xff09;是为了实施测试而向被测试的系统提供的⼀组集合&#xff0c;这组集合包含&#xff1a;测试环境、操作步骤、测试数据、预期结果等要素。 设计测试⽤…...

PopupMenuButton组件的功能和用法

文章目录 1 概念介绍2 使用方法3 示例代码 我们在上一章回中介绍了Sliver综合示例相关的内容&#xff0c;本章回中将介绍PopupMenuButton组件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1 概念介绍 我们在本章回中介绍的PopupMenuButton组件位于AppBar右侧&#xff0c;…...

Python进行模型优化与调参

在数据科学与机器学习领域,模型的优化与调参是提高模型性能的重要步骤之一。模型优化可以帮助提高模型的准确性和泛化能力,而合理的调参则能够充分发挥模型的潜力。这篇教程将重点介绍几种常用的模型优化与调参方法,特别是超参数调整和正则化技术的应用。这些技术能够有效地…...

vue2-组件通信

文章目录 vue2-组件通信1. 为什么需要组件通信2. props传递数据3. $emit触发自定义事件4.ref5. EventBus6. p a r e n t 和 parent和 parent和root7. a t t r s 和 attrs和 attrs和listeners8. provide和inject9. vuex10. 总结 vue2-组件通信 1. 为什么需要组件通信 在VUE中…...

20250205确认荣品RK3566开发板在Android13下可以使用命令行reboot -p关机

20250205确认荣品RK3566开发板在Android13下可以使用命令行reboot -p关机 2025/2/5 16:10 缘起&#xff1a;荣品RK3566开发板在Android13下&#xff0c;希望通过Native C语言程序来控制RK3566的关机。 通过ADB&#xff0c;很容易通过reboot -p命令关机。 最开始以为需要su/root…...

设计模式---观察者模式

设计模式—观察者模式 定义对象间的一种一对多的依赖关系&#xff0c;当一个对象的状态发生改变时&#xff0c;所有依赖于它的对象都得到通知并被自动更新。 主要解决的问题&#xff1a;一个对象状态改变给其他对象通知的问题&#xff0c;而且要考虑到易用和低耦合&#xff0c;…...

初八开工!开启数字化转型新征程!

新年新气象&#xff0c;大年初八&#xff0c;我们斗志昂扬&#xff0c;共同奔赴充满希望的新一年&#xff01; 2025 年意义非凡&#xff0c;这是广州市开利网络科技有限公司成立的第 18 个年头 。回首过往&#xff0c;我们一路拼搏&#xff0c;一路成长&#xff0c;积累了深厚的…...

文本分析NLP的常用工具和特点

1&#xff09;非上下文感知型文本分析工具和特点 特性VADERTextBlob适合文本类型短文本、非正式语言&#xff08;如评论、推文&#xff09;中等长度、正式文本情感强度分析支持&#xff08;正面、负面、中性&#xff09;支持&#xff08;极行、主观性&#xff09;处理表情符号…...

DeepSeek 与 ChatGPT 对比分析

一、技术背景与研发团队 ChatGPT 由 OpenAI 开发&#xff0c;自 2015 年 OpenAI 成立以来&#xff0c;经过多年的技术积累和迭代&#xff0c;从 GPT-1 到 GPT-4o&#xff0c;每一次升级都带来了技术上的突破。OpenAI 拥有雄厚的技术实力和海量的数据、强大的算力支持&#xff…...

vite---依赖优化选项esbuildOptions详解

optimizeDeps.esbuildOptions vite.optimizeDeps.esbuildOptions 是 Vite 配置中的一个选项&#xff0c;它允许你在 Vite 启动时&#xff0c;给 esbuild&#xff08;Vite 用来处理代码转换和优化的工具&#xff09;传递额外的配置。通过这个配置项&#xff0c;你可以自定义 esb…...

ElasticSearch 学习课程入门(二)

引子 前文已经介绍了ES的增删改查基本操作&#xff0c;接下来&#xff0c;我们学习下高级点的用法。OK&#xff0c;那就让我们开始吧。 一、ES高级操作 1、条件查询 &#xff08;1&#xff09;GET https://127.0.0.1:9200/shopping/_search?qcategory:小米 &#xff08;2&…...

使用 Redis Streams 实现高性能消息队列

1. 引言 在后端开发中&#xff0c;消息队列是一个常见的组件&#xff0c;主要用于解耦系统、提高吞吐量以及实现异步处理。常见的消息队列包括 Kafka、RabbitMQ 以及 ActiveMQ&#xff0c;但 Redis Streams 作为 Redis 5.0 引入的新特性&#xff0c;也提供了一种高效、轻量的消…...

深度学习|表示学习|卷积神经网络|DeconvNet是什么?|18

如是我闻&#xff1a; DeconvNet&#xff08;反卷积网络&#xff09;是一种可视化 CNN&#xff08;卷积神经网络&#xff09;内部特征的方法&#xff0c;用于理解 CNN 是如何提取图像特征的。这个方法由 Zeiler & Fergus&#xff08;2013&#xff09; 提出&#xff0c;目的…...

(优先级队列(堆)) 【本节目标】 1. 掌握堆的概念及实现 2. 掌握 PriorityQueue 的使用

优先级队列&#xff08;堆&#xff09; 1. 优先级队列1.1 概念 2. 优先级队列的模拟实现2.1 堆的概念2.2 堆的存储方式2.3 堆的创建2.3.1 堆向下调整2.3.2 堆的创建2.3.3 建堆的时间复杂度 【本节目标】 掌握堆的概念及实现掌握 PriorityQueue 的使用 1. 优先级队列 1.1 概念…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件&#xff1a;-&#xff08;纯文本文件&#xff0c;二进制文件&#xff0c;数据格式文件&#xff09; 如文本文件、图片、程序文件等。 目录文件&#xff1a;d&#xff08;directory&#xff09; 用来存放其他文件或子目录。 设备…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

《通信之道——从微积分到 5G》读书总结

第1章 绪 论 1.1 这是一本什么样的书 通信技术&#xff0c;说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号&#xff08;调制&#xff09; 把信息从信号中抽取出来&am…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

Device Mapper 机制

Device Mapper 机制详解 Device Mapper&#xff08;简称 DM&#xff09;是 Linux 内核中的一套通用块设备映射框架&#xff0c;为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程&#xff0c;并配以详细的…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

Fabric V2.5 通用溯源系统——增加图片上传与下载功能

fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...