可以恢复失败的文件传输的程序如何知道从哪里开始追加数据?

可以恢复失败的文件传输的程序如何知道从哪里开始追加数据?

某些文件复制程序rsync可以curl恢复失败的传输/副本。

请注意,导致这些故障的原因可能有很多,在某些情况下,程序可以进行“清理”,而在某些情况下,程序则不能。

当这些程序恢复时,它们似乎只是计算成功传输的文件/数据的大小,然后开始从源读取下一个字节并附加到文件片段。

例如,“到达”目的地的文件片段的大小为 1378 字节,因此它们只是从原始文件的字节 1379 开始读取并添加到片段中。

我的问题是,知道字节是由位组成的,并且并非所有文件都将数据分段为干净的字节大小的块,这些程序如何知道它们选择开始添加数据的点是正确的?

当写入目标文件时,会在程序、内核或文件系统级别发生某种类似于 SQL 数据库的缓冲或“事务”,以确保只有干净、格式良好的字节才能到达底层块设备?
或者程序是否假设最新的字节可能不完整,因此他们在假设其损坏的情况下将其删除,重新复制该字节并从那里开始附加?

知道并非所有数据都表示为字节,这些猜测似乎不正确。

当这些程序“恢复”时,它们如何知道它们是在正确的位置开始的?

答案1

为了清楚起见 - 真正的机制更加复杂,以提供更好的安全性 - 您可以想象像这样的写入磁盘操作:

  • 应用程序写入字节(1)
  • 内核(和/或文件系统 IOSS)缓冲它们
  • 一旦缓冲区满了,它就会得到到文件系统:
    • 该块已分配 (2)
    • 该块已写入 (3)
    • 文件和块信息已更新 (4)

如果进程在 (1) 处中断,则磁盘上不会有任何内容,文件完好无损并在前一个块处被截断。您发送了 5000 个字节,磁盘上只有 4096 个字节,您在偏移量 4096 处重新启动传输。

如果在(2)处,除了内存之外什么都没有发生。与(1)相同。如果在(3)处,数据被写入但没有人记得这件事。您发送了 9000 个字节,已写入 4096 个字节,已写入 4096 个字节并迷失了,剩下的就迷失了。传输在偏移量 4096 处恢复。

如果处于 (4),则数据现在应该已提交到磁盘上。流中的下一个字节可能会丢失。您发送了 9000 个字节,8192 个字节被写入,其余部分丢失,传输在偏移量 8192 处恢复。

这是一个简化的拿。例如,阶段 3-4 中的每个“逻辑”写入都不是“原子”的,而是产生另一个序列(让我们将其编号为 #5),从而将块细分为适合目标设备(例如硬盘)的子块。 )被发送到设备的主机控制器,它还具有缓存机制,最后存放在磁盘上。该子序列并不总是完全在系统的控制之下,因此将数据发送到硬盘并不能保证它已被实际写入并且可以读回。

几个文件系统实现写日记,以确保最脆弱的点 (4) 不是实际上易受攻击,通过写入元数据,你猜对了,交易无论阶段(5)中发生什么,它都将始终如一地工作。

如果系统在交易过程中重置,它可以恢复到最近的完整检查点。写入的数据仍然会丢失,与情况 (1) 相同,但恢复会解决这个问题。不信息实际上迷路了。

答案2

注意:我没有查看rsync任何其他文件传输实用程序的来源。

编写一个跳转到文件末尾并获取该位置(以字节为单位)的位置的 C 程序很简单。

这两个操作都是通过对标准 C 库函数的一次调用来完成的lseek()lseek(fd, 0, SEEK_END)返回为文件描述符打开的文件的长度fd,以字节为单位)。

lseek()一旦对目标文件完成了此操作,就可以对源文件执行类似的调用以跳转到适当的位置: lseek(fd, pos, SEEK_SET).然后,假设源文件的较早部分已被识别为未更改(不同的实用程序可以以不同的方式执行此操作),则传输可以在该点继续。

一个文件可能是支离破碎的在磁盘上,但文件系统将确保应用程序将文件视为连续的字节序列。


关于评论中有关位和字节的讨论:可以写入磁盘的最小数据单位是字节。一个字节至少需要一个堵塞要在磁盘上分配的数据。块的大小取决于文件系统的类型,也可能取决于管理员在初始化文件系统时使用的参数,但通常在 512 字节到 4 KiB 之间。写操作可以由内核、底层 C 库或应用程序本身进行缓冲,并且作为优化,实际写入磁盘可能会以适当块大小的倍数发生。

不可能将单个位写入文件,并且如果写入操作失败,则不会在文件中留下“半写入字节”。

答案3

这基本上是两个问题,因为像curl和rsync这样的程序非常不同。

对于像curl这样的HTTP客户端,它们检查当前文件的大小,然后Content-Range随请求发送标头。服务器要么使用状态代码206(部分内容)而不是(成功)恢复发送文件范围200并恢复下载,要么忽略标头并从头开始,HTTP 客户端除了重新下载所有内容之外别无选择再次。

此外,服务器可以发送也可以不发送Content-Length标头。您可能已经注意到,某些下载没有显示百分比和文件大小。在这些下载中,服务器不会告诉客户端长度,因此客户端只知道下载的数量,但不知道接下来有多少字节。

使用Content-Range带有开始的标头某些下载管理器使用停止位置来一次从不同源下载文件,如果每个镜像本身比您的网络连接慢,则可以加快传输速度。

另一方面,rsync 是一种用于增量文件传输的高级协议。它在服务器和客户端上生成文件部分的校验和,以检测哪些字节相同。然后它只发送差异。这意味着它不仅可以恢复下载,而且如果您在一个非常大的文件中间更改了几个字节而无需重新下载该文件,它甚至可以下载更改的字节。

另一个用于恢复传输的协议是 BitTorrent,其中.torrent文件包含文件中块的校验和列表,因此可以以任意顺序从不同源并行下载和验证块。

请注意,rsync 和 bittorent 将验证磁盘上的部分数据,而恢复 HTTP 下载则不会。因此,如果您怀疑部分数据已损坏,则需要检查完整性,即使用最终文件的校验和。但是,仅中断下载或丢失网络连接通常不会损坏部分文件,而传输过程中的电源故障可能会损坏部分文件。

答案4

取决于用于传输的协议。但curl 使用http,它按照数据在文件中出现的顺序顺序传输数据。因此,curl 可以根据部分完成的传输的文件大小恢复。事实上,您可以通过创建长度为 N(任何内容)的文件并要求它将该文件视为部分完成的下载(然后丢弃前 N 个字节)来欺骗它跳过前 N 个字节。

相关内容