#flash #key-value-store #embedded #fifo-queue #storage #byte-slice #no-std

无 std sequential-storage

一个用于在最小擦除周期下存储数据的 crate

23 个版本 (3 个主要版本更新)

3.0.1 2024 年 7 月 25 日
2.0.2 2024 年 5 月 7 日
1.0.0 2024 年 3 月 1 日
0.9.1 2024 年 2 月 13 日
0.2.1 2023 年 1 月 19 日

#54 in 数据库接口

Download history 154/week @ 2024-04-16 147/week @ 2024-04-23 371/week @ 2024-04-30 377/week @ 2024-05-07 155/week @ 2024-05-14 476/week @ 2024-05-21 515/week @ 2024-05-28 304/week @ 2024-06-04 329/week @ 2024-06-11 372/week @ 2024-06-18 263/week @ 2024-06-25 344/week @ 2024-07-02 499/week @ 2024-07-09 545/week @ 2024-07-16 481/week @ 2024-07-23 294/week @ 2024-07-30

1,973 每月下载量
4 个 crate 中使用 (2 个直接使用)

MIT/Apache

220KB
4.5K SLoC

Sequential-storage

crates.io Documentation

一个用于在最小擦除周期下存储数据的 crate。

存在两种数据结构

  • Map: 键值对存储
  • Queue: fifo 存储

它们各自存在于自己的模块中。查看模块文档以获取更多信息及示例。

注意:请确保不要在闪存中混合数据结构!
例如,您不能从您推送到队列的闪存区域中检索键值项。

要搜索数据,crate 首先搜索最有可能包含它的闪存页,然后对数据进行线性扫描,跳过可以跳过的数据块。

状态

此 crate 已在 Tweede golf 内部和外部多个项目中投入生产使用。

闪存中的表示目前(尚)不稳定。这也遵循 semver。

  • 对闪存表示的破坏性更改将导致主要版本号的增加
  • 新功能添加将导致次要版本号的增加
    • 这总是向后兼容的。因此,由例如 1.0.0 创建的数据可以由 1.1.0 使用。
    • 这可能不是向前兼容的。因此,例如由 1.0.1 创建的数据可能无法由 1.0.0 使用。
  • 从1.0版本开始,补丁发布仅修复错误,不改变闪存中的表示形式

对于任何更新,请查看变更日志以了解更改内容。任何外部可观察到的更改都会记录在那里。

该crate的_test功能被视为私有。它及其启用的任何内容都不受semver的约束。

任何缓存类型的性能也不受semver的约束。如果您在一个性能敏感的应用程序中使用此crate,那么请确保在没有使用缓存的情况下一切正常工作。这样,您就覆盖了该应用程序部分的最坏情况执行时间。

缓存性能退步可能是一个错误。如果您发现退步,请打开一个问题来讨论您的状况。

MSRV

除了能够在最新稳定编译器上运行外,此crate没有其他保证。
增加MSRV在semver意义上不被视为破坏性更改。
如果您遇到这个问题,请随时打开一个问题。

示例

请参阅mapqueue模块级别的文档以获取示例。

功能

  • 键值数据存储(Map)
    • 用户定义的键和值类型
    • 非常适合创建配置
  • 先进先出队列数据存储(Queue)
    • 在内存中存储字节切片
    • 非常适合缓存数据
  • 简单的API
    • 只需调用您认为需要的函数
    • 无需担心其他任何事情
  • 项目标题CRC保护
  • 项目数据CRC保护
  • 断电安全
    • 系统总是正常或完全可恢复
  • 损坏的项目将被忽略
  • 可选缓存以加快速度
  • 均衡磨损
    • 页面循环使用,因此所有页面都会被擦除相同数量的次数
  • 建立在embedded-storage之上
    • 这是唯一必需的依赖项

如果您正在寻找具有不同权衡的替代方案,请查看ekv

注意:该crate使用futures进行操作。这些futures写入闪存。如果取消future,这可能导致闪存状态损坏,因此取消操作由您自行承担风险。如果发生这种情况,状态将得到修复。 无论如何,您尝试存储或擦除的内容可能已经完全发生或可能没有完全发生。

损坏修复

如果在操作过程中发现损坏,crate将自动尝试修复它。某些损坏会导致不可恢复的数据,遗憾的是无法修复。然而,修复将确保恢复闪存状态,因此任何后续操作都应成功。

如果任何函数仍然返回损坏的错误,这意味着修复无法修复状态。在这种情况下,请打开一个问题!

缓存

有各种缓存选项可以加快操作。默认情况下(无缓存)所有状态都存储在闪存中,并且每次都必须完全读取状态。相反,我们可以选择将一些状态存储在ram中。

这些数字是从缓存模块的测试用例中获得的

名称 RAM字节 Map # 闪存读取 Map 闪存读取字节 Queue # 闪存读取 Queue 闪存读取字节
NoCache 0 100% 100% 100% 100%
PageStateCache 1 * 页数 77% 97% 51% 90%
PagePointerCache 9 * 页数 70% 89% 35% 61%
KeyPointerCache 9 * 页数 + (键大小 + 4) * 键数量 6.2% 8.2% - -

要点

  • PageStateCache
    • 主要解决读取次数问题
    • 在RAM中非常便宜,因此容易赢得胜利
  • PagePointerCache
    • 对队列非常有效
    • 影响地图的最小缓存级别
  • KeyPointerCache
    • 惊人的节省!
    • 如果键的数量超过缓存可以存储的数量,数字就不那么好了
    • 在用作队列时与PagePointerCache相同

内部工作原理

为了节省擦除周期,这个crate只真正将数据追加到页面上。具体如何操作取决于你是否使用map或队列。

为此有两个概念

页面 & 页面状态

闪存被分成多个页面。一个页面可以是三种状态之一

  1. 开放 - 此页面处于擦除状态
  2. 部分开放 - 此页面已被写入,但尚未满
  3. 关闭 - 此页面已完全写入

页面状态被编码到页面的第一个和最后一个单词中。如果这两个单词都是 FF(擦除),则页面为开放。如果第一个单词被写入标记,则页面为部分开放。如果两个单词都被写入,则页面为关闭。

项目

所有数据都存储为项目。

一个项目由一个包含数据长度、该长度的CRC、数据CRC和一些数据的头组成。当一个项目的数据CRC字段为0时,它被认为已被擦除。

注意:这意味着当它被认为已擦除时,数据本身仍然存储在闪存上。 根据您的用例,这可能不安全

长度是u16,因此任何项目都不能超过0xFFFF或 页面大小 - 项目头 (填充到字边界) - 页面状态 (2 个单词)

map的内部工作原理

map将每个键值存储为项目。每个新值都追加到最后的部分开放页面或最后一个关闭页面之后的第一个开放页面。

一旦页面填满,它将被关闭,下一个页面需要存储项目。然而,我们最终需要擦除一个旧页面。因为我们不希望丢失任何数据,所以将要擦除的页面上所有的项目都将进行检查。如果一个项目没有比页面上找到的更新的值,它将从将要擦除的页面复制到当前的partial-open页面。这样就不会丢失数据(只要闪存足够大以容纳所有数据)。

队列的内部工作原理

在推送时,将搜索放置项目的最新位置。如果它不合适,它将返回错误或如果指定了它将擦除旧页面。你应该只在获得许可时才会丢失数据。

窥视和弹出查看它可以找到的最旧数据。在弹出时,项目也将被擦除。

在使用peek_many时,你可以查看从最旧到最新的所有数据。

依赖关系

~26–370KB