mini-lsm通关笔记Week2Day3

news2024/12/28 6:30:24

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

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

Summary

在本章中,您将:

  • 实现tiered合并策略并在压缩模拟器上对其进行模拟。
  • tiered合并策略纳入系统。

我们在本章所讲的tiered合并和RocksDB的universal合并是一样的。我们将互换使用这两个术语。

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

cargo x copy-test --week 2 --day 3
cargo x scheck

Task 1-Universal Compaction

在本章中,您将实现RocksDB的universal合并,它是tiered合并家族的合并策略。与simple leveled合并策略类似,在此合并策略中,我们只使用文件数量作为指标。当我们触发合并任务时,我们总是在合并任务中包含一个完整的排序run(层)。

Task 1.0-Precondition

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

src/compact/tiered.rs

universal合并中,我们不使用LSM状态下的L0 SST。相反,我们直接将新的SST转储到单个排序run(称为层)。在LSM状态中,levels现在将包括所有层,其中最小的索引是最新转储的SSTlevels数组中的每个元素存储一个元组:级别ID(用作层ID)和该级别中的SST。每次转储L0 SST时,都应该将SST转储到放置在向量前面的层中。compaction模拟器根据第一个SST id生成层id,您应该在您的实现中执行相同的操作。

只有在层数(排序run数)大于num_tiers时,universal合并才会触发任务。否则,它不会触发任何合并。

该子任务就是在generate_compaction_task函数中先判断_snapshot.levels数组的大小是否大于num_tiers。若不大于则无需进行任务合并操作。

pub fn generate_compaction_task(
    &self,
    _snapshot: &LsmStorageState,
) -> Option<TieredCompactionTask> {
    if _snapshot.levels.len() < self.options.num_tiers {
        return None
    }
    None
}

Task 1.1-Triggered by Space Amplification Ratio

universal合并的第一个触发因素是空间放大比。正如我们在概述章节中所讨论的,空间放大可以通过engine_size/last_level_size来估计。在我们的实现中,我们通过除最后一级之外的所有级别大小之和/最后一级大小来计算空间放大比,从而可以将比值缩放为[0,+inf]而不是[1, +inf]。这也与RocksDB的实现是一致的。

除最后一级之外的所有级别大小之和/最后一级大小 >= max_size_amplification_percent * 100%时,我们将需要触发一个完整的合并。

实现了这个触发器之后,就可以运行合并模拟器了。您将看到:

cargo run --bin compaction-simulator tiered
--- After Flush ---
L3 (1): [3]
L2 (1): [2]
L1 (1): [1]
--- Compaction Task ---
compaction triggered by space amplification ratio: 200
L3 [3] L2 [2] L1 [1] -> [4, 5, 6]
--- After Compaction ---
L4 (3): [3, 2, 1]

有了这个触发器,我们只有在达到空间放大比的时候才会触发完全压缩。在模拟结束时,您将看到:

--- After Flush ---
L73 (1): [73]
L72 (1): [72]
L71 (1): [71]
L70 (1): [70]
L69 (1): [69]
L68 (1): [68]
L67 (1): [67]
L40 (27): [39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 13, 14, 15, 16, 17, 18, 19, 20, 21]

合并模拟器中的num_tiers设置为3。然而,LSM状态中的层远远不止3层,这导致了很大的读放大。

当前触发合并机制只能减少空间放大。我们需要在合并算法中添加新的触发器,以减少读取放大。

generate_compaction_task
  • 统计除最后一级之外的所有级别大小之和,因为每个SST的大小都是固定的,所以可以近似的使用数量代替大小计算
  • 计算除最后一级之外的所有级别大小之和/最后一级大小,若大于阈值,则创建新的合并任务
pub fn generate_compaction_task(
    &self,
    _snapshot: &LsmStorageState,
) -> Option<TieredCompactionTask> {
    // Task 1.0-Precondition
    if _snapshot.levels.len() < self.options.num_tiers {
        return None;
    }
    // Task 1.1-Triggered by Space Amplification Ratio
    let levels_num = _snapshot.levels.len();
    let last_level_size = _snapshot.levels[levels_num - 1].1.len();
    let mut engine_size = 0;
    for (index, level) in _snapshot.levels.iter().enumerate() {
        if index == levels_num - 1 {
            break;
        }
        engine_size += level.1.len();
    }
    println!("levels_num:{}, last_level_size:{}, engine_size:{}", levels_num, last_level_size, engine_size);
    if engine_size as f64 / last_level_size as f64 >= self.options.max_size_amplification_percent as f64 / 100.0f64 {
        return Some(TieredCompactionTask { tiers: _snapshot.levels.clone(), bottom_tier_included: true });
    }

    None
}
apply_compaction_result
  • 将此前的都清空删除,新合并的SST放置到最底层
pub fn apply_compaction_result(
    &self,
    _snapshot: &LsmStorageState,
    _task: &TieredCompactionTask,
    _output: &[usize],
) -> (LsmStorageState, Vec<usize>) {
    let mut snapshot = _snapshot.clone();
    let mut files_to_remove = Vec::new();
    let tiered_id = _output.first().unwrap();
    if _task.bottom_tier_included {
        snapshot.levels.clear();
    }
    for levels in _task.tiers.iter() {
        files_to_remove.extend(levels.clone().1)
    }
    snapshot.levels.insert(0, (*tiered_id, _output.to_vec()));
    (snapshot, files_to_remove)
}

如图展示前两次的情况,第一次触发合并:

第二次触发合并:

可以看到后续触发合并的条件越来越苛刻,以至于层数过多,这将导致读放大。因为每一层都需要进行一次IO。

通过运行合并模拟器可以看到最后转储50个SST后的结果,可以看到存在24层:

=== Iteration 49 ===
--- After Flush ---
L89 (1): [89]
L88 (1): [88]
L87 (1): [87]
L86 (1): [86]
L85 (1): [85]
L84 (1): [84]
L83 (1): [83]
L82 (1): [82]
L81 (1): [81]
L80 (1): [80]
L79 (1): [79]
L78 (1): [78]
L77 (1): [77]
L76 (1): [76]
L75 (1): [75]
L74 (1): [74]
L73 (1): [73]
L72 (1): [72]
L71 (1): [71]
L70 (1): [70]
L69 (1): [69]
L68 (1): [68]
L67 (1): [67]
L40 (27): [39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 13, 14, 15, 16, 17, 18, 19, 20, 21]
--- Compaction Task ---
--- Compaction Task ---
levels_num:24, last_level_size:27, engine_size:23
no compaction triggered
--- Statistics ---
Write Amplification: 89/50=1.780x
Maximum Space Usage: 54/50=1.080x
Read Amplification: 24x

Task 1.2-Triggered by Size Ratio

下一个触发器是大小比触发器。对于所有层,如果有一个层n的所有之前层的大小/此层>= (100 + size_ratio) * 100%,我们将合并所有n层。我们只在要合并的层超过min_merge_width的情况下执行此合并。

使用此触发器,您将在合并模拟器中观察到以下内容:

L207 (1): [207]
L204 (3): [203, 202, 201]
L186 (15): [185, 178, 179, 180, 181, 182, 183, 184, 158, 159, 160, 161, 162, 163, 164]
L114 (31): [113, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56]

将有更少的1-SST层,并且合并算法将保持这些层按大小比从较小到较大的大小。但是,当处于LSM状态的SST更多时,仍然会有超过num_tiers层的情况。为了限制层数,我们需要另一个触发器。

generate_compaction_task函数新增触发条件

// Task 1.2-Triggered by Size Ratio
let mut previous_tiers_size = 0;
for (index, level) in _snapshot.levels.iter().enumerate() {
    if (index + 1) < self.options.min_merge_width {
        previous_tiers_size += level.1.len();
        continue;
    }
    let this_tier = level.1.len();
    if previous_tiers_size as f64 / this_tier as f64 >= (self.options.size_ratio as f64 + 100.0f64) / 100.0f64 {
        println!("previous_tiers_size:{}, this_tier:{}, n:{}", previous_tiers_size, this_tier, index + 1);
        return Some(TieredCompactionTask {
            tiers: _snapshot
                .levels
                .iter()
                .take(index + 1)
                .cloned()
                .collect::<Vec<_>>(),
            bottom_tier_included: index == levels_num - 1,
        });
    }
    previous_tiers_size += level.1.len();
}

实现第二个触发器后,除了往最底层合并外,也能触发前n层进行合并:

Task 1.3:-Reduce Sorted Runs

如果前面的触发器都没有产生合并任务,那么我们将进行一次合并以减少层数。我们将简单地将前面几层压缩为一层,以便最终状态将具有正好num_tiers层(如果在压缩期间没有刷新SST)。

启用此压缩后,您将看到:

L427 (1): [427]
L409 (18): [408, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407]
L208 (31): [207, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72]

所有的合并结果都不会超过num_tiers层。

注意:这部分我们不提供细粒度的单元测试。您可以运行合并模拟器,并与参考解决方案的
输出进行比较,以查看您的实现是否正确。

generate_compaction_task函数新增触发条件,就是在最后返回的时候,判断当前层级个数是否大于num_tiers。如果大于就将前面几个层级进行合并。

if _snapshot.levels.len() == self.options.num_tiers {
    return None;
}
// Task 1.3:-Reduce Sorted Runs
let nums = _snapshot.levels.len() - self.options.num_tiers + 1;
println!("Reduce Sorted Runs, levels size: {}, num_tiers:{}, nums:{}", _snapshot.levels.len(), self.options.num_tiers, nums);
return Some(TieredCompactionTask {
    tiers: _snapshot
        .levels
        .iter()
        .take(nums)
        .cloned()
        .collect::<Vec<_>>(),
    bottom_tier_included: false,
});

Task2-Integrate with the Read Path

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

src/compact.rs
src/lsm_storage.rs

由于tiered合并不使用LSM状态的L0级别,所以应该直接将memtable转储到新的层,而不是作为L0 SST。可以通过self.compaction_controller.flush_to_l0()来知道是否要刷新到L0。您可以使用第一个输出SST id作为新排序运行的级别/层ID。您还需要修改您的合并过程,以为tiered合并作业构造合并迭代器。

lsm_storage.rsforce_flush_next_imm_memtable函数中的force_flush_next_imm_memtable修改为:

if self.compaction_controller.flush_to_l0() {
    // In leveled compaction or no compaction, simply flush to L0
    snapshot.l0_sstables.insert(0, sst.sst_id());
} else {
    // In tiered compaction, create a new tier
    snapshot.levels.insert(0, (sst.sst_id(), vec![sst.sst_id()]));
}

compact.rs修改compact函数,实现CompactionTask::Tiered分支,因为tired合并中只有排好序的run所以实现比较简单:

CompactionTask::Tiered(TieredCompactionTask { tiers, .. }) => {
    let mut iters = Vec::with_capacity(tiers.len());
    for (_, tier_sst_ids) in tiers {
        let mut ssts = Vec::with_capacity(tier_sst_ids.len());
        for id in tier_sst_ids.iter() {
            ssts.push(snapshot.sstables.get(id).unwrap().clone());
        }
        iters.push(Box::new(SstConcatIterator::create_and_seek_to_first(ssts)?));
    }
    self.compact_generate_sst_from_iter(
        MergeIterator::create(iters),
        _task.compact_to_bottom_level(),
    )
},

相关阅读

Universal Compaction - RocksDB Wiki

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2164746.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

车载网络测试实操源码_使用CAPL脚本实现安全访问解锁,并模拟各种测试场景

系列文章目录 使用CAPL脚本解析hex、S19、vbf文件 使用CAPL脚本对CAN报文的Counter、CRC、周期、错误帧进行实时监控 使用CAPL脚本模拟发送符合协议要求(Counter和CRC)的CAN报文 使用CAPL脚本控制继电器实现CAN线、电源线的通断 使用CAPL脚本实现安全访问解锁 使用CAPL脚本实现…

IDEA忽略node_modules减少内存消耗,提升索引速度

IDEA忽略node_modules减少内存消耗&#xff0c;提升索引速度 简介 在后端开发中&#xff0c;IDEA 在运行前端代码时&#xff0c;频繁扫描 node_modules 文件夹会导致高内存消耗和慢索引速度&#xff0c;甚至可能会导致软件卡死。为了改善这一问题&#xff0c;可以按照以下步骤…

STM32基础学习笔记-USART外设面试基础题3

第三章、USART 常见问题 通讯定义 &#xff1f;通讯分类 &#xff08;有无时钟源、通讯方式、传输方向&#xff09;&#xff1f; 波特率的本质&#xff1a;隐形的时钟 电平转换 &#xff1f;TTL、COMS、RS232、RS485、USB电平标准 &#xff1f; STM32串口与RS-232通讯 &…

《热血江湖》v23巅峰对决游戏程序(真端+最新官方版本)

《热血江湖》v23巅峰对决游戏程序&#xff08;真端最新官方版本&#xff09; 下载地址&#xff1a; 通过网盘分享的文件&#xff1a;【游戏】《热血江湖》v23巅峰对决游戏程序&#xff08;真端最新官方版本&#xff09; 链接: https://pan.baidu.com/s/18svlGuFnPM9ccwEAb7oBMw…

肺结节检测-目标检测数据集(包括VOC格式、YOLO格式)

肺结节检测-目标检测数据集&#xff08;包括VOC格式、YOLO格式&#xff09; 数据集&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1hz3Y6WgWoS3Gubsw_83WnA?pwdaon1 提取码&#xff1a;aon1 数据集信息介绍&#xff1a; 共有 1180 张图像和一一对应的标注文件 标注…

输出不能被3整除的数-C语言

1.问题&#xff1a; 统计0~100之间的不能被3整除的数。 2.解答&#xff1a; 对100-200之间的每一个数进行遍历&#xff0c;如果不能被3整除&#xff0c;就将此数输出&#xff0c;若能被3整除&#xff0c;就不输出此数。 3.代码&#xff1a; #include<stdio.h>//头文件…

图像超补全(Outpainting)技术的前沿模型与数据集资源汇总

“lmage outpainting”这一概念是由斯坦福大学 CS230 课程的 Mark Sabini 等人提出&#xff0c;相较于图像修复技术&#xff0c;lmage outpainting 更进一步&#xff0c;能够从给定的图像片段中“补全”出缺失的外延部分&#xff0c;以精妙的方式补全画面&#xff0c;从而构建出…

基于实验的低光照图像增强方法综述

这篇论文的标题是《An Experiment-Based Review of Low-Light Image Enhancement Methods》&#xff0c;作者包括Wencheng Wang、Xiaojin Wu、Xiaohui Yuan 和 Zairui Gao。论文主要回顾了过去几十年中发展的低光照图像增强技术的主要技术。 以下是论文的详细内容概述&#xf…

Flutter中很有意思的Future

最近在使用Flutter来开发完全免费开放的E6开发平台对应的手机app客户端。 由于Flutter基于Dart语言开发&#xff0c;而Dart具有一个非常有趣的特性&#xff1a;Future&#xff0c;如果一个方法如果被定义为Future&#xff0c;意味着它可以被异步调用&#xff0c;这一特性对页面…

用于多模态MRI重建的具有空间对齐的深度展开网络|文献速递--基于多模态-半监督深度学习的病理学诊断与病灶分割

Title 题目 Deep unfolding network with spatial alignment for multi-modal MRI reconstruction 用于多模态MRI重建的具有空间对齐的深度展开网络 01 文献速递介绍 磁共振成像&#xff08;MRI&#xff09;因其无创性、高分辨率和显著的软组织对比度&#xff0c;已成为广…

算法记录——链表

2.链表 2.1判断是否是回文链表 1.方法一&#xff1a;利用栈反转链表 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode(int val, ListNode…

IO(输入输出流)

1.IO a.介绍 i.IO是指Input和Output&#xff0c;即输入和输出&#xff0c;以内存为中心&#xff1a; 1.Input是指从外部读入数据到内存。 2.Output是指把数据从内存输出到外部。 ii.IO流是一种顺序读写数据的模式&#xff0c;它的特点是单向流动。数据类似自…

【AIGC】ChatGPT提示词解析:如何生成爆款标题、节日热点文案与完美文字排版

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;情绪化的吸睛爆款标题提示词使用方法 &#x1f4af;紧跟节日热点选题文案提示词使用方法 &#x1f4af;高效文字排版技巧提示词使用方法 &#x1f4af;小结 &#x1f4af…

python-获取浏览器静态/动态素材

f12浏览器中 1&#xff1a;静态爬取 2.动态资源图片获取。斗鱼 3获取视频-抖音 一长串&#xff0c;最后一个http就是视频

Unity-物理系统-碰撞检测-物理材质

物理材质的作用&#xff1a;改变碰撞效果 因为碰撞的过程是相互的&#xff0c;所以在碰撞双方都要加相同的物理材质才能实现效果 物理材质创建 参数

【FPGA】IO电平标准

【FPGA】IO 电平标准 1 LVCMOS&#xff08;低压CMOS&#xff09;1.1 TTL、CMOS、LVTTL、LVCMOS逻辑电平定义1.2 ZYNQ-7000 PS、PL IO Level示例 2 LVTTL&#xff08;低压TTL&#xff09;3 HSTL&#xff08;高速TTL&#xff09;4 SSTL&#xff08;高速&#xff09;5 LVDS&#x…

Pytest测试实战|Conftest.py详解

Pytest测试实战 本文章主要详细地阐述下Pytest测试框架中Conftest.py特性。 Conftest.py实战 Fixture强大的特性在实际的工作中是非常有价值并且是实用的&#xff0c;这样可以根据需求&#xff0c;在对应的测试模块中编写Fixture函数来达到测试需求的目的。但是这样也产生了…

【面经合集】Java基础精选面试题(三)

最近&#xff0c;小编整理了不少Java领域面试题&#xff0c;如有需要&#xff0c;点击关注&#xff0c;回复【面试题】&#xff0c;即可下载。 31 、说说List,Set,Map三者的区别&#xff1f; List、Set、Map是三种不同数据结构的集合&#xff0c;它们的主要区别体现在存储方式…

Linux命令:用来列出当前系统内核加载的所有模块的工具lsmod详解

目录 一、概述 二、 使用方法 三、 输出格式 四、 示例 五、 相关命令 六、 高级用法 1、结合管道符 | 和 grep 命令 2、结合其他命令使用 七、应用和注意 一、概述 lsmod 是一个 Linux 命令行工具&#xff0c;用来列出当前内核加载的所有模块。这个命令对于了解哪些模…

分布式计算技术是什么?在数据集成值得作用?

数据是现代科技技术的基础&#xff0c;面对爆炸性数据的增长&#xff0c;要求计算能力要求更高、数据整合和处理更有效&#xff0c;如何应对数据集成带来的挑战&#xff1f;本文将探讨分布式计算技术在数据集成中的优化作用。 一 分布式计算技术。 定义&#xff1a;分布式计算…