想起以前做項目,用到了Rsync check 文件內(nèi)容,未免以后忘記,現(xiàn)在整理下 大致邏輯
背景:
? ? ? ?我們新建一個文件,上傳,再改動一點點東西,通用辦法就是,把改動后的文件,上傳覆蓋以前的文件,這樣不會錯,但是有個問題,如果這個文件很大,那么整個上傳就會消耗大量的時間和流量,哪怕我們只是編輯了一個標點符號。
解決方案:
? ? ? ?那么有沒有什么辦法,我只上傳編輯的部分,那就萬事大吉了,但是沒有編輯的部分,我怎么告訴server 呢,我可以告訴server ,我沒有改變的部分的 offset ,比如: 0-121 byte,180- 300byte,編輯的部分我上傳data,那么最后的結(jié)果是什么呢:
0-121byte(location),122-179byte(data),180-300 byte.
?????那么,我怎么找出編輯的部分呢,大致方案如下:
? ? 1. 我將原內(nèi)容分割成若干部分(具體每部分多大,根據(jù)文件大小確定),每部分通過算法,得到兩個值,sha -> sum1,md5 ->sum2?
? ? 2. 我將編輯后的文件,按照同樣大小,分割,依次對比,如果發(fā)現(xiàn)sum1 和 sum2 都一樣,那么我們認為這部分是以前的內(nèi)容,記錄下來
? ? 3. 遇到sum1 不一致,或者sum1一致,sum2 不一致的內(nèi)容(這就是為什么要通過兩個算法去校驗,sum2 準確,但是消耗性能,sum1 性能消耗較低,但是不準確),那么我們往后移動一個byte,這一個byte 作為新增的內(nèi)容,記錄下位置,接著從移動過后的位置對比
????4. 一個字節(jié)一個字節(jié)的添加太麻煩,還有如果重用的部分是連續(xù)的,那么我們可以添加邏輯把連續(xù)新增的字節(jié)或者連續(xù)重用的字節(jié)連起來,最后上傳的時候,再上傳連起來的部分的offset 和data
? ? 大致的邏輯就是這樣,但是有個問題:
? ? 原內(nèi)容:[(sum1,sum2),(sum1,sum2),(sum1,sum2).......]
? ? 我們計算編輯后的文件的時候,拿到sum1 和sum2 ,怎么去對比呢,要知道,上面的數(shù)組是相當龐大的,你要挨個去對比,我的天,性能災難,得不償失。
? ? 有什么辦法呢,如果能想key ,value 這樣挨個對應起來就好了,這樣,直接找key,看value 是否有值。
? ??原內(nèi)容:[{sum1:{sum2:xxxxx,location :123-456}}.......]
? ? 但是,這樣有新的問題:
? ? ? ? ? ? 1. sum1 有可能碰撞(不精確)
? ? ? ? ? ? 2. sum1 還是很長,key value 都很長,這樣的性能我們是無法接受的
? ? 如果有什么辦法,能夠?qū)um1 或者sum2 編程一個數(shù)字或者簡單的字符就好了。
? ? 網(wǎng)上找找,果然有,將可以通過一個算法將sum1 變成一個 數(shù)字:
? ? ? ? ? ? ? ? f(sum1) -> 10233
? ? 我們再構(gòu)建一個hashtable 樣子, 表的樣子是什么呢
? ? hashTable[10233] = i, i 表示在原文件中的第幾端,至于其他的都設置成-1,最后結(jié)果
? ? hashTable[0] = -1,....hashTable[10233] = 0,......
? ? 我們拿到編輯后的文件段的sum1, 通過同樣的運算, 獲得的值也是 10233, 那么我們拿這個10233 反過來找hashTable, 發(fā)現(xiàn)value 不是-1, 恭喜你可能找到了,這時再對比下sum2,這樣就能最終確定了,這樣是不是性能提高了很多
? ? 但是還有一個問題,不同內(nèi)容的sum1 可能一樣啊,這咋整,也就是,可能第57 段和第89段的sum1都是10233,那么結(jié)果就是,后面的把前面的覆蓋,結(jié)果就是 hashTabel[10233] = 89
? ? 這咋整?
? ? 我們想如果能記錄后一段,也就是在覆蓋前一段的時候能夠把前一段的location 記錄下來就好了,ok,那么我們新定義一個變量chain,通常情況下,chain值為-1,只有發(fā)現(xiàn)hashTable[10233]有值時,我們把后一個位置的chain 設置成前一個位置的location,這樣是不是就不怕覆蓋了,結(jié)果就是,假設第0,57,89 的結(jié)果都是10233,那么:
hashTable[10233] = 89, data[89].chain = 57, data[57].chain = 0
代碼如下:
for I in 0..<count {
? ? ? ? ? ? ? ? let sumData = file.sums[I] ? ? ? ?
?????????? ? ? ?let t =self.getHashEntry( sum1: sumData.sum1,true)
? ? ? ? ? ? ? ? let subsum = file.sums[i]
? ? ? ? ? ? ? ? subsum.chain=hashTable[Int(t)]
? ? ? ? ? ? ? ? self.hashTable[Int(t)] = i
? ? ? ? ? ? }
perfect!