#diff #undo #binary #数据管理 #json5 #二进制数据 #autosave

docchi

一种基于差异的数据管理语言,用于实现无限撤销、游戏的自动保存以及需要频繁保留更改的云应用。

5个版本

0.8.0 2021年12月8日
0.7.3 2021年12月3日
0.7.2 2021年11月25日
0.7.1 2021年11月25日
0.7.0 2021年11月21日

#281 in 压缩

每月32次下载

MIT/Apache

575KB
12K SLoC

crates.io link

Docchi是一种基于差异的数据管理语言,用于实现无限撤销、游戏的自动保存以及需要频繁保存更改的云应用。

Docchi是一种语言,因此API文档并不适合学习。你可能需要阅读用户手册

  • Rust支持的最小版本

1.57.0(稳定版)

  • 演示

演示

测试数据

{
  "data0": "oiufsjdsj...", //1 MB of random string
  "data1": "abuisoehg...", //1 MB of random string
  //...
  "data9": "bhsiofdis...", //1 MB of random string
}

伪代码

for i in 0..100{
    modify_one_string(json.get_data_mut(rand.gen_range(0..10)));
    let s = serde_json::to_string(&json);
    let mut file = std::fs::File::create(format!("{}/d{}.json", json_dir, i))?;
    file.write_all(s.as_bytes())?;
}

JSON包含十个随机的1 MB字符串,因此整个JSON文件约为10 MB。

我们一次修改一个字符串,并以JSON格式保存,重复了100次。文件总数约为1 GB。

这意味着每次修改了10%的数据。数据通常只部分修改,因此10%并不是非常不常见。

相当于Docchi数据被创建、修改和保存了100次。

Docchi只保存"差异"。在最理想的情况下,只保存1 MB的修改数据。

结果如下

JSON
sum of file sizes 1021435957
1906 milliseconds

Docchi
sum of file sizes 173005171
604 milliseconds

JSON保存了约1 GB的数据,耗时1906毫秒。

Docchi保存了约173 MB的数据,耗时604毫秒。

Docchi只占用了17%的存储空间,约三分之一的时间。

怎么样?

Docchi只保存了17%的数据,所以当然更快。

为了比较,我们将JSON字符串的长度改为17%,然后运行演示。

JSON(short)
sum of file sizes 173570901
338 milliseconds

文件大小大致相同,JSON比Docchi快两倍。

Serde非常快,因此结果是合理的。

但我认为Docchi的开销是合理的,Docchi可以以非阻塞方式保存,因此保存时间可能不会降低用户体验。

*加载演示

加载是Docchi付出代价的地方。Docchi创建"差异层次结构"。

Diff Hierarchy Concept

Diff0(10 MB) - Diff00(1 MB) - Diff000(1 MB)
                                   │
                              Diff001(1 MB)
                                   │
                              Diff002(1 MB)
             - Diff01(5 MB) - Diff010(1 MB)
                                   │
                              Diff011(1 MB)
                                   │
                              Diff012(1 MB)
                                  ...
             - Diff02(10 MB)- Diff020(1 MB)
                                   │
                              Diff021(1 MB)
                                  ...
                  ...
 Diff1(10 MB)
   ... 

要加载Docchi的差异,我们必须从顶部到底部按层次加载文件,并重复应用差异。

我们使用了Docchi的默认设置,最多需要13个文件来加载一个数据。

要加载的总文件大小可以是最大差异文件(在这种情况下为10 MB)的四倍,因此为40 MB。

我们从层次结构中搜索最深的文件并加载数据。

Docchi 
40 milliseconds

JSON
94 milliseconds

JSON(Short)
16 milliseconds

Docchi 的数据总量是 JSON 的 4 倍,但比 JSON 快超过 2 倍。

Docchi 是一种二进制数据格式,并且高效地多线程加载,所以它能够击败 Serde,我想。

* 如何做到这一点?

构造差异是一个成本很高的自然过程,但 Rust 的 Arc(原子引用计数指针)使它变得非常简单。

Docchi 的数据在保存时被克隆,因此可以进行非阻塞保存。Docchi 的数据由 Arc 组成,所以克隆可以瞬间完成。

使用 Arc::make_mut,当两个不同的 Arc 指向同一对象并且其中一个被修改时,实际上会发生内部数据的复制。当它被修改时,两个 Arc 指向不同的对象,所以比较两个 Arc 指针的指针就足够确认是否被修改。比较实际值是不必要的。

实际复制发生在实际要修改的部分。复制一切也是不必要的。Rust 的 Arc 真的是神奇的。

在比较数据和构造差异时,我们比较当前对象与保存时克隆的对象,并比较指针。这是一个非常快速的过程。

另一方面,我们在加载时没有做任何特别的事情。如果它很快,那要归功于 Rayon。

许可证

根据您的选择,许可权为以下之一

自行决定。

贡献

除非您明确表示,否则根据 Apache-2.0 许可证定义的,您有意提交的任何贡献,包括在本工作中,将如上所述双重许可,没有任何额外的条款或条件。

我非常期待有人能

  • 纠正我的英语(我不是英语母语者)
  • 批评我的代码/API

依赖关系

~8MB
~151K SLoC