# 2022-50: Sccache 和 OpenDAL 的故事

最近特别开心！

在周报 [2022-45: 使用 sccache 加快 Rust 编译速度](https://xuanwo.io/reports/2022-45/) 的末尾，我提到希望能把 [sscache](https://github.com/mozilla/sccache) 的存储后端替换为 [Apache OpenDAL](https://github.com/datafuselabs/opendal):

> 我给上游提交了一个 [proposal: Use opendal to handle the cache storage operations](https://github.com/mozilla/sccache/issues/1404)，看看能不能把 sccache 的存储后端访问改为使用 opendal，这样对接存储和调试起来就更方便了～

现在它成真了！今天这篇周报就聊一聊 Sccache 和 OpenDAL 的故事。

## 不满现状

为了能够在 Databend 的 CI 中快速上线编译缓存的功能，我 fork 了 sscache 并做一些修改，但是在修改的过程中我发现在现有的 codebase 上缝缝补补远不如直接上 opendal 来得效率更高，于是我花了一些时间把 sscache 的 s3 存储后端实现修改成了 opendal。得益于 opendal 良好的日志等基础设施，我很快定位到 AWS 配置侧的一些问题并顺利上线，其中经过和最后的产出已经在 2022-45 的周报中都展开说了。为了便于线上的 CI 使用，我修改了 Cargo.toml，推送了 [cccache](https://crates.io/crates/cccache)。

编译缓存上线之后运行非常稳定，于是决定就这样用下去。但是这样就面临一个未来长期维护的问题：我对编译这块一窍不通，长期维护类似 sscache 这样的项目肯定是做不到的，且不说实现更多功能，光是应对可能的 bug 都头疼。最好的办法是我能够把现在的修改反馈给上游，从而保证我的服务能够长期稳定的运行。

## 提出草案

于是我提出了草案：[proposal: Use opendal to handle the cache storage operations](https://github.com/mozilla/sccache/issues/1404)。在草案中我简单介绍了一下 opendal 是什么，并介绍了使用 OpenDAL 能带来哪些好处：

- 能够修复很多现存的 BUG（过去手写的 s3/gcs/azblob 实现都比较简单，很多细节没考虑到）
- 减轻维护者的负担（把具体的服务实现逻辑交给 opendal，sscache 不再需要操心存储的实现细节）
- 实现服务支持更容易（比如说社区想要原生的 OSS 支持）

维护者的反馈比较中性，提了一些关于性能和目前 OpenDAL 用户有哪些的问题。性能方面我使用 sscache 和 cccache 分别做了 benchmark （我本来以为应该差不多，但是 cccache 要比 sscache 快一些，不知道为什么）。我发现维护者更关心的还是目前 OpenDAL 有哪些用户在用，他们不希望自己的项目依赖一个没几个月就黄了的项目。从维护者的角度来看，依赖的长期维护承诺往往比短时间的些许优势更重要。[@sylvestre](https://github.com/sylvestre) 的原话是：

> Sure, I just don't want to add a critical dependency which could be unmaintained in a few months

## 主动出击

在收到我的答复之后维护者并没有做出回应，我大胆的决定主动出击：提交了一个使用 OpenDAL 来替换 s3 实现的 PR，用意是秀一下肌肉，证明使用 OpenDAL 真的特别容易，确实能降低维护的负担。可惜这个 Demo PR 没有通过 CI，因为 OpenDAL 最低要求 Rust 1.60 才能进行构建。我本来已经有点丧气了，但是维护者确实非常 Nice，在询问了 OpenDAL MSRV 是多少之后，他们把 sscache 的 MSRV 提升到了 1.60。后来 OpenDAL 的 Demo 顺利通过了所有的 CI，接下来就等待维护者的反馈了。

等待了不少天之后，项目的另一位维护者 [@drahnr](https://github.com/drahnr) 出面给了一个正式的回应，指出了使用 OpenDAL 的风险点，提出了一些开放式问题，并总结了使用 OpenDAL 带来的一些好处，整体态度偏向于支持。

这里提出的一些风险点和问题都是开源项目经常要面对的问题，我逐个列出来并聊一下我的回应：

> opendal 有很多 sscache 不需要的后端，比如 rocksdb。

这个比较好解决，毕竟 opendal 本身就使用 feature flag 来保证这些有额外依赖的后端不会参与编译。我在回应中解释了这一行为，并且保证 sscache 不会因为这些用不到的后端受到影响。

> 如何保证 opendal 的后续长期维护？

说实话，我不知道这种问题怎么样回答比较好。毕竟长期维护都是做出来的，靠嘴巴说出来的都不靠谱。更何况我之前就经历过 [`beyondstorage`](https://github.com/beyondstorage/go-storage) 全团队裁撤，项目原地停摆的惨剧，所以我对这样的问题十分畏惧。

最后我的回答是坦白说了目前的情况，OpenDAL 是 databend 的核心依赖，由 datafuselabs 团队负责长期维护，并且提到了我们正计划壮大我们的社区以吸引更多的维护者。

> API 的稳定性如何保证？是否遵循 semver 的原则？

这个 OpenDAL 一直做的还不错，发版完全遵循 semver 的原则，还维护了 [CHANGELOG](https://github.com/datafuselabs/opendal/blob/main/CHANGELOG.md)，感觉这是一个大大的加分项。

> MSRV 如何处理？

在 Demo PR 翻车后，我就赶紧给 OpenDAL 设定了 MSRV，并且加入到了 CI 中，在这里就被用到了。

我秀了一下 OpenDAL 的 [MSRV Check CI](https://github.com/datafuselabs/opendal/blob/main/.github/workflows/ci.yml#L42)，并且给出了在 `1.0` 之前不再修改 MSRV 的承诺。

在我回应了上述的所有问题之后，维护者们纷纷点下了自己的 Approve～

## 目前进展

在迁移完成 s3 之后，我又陆续实现了 azure 和 gcs 的支持：

- [refactor: Migrate azblob to opendal based](https://github.com/mozilla/sccache/pull/1463)
- [refactor: Migrate gcs cache to opendal based](https://github.com/mozilla/sccache/pull/1474)

值得一提的是这两个 PR 都删除了大量的代码，现在为 sscache 增加一个 cache 服务的实现已经简单到只需要几行：

```rust
pub struct AzureBlobCache;

impl AzureBlobCache {
    pub fn build(connection_string: &str, container: &str, key_prefix: &str) -> Result<Operator> {
        let mut builder = azblob::Builder::from_connection_string(connection_string)?;
        builder.container(container);
        builder.root(key_prefix);

        Ok(builder.build()?.into())
    }
}
```

接下来计划给 sscache 增加 OSS 的原生支持～

等 sccache 下一次发版的时候，我就可以彻底干掉 databend CI 中 cccache，使用上游的 sscache 来替换。据说 sscache 同样会被用到 Firefox CI 之中，非常期待，感觉真的在改变世界。

## 事后感想

- Show Me The Code：实际的代码比抽象的 Proposal 更能打动人心，所以在提这种大型重构的时候附上一个简单的 PoC 来说明自己的思路往往更容易获得维护者的支持
- 长期维护的价值：项目的维护者往往更在意项目的长期维护承诺，而不是项目短期的优势和 Fancy 特性
- 代码风格和文档：这些都是长期的背后工作，但是在项目决策时候却会成为很重要的考量因素，Sccache 看重 OpenDAL 的一点就是丰富的文档和代码比现有的好很多

在 Databend / Greptime / Sccache 之后，OpenDAL 如果再能找到两个社区大用户，并且能找到几位 Committer 的话，感觉就能开始捐赠给 Apache 的工作，有点期待。

冲！
