366
366
/* Read the source stream. */
367
367
if (b->more_source)
369
SVN_ERR(svn_stream_read(b->source, b->buf, &source_len));
369
SVN_ERR(svn_stream_read_full(b->source, b->buf, &source_len));
370
370
b->more_source = (source_len == SVN_DELTA_WINDOW_SIZE);
375
375
/* Read the target stream. */
376
SVN_ERR(svn_stream_read(b->target, b->buf + source_len, &target_len));
376
SVN_ERR(svn_stream_read_full(b->target, b->buf + source_len, &target_len));
377
377
b->pos += source_len;
379
379
if (target_len == 0)
623
623
return SVN_NO_ERROR;
626
/* Copy LEN bytes from SOURCE to TARGET, optimizing for the case where LEN
627
* is often very small. Return a pointer to the first byte after the copied
628
* target range, unlike standard memcpy(), as a potential further
629
* optimization for the caller.
631
* memcpy() is hard to tune for a wide range of buffer lengths. Therefore,
632
* it is often tuned for high throughput on large buffers and relatively
633
* low latency for mid-sized buffers (tens of bytes). However, the overhead
634
* for very small buffers (<10 bytes) is still high. Even passing the
635
* parameters, for instance, may take as long as copying 3 bytes.
637
* Because short copy sequences seem to be a common case, at least in
638
* "format 2" FSFS repositories, we copy them directly. Larger buffer sizes
639
* aren't hurt measurably by the exta 'if' clause. */
640
static APR_INLINE char *
641
fast_memcpy(char *target, const char *source, apr_size_t len)
645
memcpy(target, source, len);
650
/* memcpy is not exactly fast for small block sizes.
651
* Since they are common, let's run optimized code for them. */
652
const char *end = source + len;
653
for (; source != end; source++)
654
*(target++) = *source;
660
626
/* Copy LEN bytes from SOURCE to TARGET. Unlike memmove() or memcpy(),
661
627
* create repeating patterns if the source and target ranges overlap.
662
628
* Return a pointer to the first byte after the copied target range. */
663
629
static APR_INLINE char *
664
630
patterning_copy(char *target, const char *source, apr_size_t len)
666
const char *end = source + len;
668
/* On many machines, we can do "chunky" copies. */
670
#if SVN_UNALIGNED_ACCESS_IS_OK
672
if (end + sizeof(apr_uint32_t) <= target)
674
/* Source and target are at least 4 bytes apart, so we can copy in
676
for (; source + sizeof(apr_uint32_t) <= end;
677
source += sizeof(apr_uint32_t),
678
target += sizeof(apr_uint32_t))
679
*(apr_uint32_t *)(target) = *(apr_uint32_t *)(source);
684
/* fall through to byte-wise copy (either for the below-chunk-size tail
685
* or the whole copy) */
686
for (; source != end; source++)
687
*(target++) = *source;
632
/* If the source and target overlap, repeat the overlapping pattern
633
in the target buffer. Always copy from the source buffer because
634
presumably it will be in the L1 cache after the first iteration
635
and doing this should avoid pipeline stalls due to write/read
637
const apr_size_t overlap = target - source;
638
while (len > overlap)
640
memcpy(target, source, overlap);
645
/* Copy any remaining source pattern. */
648
memcpy(target, source, len);
750
/* This is a private interlibrary compatibility wrapper. */
752
svn_txdelta__apply_instructions(svn_txdelta_window_t *window,
753
const char *sbuf, char *tbuf,
756
svn_txdelta__apply_instructions(svn_txdelta_window_t *window,
757
const char *sbuf, char *tbuf,
760
svn_txdelta_apply_instructions(window, sbuf, tbuf, tlen);
764
718
/* Apply WINDOW to the streams given by APPL. */
765
719
static svn_error_t *
766
720
apply_window(svn_txdelta_window_t *window, void *baton)
819
773
if (ab->sbuf_len < window->sview_len)
821
775
len = window->sview_len - ab->sbuf_len;
822
err = svn_stream_read(ab->source, ab->sbuf + ab->sbuf_len, &len);
776
err = svn_stream_read_full(ab->source, ab->sbuf + ab->sbuf_len, &len);
823
777
if (err == SVN_NO_ERROR && len != window->sview_len - ab->sbuf_len)
824
778
err = svn_error_create(SVN_ERR_INCOMPLETE_DATA, NULL,
825
779
"Delta source ended unexpectedly");
837
791
/* Write out the output. */
839
/* ### We've also considered just adding two (optionally null)
840
arguments to svn_stream_create(): read_checksum and
841
write_checksum. Then instead of every caller updating an md5
842
context when it calls svn_stream_write() or svn_stream_read(),
843
streams would do it automatically, and verify the checksum in
844
svn_stream_closed(). But this might be overkill for issue #689;
845
so for now we just update the context here. */
793
/* Just update the context here. */
846
794
if (ab->result_digest)
847
795
apr_md5_update(&(ab->md5_context), ab->tbuf, len);