网站开发排行/惠州百度关键词优化
项目地址: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.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::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 概念…...

优化数据库结构
MySQL学习大纲 一个好的数据库设计方案对于数据库的性能尝尝会起到事倍功半的效果,合理的数据库结构不仅使数据库占用更小的磁盘空间,而且使查询速度更快。数据库结构的设计需要考虑数据冗余、查询和更新速度、字段的数据类型是否合理等多方面的内容&…...

密云生活的初体验
【】在《岁末随笔之碎碎念》里,我通告了自己搬新家的事情。乙巳年开始,我慢慢与大家分享自己买房装修以及在新家的居住体验等情况。 跳过买房装修的内容,今天先说说这三个月的生活体验。 【白河】 潮白河是海河水系五大河之一,贯穿…...

图像分类与目标检测算法
在计算机视觉领域,图像分类与目标检测是两项至关重要的技术。它们通过对图像进行深入解析和理解,为各种应用场景提供了强大的支持。本文将详细介绍这两项技术的算法原理、技术进展以及当前的落地应用。 一、图像分类算法 图像分类是指将输入的图像划分为…...

计算机网络——流量控制
流量控制的基本方法是确保发送方不会以超过接收方处理能力的速度发送数据包。 通常的做法是接收方会向发送方提供某种反馈,如: (1)停止&等待 在任何时候只有一个数据包在传输,发送方发送一个数据包,…...

体验 DeepSeek 多模态大模型 Janus-Pro-7B
含有图片的链接: https://mp.weixin.qq.com/s/i6kuVcGU1CUMYRPDM-bKog?token2020918682&langzh_CN 继上篇文章下载了 Janus-Pro-7B 后,准备本地运行时发现由于电脑配置配置太低(显存小于24G),无法运行࿰…...

使用mockttp库模拟HTTP服务器和客户端进行单元测试
简介 mockttp 是一个用于在 Node.js 中模拟 HTTP 服务器和客户端的库。它可以帮助我们进行单元测试和集成测试,而不需要实际发送 HTTP 请求。 安装 npm install mockttp types/mockttp模拟http服务测试 首先导入并创建一个本地服务器实例 import { getLocal } …...

解决每次打开终端都需要source ~/.bashrc的问题(记录)
新服务器或者电脑通常需要设置一些环境变量,例如新电脑安装了Anaconda等软件,在配置环境变量后发现每次都需要重新source,非常麻烦,执行下面添加脚本实现一劳永逸 vim .bash_profile# .bash_profileif [ -f ~/.bashrc ]; then. ~…...

UE5 蓝图学习计划 - Day 14:搭建基础游戏场景
在上一节中,我们 确定了游戏类型,并完成了 项目搭建、角色蓝图的基础设置(移动)。今天,我们将进一步完善 游戏场景,搭建 地形、墙壁、机关、触发器 等基础元素,并添加角色跳跃功能,为…...

C++常用拷贝和替换算法
算法简介: copy // 容器内指定的元素拷贝到另一容器replace // 将容器内指定范围的旧元素改为新元素replace_if // 容器内指定范围满足条件的元素替换为新元素swap //互换两个容器的元素 1. copy 功能描述: 将容器内指定范围的数据拷贝到另一容器中函…...

取消和确认按钮没有显示的问题
取消和确认按钮没有显示的问题<template #footer> <template #footer> <!-- 使用插槽名称 #footer --> <span class"dialog-footer"> <el-button click"dialogVisible false">取消</el-button> …...