bsdiff差分算法

bsdiff的基本原理

 bsdiff是由Conlin Percival開源的一個優秀的差分算法,並且是跨平臺的。在Android系統中所使用的imgdiff本質上就是bsdiff。html

bsdiff的依據c++

在傳統更新中,包含了複製和插入兩種操做,複製指的是找到old文件中所匹配的部分,將其複製到新文件中。插入指的是將old文件中所沒有的數據插入到新文件中。這種方式在二進制文件更新中並不適用,由於對源代碼進行少許的修改就會致使二進制文件產生較大的差別,從而複製和插入指令增多,生成的更新包遠大於理想狀態。因此bsdiff並無這樣作,在一個新的二進制文件,每每會包含這樣幾部分:不受更新代碼影響的部分,更新代碼後直接影響的部分,更新代碼後間接影響的部分。算法

不受更新代碼影響的部分:這一區域變化很是稀疏,即便有變化也是部分指針或寄存器的地址進行了一兩個字節的變更,這就致使字節差別幾乎爲0ide

更新代碼後間接影響的部分:在更新了源代碼後,有些代碼和數據的地址會發生偏移,並且偏移值相同。網站

也就是說,在新舊兩個文件中,源代碼塊相同的部分,字節差別爲0或一個固定值,這個固定值就是地址變化的偏移量。因爲這一特性,致使產生的數據將會是高度可壓縮的。在bsdiff算法中會找到這兩部分,求出字節差別,做爲diff string並進行壓縮保存。google

如圖在old中添加代碼塊1(和代碼塊A不相關),在二進制文件中會致使代碼塊A的地址發生偏移,偏移值是相同的,這樣old中的代碼塊A和new中的代碼塊A求字節差別時就會爲一個固定值,具備高度可壓縮性。spa

更新代碼後直接影響的部分:如上圖,當添加了代碼塊1後,會致使二進制文件產生新的數據,這部分數據在old中並不存在,bsdiff算法會將其做爲extra string進行壓縮保存。因此到這裏咱們可以得出bsdiff的更新數據=diff string+extra string。.net

bsdiff更新數據的基本結構     指針

bsdiff更新數據由四部分組成:Header,ctrl block,diff block,extra block。code

Header的結構:                                          

start/bytes length/bytes content
0 8 "BSDIFF40"
8 8 the length of ctrl block
16 8 the length of diff block
24 8 新文件的大小

 

 

 

 

ctrl block:這部份內容是由(x,y,z)組成。x表明從old中讀取x字節和diff block中讀取x字節作字節加運算,y表明從extra block中讀取y字節數據而且插入到新文件中,z表明在old中向前移動z字節。

diff block:記錄了diff string,也就是字節的差值

extra block:記錄了new文件中新生成的字節值

算法基本分析

bsdiff主要能夠分爲三部分:

1.經過排序技術對old文件的內容進行排序,造成字典序。這裏的排序使用的是後綴排序時間複雜度nlogn,空間複雜度O(n),固然也能夠使用hash技術進行排序。

2.經過二分法查找最長的匹配len,有了這個len,就能夠計算出diff string,和extra string.

3.將diff string+extra string壓縮到更新文件中。

關於後綴排序和二分法查找能夠自行百度或google。下面邊閱讀代碼邊進行分析

	off_t *I; 
	off_t scan,pos,len;
	off_t lastscan,lastpos,lastoffset; 
        off_t oldscore,scsc;
	off_t s,Sf,lenf,Sb,lenb;

上面有幾個變量表明的意義,對分析算法有着很重要的意義。I表明已經排好的字典序,scan表明new中要查詢的字符,pos表明old中相匹配的字符,len表明匹配的長度,lastscan=scan-lenb,lastpos=pos-lenb。lastoffset=scan-pos。lastoffset爲new和old的偏移量,若是在old中的內容A在new中能夠找到,並且A+lastoffset=new中的A,則認爲old和new中的A相同。oldscore表明相同內容的len,scsc表明new中開始和old中比較是否相同開始的位置,而old中開始的位置是scsc+lastoffset。lenf表明擴展前綴,lenb表明擴展後綴。

 

 1     while(scan<newsize) {  2         oldscore=0;  3 
 4         for(scsc=scan+=len;scan<newsize;scan++) {  5             len=search(I,old,oldsize,new+scan,newsize-scan,  6                     0,oldsize,&pos);  7             printf("len==%d\n",len);  8             for(;scsc<scan+len;scsc++)  9             if((scsc+lastoffset<oldsize) &&
10                 (old[scsc+lastoffset] == new[scsc])) 11                 oldscore++; 12 
13             printf("oldscore+===%d\n",oldscore); 14         
15             if(((len==oldscore) && (len!=0)) || 
16                 (len>oldscore+8)) break; 17 
18             if((scan+lastoffset<oldsize) &&
19                 (old[scan+lastoffset] == new[scan])) 20                 oldscore--; 21             
22             printf("oldscore-====%d\n",oldscore); 23  }; 24 
25         if((len!=oldscore) || (scan==newsize)) { 26             printf("cal len=%d,scan=%d\n",len,scan); 27             s=0;Sf=0;lenf=0; 28             for(i=0;(lastscan+i<scan)&&(lastpos+i<oldsize);) { 29                 if(old[lastpos+i]==new[lastscan+i]) s++; 30                 i++; 31                 if(s*2-i>Sf*2-lenf) { Sf=s; lenf=i; }; 32  }; 33             printf("Sf=%d,lenf=%d\n",Sf,lenf); 34             lenb=0; 35             if(scan<newsize) { 36                 s=0;Sb=0; 37                 for(i=1;(scan>=lastscan+i)&&(pos>=i);i++) { 38                     if(old[pos-i]==new[scan-i]) s++; 39                     if(s*2-i>Sb*2-lenb) { Sb=s; lenb=i; }; 40  }; 41                 printf("Sb=%d,lenb=%d\n",Sb,lenb); 42  }; 43              
44             if(lastscan+lenf>scan-lenb) { 45                 overlap=(lastscan+lenf)-(scan-lenb); 46                 s=0;Ss=0;lens=0; 47                 for(i=0;i<overlap;i++) { 48                     if(new[lastscan+lenf-overlap+i]==
49                        old[lastpos+lenf-overlap+i]) s++; 50                     if(new[scan-lenb+i]==
51                        old[pos-lenb+i]) s--; 52                     if(s>Ss) { Ss=s; lens=i+1; }; 53  }; 54 
55                 lenf+=lens-overlap; 56                 lenb-=lens; 57  }; 58 
59             for(i=0;i<lenf;i++) 60                 db[dblen+i]=new[lastscan+i]-old[lastpos+i]; 61             for(i=0;i<(scan-lenb)-(lastscan+lenf);i++) 62                 eb[eblen+i]=new[lastscan+lenf+i]; 63 
64             dblen+=lenf; 65             eblen+=(scan-lenb)-(lastscan+lenf); 66 
67  offtout(lenf,buf); 68             BZ2_bzWrite(&bz2err, pfbz2, buf, 8); 69             if (bz2err != BZ_OK) 70                 errx(1, "BZ2_bzWrite, bz2err = %d", bz2err); 71 
72             offtout((scan-lenb)-(lastscan+lenf),buf); 73             BZ2_bzWrite(&bz2err, pfbz2, buf, 8); 74             if (bz2err != BZ_OK) 75                 errx(1, "BZ2_bzWrite, bz2err = %d", bz2err); 76 
77             offtout((pos-lenb)-(lastpos+lenf),buf); 78             BZ2_bzWrite(&bz2err, pfbz2, buf, 8); 79             if (bz2err != BZ_OK) 80                 errx(1, "BZ2_bzWrite, bz2err = %d", bz2err); 81 
82             lastscan=scan-lenb; 83             lastpos=pos-lenb; 84             lastoffset=pos-scan; 85  }; 86     };

這一部分是bsdiff的核心,主要的工做就是查詢到len,比較new和old中的內容是否相同,若是len範圍內都相同則直接進行下一次循環。若是不相同的字節數大於8或scan達到了最大則跳出對應的循環,開始生成lenf,lenb,extra數據等。lenf其實就是diff string,能夠看到diff string就是由lastscan到scan與lastpos到pos這個區間獲得的,這個區間會被劃分爲lenf,表明diff string,而剩下的部分即爲extra string。lenf表明的擴展前綴,其實也就是diff string. lenb表明的是擴展後綴,會在下次生成diff string時包含進去。那麼爲何要這樣作呢?由於在匹配到最長的len後,bsdiff並非直接將匹配到的內容打包,而是從lastscan到scan開始前向延伸進行後綴擴展,獲得lenf,稱爲擴展前綴。在lastscan也包含了擴展後綴,擴展前綴和擴展後綴必須至少有50%與old相同。如圖所示:

算法實例

下面以一個例子解釋bsdiff運行過程:

old:abcdfghilklmnopqrstuvwxyz1234567890abcd

new:abcdffhijkluvaxyz123456789zxcvbnm

1.首先獲取到字典序

 1 qsufsort:I[0]==40,0,
 2 qsufsort:I[1]==39,10,
 3 
 4 qsufsort:I[2]==34,48,0abcd
 5 
 6 qsufsort:I[3]==25,49,1234567890abcd
 7 
 8 qsufsort:I[4]==26,50,234567890abcd
 9 
10 qsufsort:I[5]==27,51,34567890abcd
11 
12 qsufsort:I[6]==28,52,4567890abcd
13 
14 qsufsort:I[7]==29,53,567890abcd
15 
16 qsufsort:I[8]==30,54,67890abcd
17 
18 qsufsort:I[9]==31,55,7890abcd
19 
20 qsufsort:I[10]==32,56,890abcd
21 
22 qsufsort:I[11]==33,57,90abcd
23 
24 qsufsort:I[12]==35,97,abcd
25 
26 qsufsort:I[13]==0,97,abcdfghilklmnopqrstuvwxyz1234567890abcd
27 
28 qsufsort:I[14]==36,98,bcd
29 
30 qsufsort:I[15]==1,98,bcdfghilklmnopqrstuvwxyz1234567890abcd
31 
32 qsufsort:I[16]==37,99,cd
33 
34 qsufsort:I[17]==2,99,cdfghilklmnopqrstuvwxyz1234567890abcd
35 
36 qsufsort:I[18]==38,100,d
37 
38 qsufsort:I[19]==3,100,dfghilklmnopqrstuvwxyz1234567890abcd
39 
40 qsufsort:I[20]==4,102,fghilklmnopqrstuvwxyz1234567890abcd
41 
42 qsufsort:I[21]==5,103,ghilklmnopqrstuvwxyz1234567890abcd
43 
44 qsufsort:I[22]==6,104,hilklmnopqrstuvwxyz1234567890abcd
45 
46 qsufsort:I[23]==7,105,ilklmnopqrstuvwxyz1234567890abcd
47 
48 qsufsort:I[24]==9,107,klmnopqrstuvwxyz1234567890abcd
49 
50 qsufsort:I[25]==8,108,lklmnopqrstuvwxyz1234567890abcd
51 
52 qsufsort:I[26]==10,108,lmnopqrstuvwxyz1234567890abcd
53 
54 qsufsort:I[27]==11,109,mnopqrstuvwxyz1234567890abcd
55 
56 qsufsort:I[28]==12,110,nopqrstuvwxyz1234567890abcd
57 
58 qsufsort:I[29]==13,111,opqrstuvwxyz1234567890abcd
59 
60 qsufsort:I[30]==14,112,pqrstuvwxyz1234567890abcd
61 
62 qsufsort:I[31]==15,113,qrstuvwxyz1234567890abcd
63 
64 qsufsort:I[32]==16,114,rstuvwxyz1234567890abcd
65 
66 qsufsort:I[33]==17,115,stuvwxyz1234567890abcd
67 
68 qsufsort:I[34]==18,116,tuvwxyz1234567890abcd
69 
70 qsufsort:I[35]==19,117,uvwxyz1234567890abcd
71 
72 qsufsort:I[36]==20,118,vwxyz1234567890abcd
73 
74 qsufsort:I[37]==21,119,wxyz1234567890abcd
75 
76 qsufsort:I[38]==22,120,xyz1234567890abcd
77 
78 qsufsort:I[39]==23,121,yz1234567890abcd
79 
80 qsufsort:I[40]==24,122,z1234567890abcd
View Code

2.new:abcdffhijkl-old:abcdfghilkl 字節值相減得到diffstring

3.new:uvaxyz123456789-old:uvwxyz123456789 字節值相減得到diff string

4.zxcvbnm做爲extra string進行打包

5.經過bzip2壓縮生成升級文件。bzip2具備高度可壓縮性,很是適合bsdiff

 

參考連接:

bsdiff官方網站

http://www.daemonology.net/bsdiff/

bsdfii介紹

http://www.daemonology.net/papers/bsdiff.pdf

bsdiff理解

https://cloud.tencent.com/developer/article/1008518

bsdiff理解

https://blog.csdn.net/darling757267/article/details/80652267

編譯bsdiff所遇到問題的解決方法

http://www.javashuo.com/article/p-aiocgmho-cw.html

相關文章
相關標籤/搜索