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

mini-bitcask学习笔记

代码仓库:mini-bitcask

type KeyDir = std::collections::BTreeMap<Vec<u8>, (u64, u32)>;
pub type Result<T> = std::result::Result<T, std::io::Error>;
  • keyDir的值:(文件偏移量, 值长度)

  • pub type Result<T> 是错误处理惯用法,这里统一使用 std::io::Error

选择BTreeMap:自动按键排序,支持范围查询

pub struct MiniBitcask {log: Log,keydir: KeyDir,
}pub struct ScanIterator<'a> {inner: btree_map::Range<'a, Vec<u8>, (u64, u32)>,log: &'a mut Log,
}

MiniBitcask:对外提供 API(set/get/delete/scan),内部持有 Log 和 KeyDir。

  • Log:负责文件IO操作
  • KeyDir:内存中的索引,快速定位键的位置

ScanIterator 是迭代器,引用 MiniBitcask 里的资源,必须用生命周期 'a 约束:

  • inner: btree_map::Range<'a, ...>RangeBTreeMap 的范围迭代器,是对 KeyDirMiniBitcask 的字段)的不可变引用'a 表示这个引用和 KeyDir 的存活时间一致。
  • log: &'a mut Log:是对 MiniBitcasklog 字段的可变引用'a 同样约束这个可变引用的必须和 Log 的存活时间一致。

效果:

fn bad_example() {let mut iter: ScanIterator;{let mut db = MiniBitcask::new(path).unwrap(); // db 是 MiniBitcask 实例iter = db.scan(...); // iter 引用了 db 的 keydir 和 log} // db 在这里被销毁,它的 keydir 和 log 也没了iter.next(); // 错误:iter 引用的资源已经不存在(悬垂引用)
}

impl Drop for MiniBitcask {fn drop(&mut self) {if let Err(error) = self.flush() {log::error!("failed to flush file: {:?}", error)}}
}
  • Drop trait类似于其他语言的析构函数

  • MiniBitcask离开作用于时自动调用

  • if let 模式匹配:只处理 Err 情况,成功时不作任何操作

fn new(path: PathBuf) -> Result<Self> {let file = std::fs::OpenOptions::new().read(true).write(true).create(true).open(&path)?;file.try_lock_exclusive()?;Ok(Self { path, file })
}
  • OpenOptions 构建器模式:链式调用配置文件打开方式
  • ? 操作符:错误传播,如果失败直接返回 Err
  • try_lock_exclusive() 文件锁防止多进程同时写入

fn load_index(&mut self) -> Result<KeyDir> {while pos < file_len {let read_one = || -> Result<(Vec<u8>, u64, Option<u32>)> {// 读取操作...}();match read_one {Ok((key, value_pos, Some(value_len))) => {keydir.insert(key, (value_pos, value_len));}Ok((key, value_pos, None)) => {keydir.remove(&key);pos = value_pos;}Err(err) => return Err(err.into()),}}Ok(keydir)
}
  • 缓冲区设计:
    • len_buf: [0u8; 4]: 复用缓冲区读取长度字段
    • BufReader: 缓冲读取,减少系统调用
  • 立即执行闭包:
    • let read_one = || { ... }(): 定义并立即执行
  • 删除标记处理:
    • i32::from_be_bytes(len_buf): 值长度用有符号整数存储
    • l >= 0: 正常数据
    • l < 0: 删除标记(tombstone)

为什么需要这个方法:

日志文件是追加写入的(新的键值对/删除操作 都往文件末尾加),程序重启后,必须知道哪些键有效、值存在哪里。load_index 就是干这个的:通过一次完整的文件扫描,把所有键的最新状态(存在 / 删除)记录到 KeyDir 里,后续操作(get/set 等)直接查 KeyDir 就能快速定位,不用再扫整个文件。


impl<'a> Iterator for ScanIterator<'a> {type Item = Result<(Vec<u8>, Vec<u8>)>;fn next(&mut self) -> Option<Self::Item> {self.inner.next().map(|item| self.map(item))}
}
  • type Item = Result<(Vec<u8>, Vec<u8>)>Iterator trait的关联类型,定义了迭代器每次迭代返回的元素类型

  • fn next(&mut self) -> Option<Self::Item>Iterator trait的核心方法,定义了如何获取下一个元素

    • 返回值 Option<Self::Item>:迭代未结束时返回 Some(Result<...>),迭代结束时返回 None
    • 实现逻辑分两步: ① self.inner.next()self.innerBTreeMap 的范围迭代器(btree_map::Range),它的 next 方法会返回下一个“键和(值位置,值长度)”的引用(类型是 Option<(&Vec<u8>, &(u64, u32))>)。简单说:先从内存索引 KeyDir 中拿到下一个符合条件的 key,以及它的 value 在文件中的位置和长度。 ② .map(|item| self.map(item)):对第一步拿到的结果进行转换。self.map(item)ScanIterator 自己的方法,作用是:根据 item 中的“值位置”和“值长度”,从日志文件(self.log)中读取实际的 value,最终返回 Result<(Vec<u8>, Vec<u8>)>(即键值对)
pub struct ScanIterator<'a> {inner: btree_map::Range<'a, Vec<u8>, (u64, u32)>, // 引用了 'a 生命周期的资源log: &'a mut Log, // 引用了 'a 生命周期的资源
}

ScanIterator 结构体本身是带生命周期的

ScanIterator<'a> 中的 'a 表示:它包含的两个字段(innerlog)都是引用,且这些引用的 存活时间被约束在 'a 这个范围内。

当你为 ScanIterator<'a> 实现 Iterator trait 时,必须在 impl 后面加上 <'a>,原因是:

要告诉编译器:当前 impl 块是针对 ScanIterator<'a> 这个带生命周期的类型的,块里的方法(比如 next)会用到 'a 约束的引用,需要保持生命周期一致

'a 在这里绑定了三个东西的存活时间:

  1. ScanIterator 结构体本身的存活时间;
  2. 它的字段 innerBTreeMap 的范围迭代器,本质是对 KeyDir 的引用)的存活时间;
  3. 它的字段 log(对 Log 的可变引用)的存活时间。

编译器通过这个标签会强制检查:ScanIterator 实例的存活时间,不能超过它引用的 KeyDirLog 的存活时间

http://www.dtcms.com/a/569939.html

相关文章:

  • 东莞网站建设公司哪家好电商平面设计主要做什么
  • 解决远程调用微服务之后无法通过上下文获取用户id问题
  • 网站代付系统怎么做大型网站seo策略
  • 国家住房城乡建设部网站住房和城乡建设部网站北京
  • 制作网站的程序网站查找工具
  • 网站建设 图片压缩网站开发多少费用
  • React Native App 自动检测版本更新完整实现指南
  • 网站建站是 什么企业网站托管运营
  • 字母象形的力量:单词速记之多种意象融合一体
  • xtuoj Binary
  • 南沙网站开发企业网站建设需要多少钱知乎
  • python 包 检测自己是否为 editable 模式安装的
  • ToB销售获客策略全解析:实现精准客户开发方法论
  • 成都医院手机网站建设湖北做网站找谁
  • 网站需求分析怎么写设计网站大全湖南岚鸿设计
  • css 画一个圆角渐变色边框
  • 网站路径问题国外h5建站
  • 数字营销技术应用网站大连网页搜索排名提升
  • 简化Java开发——Hutool工具使用案例
  • 某次钓鱼邮件安全事件应急
  • TCP/IP 五层协议栈
  • Linex操作系统-Shell脚本(七)
  • Linux系统编程——守护进程
  • 【打靶日记】VulNyx 之 Fing
  • 个人简历模板电子版可填写郑州专业seo哪家好
  • 开发与测试的微妙平衡:从“对立”到“合作”的实战经验
  • 开源网站代码濮阳市城乡建设管理局网站
  • C++ 贪心算法(Greedy Algorithm)详解:从思想到实战
  • 新手从零开始学电脑,0元学会重装系统
  • 六安网站制作公司排名网站 绝对路径