流式rdiff - 差异比较?

1 投票
1 回答
2454 浏览
提问于 2025-04-16 11:57

我有一个产品,用来进行在线备份,使用的是rdiff。现在的流程是这样的:

  1. 先把文件复制到一个临时区域(这样在处理文件的时候,它就不会消失或者被修改)

  2. 对原始文件进行哈希计算,并生成一个rdiff签名(这个是用来做差异比较的); 如果之前没有版本,就跳过计算rdiff的差异步骤。

  3. 对生成的差异结果进行压缩和加密。

目前,这些步骤是分开进行的。最终的结果是我们需要多次处理同一个文件。对于小文件来说,这没什么大不了的(尤其是考虑到磁盘缓存),但对于大文件(比如几十GB甚至上百GB),这就会严重影响性能。

我想把这些步骤合并成一次读写操作。

为了做到这一点,我们需要能够以流的方式执行上述所有步骤,同时保留所有的“输出”——文件哈希、rdiff签名、压缩和加密后的差异文件。这意味着我们需要从源文件中读取一块数据(比如100k),然后在内存中处理这个文件,更新哈希、rdiff签名,进行差异比较,然后将结果写入一个压缩/加密的输出流。目标是大大减少磁盘的频繁读写。

目前我们使用rdiff.exe(这是在底层的librsync库之上的一个薄层)来计算签名和生成二进制差异。这意味着这些操作是在一个单独的进程中完成的,而不是以流的方式进行。

我该如何使用librsync库来实现我需要的功能呢?

1 个回答

0

你可以完全跳过第一步。文件在打开的时候是不能被删除的,而且在打开文件时选择合适的锁定标志可以防止文件被修改。例如,CreateFile 函数有一个叫做 dwShareMode 的参数。

在开始创建 rdiff 差异文件之前,你需要先计算整个 rdiff 签名。你可以通过每次计算文件的每个(比如说)100MB 块的签名和差异,来避免读取整个文件。这样做会损失一些压缩效率*。你也可以考虑从 rdiff 切换到 xdelta,它可以在一次读取中创建差异文件。

压缩和加密可以和计算差异同时进行。如果压缩和加密是由不同的程序完成的,它们通常允许从标准输入读取和写入到标准输出。比如在批处理文件中可以通过管道轻松实现:

rdiff signature oldfile oldfile.sig
rdiff delta oldfile.sig newfile | gzip -c | gpg -e -r ... > compressed_encrypted_delta

如果你在程序中使用压缩/加密的库,你需要选择支持流式操作的库。

*如果文件中的数据被移动,效率会损失得很严重。如果有人在一个10GB的文件前面加了100MB,rdiff会生成大约100MB的差异文件。而如果每次处理100MB或更小的块,rdiff会生成大约10GB的差异文件。处理200MB的块会生成大约5GB的差异,因为每个块中只有一半的数据来自于旧版本文件的对应块。

撰写回答