diff options
Diffstat (limited to 'xdelta3/xdelta3.c')
-rw-r--r-- | xdelta3/xdelta3.c | 272 |
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); |
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; |