大多数操作系统根本不管复制有没有出错,只管复制过程有没有出错。这中间是有区别的。得说细一些。
检查复制没出错需要做复制校验,这事是有几个层次的。
最直观的,也是成本最高的,就是把复制过去的东西再拿来读一遍,和来源全部对照一遍。叫做全读校验。很显然,这是一定能确认复制没有错的方法。然而它也很显然太“贵”了,因为等于源数据要读至少两遍,拷贝数据要读至少一遍写至少一遍,相比不检查多出了许多工作量。而且对很多应用场景来说,这甚至是做不到的。所以大多数操作系统默认不做这种程度的校验。
为什么很多场景下做不到?因为复制数据的场景比大多数人直观想象要复杂得多,简单直接顺利的情景占不到全部的九成。比如,最令人讨厌情况有复制数据到慢速设备,写入10Mbps读取0.1Mbps,全读校验花的时间是复制本身的100倍。还有各种复制锁无法保证的情况。例如源数据在校验过程中改变了,或者你只有目标的写权限没有读权限,或者你的来源数据只能读一遍的情况。大量常见场景使得全读校验无法实现。
不用这种一定能确认复制没错的方法,还有什么别的办法吗?那就分好几种妥协方法了。
有些操作系统采用的妥协省事方法是hash校验。复制的目标端有某种内置方法生成文件hash值,复制过程生成源数据的hash值,复制完成时对照一下两个hash,一致就ok。这是一种比较聪明的低成本近似全读校验的办法。这个方法显然需要目标支持生成hash的方法,不然就得再读一遍了,所以适用场景有限。
再弱一些,也就是Windows和大多数操作系统都支持的方法,就是管道可靠性校验,也就是只管复制过程有没有出错。思路是这样的:我读的时候要求读数据管道确认读没出错,写的时候要求写数据管道确认写没出错,那基本的数据一致性就得到保证了。具体实现细节就不展开说了,情景其实也很复杂。只要知道这种校验其实可以很弱,但总归比没有强太多。Windows用户在复制文件时看到的CRC循环冗余校验错误实际上就是在写管道上的校验机制不能通过报的错。这种方法也往往是所有其他更复杂校验的基础。
为什么说这种校验可以很弱呢?因为管道的可验证性在很多常见条件下是很弱的。有时候甚至管道并没有办法去确认有没有出错。比如直到SATA年代硬盘的指令才有统一的校验机制,在此之前很可能你让硬盘写数据你是无法判断硬盘到底有没有干这事的。外加这个方法其实不能覆盖端到端,因为读出来的数据会停留在内存一段时间,而普通的内存是没有数据一致性保护的。所以有少数运气不好的用户会发现内存损坏导致复制出现错误,而复制过程不报错的现象。
大多数操作系统不管这事,错了就错了。
有些软件本身会额外校验,这算加了个保险。
某些文件系统本身就对数据块有校验,这算是在系统底层加了道保险(但这不是系统自己的功能),比如ZFS这样的文件系统,每个数据块都带校验,但这仍然属于软件层面的活,而不是磁盘扇区校验这种硬件级的手段。
磁盘(或者其他存储设备)在数据介质上都有额外编码用于校验或纠错(以扇区为单位?),发现数据不对会尝试重新读取或者纠错,如果多次尝试后仍然失败/操作超时/严重错误则会自行记录(磁盘的S.M.A.R.T功能)并且提交到操作系统,告诉用户“哥们,我尽力了,节哀顺变吧”。
磁盘的数据从内部电路出来,要经过SATA或者其他接口,可能要再过PCI-E接口,途中可能还得在内存中留一份拷贝,完事可能还得从网络接口出去……每一次接口通信都是一场冒险,天晓得数据会不会出错,有时候会出点可以纠正的小错误,硬件失效/环境干扰则会出大错(磁盘S.M.A.R.T里有一项叫ECC错误,如果数值经常增大那说明SATA口或者SATA线有点毛病,不过这个过程本身是带纠错的,所以报错不代表数据出错)。
所以本着“早发现早治疗”的原则,这些高速接口都带验证和纠错,能改就改,不能改就丢弃重传,实在不行就向上报错。
所以,如果硬件可靠,那么整个数据传输过程亦可靠,操作系统不会劳神费心做额外检测。有些文件系统自带数据分块校验的功能,这属于特定软件的特性。
如果硬件不靠谱,大多数错误都会被上报或者记录下来,比如文件传到一半停下来没速度了,可能就是磁盘发现扇区读到的数据校验不通过,在尝试重新读取,如果很久都没响应那这个扇区十有八九完蛋了,有时候磁盘 的控制电路出毛病了,往往会直接报IO错误。
但是有个硬件例外,错了就是错了,不报错,等到发现不对一切都晚了,这就是普通内存(另外还有带校验的内存,算是加了道保险,服务器常用)。内存整个失效那就不多说了,如果颗粒内部数据位翻转,这种事天知地知但你我不知,如果有机会这部分变形的数据还能被写回磁盘盖掉原始数据,这也是为什么有些软件和文件系统要额外加校验的原因。
留言与评论(共有 0 条评论) |