diff options
author | Josh MacDonald <josh.macdonald@gmail.com> | 2015-12-27 22:12:34 -0800 |
---|---|---|
committer | Josh MacDonald <josh.macdonald@gmail.com> | 2015-12-27 22:12:34 -0800 |
commit | ec9905aa755eafb64f08fc59ca7e67ea57498264 (patch) | |
tree | 304cae17d7d856c3ef465f7fad18398347272970 | |
parent | dbbc4c4a59bb805a828bd61640ec8ba88fe92871 (diff) | |
parent | cf662894ba5b3847f06fd44dfb91f4733d9196f4 (diff) |
Merge frmo origin
-rw-r--r-- | xdelta3/Makefile.am | 3 | ||||
-rw-r--r-- | xdelta3/go/src/regtest.go | 8 | ||||
-rw-r--r-- | xdelta3/go/src/xdelta/run.go | 3 | ||||
-rw-r--r-- | xdelta3/go/src/xdelta/tgroup.go | 4 | ||||
-rwxr-xr-x | xdelta3/run_release.sh | 2 | ||||
-rw-r--r-- | xdelta3/testing/regtest.cc | 173 | ||||
-rw-r--r-- | xdelta3/testing/test.h | 4 | ||||
-rw-r--r-- | xdelta3/xdelta3-blkcache.h | 22 | ||||
-rw-r--r-- | xdelta3/xdelta3-decode.h | 16 | ||||
-rw-r--r-- | xdelta3/xdelta3-djw.h | 14 | ||||
-rw-r--r-- | xdelta3/xdelta3-internal.h | 6 | ||||
-rw-r--r-- | xdelta3/xdelta3-main.h | 9 | ||||
-rw-r--r-- | xdelta3/xdelta3-merge.h | 21 | ||||
-rw-r--r-- | xdelta3/xdelta3-second.h | 9 | ||||
-rw-r--r-- | xdelta3/xdelta3-test.h | 2 | ||||
-rw-r--r-- | xdelta3/xdelta3.c | 272 | ||||
-rw-r--r-- | xdelta3/xdelta3.h | 4 |
17 files changed, 318 insertions, 254 deletions
diff --git a/xdelta3/Makefile.am b/xdelta3/Makefile.am index 11f75b0..f437764 100644 --- a/xdelta3/Makefile.am +++ b/xdelta3/Makefile.am | |||
@@ -61,6 +61,9 @@ if DEBUG_SYMBOLS | |||
61 | common_CFLAGS += -g | 61 | common_CFLAGS += -g |
62 | endif | 62 | endif |
63 | 63 | ||
64 | #common_CFLAGS += -fsanitize=address -fno-omit-frame-pointer | ||
65 | #common_CFLAGS += -O2 | ||
66 | |||
64 | # For additional debugging, add -DXD3_DEBUG=1, 2, 3, ... | 67 | # For additional debugging, add -DXD3_DEBUG=1, 2, 3, ... |
65 | xdelta3_CFLAGS = $(C_WFLAGS) $(common_CFLAGS) -DXD3_DEBUG=0 | 68 | xdelta3_CFLAGS = $(C_WFLAGS) $(common_CFLAGS) -DXD3_DEBUG=0 |
66 | xdelta3_LDADD = -lm | 69 | xdelta3_LDADD = -lm |
diff --git a/xdelta3/go/src/regtest.go b/xdelta3/go/src/regtest.go index bcf0de9..a7cab33 100644 --- a/xdelta3/go/src/regtest.go +++ b/xdelta3/go/src/regtest.go | |||
@@ -13,8 +13,8 @@ import ( | |||
13 | 13 | ||
14 | const ( | 14 | const ( |
15 | xdataset = "/volume/home/jmacd/src/testdata" | 15 | xdataset = "/volume/home/jmacd/src/testdata" |
16 | xcompare = "/volume/home/jmacd/src/xdelta3-devel/xdelta3/xdelta3" | 16 | xcompare = "/volume/home/jmacd/src/xdelta-devel/xdelta3/xdelta3" |
17 | xdelta3 = "/volume/home/jmacd/src/xdelta-64bithash/xdelta3/xdelta3" | 17 | xdelta3 = "/volume/home/jmacd/src/xdelta-64bithash/xdelta3/xdelta3" |
18 | seed = 1422253499919909358 | 18 | seed = 1422253499919909358 |
19 | ) | 19 | ) |
20 | 20 | ||
@@ -35,12 +35,10 @@ func (c Config) smokeTest(t *xdelta.TestGroup, p xdelta.Program) { | |||
35 | 35 | ||
36 | enc, err := t.Exec("encode", p, true, []string{"-e"}) | 36 | enc, err := t.Exec("encode", p, true, []string{"-e"}) |
37 | if err != nil { | 37 | if err != nil { |
38 | fmt.Println(err) | ||
39 | t.Panic(err) | 38 | t.Panic(err) |
40 | } | 39 | } |
41 | dec, err := t.Exec("decode", p, true, []string{"-d"}) | 40 | dec, err := t.Exec("decode", p, true, []string{"-d"}) |
42 | if err != nil { | 41 | if err != nil { |
43 | fmt.Println(err) | ||
44 | t.Panic(err) | 42 | t.Panic(err) |
45 | } | 43 | } |
46 | 44 | ||
@@ -234,7 +232,7 @@ func (cfg Config) offsetTest(t *xdelta.TestGroup, p xdelta.Program, offset, leng | |||
234 | 232 | ||
235 | // The decoder output ("read", above) is compared with the | 233 | // The decoder output ("read", above) is compared with the |
236 | // test-provided output ("write", below). The following | 234 | // test-provided output ("write", below). The following |
237 | // generates the input and output twice. | 235 | // generates two identical inputs. |
238 | t.WriteRstreams("encode", seed, offset, length, enc.Srcin, enc.Stdin) | 236 | t.WriteRstreams("encode", seed, offset, length, enc.Srcin, enc.Stdin) |
239 | t.WriteRstreams("decode", seed, offset, length, dec.Srcin, write) | 237 | t.WriteRstreams("decode", seed, offset, length, dec.Srcin, write) |
240 | t.Wait(enc, dec) | 238 | t.Wait(enc, dec) |
diff --git a/xdelta3/go/src/xdelta/run.go b/xdelta3/go/src/xdelta/run.go index 6523a1c..448fabe 100644 --- a/xdelta3/go/src/xdelta/run.go +++ b/xdelta3/go/src/xdelta/run.go | |||
@@ -55,7 +55,8 @@ func (r *Runner) RunTest(name string, f func (t *TestGroup)) { | |||
55 | c := make(chan interface{}) | 55 | c := make(chan interface{}) |
56 | go func() { | 56 | go func() { |
57 | defer func() { | 57 | defer func() { |
58 | c <- recover() | 58 | rec := recover() |
59 | c <- rec | ||
59 | }() | 60 | }() |
60 | fmt.Println("Testing", name, "...") | 61 | fmt.Println("Testing", name, "...") |
61 | f(t) | 62 | f(t) |
diff --git a/xdelta3/go/src/xdelta/tgroup.go b/xdelta3/go/src/xdelta/tgroup.go index b1b04ec..602b1e1 100644 --- a/xdelta3/go/src/xdelta/tgroup.go +++ b/xdelta3/go/src/xdelta/tgroup.go | |||
@@ -58,7 +58,9 @@ func (g *Goroutine) OK() { | |||
58 | 58 | ||
59 | func (g *Goroutine) Panic(err error) { | 59 | func (g *Goroutine) Panic(err error) { |
60 | g.finish(err) | 60 | g.finish(err) |
61 | runtime.Goexit() | 61 | if g != g.TestGroup.main { |
62 | runtime.Goexit() | ||
63 | } | ||
62 | } | 64 | } |
63 | 65 | ||
64 | func (t *TestGroup) Main() *Goroutine { return t.main } | 66 | func (t *TestGroup) Main() *Goroutine { return t.main } |
diff --git a/xdelta3/run_release.sh b/xdelta3/run_release.sh index f38c44d..eb08afc 100755 --- a/xdelta3/run_release.sh +++ b/xdelta3/run_release.sh | |||
@@ -123,6 +123,7 @@ function buildit { | |||
123 | local FULLD="${SRCDIR}/${D}" | 123 | local FULLD="${SRCDIR}/${D}" |
124 | local CFLAGS="${march} ${cargs} -I${SRCDIR}/build/lib-${LIBBM}/include" | 124 | local CFLAGS="${march} ${cargs} -I${SRCDIR}/build/lib-${LIBBM}/include" |
125 | local CXXFLAGS="${march} ${cargs} -I${SRCDIR}/build/lib-${LIBBM}/include" | 125 | local CXXFLAGS="${march} ${cargs} -I${SRCDIR}/build/lib-${LIBBM}/include" |
126 | local CPPFLAGS="-I${SRCDIR}/build/lib-${LIBBM}/include" | ||
126 | local LDFLAGS="${march} -L${SRCDIR}/build/lib-${LIBBM}/lib" | 127 | local LDFLAGS="${march} -L${SRCDIR}/build/lib-${LIBBM}/lib" |
127 | 128 | ||
128 | mkdir -p ${D} | 129 | mkdir -p ${D} |
@@ -179,6 +180,7 @@ EOF | |||
179 | --enable-debug-symbols \ | 180 | --enable-debug-symbols \ |
180 | "CFLAGS=${CFLAGS}" \ | 181 | "CFLAGS=${CFLAGS}" \ |
181 | "CXXFLAGS=${CXXFLAGS}" \ | 182 | "CXXFLAGS=${CXXFLAGS}" \ |
183 | "CPPFLAGS=${CPPFLAGS}" \ | ||
182 | "LDFLAGS=${LDFLAGS}" \ | 184 | "LDFLAGS=${LDFLAGS}" \ |
183 | "CC=${USECC}" \ | 185 | "CC=${USECC}" \ |
184 | "CXX=${USECXX}" | 186 | "CXX=${USECXX}" |
diff --git a/xdelta3/testing/regtest.cc b/xdelta3/testing/regtest.cc index bee7477..e83af4b 100644 --- a/xdelta3/testing/regtest.cc +++ b/xdelta3/testing/regtest.cc | |||
@@ -92,7 +92,7 @@ public: | |||
92 | bool done = false; | 92 | bool done = false; |
93 | bool done_after_input = false; | 93 | bool done_after_input = false; |
94 | 94 | ||
95 | IF_DEBUG1 (XPR(NTR "source %"Q"[%"Q"] target %"Q" winsize %lu\n", | 95 | IF_DEBUG1 (XPR(NTR "source %"Q"u[%"Q"u] target %"Q"u winsize %"Z"u\n", |
96 | source_file.Size(), options.block_size, | 96 | source_file.Size(), options.block_size, |
97 | target_file.Size(), | 97 | target_file.Size(), |
98 | Constants::WINDOW_SIZE)); | 98 | Constants::WINDOW_SIZE)); |
@@ -153,7 +153,7 @@ public: | |||
153 | xd3_source *src = (encoding ? &encode_source : &decode_source); | 153 | xd3_source *src = (encoding ? &encode_source : &decode_source); |
154 | Block *block = (encoding ? &encode_source_block : &decode_source_block); | 154 | Block *block = (encoding ? &encode_source_block : &decode_source_block); |
155 | if (encoding) { | 155 | if (encoding) { |
156 | IF_DEBUG1(XPR(NTR "[srcblock] %"Q"u last srcpos %"Q"u " | 156 | IF_DEBUG2(XPR(NTR "[srcblock] %"Q"u last srcpos %"Q"u " |
157 | "encodepos %"Q"u\n", | 157 | "encodepos %"Q"u\n", |
158 | encode_source.getblkno, | 158 | encode_source.getblkno, |
159 | encode_stream.match_last_srcpos, | 159 | encode_stream.match_last_srcpos, |
@@ -790,32 +790,34 @@ void TestSmallStride() { | |||
790 | usize_t size = Constants::BLOCK_SIZE * 4; | 790 | usize_t size = Constants::BLOCK_SIZE * 4; |
791 | spec0.GenerateFixedSize(size); | 791 | spec0.GenerateFixedSize(size); |
792 | 792 | ||
793 | /* TODO Need to study the actual causes of missed adds for tests | 793 | // Note: Not very good performance due to hash collisions, note 3x |
794 | * less than 30 bytes. */ | 794 | // multiplier below. |
795 | const int s = 30; | 795 | for (int s = 15; s < 101; s++) { |
796 | usize_t adds = 0; | 796 | usize_t changes = 0; |
797 | ChangeList cl; | 797 | ChangeList cl; |
798 | for (usize_t j = s; j < size; j += s, ++adds) | 798 | for (usize_t j = s; j < size; j += s, ++changes) |
799 | { | 799 | { |
800 | cl.push_back(Change(Change::MODIFY, 1, j)); | 800 | cl.push_back(Change(Change::MODIFY, 1, j)); |
801 | } | 801 | } |
802 | 802 | ||
803 | FileSpec spec1(&rand); | 803 | FileSpec spec1(&rand); |
804 | spec0.ModifyTo(ChangeListMutator(cl), &spec1); | 804 | spec0.ModifyTo(ChangeListMutator(cl), &spec1); |
805 | 805 | ||
806 | Options options; | 806 | Options options; |
807 | options.encode_srcwin_maxsz = size; | 807 | options.encode_srcwin_maxsz = size; |
808 | options.iopt_size = 128; | 808 | options.iopt_size = 128; |
809 | options.smatch_cfg = XD3_SMATCH_SLOW; | 809 | options.smatch_cfg = XD3_SMATCH_SLOW; |
810 | options.size_known = false; | 810 | options.size_known = false; |
811 | 811 | ||
812 | Block block; | 812 | Block block; |
813 | InMemoryEncodeDecode(spec0, spec1, &block, options); | 813 | InMemoryEncodeDecode(spec0, spec1, &block, options); |
814 | Delta delta(block); | 814 | Delta delta(block); |
815 | 815 | ||
816 | // Allow an additional two byte of add per window | 816 | IF_DEBUG1(DP(RINT "[stride=%d] changes=%u adds=%"Q"u\n", |
817 | usize_t allowance = 2 * size / Constants::WINDOW_SIZE; | 817 | s, changes, delta.AddedBytes())); |
818 | CHECK_GE(adds + allowance, delta.AddedBytes()); | 818 | double allowance = Constants::BLOCK_SIZE < 8192 || s < 30 ? 3.0 : 1.1; |
819 | CHECK_GE(allowance * changes, (double)delta.AddedBytes()); | ||
820 | } | ||
819 | } | 821 | } |
820 | 822 | ||
821 | void TestCopyWindow() { | 823 | void TestCopyWindow() { |
@@ -927,85 +929,73 @@ void TestCopyFromEnd() { | |||
927 | } | 929 | } |
928 | 930 | ||
929 | void TestHalfBlockCopy() { | 931 | void TestHalfBlockCopy() { |
930 | MTRandom rand; | 932 | // Create a half-block copy, 7.5 blocks apart, in a pair of files: |
931 | FileSpec spec0(&rand); | 933 | // 0 1 ... 6 7 |
932 | FileSpec spec1(&rand); | 934 | // spec0 [bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb][ccccc][bbbb_] |
933 | 935 | // spec1 [aaaaa][ccccc][aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_] | |
934 | spec0.GenerateFixedSize(Constants::BLOCK_SIZE * 4); | 936 | // where stage= |
935 | 937 | // 0: the final block is full | |
936 | // Create a half-block copy, 2.5 blocks apart, from the second half | 938 | // a. (source)spec1->(target)spec0 copies block C: reads 8 source |
937 | // of the source version to the first half of the target version. | 939 | // blocks during target block 0. |
938 | // 0 1 2 3 | 940 | // b. (source)spec0->(target)spec1 does not copy block C b/c attempt |
939 | // spec0 [bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb][ccccc][bbbbb] | 941 | // to read past EOF empties block 0 from (virtual) block cache |
940 | // spec1 [aaaaa][ccccc][aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] | 942 | // 1: the final block is less than full. |
941 | ChangeList cl1; | 943 | // a. (same) copies block C |
942 | cl1.push_back(Change(Change::MODIFY, | 944 | // b. (same) copies block C, unlike 0a, no attempt to read past EOF |
943 | Constants::BLOCK_SIZE / 2, // size | 945 | // |
944 | 0)); | 946 | // "virtual" above refers to XD3_TOOFARBACK, since there is no caching |
945 | cl1.push_back(Change(Change::COPYOVER, | 947 | // in the API, there is simply a promise not to request blocks that are |
946 | Constants::BLOCK_SIZE / 2, // size | 948 | // beyond source->max_winsize from the last known source file position. |
947 | Constants::BLOCK_SIZE * 3, // offset | 949 | for (int stage = 0; stage < 2; stage++) |
948 | Constants::BLOCK_SIZE / 2)); | ||
949 | cl1.push_back(Change(Change::MODIFY, | ||
950 | Constants::BLOCK_SIZE * 3, | ||
951 | Constants::BLOCK_SIZE)); | ||
952 | spec0.ModifyTo(ChangeListMutator(cl1), &spec1); | ||
953 | |||
954 | const int onecopy_adds = | ||
955 | 4 * Constants::BLOCK_SIZE - Constants::BLOCK_SIZE / 2; | ||
956 | const int nocopy_adds = 4 * Constants::BLOCK_SIZE; | ||
957 | |||
958 | // Note the case b=4 is contrived: the caller should use a single block | ||
959 | // containing the entire source, if possible. | ||
960 | for (int b = 1; b <= 4; b++) | ||
961 | { | 950 | { |
951 | IF_DEBUG1 (DP(RINT "half_block_copy stage %d\n", stage)); | ||
952 | |||
953 | MTRandom rand; | ||
954 | FileSpec spec0(&rand); | ||
955 | FileSpec spec1(&rand); | ||
956 | |||
957 | spec0.GenerateFixedSize(Constants::BLOCK_SIZE * 8 - stage); | ||
958 | |||
959 | ChangeList cl1; | ||
960 | cl1.push_back(Change(Change::MODIFY, | ||
961 | Constants::BLOCK_SIZE / 2, // size | ||
962 | 0)); | ||
963 | cl1.push_back(Change(Change::COPYOVER, | ||
964 | Constants::BLOCK_SIZE / 2, // size | ||
965 | Constants::BLOCK_SIZE * 7, // offset | ||
966 | Constants::BLOCK_SIZE / 2)); | ||
967 | cl1.push_back(Change(Change::MODIFY, | ||
968 | Constants::BLOCK_SIZE * 7, | ||
969 | Constants::BLOCK_SIZE - stage)); | ||
970 | spec0.ModifyTo(ChangeListMutator(cl1), &spec1); | ||
971 | |||
962 | Options options; | 972 | Options options; |
963 | options.encode_srcwin_maxsz = Constants::BLOCK_SIZE * b; | 973 | options.encode_srcwin_maxsz = Constants::BLOCK_SIZE * 8; |
964 | 974 | ||
965 | Block block0; | 975 | Block block0; |
966 | Block block1; | 976 | Block block1; |
967 | InMemoryEncodeDecode(spec0, spec1, &block0, options); | 977 | InMemoryEncodeDecode(spec0, spec1, &block0, options); |
968 | InMemoryEncodeDecode(spec1, spec0, &block1, options); | 978 | InMemoryEncodeDecode(spec1, spec0, &block1, options); |
979 | |||
969 | Delta delta0(block0); | 980 | Delta delta0(block0); |
970 | Delta delta1(block1); | 981 | Delta delta1(block1); |
971 | 982 | ||
972 | // The first block never copies from the last source block, by | 983 | const int yes = |
973 | // design, because if the last source block is available when | 984 | Constants::BLOCK_SIZE * 8 - Constants::BLOCK_SIZE / 2; |
974 | // the first target block is ready, the caller is expected to | 985 | const int no = |
975 | // use a single block. | 986 | Constants::BLOCK_SIZE * 8 - Constants::BLOCK_SIZE / 2; |
976 | CHECK_EQ(nocopy_adds, delta0.AddedBytes()); | 987 | |
977 | if (Constants::BLOCK_SIZE < 8192 || b > 2) | 988 | if (stage == 0) |
978 | { | 989 | { |
979 | // For small-block inputs, the entire file is read into one | 990 | CHECK_EQ(yes, delta0.AddedBytes()); |
980 | // block (the min source window size is 16kB). | 991 | CHECK_EQ(no, delta1.AddedBytes()); |
981 | // | 992 | } |
982 | // For large blocks, at least 3 blocks of source window are | ||
983 | // needed. | ||
984 | CHECK_EQ(onecopy_adds, delta1.AddedBytes()); | ||
985 | } | ||
986 | else | 993 | else |
987 | { | 994 | { |
988 | // When there are fewer than 3 source blocks. | 995 | CHECK_EQ(yes, delta0.AddedBytes()); |
989 | CHECK_EQ(nocopy_adds, delta1.AddedBytes()); | 996 | CHECK_EQ(yes, delta1.AddedBytes()); |
990 | } | 997 | } |
991 | } | 998 | } |
992 | |||
993 | Options options; | ||
994 | options.encode_srcwin_maxsz = Constants::BLOCK_SIZE * 4; | ||
995 | options.block_size = Constants::BLOCK_SIZE * 4; | ||
996 | |||
997 | // Test the whole-buffer case. | ||
998 | Block block0; | ||
999 | Block block1; | ||
1000 | InMemoryEncodeDecode(spec0, spec1, &block0, options); | ||
1001 | InMemoryEncodeDecode(spec1, spec0, &block1, options); | ||
1002 | Delta delta0(block0); | ||
1003 | Delta delta1(block1); | ||
1004 | // This <= >= are only for blocksize = 512, which has irregular readsize. | ||
1005 | CHECK_LE(onecopy_adds, delta0.AddedBytes()); | ||
1006 | CHECK_GE(onecopy_adds + 1, delta0.AddedBytes()); | ||
1007 | |||
1008 | CHECK_EQ(onecopy_adds, delta1.AddedBytes()); | ||
1009 | } | 999 | } |
1010 | 1000 | ||
1011 | void FourWayMergeTest(const FileSpec &spec0, | 1001 | void FourWayMergeTest(const FileSpec &spec0, |
@@ -1310,3 +1300,4 @@ int main(int argc, char **argv) | |||
1310 | 1300 | ||
1311 | return 0; | 1301 | return 0; |
1312 | } | 1302 | } |
1303 | |||
diff --git a/xdelta3/testing/test.h b/xdelta3/testing/test.h index 30d13a3..7de24fb 100644 --- a/xdelta3/testing/test.h +++ b/xdelta3/testing/test.h | |||
@@ -22,8 +22,8 @@ extern "C" { | |||
22 | __typeof__(x) _y(y); \ | 22 | __typeof__(x) _y(y); \ |
23 | if (!(_x OP _y)) { \ | 23 | if (!(_x OP _y)) { \ |
24 | cerr << __FILE__ << ":" << __LINE__ << " Check failed: " << #x " " #OP " " #y << endl; \ | 24 | cerr << __FILE__ << ":" << __LINE__ << " Check failed: " << #x " " #OP " " #y << endl; \ |
25 | cerr << __FILE__ << ":" << __LINE__ << " Expected: " << _x << endl; \ | 25 | cerr << __FILE__ << ":" << __LINE__ << " {0} " << _x << endl; \ |
26 | cerr << __FILE__ << ":" << __LINE__ << " Actual: " << _y << endl; \ | 26 | cerr << __FILE__ << ":" << __LINE__ << " {1} " << _y << endl; \ |
27 | abort(); \ | 27 | abort(); \ |
28 | } } while (false) | 28 | } } while (false) |
29 | #undef CHECK | 29 | #undef CHECK |
diff --git a/xdelta3/xdelta3-blkcache.h b/xdelta3/xdelta3-blkcache.h index 8de5d13..20a2a4a 100644 --- a/xdelta3/xdelta3-blkcache.h +++ b/xdelta3/xdelta3-blkcache.h | |||
@@ -183,6 +183,7 @@ main_set_source (xd3_stream *stream, xd3_cmd cmd, | |||
183 | if (!sfile->size_known && source->onblk < blksize) | 183 | if (!sfile->size_known && source->onblk < blksize) |
184 | { | 184 | { |
185 | source_size = source->onblk; | 185 | source_size = source->onblk; |
186 | source->onlastblk = source_size; | ||
186 | sfile->size_known = 1; | 187 | sfile->size_known = 1; |
187 | } | 188 | } |
188 | 189 | ||
@@ -194,8 +195,10 @@ main_set_source (xd3_stream *stream, xd3_cmd cmd, | |||
194 | /* Modify block 0, change blocksize. */ | 195 | /* Modify block 0, change blocksize. */ |
195 | blksize = option_srcwinsz / MAX_LRU_SIZE; | 196 | blksize = option_srcwinsz / MAX_LRU_SIZE; |
196 | source->blksize = blksize; | 197 | source->blksize = blksize; |
197 | source->onblk = blksize; /* xd3 sets onblk */ | 198 | source->onblk = blksize; |
198 | /* Note: source->max_winsize is unchanged. */ | 199 | source->onlastblk = blksize; |
200 | source->max_blkno = MAX_LRU_SIZE - 1; | ||
201 | |||
199 | lru[0].size = blksize; | 202 | lru[0].size = blksize; |
200 | lru_size = MAX_LRU_SIZE; | 203 | lru_size = MAX_LRU_SIZE; |
201 | 204 | ||
@@ -309,9 +312,13 @@ main_getblk_lru (xd3_source *source, xoff_t blkno, | |||
309 | main_blklru_list_remove (blru); | 312 | main_blklru_list_remove (blru); |
310 | main_blklru_list_push_back (& lru_list, blru); | 313 | main_blklru_list_push_back (& lru_list, blru); |
311 | (*blrup) = blru; | 314 | (*blrup) = blru; |
315 | IF_DEBUG1 (DP(RINT "[getblk_lru] HIT blkno = %"Z"u lru_size=%d\n", | ||
316 | blkno, lru_size)); | ||
312 | return 0; | 317 | return 0; |
313 | } | 318 | } |
314 | } | 319 | } |
320 | IF_DEBUG1 (DP(RINT "[getblk_lru] MISS blkno = %"Z"u lru_size=%d\n", | ||
321 | blkno, lru_size)); | ||
315 | } | 322 | } |
316 | 323 | ||
317 | if (do_src_fifo) | 324 | if (do_src_fifo) |
@@ -467,7 +474,6 @@ main_getblk_func (xd3_stream *stream, | |||
467 | main_file *sfile = (main_file*) source->ioh; | 474 | main_file *sfile = (main_file*) source->ioh; |
468 | main_blklru *blru; | 475 | main_blklru *blru; |
469 | int is_new; | 476 | int is_new; |
470 | int did_seek = 0; | ||
471 | size_t nread = 0; | 477 | size_t nread = 0; |
472 | 478 | ||
473 | if (allow_fake_source) | 479 | if (allow_fake_source) |
@@ -504,20 +510,10 @@ main_getblk_func (xd3_stream *stream, | |||
504 | { | 510 | { |
505 | return ret; | 511 | return ret; |
506 | } | 512 | } |
507 | |||
508 | /* Indicates that another call to main_getblk_lru() may be | ||
509 | * needed */ | ||
510 | did_seek = 1; | ||
511 | } | 513 | } |
512 | 514 | ||
513 | XD3_ASSERT (sfile->source_position == pos); | 515 | XD3_ASSERT (sfile->source_position == pos); |
514 | 516 | ||
515 | if (did_seek && | ||
516 | (ret = main_getblk_lru (source, blkno, & blru, & is_new))) | ||
517 | { | ||
518 | return ret; | ||
519 | } | ||
520 | |||
521 | if ((ret = main_read_primary_input (sfile, | 517 | if ((ret = main_read_primary_input (sfile, |
522 | (uint8_t*) blru->blk, | 518 | (uint8_t*) blru->blk, |
523 | source->blksize, | 519 | source->blksize, |
diff --git a/xdelta3/xdelta3-decode.h b/xdelta3/xdelta3-decode.h index abe8c83..0cb8857 100644 --- a/xdelta3/xdelta3-decode.h +++ b/xdelta3/xdelta3-decode.h | |||
@@ -162,6 +162,9 @@ xd3_decode_allocate (xd3_stream *stream, | |||
162 | uint8_t **buf_ptr, | 162 | uint8_t **buf_ptr, |
163 | usize_t *buf_alloc) | 163 | usize_t *buf_alloc) |
164 | { | 164 | { |
165 | IF_DEBUG2 (DP(RINT "[xd3_decode_allocate] size %u alloc %u\n", | ||
166 | size, *buf_alloc)); | ||
167 | |||
165 | if (*buf_ptr != NULL && *buf_alloc < size) | 168 | if (*buf_ptr != NULL && *buf_alloc < size) |
166 | { | 169 | { |
167 | xd3_free (stream, *buf_ptr); | 170 | xd3_free (stream, *buf_ptr); |
@@ -204,6 +207,8 @@ xd3_decode_section (xd3_stream *stream, | |||
204 | /* No allocation/copy needed */ | 207 | /* No allocation/copy needed */ |
205 | section->buf = stream->next_in; | 208 | section->buf = stream->next_in; |
206 | sect_take = section->size; | 209 | sect_take = section->size; |
210 | IF_DEBUG1 (DP(RINT "[xd3_decode_section] zerocopy %u @ %u avail %u\n", | ||
211 | sect_take, section->pos, stream->avail_in)); | ||
207 | } | 212 | } |
208 | else | 213 | else |
209 | { | 214 | { |
@@ -227,6 +232,10 @@ xd3_decode_section (xd3_stream *stream, | |||
227 | section->buf = section->copied1; | 232 | section->buf = section->copied1; |
228 | } | 233 | } |
229 | 234 | ||
235 | IF_DEBUG2 (DP(RINT "[xd3_decode_section] take %u @ %u [need %u] avail %u\n", | ||
236 | sect_take, section->pos, sect_need, stream->avail_in)); | ||
237 | XD3_ASSERT (section->pos + sect_take <= section->alloc1); | ||
238 | |||
230 | memcpy (section->copied1 + section->pos, | 239 | memcpy (section->copied1 + section->pos, |
231 | stream->next_in, | 240 | stream->next_in, |
232 | sect_take); | 241 | sect_take); |
@@ -241,6 +250,7 @@ xd3_decode_section (xd3_stream *stream, | |||
241 | 250 | ||
242 | if (section->pos < section->size) | 251 | if (section->pos < section->size) |
243 | { | 252 | { |
253 | IF_DEBUG1 (DP(RINT "[xd3_decode_section] further input required %u\n", section->size - section->pos)); | ||
244 | stream->msg = "further input required"; | 254 | stream->msg = "further input required"; |
245 | return XD3_INPUT; | 255 | return XD3_INPUT; |
246 | } | 256 | } |
@@ -1156,9 +1166,9 @@ xd3_decode_input (xd3_stream *stream) | |||
1156 | &src->cpyoff_blocks, | 1166 | &src->cpyoff_blocks, |
1157 | &src->cpyoff_blkoff); | 1167 | &src->cpyoff_blkoff); |
1158 | 1168 | ||
1159 | IF_DEBUG1(DP(RINT | 1169 | IF_DEBUG2(DP(RINT |
1160 | "decode cpyoff %"Q" " | 1170 | "[decode_cpyoff] %"Q"u " |
1161 | "cpyblkno %"Q" " | 1171 | "cpyblkno %"Q"u " |
1162 | "cpyblkoff %u " | 1172 | "cpyblkoff %u " |
1163 | "blksize %u\n", | 1173 | "blksize %u\n", |
1164 | stream->dec_cpyoff, | 1174 | stream->dec_cpyoff, |
diff --git a/xdelta3/xdelta3-djw.h b/xdelta3/xdelta3-djw.h index e6be032..414702a 100644 --- a/xdelta3/xdelta3-djw.h +++ b/xdelta3/xdelta3-djw.h | |||
@@ -1456,7 +1456,7 @@ djw_decode_symbol (xd3_stream *stream, | |||
1456 | if (*input == input_end) | 1456 | if (*input == input_end) |
1457 | { | 1457 | { |
1458 | stream->msg = "secondary decoder end of input"; | 1458 | stream->msg = "secondary decoder end of input"; |
1459 | return XD3_INTERNAL; | 1459 | return XD3_INVALID_INPUT; |
1460 | } | 1460 | } |
1461 | 1461 | ||
1462 | bstate->cur_byte = *(*input)++; | 1462 | bstate->cur_byte = *(*input)++; |
@@ -1479,7 +1479,7 @@ djw_decode_symbol (xd3_stream *stream, | |||
1479 | 1479 | ||
1480 | corrupt: | 1480 | corrupt: |
1481 | stream->msg = "secondary decoder invalid code"; | 1481 | stream->msg = "secondary decoder invalid code"; |
1482 | return XD3_INTERNAL; | 1482 | return XD3_INVALID_INPUT; |
1483 | } | 1483 | } |
1484 | 1484 | ||
1485 | static int | 1485 | static int |
@@ -1606,7 +1606,7 @@ djw_decode_1_2 (xd3_stream *stream, | |||
1606 | if (rep != 0) | 1606 | if (rep != 0) |
1607 | { | 1607 | { |
1608 | stream->msg = "secondary decoder invalid repeat code"; | 1608 | stream->msg = "secondary decoder invalid repeat code"; |
1609 | return XD3_INTERNAL; | 1609 | return XD3_INVALID_INPUT; |
1610 | } | 1610 | } |
1611 | 1611 | ||
1612 | return 0; | 1612 | return 0; |
@@ -1654,7 +1654,7 @@ xd3_decode_huff (xd3_stream *stream, | |||
1654 | if (output_bytes == 0) | 1654 | if (output_bytes == 0) |
1655 | { | 1655 | { |
1656 | stream->msg = "secondary decoder invalid input"; | 1656 | stream->msg = "secondary decoder invalid input"; |
1657 | return XD3_INTERNAL; | 1657 | return XD3_INVALID_INPUT; |
1658 | } | 1658 | } |
1659 | 1659 | ||
1660 | /* Decode: number of groups */ | 1660 | /* Decode: number of groups */ |
@@ -1796,7 +1796,11 @@ xd3_decode_huff (xd3_stream *stream, | |||
1796 | gp_maxlen = maxlen[gp]; | 1796 | gp_maxlen = maxlen[gp]; |
1797 | } | 1797 | } |
1798 | 1798 | ||
1799 | XD3_ASSERT (output_end - output > 0); | 1799 | if (output_end < output) |
1800 | { | ||
1801 | stream->msg = "secondary decoder invalid input"; | ||
1802 | return XD3_INVALID_INPUT; | ||
1803 | } | ||
1800 | 1804 | ||
1801 | /* Decode next sector. */ | 1805 | /* Decode next sector. */ |
1802 | n = xd3_min (sector_size, (usize_t) (output_end - output)); | 1806 | n = xd3_min (sector_size, (usize_t) (output_end - output)); |
diff --git a/xdelta3/xdelta3-internal.h b/xdelta3/xdelta3-internal.h index 6482721..d54584d 100644 --- a/xdelta3/xdelta3-internal.h +++ b/xdelta3/xdelta3-internal.h | |||
@@ -335,6 +335,7 @@ xd3_emit_uint64_t (xd3_stream *stream, xd3_output **output, uint64_t num) | |||
335 | 335 | ||
336 | #if SIZEOF_USIZE_T == 4 | 336 | #if SIZEOF_USIZE_T == 4 |
337 | #define USIZE_T_MAX UINT32_MAX | 337 | #define USIZE_T_MAX UINT32_MAX |
338 | #define USIZE_T_MAXBLKSZ 0x80000000U | ||
338 | #define xd3_decode_size xd3_decode_uint32_t | 339 | #define xd3_decode_size xd3_decode_uint32_t |
339 | #define xd3_emit_size xd3_emit_uint32_t | 340 | #define xd3_emit_size xd3_emit_uint32_t |
340 | #define xd3_sizeof_size xd3_sizeof_uint32_t | 341 | #define xd3_sizeof_size xd3_sizeof_uint32_t |
@@ -342,9 +343,10 @@ xd3_emit_uint64_t (xd3_stream *stream, xd3_output **output, uint64_t num) | |||
342 | #define xd3_large_cksum xd3_large32_cksum | 343 | #define xd3_large_cksum xd3_large32_cksum |
343 | #define xd3_large_cksum_update xd3_large32_cksum_update | 344 | #define xd3_large_cksum_update xd3_large32_cksum_update |
344 | #define xd3_hash_multiplier xd3_hash_multiplier32 | 345 | #define xd3_hash_multiplier xd3_hash_multiplier32 |
345 | #define XD3_MAXSRCWINSZ (1ULL << 31) | 346 | #define XD3_MAXSRCWINSZ (1ULL << 31) |
346 | #elif SIZEOF_USIZE_T == 8 | 347 | #elif SIZEOF_USIZE_T == 8 |
347 | #define USIZE_T_MAX UINT64_MAX | 348 | #define USIZE_T_MAX UINT64_MAX |
349 | #define USIZE_T_MAXBLKSZ 0x8000000000000000ULL | ||
348 | #define xd3_decode_size xd3_decode_uint64_t | 350 | #define xd3_decode_size xd3_decode_uint64_t |
349 | #define xd3_emit_size xd3_emit_uint64_t | 351 | #define xd3_emit_size xd3_emit_uint64_t |
350 | #define xd3_sizeof_size xd3_sizeof_uint64_t | 352 | #define xd3_sizeof_size xd3_sizeof_uint64_t |
@@ -352,7 +354,7 @@ xd3_emit_uint64_t (xd3_stream *stream, xd3_output **output, uint64_t num) | |||
352 | #define xd3_large_cksum xd3_large64_cksum | 354 | #define xd3_large_cksum xd3_large64_cksum |
353 | #define xd3_large_cksum_update xd3_large64_cksum_update | 355 | #define xd3_large_cksum_update xd3_large64_cksum_update |
354 | #define xd3_hash_multiplier xd3_hash_multiplier64 | 356 | #define xd3_hash_multiplier xd3_hash_multiplier64 |
355 | #define XD3_MAXSRCWINSZ (1ULL << 61) | 357 | #define XD3_MAXSRCWINSZ (1ULL << 61) |
356 | #endif /* SIZEOF_USIZE_T */ | 358 | #endif /* SIZEOF_USIZE_T */ |
357 | 359 | ||
358 | #if SIZEOF_XOFF_T == 4 | 360 | #if SIZEOF_XOFF_T == 4 |
diff --git a/xdelta3/xdelta3-main.h b/xdelta3/xdelta3-main.h index cfc952c..e43f6b3 100644 --- a/xdelta3/xdelta3-main.h +++ b/xdelta3/xdelta3-main.h | |||
@@ -870,6 +870,8 @@ main_file_open (main_file *xfile, const char* name, int mode) | |||
870 | return XD3_INVALID; | 870 | return XD3_INVALID; |
871 | } | 871 | } |
872 | 872 | ||
873 | IF_DEBUG1(DP(RINT "[main] open source %s\n", name)); | ||
874 | |||
873 | #if XD3_STDIO | 875 | #if XD3_STDIO |
874 | xfile->file = fopen (name, XOPEN_STDIO); | 876 | xfile->file = fopen (name, XOPEN_STDIO); |
875 | 877 | ||
@@ -1041,6 +1043,7 @@ main_file_read (main_file *ifile, | |||
1041 | const char *msg) | 1043 | const char *msg) |
1042 | { | 1044 | { |
1043 | int ret = 0; | 1045 | int ret = 0; |
1046 | IF_DEBUG1(DP(RINT "[main] read %s up to %"Z"u\n", ifile->filename, size)); | ||
1044 | 1047 | ||
1045 | #if XD3_STDIO | 1048 | #if XD3_STDIO |
1046 | size_t result; | 1049 | size_t result; |
@@ -1081,6 +1084,8 @@ main_file_write (main_file *ofile, uint8_t *buf, usize_t size, const char *msg) | |||
1081 | { | 1084 | { |
1082 | int ret = 0; | 1085 | int ret = 0; |
1083 | 1086 | ||
1087 | IF_DEBUG1(DP(RINT "[main] write %u\n bytes", size)); | ||
1088 | |||
1084 | #if XD3_STDIO | 1089 | #if XD3_STDIO |
1085 | usize_t result; | 1090 | usize_t result; |
1086 | 1091 | ||
@@ -1150,6 +1155,8 @@ main_write_output (xd3_stream* stream, main_file *ofile) | |||
1150 | { | 1155 | { |
1151 | int ret; | 1156 | int ret; |
1152 | 1157 | ||
1158 | IF_DEBUG1(DP(RINT "[main] write(%s) %u\n bytes", ofile->filename, stream->avail_out)); | ||
1159 | |||
1153 | if (option_no_output) | 1160 | if (option_no_output) |
1154 | { | 1161 | { |
1155 | return 0; | 1162 | return 0; |
@@ -3335,7 +3342,7 @@ main_input (xd3_cmd cmd, | |||
3335 | main_format_bcnt (stream.total_in, &trdb), | 3342 | main_format_bcnt (stream.total_in, &trdb), |
3336 | main_format_bcnt (stream.total_out, &twdb), | 3343 | main_format_bcnt (stream.total_out, &twdb), |
3337 | main_format_millis (millis, &tm), | 3344 | main_format_millis (millis, &tm), |
3338 | main_format_bcnt (sfile->source_position, &srcpos)); | 3345 | main_format_bcnt (stream.srcwin_cksum_pos, &srcpos)); |
3339 | } | 3346 | } |
3340 | else | 3347 | else |
3341 | { | 3348 | { |
diff --git a/xdelta3/xdelta3-merge.h b/xdelta3/xdelta3-merge.h index 72bc892..a09f814 100644 --- a/xdelta3/xdelta3-merge.h +++ b/xdelta3/xdelta3-merge.h | |||
@@ -492,10 +492,15 @@ xd3_merge_source_copy (xd3_stream *stream, | |||
492 | } | 492 | } |
493 | else | 493 | else |
494 | { | 494 | { |
495 | // TODO: this is slow because of the recursion, which | 495 | // Note: A better implementation will construct the |
496 | // could reach a depth equal to the number of target | 496 | // mapping of output ranges, starting from the input |
497 | // copies, and this is compression-inefficient because | 497 | // range, applying deltas in forward order, using an |
498 | // it can produce duplicate adds. | 498 | // interval tree. This code uses recursion to construct |
499 | // each copied range, recursively (using binary search | ||
500 | // in xd3_merge_find_position). | ||
501 | // | ||
502 | // TODO: This code can cause stack overflow. Fix as | ||
503 | // described above. | ||
499 | xd3_winst tinst; | 504 | xd3_winst tinst; |
500 | tinst.type = XD3_CPY; | 505 | tinst.type = XD3_CPY; |
501 | tinst.mode = iinst.mode; | 506 | tinst.mode = iinst.mode; |
@@ -555,12 +560,14 @@ int xd3_merge_inputs (xd3_stream *stream, | |||
555 | ret = xd3_merge_add (stream, input, iinst); | 560 | ret = xd3_merge_add (stream, input, iinst); |
556 | break; | 561 | break; |
557 | default: | 562 | default: |
558 | /* TODO: VCD_TARGET support is completely untested all | 563 | if (iinst->mode == 0) |
559 | * throughout. */ | ||
560 | if (iinst->mode == 0 || iinst->mode == VCD_TARGET) | ||
561 | { | 564 | { |
562 | ret = xd3_merge_target_copy (stream, iinst); | 565 | ret = xd3_merge_target_copy (stream, iinst); |
563 | } | 566 | } |
567 | else if (iinst->mode == VCD_TARGET) | ||
568 | { | ||
569 | ret = XD3_INVALID_INPUT; | ||
570 | } | ||
564 | else | 571 | else |
565 | { | 572 | { |
566 | ret = xd3_merge_source_copy (stream, source, iinst); | 573 | ret = xd3_merge_source_copy (stream, source, iinst); |
diff --git a/xdelta3/xdelta3-second.h b/xdelta3/xdelta3-second.h index 309c947..899902e 100644 --- a/xdelta3/xdelta3-second.h +++ b/xdelta3/xdelta3-second.h | |||
@@ -298,9 +298,12 @@ xd3_encode_secondary (xd3_stream *stream, | |||
298 | 298 | ||
299 | if (comp_size < (orig_size - SECONDARY_MIN_SAVINGS) || cfg->inefficient) | 299 | if (comp_size < (orig_size - SECONDARY_MIN_SAVINGS) || cfg->inefficient) |
300 | { | 300 | { |
301 | IF_DEBUG1(DP(RINT "secondary saved %u bytes: %u -> %u (%0.2f%%)\n", | 301 | if (comp_size < orig_size) |
302 | orig_size - comp_size, orig_size, comp_size, | 302 | { |
303 | 100.0 * (double) comp_size / (double) orig_size)); | 303 | IF_DEBUG1(DP(RINT "[encode_secondary] saved %u bytes: %u -> %u (%0.2f%%)\n", |
304 | orig_size - comp_size, orig_size, comp_size, | ||
305 | 100.0 * (double) comp_size / (double) orig_size)); | ||
306 | } | ||
304 | 307 | ||
305 | xd3_free_output (stream, *head); | 308 | xd3_free_output (stream, *head); |
306 | 309 | ||
diff --git a/xdelta3/xdelta3-test.h b/xdelta3/xdelta3-test.h index ddbfd65..335de28 100644 --- a/xdelta3/xdelta3-test.h +++ b/xdelta3/xdelta3-test.h | |||
@@ -3009,9 +3009,9 @@ int xd3_selftest (void) | |||
3009 | #endif | 3009 | #endif |
3010 | 3010 | ||
3011 | DO_TEST (recode_command, 0, 0); | 3011 | DO_TEST (recode_command, 0, 0); |
3012 | IF_LZMA (DO_TEST (secondary_lzma_default, 0, 0)); | ||
3012 | #endif | 3013 | #endif |
3013 | 3014 | ||
3014 | IF_LZMA (DO_TEST (secondary_lzma_default, 0, 0)); | ||
3015 | IF_LZMA (DO_TEST (secondary_lzma, 0, 1)); | 3015 | IF_LZMA (DO_TEST (secondary_lzma, 0, 1)); |
3016 | IF_DJW (DO_TEST (secondary_huff, 0, DJW_MAX_GROUPS)); | 3016 | IF_DJW (DO_TEST (secondary_huff, 0, DJW_MAX_GROUPS)); |
3017 | IF_FGK (DO_TEST (secondary_fgk, 0, 1)); | 3017 | IF_FGK (DO_TEST (secondary_fgk, 0, 1)); |
diff --git a/xdelta3/xdelta3.c b/xdelta3/xdelta3.c index d95d97d..9253d68 100644 --- a/xdelta3/xdelta3.c +++ b/xdelta3/xdelta3.c | |||
@@ -519,7 +519,7 @@ static void xd3_verify_large_state (xd3_stream *stream, | |||
519 | usize_t x_cksum); | 519 | usize_t x_cksum); |
520 | static void xd3_verify_small_state (xd3_stream *stream, | 520 | static void xd3_verify_small_state (xd3_stream *stream, |
521 | const uint8_t *inp, | 521 | const uint8_t *inp, |
522 | uint32_t x_cksum); | 522 | uint32_t x_cksum); |
523 | 523 | ||
524 | #endif /* XD3_DEBUG */ | 524 | #endif /* XD3_DEBUG */ |
525 | #endif /* XD3_ENCODER */ | 525 | #endif /* XD3_ENCODER */ |
@@ -1067,7 +1067,17 @@ xd3_round_blksize (usize_t sz, usize_t blksz) | |||
1067 | 1067 | ||
1068 | XD3_ASSERT (xd3_check_pow2 (blksz, NULL) == 0); | 1068 | XD3_ASSERT (xd3_check_pow2 (blksz, NULL) == 0); |
1069 | 1069 | ||
1070 | return mod ? (sz + (blksz - mod)) : sz; | 1070 | if (mod == 0) |
1071 | { | ||
1072 | return sz; | ||
1073 | } | ||
1074 | |||
1075 | if (sz > USIZE_T_MAXBLKSZ) | ||
1076 | { | ||
1077 | return USIZE_T_MAXBLKSZ; | ||
1078 | } | ||
1079 | |||
1080 | return sz + (blksz - mod); | ||
1071 | } | 1081 | } |
1072 | 1082 | ||
1073 | /*********************************************************************** | 1083 | /*********************************************************************** |
@@ -1848,7 +1858,7 @@ xd3_config_stream(xd3_stream *stream, | |||
1848 | inline | 1858 | inline |
1849 | xoff_t xd3_source_eof(const xd3_source *src) | 1859 | xoff_t xd3_source_eof(const xd3_source *src) |
1850 | { | 1860 | { |
1851 | xoff_t r = (src->blksize * src->max_blkno) + src->onlastblk; | 1861 | xoff_t r = (src->max_blkno << src->shiftby) + (xoff_t)src->onlastblk; |
1852 | return r; | 1862 | return r; |
1853 | } | 1863 | } |
1854 | 1864 | ||
@@ -1862,7 +1872,7 @@ usize_t xd3_bytes_on_srcblk (xd3_source *src, xoff_t blkno) | |||
1862 | } | 1872 | } |
1863 | 1873 | ||
1864 | /* This function interfaces with the client getblk function, checks | 1874 | /* This function interfaces with the client getblk function, checks |
1865 | * its results, updates frontier_blkno, max_blkno, onlastblk, eof_known. */ | 1875 | * its results, updates max_blkno, onlastblk, eof_known. */ |
1866 | static int | 1876 | static int |
1867 | xd3_getblk (xd3_stream *stream, xoff_t blkno) | 1877 | xd3_getblk (xd3_stream *stream, xoff_t blkno) |
1868 | { | 1878 | { |
@@ -1875,6 +1885,7 @@ xd3_getblk (xd3_stream *stream, xoff_t blkno) | |||
1875 | 1885 | ||
1876 | if (stream->getblk == NULL) | 1886 | if (stream->getblk == NULL) |
1877 | { | 1887 | { |
1888 | IF_DEBUG2 (DP(RINT "[getblk] XD3_GETSRCBLK %"Q"u\n", blkno)); | ||
1878 | stream->msg = "getblk source input"; | 1889 | stream->msg = "getblk source input"; |
1879 | return XD3_GETSRCBLK; | 1890 | return XD3_GETSRCBLK; |
1880 | } | 1891 | } |
@@ -1882,48 +1893,34 @@ xd3_getblk (xd3_stream *stream, xoff_t blkno) | |||
1882 | ret = stream->getblk (stream, source, blkno); | 1893 | ret = stream->getblk (stream, source, blkno); |
1883 | if (ret != 0) | 1894 | if (ret != 0) |
1884 | { | 1895 | { |
1885 | IF_DEBUG1 (DP(RINT "[getblk] app error blkno %"Q": %s\n", | 1896 | IF_DEBUG2 (DP(RINT "[getblk] app error blkno %"Q"u: %s\n", |
1886 | blkno, xd3_strerror (ret))); | 1897 | blkno, xd3_strerror (ret))); |
1887 | return ret; | 1898 | return ret; |
1888 | } | 1899 | } |
1889 | IF_DEBUG2 (DP(RINT "[getblk] read source block %"Q" onblk " | 1900 | |
1890 | "%u blksize %u\n", blkno, source->onblk, source->blksize)); | 1901 | IF_DEBUG2 (DP(RINT "[getblk] read source block %"Q"u onblk " |
1902 | "%u blksize %u max_blkno %"Q"u\n", blkno, source->onblk, | ||
1903 | source->blksize, source->max_blkno)); | ||
1891 | } | 1904 | } |
1892 | 1905 | ||
1893 | if (blkno >= source->frontier_blkno) | 1906 | if (blkno > source->max_blkno) |
1894 | { | 1907 | { |
1895 | if (blkno > source->max_blkno) | 1908 | source->max_blkno = blkno; |
1896 | { | ||
1897 | source->max_blkno = blkno; | ||
1898 | source->onlastblk = source->onblk; | ||
1899 | } | ||
1900 | 1909 | ||
1901 | if (source->onblk == source->blksize) | 1910 | if (source->onblk == source->blksize) |
1902 | { | 1911 | { |
1903 | source->frontier_blkno = blkno + 1; | 1912 | IF_DEBUG1 (DP(RINT "[getblk] full source blkno %"Q"u: " |
1904 | 1913 | "source length unknown %"Q"u\n", | |
1905 | IF_DEBUG2 (DP(RINT "[getblk] full source blkno %"Q": " | ||
1906 | "source length unknown %"Q"\n", | ||
1907 | blkno, | 1914 | blkno, |
1908 | xd3_source_eof (source))); | 1915 | xd3_source_eof (source))); |
1909 | } | 1916 | } |
1910 | else | 1917 | else if (!source->eof_known) |
1911 | { | 1918 | { |
1912 | source->frontier_blkno = blkno; | 1919 | IF_DEBUG1 (DP(RINT "[getblk] eof block has %d bytes; " |
1913 | 1920 | "source length known %"Q"u\n", | |
1914 | if (xd3_bytes_on_srcblk (source, blkno) != 0) | 1921 | xd3_bytes_on_srcblk (source, blkno), |
1915 | { | 1922 | xd3_source_eof (source))); |
1916 | source->frontier_blkno += 1; | 1923 | source->eof_known = 1; |
1917 | } | ||
1918 | |||
1919 | if (!source->eof_known) | ||
1920 | { | ||
1921 | IF_DEBUG2 (DP(RINT "[getblk] eof block has %d bytes; " | ||
1922 | "source length known %"Q"\n", | ||
1923 | xd3_bytes_on_srcblk (source, blkno), | ||
1924 | xd3_source_eof (source))); | ||
1925 | source->eof_known = 1; | ||
1926 | } | ||
1927 | } | 1924 | } |
1928 | } | 1925 | } |
1929 | 1926 | ||
@@ -1932,13 +1929,8 @@ xd3_getblk (xd3_stream *stream, xoff_t blkno) | |||
1932 | if (blkno == source->max_blkno) | 1929 | if (blkno == source->max_blkno) |
1933 | { | 1930 | { |
1934 | /* In case the application sets the source as 1 block w/ a | 1931 | /* In case the application sets the source as 1 block w/ a |
1935 | preset buffer. */ | 1932 | * preset buffer. */ |
1936 | source->onlastblk = source->onblk; | 1933 | source->onlastblk = source->onblk; |
1937 | |||
1938 | if (source->onblk == source->blksize) | ||
1939 | { | ||
1940 | source->frontier_blkno = blkno + 1; | ||
1941 | } | ||
1942 | } | 1934 | } |
1943 | return 0; | 1935 | return 0; |
1944 | } | 1936 | } |
@@ -1975,7 +1967,6 @@ xd3_set_source (xd3_stream *stream, | |||
1975 | IF_DEBUG1 (DP(RINT "raising src_maxsize to %u\n", src->blksize)); | 1967 | IF_DEBUG1 (DP(RINT "raising src_maxsize to %u\n", src->blksize)); |
1976 | } | 1968 | } |
1977 | src->max_winsize = xd3_max (src->max_winsize, XD3_ALLOCSIZE); | 1969 | src->max_winsize = xd3_max (src->max_winsize, XD3_ALLOCSIZE); |
1978 | |||
1979 | return 0; | 1970 | return 0; |
1980 | } | 1971 | } |
1981 | 1972 | ||
@@ -1989,11 +1980,13 @@ xd3_set_source_and_size (xd3_stream *stream, | |||
1989 | stream->src->eof_known = 1; | 1980 | stream->src->eof_known = 1; |
1990 | IF_DEBUG2 (DP(RINT "[set source] size known %"Q"\n", | 1981 | IF_DEBUG2 (DP(RINT "[set source] size known %"Q"\n", |
1991 | source_size)); | 1982 | source_size)); |
1992 | |||
1993 | xd3_blksize_div(source_size, | 1983 | xd3_blksize_div(source_size, |
1994 | stream->src, | 1984 | stream->src, |
1995 | &stream->src->max_blkno, | 1985 | &stream->src->max_blkno, |
1996 | &stream->src->onlastblk); | 1986 | &stream->src->onlastblk); |
1987 | |||
1988 | IF_DEBUG1 (DP(RINT "[set source] size known %"Q"u max_blkno %"Q"u\n", | ||
1989 | source_size, stream->src->max_blkno)); | ||
1997 | } | 1990 | } |
1998 | return ret; | 1991 | return ret; |
1999 | } | 1992 | } |
@@ -2047,8 +2040,8 @@ xd3_close_stream (xd3_stream *stream) | |||
2047 | break; | 2040 | break; |
2048 | default: | 2041 | default: |
2049 | /* If decoding, should be ready for the next window. */ | 2042 | /* If decoding, should be ready for the next window. */ |
2050 | stream->msg = "EOF in decode"; | 2043 | stream->msg = "eof in decode"; |
2051 | return XD3_INTERNAL; | 2044 | return XD3_INVALID_INPUT; |
2052 | } | 2045 | } |
2053 | } | 2046 | } |
2054 | 2047 | ||
@@ -2207,8 +2200,6 @@ xd3_iopt_finish_encoding (xd3_stream *stream, xd3_rinst *inst) | |||
2207 | } | 2200 | } |
2208 | case XD3_RUN: | 2201 | case XD3_RUN: |
2209 | { | 2202 | { |
2210 | XD3_ASSERT (inst->size >= MIN_MATCH); | ||
2211 | |||
2212 | if ((ret = xd3_emit_byte (stream, & DATA_TAIL (stream), inst->xtra))) { return ret; } | 2203 | if ((ret = xd3_emit_byte (stream, & DATA_TAIL (stream), inst->xtra))) { return ret; } |
2213 | 2204 | ||
2214 | stream->n_run += 1; | 2205 | stream->n_run += 1; |
@@ -3194,6 +3185,7 @@ xd3_encode_input (xd3_stream *stream) | |||
3194 | * or else it can get stuck in a match-backward | 3185 | * or else it can get stuck in a match-backward |
3195 | * (getsrcblk) then match-forward (getsrcblk), | 3186 | * (getsrcblk) then match-forward (getsrcblk), |
3196 | * find insufficient match length, then repeat | 3187 | * find insufficient match length, then repeat |
3188 | |||
3197 | * exactly the same search. | 3189 | * exactly the same search. |
3198 | */ | 3190 | */ |
3199 | stream->input_position += stream->match_fwd; | 3191 | stream->input_position += stream->match_fwd; |
@@ -3219,7 +3211,7 @@ xd3_encode_input (xd3_stream *stream) | |||
3219 | 3211 | ||
3220 | case ENC_INSTR: | 3212 | case ENC_INSTR: |
3221 | /* Note: Jump here to encode VCDIFF deltas w/o using this | 3213 | /* Note: Jump here to encode VCDIFF deltas w/o using this |
3222 | * string-matching code. Merging code code enters here. */ | 3214 | * string-matching code. Merging code enters here. */ |
3223 | 3215 | ||
3224 | /* Flush the instrution buffer, then possibly add one more | 3216 | /* Flush the instrution buffer, then possibly add one more |
3225 | * instruction, then emit the header. */ | 3217 | * instruction, then emit the header. */ |
@@ -3674,7 +3666,7 @@ xd3_srcwin_setup (xd3_stream *stream) | |||
3674 | /* Otherwise, we have to make a guess. More copies may still be | 3666 | /* Otherwise, we have to make a guess. More copies may still be |
3675 | * issued, but we have to decide the source window base and length | 3667 | * issued, but we have to decide the source window base and length |
3676 | * now. | 3668 | * now. |
3677 | * TODO: This >> 2 is arbitrary--try other values. */ | 3669 | * TODO: This may not working well in practice, more testing needed. */ |
3678 | src->srcbase = stream->match_minaddr; | 3670 | src->srcbase = stream->match_minaddr; |
3679 | src->srclen = xd3_max ((usize_t) length, | 3671 | src->srclen = xd3_max ((usize_t) length, |
3680 | stream->avail_in + (stream->avail_in >> 2)); | 3672 | stream->avail_in + (stream->avail_in >> 2)); |
@@ -3707,9 +3699,8 @@ xd3_srcwin_setup (xd3_stream *stream) | |||
3707 | static int | 3699 | static int |
3708 | xd3_source_match_setup (xd3_stream *stream, xoff_t srcpos) | 3700 | xd3_source_match_setup (xd3_stream *stream, xoff_t srcpos) |
3709 | { | 3701 | { |
3710 | xd3_source *src = stream->src; | 3702 | xd3_source *const src = stream->src; |
3711 | usize_t greedy_or_not; | 3703 | usize_t greedy_or_not; |
3712 | xoff_t frontier_pos; | ||
3713 | 3704 | ||
3714 | stream->match_maxback = 0; | 3705 | stream->match_maxback = 0; |
3715 | stream->match_maxfwd = 0; | 3706 | stream->match_maxfwd = 0; |
@@ -3733,18 +3724,24 @@ xd3_source_match_setup (xd3_stream *stream, xoff_t srcpos) | |||
3733 | /* Implement src->max_winsize, which prevents the encoder from seeking | 3724 | /* Implement src->max_winsize, which prevents the encoder from seeking |
3734 | * back further than the LRU cache maintaining FIFO discipline, (to | 3725 | * back further than the LRU cache maintaining FIFO discipline, (to |
3735 | * avoid seeking). */ | 3726 | * avoid seeking). */ |
3736 | frontier_pos = stream->src->frontier_blkno * stream->src->blksize; | 3727 | if (srcpos < stream->srcwin_cksum_pos && |
3737 | IF_DEBUG2(DP(RINT "[match_setup] frontier_pos %"Q", srcpos %"Q", " | 3728 | stream->srcwin_cksum_pos - srcpos > src->max_winsize) |
3738 | "src->max_winsize %"Q"\n", | 3729 | { |
3739 | frontier_pos, srcpos, stream->src->max_winsize)); | 3730 | IF_DEBUG2(DP(RINT "[match_setup] rejected due to src->max_winsize " |
3740 | if (srcpos < frontier_pos && | 3731 | "distance eof=%"Q"u srcpos=%"Q"u max_winsz=%"Q"u\n", |
3741 | frontier_pos - srcpos > stream->src->max_winsize) { | 3732 | xd3_source_eof (src), |
3742 | IF_DEBUG1(DP(RINT "[match_setup] rejected due to src->max_winsize " | 3733 | srcpos, src->max_winsize)); |
3743 | "distance eof=%"Q" srcpos=%"Q" maxsz=%"Q"\n", | 3734 | goto bad; |
3744 | xd3_source_eof (stream->src), | 3735 | } |
3745 | srcpos, stream->src->max_winsize)); | 3736 | |
3746 | goto bad; | 3737 | /* There are cases where the above test does not reject a match that |
3747 | } | 3738 | * will experience XD3_TOOFARBACK at the first xd3_getblk call |
3739 | * because the input may have advanced up to one block beyond the | ||
3740 | * actual EOF. */ | ||
3741 | IF_DEBUG2(DP(RINT "[match_setup] %"Q"u srcpos %"Q"u, " | ||
3742 | "src->max_winsize %"Q"u\n", | ||
3743 | stream->total_in + stream->input_position, | ||
3744 | srcpos, src->max_winsize)); | ||
3748 | 3745 | ||
3749 | /* Going backwards, the 1.5-pass algorithm allows some | 3746 | /* Going backwards, the 1.5-pass algorithm allows some |
3750 | * already-matched input may be covered by a longer source match. | 3747 | * already-matched input may be covered by a longer source match. |
@@ -3788,9 +3785,9 @@ xd3_source_match_setup (xd3_stream *stream, xoff_t srcpos) | |||
3788 | stream->match_maxback = (usize_t) srcpos; | 3785 | stream->match_maxback = (usize_t) srcpos; |
3789 | } | 3786 | } |
3790 | 3787 | ||
3791 | if (stream->src->eof_known) | 3788 | if (src->eof_known) |
3792 | { | 3789 | { |
3793 | xoff_t srcavail = xd3_source_eof (stream->src) - srcpos; | 3790 | xoff_t srcavail = xd3_source_eof (src) - srcpos; |
3794 | 3791 | ||
3795 | if (srcavail < stream->match_maxfwd) | 3792 | if (srcavail < stream->match_maxfwd) |
3796 | { | 3793 | { |
@@ -3834,8 +3831,8 @@ xd3_source_match_setup (xd3_stream *stream, xoff_t srcpos) | |||
3834 | stream->match_maxfwd = srcavail; | 3831 | stream->match_maxfwd = srcavail; |
3835 | } | 3832 | } |
3836 | 3833 | ||
3837 | IF_DEBUG1(DP(RINT | 3834 | IF_DEBUG2(DP(RINT |
3838 | "[match_setup] srcpos %"Q" (tgtpos %"Q") " | 3835 | "[match_setup] srcpos %"Q"u (tgtpos %"Q"u) " |
3839 | "restricted maxback %u maxfwd %u\n", | 3836 | "restricted maxback %u maxfwd %u\n", |
3840 | srcpos, | 3837 | srcpos, |
3841 | stream->total_in + stream->input_position, | 3838 | stream->total_in + stream->input_position, |
@@ -3852,6 +3849,7 @@ xd3_source_match_setup (xd3_stream *stream, xoff_t srcpos) | |||
3852 | 3849 | ||
3853 | bad: | 3850 | bad: |
3854 | stream->match_state = MATCH_SEARCHING; | 3851 | stream->match_state = MATCH_SEARCHING; |
3852 | stream->match_last_srcpos = srcpos; | ||
3855 | return 1; | 3853 | return 1; |
3856 | } | 3854 | } |
3857 | 3855 | ||
@@ -3903,7 +3901,7 @@ static int | |||
3903 | xd3_source_extend_match (xd3_stream *stream) | 3901 | xd3_source_extend_match (xd3_stream *stream) |
3904 | { | 3902 | { |
3905 | int ret; | 3903 | int ret; |
3906 | xd3_source *src = stream->src; | 3904 | xd3_source *const src = stream->src; |
3907 | xoff_t matchoff; /* matchoff is the current right/left-boundary of | 3905 | xoff_t matchoff; /* matchoff is the current right/left-boundary of |
3908 | the source match being tested. */ | 3906 | the source match being tested. */ |
3909 | usize_t streamoff; /* streamoff is the current right/left-boundary | 3907 | usize_t streamoff; /* streamoff is the current right/left-boundary |
@@ -3923,7 +3921,7 @@ xd3_source_extend_match (xd3_stream *stream) | |||
3923 | if (stream->match_state == MATCH_BACKWARD) | 3921 | if (stream->match_state == MATCH_BACKWARD) |
3924 | { | 3922 | { |
3925 | /* Note: this code is practically duplicated below, substituting | 3923 | /* Note: this code is practically duplicated below, substituting |
3926 | * match_fwd/match_back and direction. TODO: Consolidate? */ | 3924 | * match_fwd/match_back and direction. */ |
3927 | matchoff = stream->match_srcpos - stream->match_back; | 3925 | matchoff = stream->match_srcpos - stream->match_back; |
3928 | streamoff = stream->input_position - stream->match_back; | 3926 | streamoff = stream->input_position - stream->match_back; |
3929 | xd3_blksize_div (matchoff, src, &tryblk, &tryoff); | 3927 | xd3_blksize_div (matchoff, src, &tryblk, &tryoff); |
@@ -3940,10 +3938,22 @@ xd3_source_extend_match (xd3_stream *stream) | |||
3940 | 3938 | ||
3941 | if ((ret = xd3_getblk (stream, tryblk))) | 3939 | if ((ret = xd3_getblk (stream, tryblk))) |
3942 | { | 3940 | { |
3943 | /* if search went too far back, continue forward. */ | ||
3944 | if (ret == XD3_TOOFARBACK) | 3941 | if (ret == XD3_TOOFARBACK) |
3945 | { | 3942 | { |
3946 | break; | 3943 | IF_DEBUG2(DP(RINT "[maxback] %"Q"u TOOFARBACK: %u INP %"Q"u CKSUM %"Q"u\n", |
3944 | tryblk, stream->match_back, | ||
3945 | stream->total_in + stream->input_position, | ||
3946 | stream->srcwin_cksum_pos)); | ||
3947 | |||
3948 | /* the starting position is too far back. */ | ||
3949 | if (stream->match_back == 0) | ||
3950 | { | ||
3951 | XD3_ASSERT(stream->match_fwd == 0); | ||
3952 | goto donefwd; | ||
3953 | } | ||
3954 | |||
3955 | /* search went too far back, continue forward. */ | ||
3956 | goto doneback; | ||
3947 | } | 3957 | } |
3948 | 3958 | ||
3949 | /* could be a XD3_GETSRCBLK failure. */ | 3959 | /* could be a XD3_GETSRCBLK failure. */ |
@@ -3989,7 +3999,14 @@ xd3_source_extend_match (xd3_stream *stream) | |||
3989 | 3999 | ||
3990 | if ((ret = xd3_getblk (stream, tryblk))) | 4000 | if ((ret = xd3_getblk (stream, tryblk))) |
3991 | { | 4001 | { |
3992 | XD3_ASSERT (ret != XD3_TOOFARBACK); | 4002 | if (ret == XD3_TOOFARBACK) |
4003 | { | ||
4004 | IF_DEBUG2(DP(RINT "[maxfwd] %"Q"u TOOFARBACK: %u INP %"Q"u CKSUM %"Q"u\n", | ||
4005 | tryblk, stream->match_fwd, | ||
4006 | stream->total_in + stream->input_position, | ||
4007 | stream->srcwin_cksum_pos)); | ||
4008 | goto donefwd; | ||
4009 | } | ||
3993 | 4010 | ||
3994 | /* could be a XD3_GETSRCBLK failure. */ | 4011 | /* could be a XD3_GETSRCBLK failure. */ |
3995 | return ret; | 4012 | return ret; |
@@ -4020,8 +4037,14 @@ xd3_source_extend_match (xd3_stream *stream) | |||
4020 | } | 4037 | } |
4021 | } | 4038 | } |
4022 | 4039 | ||
4040 | donefwd: | ||
4023 | stream->match_state = MATCH_SEARCHING; | 4041 | stream->match_state = MATCH_SEARCHING; |
4024 | 4042 | ||
4043 | IF_DEBUG2(DP(RINT "[extend match] input %"Q"u srcpos %"Q"u len %u\n", | ||
4044 | stream->input_position + stream->total_in, | ||
4045 | stream->match_srcpos, | ||
4046 | stream->match_fwd)); | ||
4047 | |||
4025 | /* If the match ends short of the last instruction end, we probably | 4048 | /* If the match ends short of the last instruction end, we probably |
4026 | * don't want it. There is the possibility that a copy ends short | 4049 | * don't want it. There is the possibility that a copy ends short |
4027 | * of the last copy but also goes further back, in which case we | 4050 | * of the last copy but also goes further back, in which case we |
@@ -4073,8 +4096,9 @@ xd3_source_extend_match (xd3_stream *stream) | |||
4073 | 4096 | ||
4074 | IF_DEBUG2 ({ | 4097 | IF_DEBUG2 ({ |
4075 | static int x = 0; | 4098 | static int x = 0; |
4076 | DP(RINT "[source match:%d] <inp %"Q" %"Q"> <src %"Q" %"Q"> (%s) [ %u bytes ]\n", | 4099 | DP(RINT "[source match:%d] length %u <inp %"Q"u %"Q"u> <src %"Q"u %"Q"u> (%s) [ %u bytes ]\n", |
4077 | x++, | 4100 | x++, |
4101 | match_length, | ||
4078 | stream->total_in + target_position, | 4102 | stream->total_in + target_position, |
4079 | stream->total_in + target_position + match_length, | 4103 | stream->total_in + target_position + match_length, |
4080 | match_position, | 4104 | match_position, |
@@ -4315,17 +4339,18 @@ xd3_verify_run_state (xd3_stream *stream, | |||
4315 | * stream->input_position reaches the value returned as | 4339 | * stream->input_position reaches the value returned as |
4316 | * *next_move_point. NB: this is one of the most expensive functions | 4340 | * *next_move_point. NB: this is one of the most expensive functions |
4317 | * in this code and also the most critical for good compression. | 4341 | * in this code and also the most critical for good compression. |
4318 | * TODO: optimize the inner loop | ||
4319 | */ | 4342 | */ |
4320 | static int | 4343 | static int |
4321 | xd3_srcwin_move_point (xd3_stream *stream, usize_t *next_move_point) | 4344 | xd3_srcwin_move_point (xd3_stream *stream, usize_t *next_move_point) |
4322 | { | 4345 | { |
4323 | xoff_t logical_input_cksum_pos; | 4346 | /* the source file is indexed until this point */ |
4324 | xoff_t source_size; | 4347 | xoff_t target_cksum_pos; |
4348 | /* the absolute target file input position */ | ||
4349 | xoff_t absolute_input_pos; | ||
4325 | 4350 | ||
4326 | if (stream->src->eof_known) | 4351 | if (stream->src->eof_known) |
4327 | { | 4352 | { |
4328 | source_size = xd3_source_eof (stream->src); | 4353 | xoff_t source_size = xd3_source_eof (stream->src); |
4329 | XD3_ASSERT(stream->srcwin_cksum_pos <= source_size); | 4354 | XD3_ASSERT(stream->srcwin_cksum_pos <= source_size); |
4330 | 4355 | ||
4331 | if (stream->srcwin_cksum_pos == source_size) | 4356 | if (stream->srcwin_cksum_pos == source_size) |
@@ -4335,19 +4360,31 @@ xd3_srcwin_move_point (xd3_stream *stream, usize_t *next_move_point) | |||
4335 | } | 4360 | } |
4336 | } | 4361 | } |
4337 | 4362 | ||
4338 | /* Begin by advancing at twice the input rate, up to half the | 4363 | absolute_input_pos = stream->total_in + stream->input_position; |
4339 | * maximum window size. */ | ||
4340 | logical_input_cksum_pos = xd3_min((stream->total_in + stream->input_position) * 2, | ||
4341 | (stream->total_in + stream->input_position) + | ||
4342 | (stream->src->max_winsize / 2)); | ||
4343 | 4364 | ||
4344 | /* If srcwin_cksum_pos is already greater, wait until the difference | 4365 | /* Immediately read the entire window. |
4345 | * is met. */ | 4366 | * |
4346 | if (stream->srcwin_cksum_pos > logical_input_cksum_pos) | 4367 | * Note: this reverses a long held policy, at this point in the |
4368 | * code, of advancing relatively slowly as the input is read, which | ||
4369 | * results in better compression for very-similar inputs, but worse | ||
4370 | * compression where data is deleted near the beginning of the file. | ||
4371 | * | ||
4372 | * The new policy is simpler, somewhat slower and can benefit, or | ||
4373 | * slightly worsen, compression performance. */ | ||
4374 | if (absolute_input_pos < stream->src->max_winsize / 2) | ||
4347 | { | 4375 | { |
4348 | *next_move_point = stream->input_position + | 4376 | target_cksum_pos = stream->src->max_winsize; |
4349 | (usize_t)(stream->srcwin_cksum_pos - logical_input_cksum_pos); | 4377 | } |
4350 | return 0; | 4378 | else |
4379 | { | ||
4380 | /* TODO: The addition of 2 blocks here is arbitrary. Do a | ||
4381 | * better job of stream alignment based on observed source copy | ||
4382 | * addresses, and when both input sizes are known, the | ||
4383 | * difference in size. */ | ||
4384 | target_cksum_pos = absolute_input_pos + | ||
4385 | stream->src->max_winsize / 2 + | ||
4386 | stream->src->blksize * 2; | ||
4387 | target_cksum_pos &= ~stream->src->maskby; | ||
4351 | } | 4388 | } |
4352 | 4389 | ||
4353 | /* A long match may have extended past srcwin_cksum_pos. Don't | 4390 | /* A long match may have extended past srcwin_cksum_pos. Don't |
@@ -4357,27 +4394,12 @@ xd3_srcwin_move_point (xd3_stream *stream, usize_t *next_move_point) | |||
4357 | stream->srcwin_cksum_pos = stream->maxsrcaddr; | 4394 | stream->srcwin_cksum_pos = stream->maxsrcaddr; |
4358 | } | 4395 | } |
4359 | 4396 | ||
4360 | if (logical_input_cksum_pos < stream->srcwin_cksum_pos) | 4397 | if (target_cksum_pos < stream->srcwin_cksum_pos) |
4361 | { | 4398 | { |
4362 | logical_input_cksum_pos = stream->srcwin_cksum_pos; | 4399 | target_cksum_pos = stream->srcwin_cksum_pos; |
4363 | } | 4400 | } |
4364 | 4401 | ||
4365 | /* Advance at least one source block. With the command-line | 4402 | while (stream->srcwin_cksum_pos < target_cksum_pos && |
4366 | * defaults this means: | ||
4367 | * | ||
4368 | * if (src->size <= src->max_winsize), index the entire source at once | ||
4369 | * using the position of the first non-match. This is good for | ||
4370 | * small inputs, especially when the content may have moved anywhere | ||
4371 | * in the file (e.g., tar files). | ||
4372 | * | ||
4373 | * if (src->size > src->max_winsize), index at least one block ahead | ||
4374 | * of the logical position. This is good for different reasons: | ||
4375 | * when a long match spanning several source blocks is encountered, | ||
4376 | * this avoids computing checksums for those blocks. | ||
4377 | */ | ||
4378 | logical_input_cksum_pos += stream->src->blksize; | ||
4379 | |||
4380 | while (stream->srcwin_cksum_pos < logical_input_cksum_pos && | ||
4381 | (!stream->src->eof_known || | 4403 | (!stream->src->eof_known || |
4382 | stream->srcwin_cksum_pos < xd3_source_eof (stream->src))) | 4404 | stream->srcwin_cksum_pos < xd3_source_eof (stream->src))) |
4383 | { | 4405 | { |
@@ -4399,17 +4421,19 @@ xd3_srcwin_move_point (xd3_stream *stream, usize_t *next_move_point) | |||
4399 | { | 4421 | { |
4400 | ret = XD3_INTERNAL; | 4422 | ret = XD3_INTERNAL; |
4401 | } | 4423 | } |
4424 | |||
4402 | IF_DEBUG1 (DP(RINT | 4425 | IF_DEBUG1 (DP(RINT |
4403 | "[srcwin_move_point] async getblk return for %"Q"\n", | 4426 | "[srcwin_move_point] async getblk return for %"Q"u: %s\n", |
4404 | blkno)); | 4427 | blkno, xd3_strerror (ret))); |
4405 | return ret; | 4428 | return ret; |
4406 | } | 4429 | } |
4407 | 4430 | ||
4408 | IF_DEBUG1 (DP(RINT | 4431 | IF_DEBUG1 (DP(RINT |
4409 | "[srcwin_move_point] T=%"Q"{%"Q"} S=%"Q" EOF=%"Q" %s\n", | 4432 | "[srcwin_move_point] block %"Q"u T=%"Q"u S=%"Q"u L=%"Q"u EOF=%"Q"u %s\n", |
4433 | blkno, | ||
4410 | stream->total_in + stream->input_position, | 4434 | stream->total_in + stream->input_position, |
4411 | logical_input_cksum_pos, | ||
4412 | stream->srcwin_cksum_pos, | 4435 | stream->srcwin_cksum_pos, |
4436 | target_cksum_pos, | ||
4413 | xd3_source_eof (stream->src), | 4437 | xd3_source_eof (stream->src), |
4414 | stream->src->eof_known ? "known" : "unknown")); | 4438 | stream->src->eof_known ? "known" : "unknown")); |
4415 | 4439 | ||
@@ -4418,7 +4442,7 @@ xd3_srcwin_move_point (xd3_stream *stream, usize_t *next_move_point) | |||
4418 | if (blkpos < (ssize_t) stream->smatcher.large_look) | 4442 | if (blkpos < (ssize_t) stream->smatcher.large_look) |
4419 | { | 4443 | { |
4420 | stream->srcwin_cksum_pos = (blkno + 1) * stream->src->blksize; | 4444 | stream->srcwin_cksum_pos = (blkno + 1) * stream->src->blksize; |
4421 | IF_DEBUG1 (DP(RINT "[srcwin_move_point] continue (end-of-block)\n")); | 4445 | IF_DEBUG2 (DP(RINT "[srcwin_move_point] continue (end-of-block): %"Q"u\n", blkpos)); |
4422 | continue; | 4446 | continue; |
4423 | } | 4447 | } |
4424 | 4448 | ||
@@ -4468,8 +4492,7 @@ xd3_srcwin_move_point (xd3_stream *stream, usize_t *next_move_point) | |||
4468 | 4492 | ||
4469 | if (stream->src->eof_known) | 4493 | if (stream->src->eof_known) |
4470 | { | 4494 | { |
4471 | source_size = xd3_source_eof (stream->src); | 4495 | xoff_t source_size = xd3_source_eof (stream->src); |
4472 | |||
4473 | if (stream->srcwin_cksum_pos >= source_size) | 4496 | if (stream->srcwin_cksum_pos >= source_size) |
4474 | { | 4497 | { |
4475 | /* This invariant is needed for xd3_source_cksum_offset() */ | 4498 | /* This invariant is needed for xd3_source_cksum_offset() */ |
@@ -4482,9 +4505,22 @@ xd3_srcwin_move_point (xd3_stream *stream, usize_t *next_move_point) | |||
4482 | } | 4505 | } |
4483 | 4506 | ||
4484 | /* How long until this function should be called again. */ | 4507 | /* How long until this function should be called again. */ |
4485 | XD3_ASSERT(stream->srcwin_cksum_pos >= logical_input_cksum_pos); | 4508 | XD3_ASSERT(stream->srcwin_cksum_pos >= target_cksum_pos); |
4486 | *next_move_point = stream->input_position + 1 + | 4509 | |
4487 | (usize_t)(stream->srcwin_cksum_pos - logical_input_cksum_pos); | 4510 | *next_move_point = stream->input_position + |
4511 | stream->src->blksize - | ||
4512 | ((stream->srcwin_cksum_pos - target_cksum_pos) & stream->src->maskby); | ||
4513 | |||
4514 | IF_DEBUG2 (DP(RINT | ||
4515 | "[srcwin_move_point] finished T=%"Q"u " | ||
4516 | "S=%"Q"u L=%"Q"u EOF=%"Q"u %s again in %u\n", | ||
4517 | stream->total_in + stream->input_position, | ||
4518 | stream->srcwin_cksum_pos, | ||
4519 | target_cksum_pos, | ||
4520 | xd3_source_eof (stream->src), | ||
4521 | stream->src->eof_known ? "known" : "unknown", | ||
4522 | *next_move_point - stream->input_position)); | ||
4523 | |||
4488 | return 0; | 4524 | return 0; |
4489 | } | 4525 | } |
4490 | 4526 | ||
@@ -4543,6 +4579,8 @@ XD3_TEMPLATE(xd3_string_match_) (xd3_stream *stream) | |||
4543 | usize_t match_offset = 0; | 4579 | usize_t match_offset = 0; |
4544 | usize_t next_move_point; | 4580 | usize_t next_move_point; |
4545 | 4581 | ||
4582 | IF_DEBUG2(DP(RINT "[string_match] initial entry %u\n", stream->input_position)); | ||
4583 | |||
4546 | /* If there will be no compression due to settings or short input, | 4584 | /* If there will be no compression due to settings or short input, |
4547 | * skip it entirely. */ | 4585 | * skip it entirely. */ |
4548 | if (! (DO_SMALL || DO_LARGE || DO_RUN) || | 4586 | if (! (DO_SMALL || DO_LARGE || DO_RUN) || |
@@ -4554,6 +4592,8 @@ XD3_TEMPLATE(xd3_string_match_) (xd3_stream *stream) | |||
4554 | * needs to be reset. */ | 4592 | * needs to be reset. */ |
4555 | restartloop: | 4593 | restartloop: |
4556 | 4594 | ||
4595 | IF_DEBUG2(DP(RINT "[string_match] restartloop %u\n", stream->input_position)); | ||
4596 | |||
4557 | /* If there is not enough input remaining for any kind of match, | 4597 | /* If there is not enough input remaining for any kind of match, |
4558 | skip it. */ | 4598 | skip it. */ |
4559 | if (stream->input_position + SLOOK > stream->avail_in) { goto loopnomore; } | 4599 | if (stream->input_position + SLOOK > stream->avail_in) { goto loopnomore; } |
@@ -4597,7 +4637,9 @@ XD3_TEMPLATE(xd3_string_match_) (xd3_stream *stream) | |||
4597 | { | 4637 | { |
4598 | /* Source window: next_move_point is the point that | 4638 | /* Source window: next_move_point is the point that |
4599 | * stream->input_position must reach before computing more | 4639 | * stream->input_position must reach before computing more |
4600 | * source checksum. */ | 4640 | * source checksum. Note: this is called unconditionally |
4641 | * the first time after reentry, subsequent calls will be | ||
4642 | * avoided if next_move_point is > input_position */ | ||
4601 | if ((ret = xd3_srcwin_move_point (stream, & next_move_point))) | 4643 | if ((ret = xd3_srcwin_move_point (stream, & next_move_point))) |
4602 | { | 4644 | { |
4603 | return ret; | 4645 | return ret; |
diff --git a/xdelta3/xdelta3.h b/xdelta3/xdelta3.h index 63b76b0..f00f887 100644 --- a/xdelta3/xdelta3.h +++ b/xdelta3/xdelta3.h | |||
@@ -833,10 +833,6 @@ struct _xd3_source | |||
833 | xoff_t max_blkno; /* Maximum block, if eof is known, | 833 | xoff_t max_blkno; /* Maximum block, if eof is known, |
834 | * otherwise, equals frontier_blkno | 834 | * otherwise, equals frontier_blkno |
835 | * (initially 0). */ | 835 | * (initially 0). */ |
836 | xoff_t frontier_blkno; /* If eof is unknown, the next | ||
837 | * source position to be read. | ||
838 | * Otherwise, equal to | ||
839 | * max_blkno. */ | ||
840 | usize_t onlastblk; /* Number of bytes on max_blkno */ | 836 | usize_t onlastblk; /* Number of bytes on max_blkno */ |
841 | int eof_known; /* Set to true when the first | 837 | int eof_known; /* Set to true when the first |
842 | * partial block is read. */ | 838 | * partial block is read. */ |