summaryrefslogtreecommitdiff
path: root/subversion/libsvn_delta/text_delta.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_delta/text_delta.c')
-rw-r--r--subversion/libsvn_delta/text_delta.c114
1 files changed, 31 insertions, 83 deletions
diff --git a/subversion/libsvn_delta/text_delta.c b/subversion/libsvn_delta/text_delta.c
index be2c434..04eca8a 100644
--- a/subversion/libsvn_delta/text_delta.c
+++ b/subversion/libsvn_delta/text_delta.c
@@ -366,14 +366,14 @@ txdelta_next_window(svn_txdelta_window_t **window,
/* Read the source stream. */
if (b->more_source)
{
- SVN_ERR(svn_stream_read(b->source, b->buf, &source_len));
+ SVN_ERR(svn_stream_read_full(b->source, b->buf, &source_len));
b->more_source = (source_len == SVN_DELTA_WINDOW_SIZE);
}
else
source_len = 0;
/* Read the target stream. */
- SVN_ERR(svn_stream_read(b->target, b->buf + source_len, &target_len));
+ SVN_ERR(svn_stream_read_full(b->target, b->buf + source_len, &target_len));
b->pos += source_len;
if (target_len == 0)
@@ -522,7 +522,7 @@ tpush_write_handler(void *baton, const char *data, apr_size_t *len)
if (tb->source_len == 0 && !tb->source_done)
{
tb->source_len = SVN_DELTA_WINDOW_SIZE;
- SVN_ERR(svn_stream_read(tb->source, tb->buf, &tb->source_len));
+ SVN_ERR(svn_stream_read_full(tb->source, tb->buf, &tb->source_len));
if (tb->source_len < SVN_DELTA_WINDOW_SIZE)
tb->source_done = TRUE;
}
@@ -623,68 +623,31 @@ size_buffer(char **buf, apr_size_t *buf_size,
return SVN_NO_ERROR;
}
-/* Copy LEN bytes from SOURCE to TARGET, optimizing for the case where LEN
- * is often very small. Return a pointer to the first byte after the copied
- * target range, unlike standard memcpy(), as a potential further
- * optimization for the caller.
- *
- * memcpy() is hard to tune for a wide range of buffer lengths. Therefore,
- * it is often tuned for high throughput on large buffers and relatively
- * low latency for mid-sized buffers (tens of bytes). However, the overhead
- * for very small buffers (<10 bytes) is still high. Even passing the
- * parameters, for instance, may take as long as copying 3 bytes.
- *
- * Because short copy sequences seem to be a common case, at least in
- * "format 2" FSFS repositories, we copy them directly. Larger buffer sizes
- * aren't hurt measurably by the exta 'if' clause. */
-static APR_INLINE char *
-fast_memcpy(char *target, const char *source, apr_size_t len)
-{
- if (len > 7)
- {
- memcpy(target, source, len);
- target += len;
- }
- else
- {
- /* memcpy is not exactly fast for small block sizes.
- * Since they are common, let's run optimized code for them. */
- const char *end = source + len;
- for (; source != end; source++)
- *(target++) = *source;
- }
-
- return target;
-}
-
/* Copy LEN bytes from SOURCE to TARGET. Unlike memmove() or memcpy(),
* create repeating patterns if the source and target ranges overlap.
* Return a pointer to the first byte after the copied target range. */
static APR_INLINE char *
patterning_copy(char *target, const char *source, apr_size_t len)
{
- const char *end = source + len;
-
- /* On many machines, we can do "chunky" copies. */
-
-#if SVN_UNALIGNED_ACCESS_IS_OK
-
- if (end + sizeof(apr_uint32_t) <= target)
+ /* If the source and target overlap, repeat the overlapping pattern
+ in the target buffer. Always copy from the source buffer because
+ presumably it will be in the L1 cache after the first iteration
+ and doing this should avoid pipeline stalls due to write/read
+ dependencies. */
+ const apr_size_t overlap = target - source;
+ while (len > overlap)
{
- /* Source and target are at least 4 bytes apart, so we can copy in
- * 4-byte chunks. */
- for (; source + sizeof(apr_uint32_t) <= end;
- source += sizeof(apr_uint32_t),
- target += sizeof(apr_uint32_t))
- *(apr_uint32_t *)(target) = *(apr_uint32_t *)(source);
+ memcpy(target, source, overlap);
+ target += overlap;
+ len -= overlap;
}
-#endif
-
- /* fall through to byte-wise copy (either for the below-chunk-size tail
- * or the whole copy) */
- for (; source != end; source++)
- *(target++) = *source;
+ /* Copy any remaining source pattern. */
+ if (len)
+ {
+ memcpy(target, source, len);
+ target += len;
+ }
return target;
}
@@ -697,6 +660,11 @@ svn_txdelta_apply_instructions(svn_txdelta_window_t *window,
const svn_txdelta_op_t *op;
apr_size_t tpos = 0;
+ /* Nothing to do for empty buffers.
+ * This check allows for NULL TBUF in that case. */
+ if (*tlen == 0)
+ return;
+
for (op = window->ops; op < window->ops + window->num_ops; op++)
{
const apr_size_t buf_len = (op->length < *tlen - tpos
@@ -711,7 +679,7 @@ svn_txdelta_apply_instructions(svn_txdelta_window_t *window,
/* Copy from source area. */
assert(sbuf);
assert(op->offset + op->length <= window->sview_len);
- fast_memcpy(tbuf + tpos, sbuf + op->offset, buf_len);
+ memcpy(tbuf + tpos, sbuf + op->offset, buf_len);
break;
case svn_txdelta_target:
@@ -728,9 +696,9 @@ svn_txdelta_apply_instructions(svn_txdelta_window_t *window,
case svn_txdelta_new:
/* Copy from window new area. */
assert(op->offset + op->length <= window->new_data->len);
- fast_memcpy(tbuf + tpos,
- window->new_data->data + op->offset,
- buf_len);
+ memcpy(tbuf + tpos,
+ window->new_data->data + op->offset,
+ buf_len);
break;
default:
@@ -747,20 +715,6 @@ svn_txdelta_apply_instructions(svn_txdelta_window_t *window,
*tlen = tpos;
}
-/* This is a private interlibrary compatibility wrapper. */
-void
-svn_txdelta__apply_instructions(svn_txdelta_window_t *window,
- const char *sbuf, char *tbuf,
- apr_size_t *tlen);
-void
-svn_txdelta__apply_instructions(svn_txdelta_window_t *window,
- const char *sbuf, char *tbuf,
- apr_size_t *tlen)
-{
- svn_txdelta_apply_instructions(window, sbuf, tbuf, tlen);
-}
-
-
/* Apply WINDOW to the streams given by APPL. */
static svn_error_t *
apply_window(svn_txdelta_window_t *window, void *baton)
@@ -819,7 +773,7 @@ apply_window(svn_txdelta_window_t *window, void *baton)
if (ab->sbuf_len < window->sview_len)
{
len = window->sview_len - ab->sbuf_len;
- err = svn_stream_read(ab->source, ab->sbuf + ab->sbuf_len, &len);
+ err = svn_stream_read_full(ab->source, ab->sbuf + ab->sbuf_len, &len);
if (err == SVN_NO_ERROR && len != window->sview_len - ab->sbuf_len)
err = svn_error_create(SVN_ERR_INCOMPLETE_DATA, NULL,
"Delta source ended unexpectedly");
@@ -836,13 +790,7 @@ apply_window(svn_txdelta_window_t *window, void *baton)
/* Write out the output. */
- /* ### We've also considered just adding two (optionally null)
- arguments to svn_stream_create(): read_checksum and
- write_checksum. Then instead of every caller updating an md5
- context when it calls svn_stream_write() or svn_stream_read(),
- streams would do it automatically, and verify the checksum in
- svn_stream_closed(). But this might be overkill for issue #689;
- so for now we just update the context here. */
+ /* Just update the context here. */
if (ab->result_digest)
apr_md5_update(&(ab->md5_context), ab->tbuf, len);
@@ -936,7 +884,7 @@ svn_error_t *svn_txdelta_send_stream(svn_stream_t *stream,
{
apr_size_t read_len = SVN__STREAM_CHUNK_SIZE;
- SVN_ERR(svn_stream_read(stream, read_buf, &read_len));
+ SVN_ERR(svn_stream_read_full(stream, read_buf, &read_len));
if (read_len == 0)
break;