Stefan, is this an edge case bug?
rep_read_contents() in libsvn_fs_fs/cached_data.c_at_1780363 is quoted below.
rep_read_contents() potentially reads one or more times from the
fulltext cache and then finds the fulltext cache is no longer available.
I suppose this could happen because the entry could be evicted because
other entries are being more recently/frequently accessed even though we
haven't finished calling rep_read_contents() for this particular rep.
In this case, rep_read_contents() calls skip_contents() to skip-read
from the window stream, to catch up that stream to the point we'd
already reached in the fulltext cache before it became unavailable.
Then we read the requested LEN bytes from the window stream, and update
the calculated checksum with those LEN bytes ... but not with the
skipped bytes.
Won't that lead to a checksum mismatch when we reach the end of the rep?
- Julian
[[[
/* BATON is of type `rep_read_baton'; read the next *LEN bytes of the
representation and store them in *BUF. Sum as we read and verify
the MD5 sum at the end. */
static svn_error_t *
rep_read_contents(void *baton,
char *buf,
apr_size_t *len)
{
struct rep_read_baton *rb = baton;
/* Get data from the fulltext cache for as long as we can. */
if (rb->fulltext_cache)
{
svn_boolean_t cached;
SVN_ERR(get_contents_from_fulltext(&cached, rb, buf, len));
if (cached)
return SVN_NO_ERROR;
/* Cache miss. From now on, we will never read from the fulltext
* cache for this representation anymore. */
rb->fulltext_cache = NULL;
}
/* No fulltext cache to help us. We must read from the window stream. */
if (!rb->rs_list)
{
/* Window stream not initialized, yet. Do it now. */
rb->len = rb->rep.expanded_size;
SVN_ERR(build_rep_list(&rb->rs_list, &rb->base_window,
&rb->src_state, rb->fs, &rb->rep,
rb->filehandle_pool));
/* In case we did read from the fulltext cache before, make the
* window stream catch up. Also, initialize the fulltext buffer
* if we want to cache the fulltext at the end. */
SVN_ERR(skip_contents(rb, rb->fulltext_delivered));
}
/* Get the next block of data. */
SVN_ERR(get_contents_from_windows(rb, buf, len));
if (rb->current_fulltext)
svn_stringbuf_appendbytes(rb->current_fulltext, buf, *len);
/* Perform checksumming. We want to check the checksum as soon as
the last byte of data is read, in case the caller never performs
a short read, but we don't want to finalize the MD5 context
twice. */
if (!rb->checksum_finalized)
{
SVN_ERR(svn_checksum_update(rb->md5_checksum_ctx, buf, *len));
rb->off += *len;
if (rb->off == rb->len)
{
svn_checksum_t *md5_checksum;
svn_checksum_t expected;
expected.kind = svn_checksum_md5;
expected.digest = rb->md5_digest;
rb->checksum_finalized = TRUE;
SVN_ERR(svn_checksum_final(&md5_checksum, rb->md5_checksum_ctx,
rb->pool));
if (!svn_checksum_match(md5_checksum, &expected))
return svn_error_create(SVN_ERR_FS_CORRUPT,
svn_checksum_mismatch_err(&expected, md5_checksum,
rb->pool,
_("Checksum mismatch while reading
representation")),
NULL);
}
}
if (rb->off == rb->len && rb->current_fulltext)
{
fs_fs_data_t *ffd = rb->fs->fsap_data;
SVN_ERR(svn_cache__set(ffd->fulltext_cache, &rb->fulltext_cache_key,
rb->current_fulltext, rb->pool));
rb->current_fulltext = NULL;
}
return SVN_NO_ERROR;
}
]]]
Received on 2017-01-29 22:27:23 CET