3

笔记:

这是故意标记为 Clojure 和 Git 的,因为我很高兴在软件的 Clojure 和 Git 端重新设计以使事情正常运行。

问题:

我有一堆 clojure 数据结构。当写入磁盘(使用 pr)时,它们平均每个大约 100 kb。我有大约 1000 个这样的文件。这些文件是“结构化”文档——将它们视为等同于 SVG。

现在,我正在对这些文件中的每一个进行大量小更新(添加/删除节点,更改节点上的属性)。(然后我(写(pr ...))这些文件出来。

最后,我将所有这些文件存储在我的 git 存储库中。

问题:

我想知道是否有一种有效的方法来存储这些文件(因为不同的写入只有很小的修改)——也就是说,如果我在内存中有一个文档的两个副本,它将是 1MB + epsilon,而不是 2MB(因为这两个文档只有细微的差别,并且共享大部分结构。)

我想以某种方式利用这个事实,当它被存储到 git 中时,是否可以利用这种相似性。

可能考虑的解决方案:

1)在clojure方面,不要写出整个文件,而是只写一个“与前一个文件的差异[由assoc,dissoc]组成”。<-- 这需要大量的工程。

2) 在 FS 方面,不是存储单个文件,而是将整个目录放入 bzip,然后将其作为单个 *.bz2 提交(因此,相似的文件将具有相似的块)。不利的一面是,在 git 中查找 *.bz2 文件似乎不是一个坏主意。

4

2 回答 2

3

您是否考虑过使用Datomic而不是 Git?

你正在做的事情听起来像是 Datomic 的一个大致理想的用例,它本质上是一个 Clojure 风格的“事实图”数据库——这几乎就是你的结构化数据的样子。

Datomic 以非常类似于 Clojure 的不可变数据结构的方式存储数据,即它使用结构共享来确保小的更改只需要少量的额外空间。它以类似于 git 的方式保存整个历史记录 - 甚至还有一个工具可以在 Datomic ( codeq )中模拟 git repos

于 2012-12-09T20:38:18.727 回答
1

这是一个有趣的问题。让我们看看我们能做些什么。

在内部,Git 将您添加到存储库的文件的完整副本保存在其数据库中。但是,当您运行git gc以优化本地存储库时,Git 会将松散的对象打包到包文件中。类似的文件使用增量压缩存储在包文件中。引用Pro Git

当 Git 打包对象时,它会查找名称和大小相似的文件,并仅存储从一个文件版本到下一个文件版本的增量。

因此,优化了 Git 中类似文件的存储并减少了空间使用。

让我们从内部转到用户界面部分。从用户的角度来看,Git 是基于差异的。当您浏览提交、合并补丁和查看更改时,您主要处理的是差异。差异是面向行的。因此,单个行中的最小更改会导致该行的旧版本和新版本作为一个整体存储在生成的差异中。我们如何使您描述的文件之间的差异更易于阅读?使线条更短。我看到了两种简单的方法来实现它。

首先,不要保存 Clojure 数据结构,而是将它们转换为YAML。以 YAML 格式存储数据的文件具有相对较短的行,可以解决问题。clj-yaml应该会派上用场。

如果您坚持将数据存储为 s 表达式,则第二个想法是将生成的文件中的所有空格替换为换行符。如果可读性很重要,您可以在之后缩进它们。在应用一个简单的正则表达式替换每个空格之前,\n请检查您是否有任何带有空格的字符串。

于 2012-12-09T15:31:18.447 回答