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 概念…...
《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...
探索Selenium:自动化测试的神奇钥匙
目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...
Modbus RTU与Modbus TCP详解指南
目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...
从零开始了解数据采集(二十八)——制造业数字孪生
近年来,我国的工业领域正经历一场前所未有的数字化变革,从“双碳目标”到工业互联网平台的推广,国家政策和市场需求共同推动了制造业的升级。在这场变革中,数字孪生技术成为备受关注的关键工具,它不仅让企业“看见”设…...
数据结构:泰勒展开式:霍纳法则(Horner‘s Rule)
目录 🔍 若用递归计算每一项,会发生什么? Horners Rule(霍纳法则) 第一步:我们从最原始的泰勒公式出发 第二步:从形式上重新观察展开式 🌟 第三步:引出霍纳法则&…...
用js实现常见排序算法
以下是几种常见排序算法的 JS实现,包括选择排序、冒泡排序、插入排序、快速排序和归并排序,以及每种算法的特点和复杂度分析 1. 选择排序(Selection Sort) 核心思想:每次从未排序部分选择最小元素,与未排…...
