summaryrefslogtreecommitdiff
path: root/xdelta3/xdelta3.c
diff options
context:
space:
mode:
Diffstat (limited to 'xdelta3/xdelta3.c')
-rw-r--r--xdelta3/xdelta3.c272
1 files changed, 157 insertions, 115 deletions
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);
520static void xd3_verify_small_state (xd3_stream *stream, 520static 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,
1848inline 1858inline
1849xoff_t xd3_source_eof(const xd3_source *src) 1859xoff_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. */
1866static int 1876static int
1867xd3_getblk (xd3_stream *stream, xoff_t blkno) 1877xd3_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)
3707static int 3699static int
3708xd3_source_match_setup (xd3_stream *stream, xoff_t srcpos) 3700xd3_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
3903xd3_source_extend_match (xd3_stream *stream) 3901xd3_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 */
4320static int 4343static int
4321xd3_srcwin_move_point (xd3_stream *stream, usize_t *next_move_point) 4344xd3_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;