19 Commits
Author SHA1 Message Date
Kelvin Zhang 023e6aef67 Exit loop earlier for bsdiff's pathological case
Looking at bsdiff's comment, original author want to generate a diff
patch only if diff is no smaller than 8 bytes. Actual code only only
permits the diff to be generated if diff > 8 bytes.

Partners reported a pair of problematic files where BSDIFF takes more
than 10 hours(input file is only ~80MB). After applying this patch,
bsdiff takes ~1 minute.

To make sure this patch does not harm patch size for non-pathological
cases, I tested multiple pixel OTAs. Total OTA size increased by just
0.002% . Basically negligible.

Test: Multiple pixle OTAs
Bug: 285271992

Change-Id: I2a9b52939f8d17ea48dc2908942b2cc21cbe4e09
2023-06-15 10:58:41 -07:00
Sen Jiang 3a4725a877 Exit loop ealier when matching lastoffset.
|lastoffset| and |oldsize| doesn't change in this loop, no point keep
incrementing |scsc| and comparing.

bsdiff is about 2% faster with no change on the patch content.

Bug: 77817425
Test: bsdiff_unittest
Change-Id: Ie6a5ddc4b8805ed76c9c626fa75010617b7975ef
2018-04-09 17:32:51 -07:00
Alex Deymo 383f677d7e Allow to set the minimum required match length.
The minimum required match length plays an important role in the
current algorithm. This algorithm requires that the current match
has at least 8 mismatches over a region where we find a new match,
therefore imposing a minimum match length of at least 8 bytes.
This patch allows to increase this minium value to avoid using small
matches that only match a very small region. A larger value can
improve the patch size, depending on the data, but a too large value
will cause the algorithm to miss matches that were otherwise benefical.

Bug: 73107113
Test: Added unittests. Ran it with different minlen values.

Change-Id: Iac594fc1cd7ecd5cfdc676bdb6ebe7c626de6dcd
2018-02-12 17:20:51 +01:00
Tianjie Xu 1f1cdb2b6b Add an argument parser in bsdiff
Add a parser of format, type and quality in the bsdiff main function.
This allow the bsdiff binary to choose between the BSDFF40|BSDF2 patch
format and compress the patch with desired algorithms.

Bug: 34220646
Test: unittest pass; generate brotli compressed patches with bsdiff
binary
Change-Id: Ia4f7941e4eca7e6047e2749315127d1cf4a988ee
2018-01-18 12:32:09 -08:00
Tianjie Xu b4cba64184 Implement a new bsdiff format
Add a new BSDF2 format that allows compression of ctrl/diff/extra streams
with different algorithms. The compression algorithm supported for now is
bz2 and brotli. This new format is similar to the legacy "BSDIFF40" format
except for the magic headers.

File format:
0       8    magic header
8       8    X
16      8    Y
24      8    new_file_size
32      X    compressed control block
32+X    Y    compressed diff block
32+X+Y  ???  compressed extra block

The magic header for BSDF2 format:
0 5 BSDF2
5 1 compressed type for control stream
6 1 compressed type for diff stream
7 1 compressed type for extra stream

Bug: 34220646
Test: unittest pass
Change-Id: I6eb0867e88476dbc4a4b7be609783f8c8a0a41cd
2017-11-16 14:46:37 -08:00
Tianjie Xu 1c26e2ed9b Add the brotli compressor for bsdiff
Add a new compressor interface; and the brotli compressor which is
similar to the existing bz2 one.

Also add a new CompressorType argument to PatchWriter's init function;
this allows us to choose the right compressor based on the input option
in the future.

Bug: 34220646
Test:  Run bsdiff/bspatch with brotli compressor/decompressor over a
list of files from angler's system image. Make succeeds.
Change-Id: Id9a3db2d7d051dcb751a1fc362f4c3b9226e878b
2017-10-31 11:37:45 -07:00
Alex Deymo 4dadd8b443 Pass the size of the new file to the PatchWriterInterface::Init()
Most patch formats include the size of the new file in the header.
To help streaming the patch to disk while generating it, this CL
passes the size of the new file to the patch writer on initialization.

To do this, we also move the Init() call to the patch writer to the
DiffEncoder, which makes more sense since the Close() call is also made
from the DiffEnconder.

Bug: None
Test: Updated tests to check for this value.
Change-Id: Idfaedbd492d68ab6e6cb2c1cb3883947f068c3aa
2017-10-27 13:52:46 +02:00
Alex Deymo e445830222 Cleanup bsdiff public API.
The original function used to generate a patch from two files is no
longer used elsewhere so this patch removes it in favour of the newer
version that takes the streams from memory buffers and uses a patch
writer to generate the patch.

Bug: None.
Test: Ran `bsdiff` manually, verified bspatch applied correctly.

Change-Id: I17aac1d3dd405d733ff6dc35abe8e683adea0d4f
2017-10-27 13:52:46 +02:00
Alex Deymo 48ad5ab76e Select SuffixArray size at runtime.
The suffix array is used to search for strings from the new file in the
old file. The size of each element of the suffix array must be big
enough to hold the length of the old file. In most of the cases we use,
if not all of them, the old file is smaller than 2 GiB, which allows to
use 32-bit integers for the suffix array.

The previous code decided whether to use 64-bit or 32-bit integers
based on the large-file surpport, even in 32-bit computers architectures
which would not work in those cases; and would also use twice as much
memory when constructing the suffix array of inputs smaller than 2 GiB.

This patch selects the suffix array size based on the input size,
effectively using half the memory in the most common case. This also
improves the runtime performance due to lower cache pressure.

As a side effect, this patch hides the suffix array implementation
details from the public interface. This removes the limitation where
the caller of libbsdiff and libbsdiff needed to be compiled with the
same large-file support flags; and also hides the dependency on
libdivsufsort from the public interface.

While doing so, instead of re-implementing the suffix array search
algorithm (which had a history of bugs and corner cases) we re-use the
one from libdivsufsort, adapted to the bsdiff algorithm use-case.

The result is about 40% faster when diffing 10MiB files, and the patch
size is within 0.1%, due to differences in the position selected
whenever more than one match is available.

Bug: 34220646
Test: Added unittests for the suffix array.

Change-Id: Ib9dc85a83bbf10157a3937c5687e5663ab0d20d5
2017-10-20 16:37:51 +02:00
Alex Deymo 68c0e7f206 Reduce PatchWriterInterface functionality.
The recently introduced PatchWriterInterface had both the patch file
format logic and the diff/extra streams selection from the control
entries. While this simplifies the bsdiff main algorithm and makes
invalid usages of the BsdiffPatchWriter evident, writing alternative
PatchWriterInterface classes required to replicate the diff/extra
stream selection logic.

This patch splits out the diff/extra stream generation and all the
checks around those to a new helper class DiffEncoder. The public
interface PatchWriterInterface now has two methods to accept the diff
and extra stream data, and does not compute them.

Bug: 34220646
Test: Added unittests. Ran bsdiff on some pairs of files obtaining the same result as before.
Change-Id: I5f303c06f1e10910eb00dcfda38c6811977a91cf
2017-10-09 12:50:33 +02:00
Alex Deymo fb3b632fde Add unittest for the PatchWriter.
Split the unittest logic between bsdiff() function and the PatchWriter.
This patch now tests individually the PatchWriter logic that writes to
disk and the bsdiff() logic to create patches in the same very simple
cases.

We also update the Android.bp file to only pass -DBSDIFF_TARGET_UNITTEST
when building for the target.

Bug: 34220646
Test: ran unittests.

Change-Id: I9350157ee4a0b5a617f44bb187bd7652f6d6f017
2017-09-28 19:36:57 +02:00
Alex Deymo 538a75d13b Make BsdiffPatchWriter into an Interface.
Currently, all bsdiff() functions take a filename for the patch, which
is called with a temporary file in all cases. To help expose an
interface that allows to write bsdiff patches in different formats (for
example, changing the compressor and header format) we expose the
PatchWriterInterface class in the public interface so callers can use
a different one or define their own to help experimenting with bsdiff
enconding improvements.

Bug: 34220646
Test: make bsdiff and update_engine; ran bsdiff_unittest

Change-Id: Ie450b2790137665bc033cb36d037171090b18a4b
2017-09-28 19:36:53 +02:00
Alex Deymo dcd423bf89 Add the "bsdiff/" prefix to all include paths.
This prevents accidentally including a header file from another project
that happens to have the same name.

Test: `make checkbuild`; emerge-${BOARD} bsdiff
Bug: None

Change-Id: I8af132ed388738c30a8e3d7434de70b1e9d2f924
2017-09-25 10:56:24 +02:00
Alex Deymo a28e01937d Refactor bsdiff patch writing code to another file.
bsdiff.cc had code to handle both the sub-streams compression and the
patch format. This CL moves the patch file format logic to a new class
in a separated file, and the bzip2 compression to another class. This
allows to replace the core bsdiff logic separatedly from the patch
format.

There are no changes to the functionality of bsdiff and the generated
patches. The code does a bit more of memcpy() since it doesn't write
the control stream to disk as it goes.

Bug: 34220646
Test: Ran bsdiff and compared results with previous version.

Change-Id: Ibdc1482e98cbd370cbed677c326008e19a217ef8
2017-09-15 15:33:11 +02:00
Alex Deymo ddf9db5293 Update Makefile to build shared libraries.
The Makefile didn't build libbspatch and libbsdiff. This patch includes
those libraries in the Makefile and moves the header files exposed by
those to an include/bsdiff subdirectory following the Android
convention so calling program can include "bsdiff/bspatch.h" avoiding
any collision with other libraries.

The Android.mk is updated to export the new include path while keeping
the old style until calling programs are updated.

The new Makefile allows Chromium OS to build the new libraries.

Bug: None
Test: FEATURES=test emerge-link bsdiff; sudo emerge bsdiff
Test: mmma external/bsdiff

Change-Id: I2ea9251eb224e9418fe236e4c4c9c5621853f590
2017-05-03 18:29:10 -07:00
Sen Jiang 10df267c94 Support caching the suffix array.
If the same old data is passed to bsdiff repeatedly, allow caller to
cache the suffix array, this is used by imgdiff in zip mode.

Bug: 34281147
Test: =time -v imgdiff -z Chrome-ORF74B.apk Chrome-ORF76B.apk Chrome.imgdiff
Change-Id: I0a69fc2d0b1a0d5791f78d0380df957981318daa
2017-01-18 17:47:49 -08:00
Sen Jiang 01a8c86817 Fix segmentation fault with certain files.
The bug was introduced when we replaced qsufsort with divsufsort, the
implementation of qsufsort in bsdiff will set I[oldsize] for some reason,
and later on search() might access I[oldsize] in a corner case. But
divsufsort will only set I[0...oldsize-1] which is WAI, and now I[oldsize]
will be random.

The search() function is basically a binary search, and the end should
be oldsize-1 so that it will never access I[oldsize].

Interestingly, it will only segfault when used in imgdiff, even if I
extract the same old data and new data passed to bsdiff() and call bsdiff
binary with the files, segfault disappears, probably because imgdiff did
many malloc and free before calling bsdiff and the memory already contains
random data, whereas in bsdiff binary that is always 0. That's probably
why we did not encounter this bug in Chrome OS.

Bug: 28631841
Test: `imgdiff boot.img recovery.img recovery_from_boot.p` from shamu build

Change-Id: If10ec64b125131b348444364626307d379c2b8ba
2016-05-06 15:46:50 -07:00
Sen Jiang 9b93e6a792 Separate reading old and new files from bsdiff().
This is needed so that others like applypatch can use bsdiff in memory.

Bug: 26982501
Test: mma

Change-Id: Ida0e11e35f088604498d1cc919fb5ca19f36fd62
2016-05-05 10:48:59 -07:00
Alex Deymo 20891f9c24 Convert C sources to C++.
To help refactoring the FILE* access behind an interface and better
integrate with unittest code, this patch moves the C sources to C++.
Minor changes to make this conform to C++ were included.

Bug: 24478450
Test: `make all test && ./unittests`; mm

Change-Id: I27d7fb0660efc18ea0cb84ff544c9dd9c4803050
2015-10-13 02:15:02 -07:00