(转)文件增量同步算法实现

ref https://www.xuebuyuan.com/3203628.htmlhtml


 

问题:算法

如何增量同步文件,例如一个文本文件有10M,分别存放在A,B两个地方,如今两个文件是彻底同样的,可是我立刻要在A上对这个文件进行修改,B如何实现自动和A上的文件保持一致,而且网络的传输量最少。服务器

 

应用场景:网络

这样的使用场景太多,这里随便列举几个post

1.A机器为线上运营的机器,如今须要一台备份的机器B,当A发生宕机的时候,或者硬盘损坏等各类认为非人为缘由致使数据不可用时,能够很快从B恢复ui

2.SVN这样的应用场景,不须要每次修改都向服务器发送并替换掉一个文件,而是只发送被修改的部分spa

3.手机客户端对一个文本修改,若是那个文本有2M,难道我每次更新都须要上传整个文件吗?每次2M,傻子才用! 3d

等等.... code

 

解决方案:orm

.分而治之

计算机最重要的基本算法思路就是分而治之,在咱们眼里,一个文件不是一个文件,而是一堆存储块,每一个存储块可能20Byte大小,至于这个值具体多大,你能够本身设定,这里的20Byte仅提供参考。经过这样的方法,一个文件被分红了不少个块,咱们只须要比对块是否相同就能够得出哪一个部分作了相应修改。

 

.快速校验

刚上面提到如何比对文件,固然这里确定不会把文件的每一个块上传去比对,那样作就没有意义了。快速比对这不由让我想起了哈希规则,哈希表能够经过O(1)的复杂度查找某个key,为何?  由于它经过计算hash值来初步验证key,一个key的hash值是惟一的。可是仅仅验证hash值是不可靠的,由于hash值有可能会冲突,因此在验证完hash值后,咱们在进行key的比较来肯定要找的值...

经过哈希的思路,咱们可使用相似的方法来实现文件增量同步,把每个存储块,经过MD5计算其值,而后传递MD5值到服务器,让服务器比对MD5来肯定有没有被修改,如若MD5值不相等,则断定这个文件块有被修改过

为何是MD5?

1)可以将任意长度的字符串转换为128位定长字符串(MD5 16) 

2)MD5可以保证绝大部分状况下不一样的值hash以后其hash值不同,哈希冲突比较少

这样就能够了吗?

No,MD5的生成须要占用比较长的CPU时间,因此咱们须要寻找一种更简洁的校验方式,这里选用Alder32 是一个比较通用的解决方案

 

Alder32有两个优势: 
一、计算很是快,比MD5快多了,成本小;
二、当咱们有了从0-k长度的校验和后,计算出1-k或者2-k等其余校验和很是方便,只要少许运算便可。(k能够理解为上面的20Byte)

 

固然,它的缺点也很明显,就是碰撞率比MD5高多了,因此,咱们客户端须要同时计算出Alder32校验和与MD5值,传给服务器,而服务器,为了节省CPU时间,第一步只生成Alder32进行校验,当值相等时,在进行MD5校验,这样服务器就节省了很大的开支。

Alder32算法实现:

 
 A = 1 + D1 + D2 + ... + Dn (mod 65521)
 B = (1 + D1) + (1 + D1 + D2) + ... + (1 + D1 + D2 + ... + Dn) (mod 65521)
   = n×D1 + (n−1)×D2 + (n−2)×D3 + ... + Dn + n (mod 65521)

 Adler-32(D) = B × 65536 + A

C实现版本

复制代码
const int MOD_ADLER = 65521;

 
unsigned long adler32(unsigned char *data, int len) /* where data is the location of the data in physical memory and 
                                                       len is the length of the data in bytes */
{
    unsigned long a = 1, b = 0;

    int index;

 

    /* Process each byte of the data in order */

    for (index = 0; index < len; ++index)
    {
        a = (a + data[index]) % MOD_ADLER;
        b = (b + a) % MOD_ADLER;
    }

 

    return (b << 16) | a;
}
复制代码

 

三.实现更改

由于已经找出来了文件不一样的地方,因此只须要按需上传更改的部分到服务器,而后服务器作更改就能够了。 

 

 

实例分析: 

理论概述完毕,来点小例子子

客户端文件内容是: 

 taohuiissoman

而服务器的文件内容是:

itaohuiamsoman

 

首先,客户端开始分块并计算出MD5和Alder32值。

如上图,像taoh是一块,对taoh分别计算出MD5和alder32值。以此类推,最后一个n字母不足4位保留。因而,客户端把计算出的MD5和alder32按顺序发出,最后发出字符n。

 

服务器收到后,先把本身保存的File.2的内容按4字节划分。

划分出itao、huia、msom、an,固然,这些串的Alder32值确定没法从File.1里划分出的:taoh、uiis、soma、n找出相同的。因而向后移一个字节,从t开始继续按4字节划分。

从taoh上找到了alder32相同的块,接着再比较MD5值,也相同!因而记下来,跳过taoh这4个字符,看uiam,又找不到File.1上相同的块了。继续向后跳1个字节从i开始看。仍是没有找到Alder32相同,继续向后移,以此类推。

到了soma,又找到相同的块了。

 

重复上面的步骤,直到File.2文件结束。

 

经过这个简单的例子,能够设想一下其余任何的增删查改功能 

 

 

参考资料:http://cs.anu.edu.au/techreports/1996/TR-CS-96-05.pdf 

相关文章
相关标签/搜索