Skip to content

Commit 997778d

Browse files
authored
Improves bsdiff performance by preventing excessive iterations when processing similar data blocks (#2693)
* Port bsdiff optimizations for diffing large blocks that only differ by less than 8 bytes * Retrigger CI * Bump the minor version for major 2, 3, and 4 * Comments for ChromiumOS ported commits
1 parent 1681917 commit 997778d

File tree

2 files changed

+30
-5
lines changed

2 files changed

+30
-5
lines changed

Autoupdate/SUBinaryDeltaCommon.m

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,11 @@ uint16_t latestMinorVersionForMajorVersion(SUBinaryDeltaMajorVersion majorVersio
113113
case SUBinaryDeltaMajorVersion1:
114114
return 2;
115115
case SUBinaryDeltaMajorVersion2:
116-
return 4;
116+
return 5;
117117
case SUBinaryDeltaMajorVersion3:
118-
return 1;
118+
return 2;
119119
case SUBinaryDeltaMajorVersion4:
120-
return 0;
120+
return 1;
121121
}
122122
return 0;
123123
}

Vendor/bsdiff/bsdiff.c

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,9 @@ static off_t search(off_t *I, u_char *old, off_t oldsize,
8484
}
8585

8686
x = st + (en - st)/2;
87-
if (memcmp(old + I[x], new, (size_t)(MIN(oldsize - I[x], newsize))) < 0) {
87+
/* Modification ported from ChromiumOS project:
88+
* https://chromium.googlesource.com/chromiumos/third_party/bsdiff/+/58146f74abd6b1b69693943195f37f4ac6a6acef%5E%21/#F0 */
89+
if (memcmp(old + I[x], new, (size_t)(MIN(oldsize - I[x], newsize))) <= 0) {
8890
return search(I, old, oldsize, new, newsize, x, en, pos);
8991
} else {
9092
return search(I, old, oldsize, new, newsize, st, x, pos);
@@ -212,8 +214,18 @@ int bsdiff(int argc, char *argv[])
212214
lastoffset = 0;
213215
while (scan < newsize) {
214216
oldscore = 0;
215-
217+
/* Modification ported from ChromiumOS project:
218+
* https://chromium.googlesource.com/chromiumos/third_party/bsdiff/+/a055996c743add7a9558839276fd1e4994d16bd3%5E%21/#F0 */
219+
/* If we come across a large block of data that only differs
220+
* by less than 8 bytes, this loop will take a long time to
221+
* go past that block of data. We need to track the number of
222+
* times we're stuck in the block and break out of it. */
223+
int num_less_than_eight = 0;
224+
off_t prev_len, prev_oldscore, prev_pos;
216225
for (scsc = scan += len; scan < newsize; scan++) {
226+
prev_len = len;
227+
prev_oldscore = oldscore;
228+
prev_pos = pos;
217229
/* 'oldscore' is the number of characters that match between the
218230
* substrings 'old[lastoffset + scan:lastoffset + scsc]' and
219231
* 'new[scan:scsc]'. */
@@ -240,6 +252,19 @@ int bsdiff(int argc, char *argv[])
240252
if ((scan + lastoffset < oldsize) &&
241253
(old[scan + lastoffset] == new[scan]))
242254
oldscore--;
255+
256+
/* Modification ported from ChromiumOS project:
257+
* https://chromium.googlesource.com/chromiumos/third_party/bsdiff/+/426e4aa1cbeb3c8a73002047d7a796ca8e5e17d4%5E%21/#F0 */
258+
const off_t fuzz = 8;
259+
if (prev_len - fuzz <= len && len <= prev_len &&
260+
prev_oldscore - fuzz <= oldscore &&
261+
oldscore <= prev_oldscore &&
262+
prev_pos <= pos && pos <= prev_pos + fuzz &&
263+
oldscore <= len && len <= oldscore + fuzz)
264+
++num_less_than_eight;
265+
else
266+
num_less_than_eight=0;
267+
if (num_less_than_eight > 100) break;
243268
}
244269

245270
/* Skip this section if we found an exact match that would be

0 commit comments

Comments
 (0)