前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >开源一个 Rust 练手小项目

开源一个 Rust 练手小项目

作者头像
roseduan
发布2024-04-28 12:09:52
2700
发布2024-04-28 12:09:52
举报
文章被收录于专栏:roseduan写字的地方

之前写过一个 Go 语言的 mini-bitcask,实现了一个基于 bitcask 存储模型的极简 KV 存储引擎。可以结合之前的文章食用:

从零实现一个 k-v 存储引擎

这次重新用 Rust 实现了一个版本,代码量和之前的差不多,包含了常用的方法,例如 Set、Get、Delete、Scan、PrefixScan、Merge。

项目地址:https://github.com/rosedblabs/mini-bitcask-rs

Set

代码语言:javascript
复制
pub fn set(&mut self, key: &[u8], value: Vec<u8>) -> Result<()> {
    let (offset, len) = self.log.write_entry(key, Some(&value))?;
    let value_len = value.len() as u32;
    self.keydir.insert(
        key.to_vec(),
        (offset + len as u64 - value_len as u64, value_len),
    );
    Ok(())
}

Set 逻辑比较直观简洁,写入磁盘日志,并且更新内存索引结构。

Get

Get 则是先从内存中获取索引,再从磁盘中获取 Value。

代码语言:javascript
复制
pub fn get(&mut self, key: &[u8]) -> Result<Option<Vec<u8>>> {
    if let Some((value_pos, value_len)) = self.keydir.get(key) {
        let val = self.log.read_value(*value_pos, *value_len)?;
        Ok(Some(val))
    } else {
        Ok(None)
    }
}

Delete

delete 的逻辑和 Set 类似,只是写入了一个空的值,并且从内存中对应的 key 移除。

代码语言:javascript
复制
pub fn delete(&mut self, key: &[u8]) -> Result<()> {
    self.log.write_entry(key, None)?;
    self.keydir.remove(key);
    Ok(())
}

Scan

scan 功能主要借助了 Rust 自带的内存数据结构 BTreeMap 的迭代器进行实现,非常简洁和方便。

代码语言:javascript
复制
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))
    }
}

impl<'a> DoubleEndedIterator for ScanIterator<'a> {
    fn next_back(&mut self) -> Option<Self::Item> {
        self.inner.next_back().map(|item| self.map(item))
    }
}

Merge

merge 的逻辑其实也比较简单,将内存中的数据全部重写,并且替换旧的文件即可。

代码语言:javascript
复制
pub fn merge(&mut self) -> Result<()> {
    // 创建一个新的临时用于用于写入
    let mut merge_path = self.log.path.clone();
    merge_path.set_extension(MERGE_FILE_EXT);

    let mut new_log = Log::new(merge_path)?;
    let mut new_keydir = KeyDir::new();

    // 重写数据
    for (key, (value_pos, value_len)) in self.keydir.iter() {
        let value = self.log.read_value(*value_pos, *value_len)?;
        let (offset, len) = new_log.write_entry(key, Some(&value))?;
        new_keydir.insert(
            key.clone(),
            (offset + len as u64 - *value_len as u64, *value_len),
        );
    }

    // 重写完成,重命名文件
    std::fs::rename(new_log.path, self.log.path.clone())?;

    new_log.path = self.log.path.clone();
    // 替换现在的
    self.log = new_log;
    self.keydir = new_keydir;

    Ok(())
}

通过这个简单的项目,可以学习到 Rust 的大多数基础语法,例如:

  • 数据类型,数组、整型等
  • match 表达式
  • 函数
  • 结构体
  • 错误处理
  • 迭代器 Iterator 和 DoubleEndedIterator
  • 文件读写操作
  • BufWriter 和 BufReader
  • 单元测试撰写

项目地址:https://github.com/rosedblabs/mini-bitcask-rs

觉得有帮助的话请不用吝啬你的 Star ⭐️ 哦!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-04-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 roseduan写字的地方 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档