> -----Original Message----- > From: stef...@apache.org [mailto:stef...@apache.org] > Sent: zondag 25 december 2011 1:56 > To: comm...@subversion.apache.org > Subject: svn commit: r1223036 - > /subversion/trunk/subversion/libsvn_delta/xdelta.c > > Author: stefan2 > Date: Sun Dec 25 00:56:28 2011 > New Revision: 1223036 > > URL: http://svn.apache.org/viewvc?rev=1223036&view=rev > Log: > Minor xdelta optimization: find short matches at both end of the delta > window. > > * subversion/libsvn_delta/xdelta.c > (reverse_match_length): new symmetric counterpart to match_length > (store_delta_trailer): new utility to find matching ranges at the end of a > buffer > (compute_delta): prefix and postfix optimization > > Modified: > subversion/trunk/subversion/libsvn_delta/xdelta.c > > Modified: subversion/trunk/subversion/libsvn_delta/xdelta.c > URL: > http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_delta/xd > elta.c?rev=1223036&r1=1223035&r2=1223036&view=diff > ========================================================== > ==================== > --- subversion/trunk/subversion/libsvn_delta/xdelta.c (original) > +++ subversion/trunk/subversion/libsvn_delta/xdelta.c Sun Dec 25 00:56:28 > 2011 > @@ -230,6 +230,39 @@ match_length(const char *a, const char * > return pos; > } > > +/* Return the smallest byte index at which positions left of A and B differ > + * (A[-result] != B[-result]). If no difference can be found in the first > + * MAX_LEN characters, MAX_LEN will be returned. > + */ > +static apr_size_t > +reverse_match_length(const char *a, const char *b, apr_size_t max_len) > +{ > + apr_size_t pos = 0; > + > +#if SVN_UNALIGNED_ACCESS_IS_OK > + > + /* Chunky processing is so much faster ... > + * > + * We can't make this work on architectures that require aligned access > + * because A and B will probably have different alignment. So, skipping > + * the first few chars until alignment is reached is not an option. > + */ > + for (pos = sizeof(apr_size_t); pos <= max_len; pos += sizeof(apr_size_t)) > + if (*(const apr_size_t*)(a - pos) != *(const apr_size_t*)(b - pos)) > + break; > + > + pos -= sizeof(apr_size_t); > + > +#endif > + > + while (++pos <= max_len) > + if (a[-pos] != b[-pos]) > + break;
This code produces: ..\..\..\subversion\libsvn_delta\xdelta.c(264): warning C4146: unary minus operator applied to unsigned type, result still unsigned ..\..\..\subversion\libsvn_delta\xdelta.c(264): warning C4146: unary minus operator applied to unsigned type, result still unsigned Bert > + > + return pos-1; > +} > + > + > /* Try to find a match for the target data B in BLOCKS, and then > extend the match as long as data in A and B at the match position > continues to match. We set the position in A we ended up in (in > @@ -282,6 +315,38 @@ find_match(const struct blocks *blocks, > return MATCH_BLOCKSIZE + delta; > } > > +/* Utility for compute_delta() that compares the range B[START,BSIZE) with > + * the range of similar size before A[ASIZE]. Create corresponding copy and > + * insert operations. > + * > + * BUILD_BATON and POOL will be passed through from compute_delta(). > + */ > +static void > +store_delta_trailer(svn_txdelta__ops_baton_t *build_baton, > + const char *a, > + apr_size_t asize, > + const char *b, > + apr_size_t bsize, > + apr_size_t start, > + apr_pool_t *pool) > +{ > + apr_size_t end_match; > + apr_size_t max_len = asize > (bsize - start) ? bsize - start : asize; > + if (max_len == 0) > + return; > + > + end_match = reverse_match_length(a + asize, b + bsize, max_len); > + if (end_match <= 4) > + end_match = 0; > + > + if (bsize - start > end_match) > + svn_txdelta__insert_op(build_baton, svn_txdelta_new, > + start, bsize - start - end_match, b + start, > pool); > + if (end_match) > + svn_txdelta__insert_op(build_baton, svn_txdelta_source, > + asize - end_match, end_match, NULL, pool); > +} > + > > /* Compute a delta from A to B using xdelta. > > @@ -319,12 +384,24 @@ compute_delta(svn_txdelta__ops_baton_t * > apr_uint32_t rolling; > apr_size_t lo = 0, pending_insert_start = 0; > > + /* Optimization: directly compare window starts. If more than 4 > + * bytes match, we can immediately create a matching windows. > + * Shorter sequences result in a net data increase. */ > + lo = match_length(a, b, asize > bsize ? bsize : asize); > + if ((lo > 4) || (lo == bsize)) > + { > + svn_txdelta__insert_op(build_baton, svn_txdelta_source, > + 0, lo, NULL, pool); > + pending_insert_start = lo; > + } > + else > + lo = 0; > + > /* If the size of the target is smaller than the match blocksize, just > insert the entire target. */ > - if (bsize < MATCH_BLOCKSIZE) > + if ((bsize - lo < MATCH_BLOCKSIZE) || (asize < MATCH_BLOCKSIZE)) > { > - svn_txdelta__insert_op(build_baton, svn_txdelta_new, > - 0, bsize, b, pool); > + store_delta_trailer(build_baton, a, asize, b, bsize, lo, pool); > return; > } > > @@ -332,7 +409,7 @@ compute_delta(svn_txdelta__ops_baton_t * > init_blocks_table(a, asize, &blocks, pool); > > /* Initialize our rolling checksum. */ > - rolling = init_adler32(b); > + rolling = init_adler32(b + lo); > while (lo < bsize) > { > apr_size_t matchlen = 0; > @@ -377,12 +454,7 @@ compute_delta(svn_txdelta__ops_baton_t * > } > > /* If we still have an insert pending at the end, throw it in. */ > - if (lo - pending_insert_start > 0) > - { > - svn_txdelta__insert_op(build_baton, svn_txdelta_new, > - 0, lo - pending_insert_start, > - b + pending_insert_start, pool); > - } > + store_delta_trailer(build_baton, a, asize, b, bsize, pending_insert_start, > pool); > } > > void >