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>。有两种类型的记录:delete和put。您可以以与您的put和delete函数相同的方式处理它们。之后,你可以重构你原来的
put和delete函数来调用write_batch。在实现此功能之后,您应该通过前面章节中的所有测试用例。
该任务就是实现write_batch函数,其实就是把之前写在put、delete中的函数,放在一起循环遍历:
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(())
}
再修改put、delete的实现,调用该函数:
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.rsSST的格式将更改为:
--------------------------------------------------------------------------------------------------------------------------- | 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::coding和Bloom::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
项目地址:https://github.com/skyzh/mini-lsm 个人实现地址:https://gitee.com/cnyuyang/mini-lsm 在上一章中,您已经构建了一个完整的基于LSM的存储引擎。在本周末,我们将实现存储引擎的一些简单但重要的优化。欢迎来到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真的是伪风口吗?
曾经,AR游戏一度异常火热,宝可梦go让多少人不惜翻墙都要去玩,但是也没过去几年,苹果被曝出再度砍掉了AR眼镜项目,面对着市场的变化,让人不禁想问AR真的是伪风口吗? 一、苹果再度砍掉AR眼镜项目&…...
18 大量数据的异步查询方案
在分布式的应用中分库分表大家都已经熟知了。如果我们的程序中需要做一个模糊查询,那就涉及到跨库搜索的情况,这个时候需要看中间件能不能支持跨库求交集的功能。比如mycat就不支持跨库查询,当然现在mycat也渐渐被摒弃了(没有处理笛卡尔交集的…...
DRM系列八:Drm之DRM_IOCTL_MODE_ADDFB2
本系列文章基于linux 5.15 在上一篇文章DRM系列七:Drm之DRM_IOCTL_MODE_CREATE_DUMB获取buf的handle和pitch之后,接着使用ioctl(fd, DRM_IOCTL_MODE_ADDFB2, &fb_cmd)创建一个新的帧缓冲区对象(framebuffer object),并将帧缓冲区对象与显…...
软件测试用例篇
设计测试用例是测试面试的必考题,务必好好学 1. 测试用例 测试用例的概念 测试⽤例(Test Case)是为了实施测试而向被测试的系统提供的⼀组集合,这组集合包含:测试环境、操作步骤、测试数据、预期结果等要素。 设计测试⽤…...
PopupMenuButton组件的功能和用法
文章目录 1 概念介绍2 使用方法3 示例代码 我们在上一章回中介绍了Sliver综合示例相关的内容,本章回中将介绍PopupMenuButton组件.闲话休提,让我们一起Talk Flutter吧。 1 概念介绍 我们在本章回中介绍的PopupMenuButton组件位于AppBar右侧,…...
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 缘起:荣品RK3566开发板在Android13下,希望通过Native C语言程序来控制RK3566的关机。 通过ADB,很容易通过reboot -p命令关机。 最开始以为需要su/root…...
设计模式---观察者模式
设计模式—观察者模式 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。 主要解决的问题:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,…...
初八开工!开启数字化转型新征程!
新年新气象,大年初八,我们斗志昂扬,共同奔赴充满希望的新一年! 2025 年意义非凡,这是广州市开利网络科技有限公司成立的第 18 个年头 。回首过往,我们一路拼搏,一路成长,积累了深厚的…...
文本分析NLP的常用工具和特点
1)非上下文感知型文本分析工具和特点 特性VADERTextBlob适合文本类型短文本、非正式语言(如评论、推文)中等长度、正式文本情感强度分析支持(正面、负面、中性)支持(极行、主观性)处理表情符号…...
DeepSeek 与 ChatGPT 对比分析
一、技术背景与研发团队 ChatGPT 由 OpenAI 开发,自 2015 年 OpenAI 成立以来,经过多年的技术积累和迭代,从 GPT-1 到 GPT-4o,每一次升级都带来了技术上的突破。OpenAI 拥有雄厚的技术实力和海量的数据、强大的算力支持ÿ…...
vite---依赖优化选项esbuildOptions详解
optimizeDeps.esbuildOptions vite.optimizeDeps.esbuildOptions 是 Vite 配置中的一个选项,它允许你在 Vite 启动时,给 esbuild(Vite 用来处理代码转换和优化的工具)传递额外的配置。通过这个配置项,你可以自定义 esb…...
ElasticSearch 学习课程入门(二)
引子 前文已经介绍了ES的增删改查基本操作,接下来,我们学习下高级点的用法。OK,那就让我们开始吧。 一、ES高级操作 1、条件查询 (1)GET https://127.0.0.1:9200/shopping/_search?qcategory:小米 (2&…...
使用 Redis Streams 实现高性能消息队列
1. 引言 在后端开发中,消息队列是一个常见的组件,主要用于解耦系统、提高吞吐量以及实现异步处理。常见的消息队列包括 Kafka、RabbitMQ 以及 ActiveMQ,但 Redis Streams 作为 Redis 5.0 引入的新特性,也提供了一种高效、轻量的消…...
深度学习|表示学习|卷积神经网络|DeconvNet是什么?|18
如是我闻: DeconvNet(反卷积网络)是一种可视化 CNN(卷积神经网络)内部特征的方法,用于理解 CNN 是如何提取图像特征的。这个方法由 Zeiler & Fergus(2013) 提出,目的…...
(优先级队列(堆)) 【本节目标】 1. 掌握堆的概念及实现 2. 掌握 PriorityQueue 的使用
优先级队列(堆) 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 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
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 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&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 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
