1 个不稳定版本

0.1.0 2024年2月17日

#159缓存

MPL-2.0 许可证

52KB
1K SLoC

dir-cache - 一个非常低成本的目录缓存

一种映射接口,可以将写入磁盘以某种可浏览的格式传播。

设计得简单易用易懂,效果并不特别出色。

性能

很糟糕。

性能第2部分

如果你懒散地写入磁盘,那么还可以。由于(可能取决于选项)每个映射操作至少对应一次磁盘操作,因此映射不适合高频率操作。

由于特定的值将产生一个磁盘表示形式,其大小严格大于原始内容大小。这意味着,dir-cache 在空间效率上并不高。

最后,文件系统的特定属性可能会使许多键的性能不佳(NTFS 就是一个例子)。

应使用场景

如果你有一个玩具项目,它正在调用外部 API,并且你只想简单地缓存某些请求的响应以减少对对方服务器的负载,或者类似的情况。

生产使用案例中你应该检查什么

如果你想在 Rust 中使用嵌入式 KV-store,请考虑 Sled

如果你想在 Rust 之外使用嵌入式 KV-store,请考虑 RocksDB (github)RocksDB(docs.rs)

如果你想在 Rust 之外使用嵌入式 SQL-store,请考虑 Sqlite(网站)同步 Rust crate(Rusqlite)异步 Rust crate (Sqlx)

为什么

现在我们已经谈过了以上内容,我们可以深入了解为什么这个 crate 存在。

在我使用 Rust 探索公共 API 的过程中,我多次遇到了相同的问题

我正在探索一个 API,分析响应并编写代码,但我不希望每次迭代都发出新的网络请求,出于延迟和对他人的尊重。

在这些情况下,我通常会将响应保存到磁盘上,并在它们上执行离线分析。这可行,但很麻烦,它处理的是同样的老错误 std::fs::...,确定合适的目录结构,最糟糕的是,需要编写两个独立的代码部分,一个是获取,另一个是分析。

目的

我想写这个

fn iterate_on_api_response_handling(dir_cache: &mut Cache) {
    // This is preferably not dynamic
    let req_key = Path::new("examplerequest");
    // If this has run before then don't send an http request
    let resp = dir_cache.get_or_insert_with(req_key, || {
        let resp = http::client::get("https://example.com")?;
        Ok(resp)
    });
    // Mess around with resp here
    println!("Got length {}", resp.len());
}

有了上面的方法,获取和分析代码可以放在同一个地方。

功能

功能集保持相当简单,以支持上述用例。

类似于映射的接口

DirCache 上有 getget_or_insert_withinsertremove 方法。

可浏览的磁盘表示

值被写入到磁盘上的 cache-location/{key}/,这使得检查保存的文件变得容易,在我的案例中通常是 json 文件。

响应的最大年龄

由于值可能会过时,这取决于迭代所需的时间,可以通过持续时间设置最大年龄,在此之后,值将被视为不存在。这意味着,第一次运行相同的 get_or_insert_with 会获取数据,直到最大年龄过去,每次返回缓存数据,最大年龄过去后获取新数据。

数据可选地以代数保存

覆盖相同的键可以选择将旧键向下移动一代,保留在磁盘上。
在某些情况下很有用,其中响应随时间变化,并且您希望保留历史记录。尽管这绝对是功能最不强大的一项。

可选压缩代数数据

我在处理一个非常稀疏的 json 数据集时发现这很有用,其中响应非常大,可以使用具有 lz4 压缩功能的 lz4 压缩来选择旧代。

注意事项

除了性能外,还有一点需要注意。

磁盘危险

键是 PathBufs,并与 dir-cache 基目录连接。这打开了一个潘多拉盒子,最糟糕的是,不小心与绝对路径连接,请参阅 Path::join 的文档。

这可能导致具有破坏性的结果。

有一些缓解措施

  1. 如果右侧是绝对路径,则永远不会连接路径,并且路径不允许是除 Component::Normal 之外的内容。同时确保解析的组件组合长度与提供的 OsStr 长度合理(缓解意外有效路径)。
  2. 仅对特定文件名执行写入操作 dir-cache-generation-{manifest.txt | n}。(降低意外覆盖重要文件的风险)。
  3. 仅对上述特定文件名以及空目录执行删除操作。

这涵盖了我想到的所有情况,但当然,不包括我想不到的情况。

如果使用此库,建议不要使用动态键。模糊测试仅在 Linux 上进行,因此在其他操作系统上使用动态键存在额外风险,尽管在 Linux 上进行模糊测试也不一定安全。

许可证

该项目在 MPL-2.0 许可证下授权。

依赖项

~195KB