Author: stefan2
Date: Fri Mar 7 23:52:09 2014
New Revision: 1575453
URL: http://svn.apache.org/r1575453
Log:
Avoid needless prefetching txdelta data as part of our block_read() feature
because it is computationally expensive - mainly due to unzip.
Hence, we tune block_read as follows: Don't prefetch the windows of a
representation beyond the current block if we are not currently reading
a window from that rep. Also, skip cached windows entirely using the
cached size information instead of reading window dimensions from disk.
* subversion/libsvn_fs_fs/cached_data.c
(get_window_header): Getter function to fetch the window size info
from cache.
(cache_windows): Drop the unused FULLTEXT_LEN parameter and add a limit
to the prefetch length. Fetch the continuation offset
for cached windows from that cache instead of fetching
the window header from disk.
(block_read_windows,
block_read_contents): Pass through the MAX_OFFSET parameter.
(block_read): Set the MAX_OFFSET parameter to the end of the current
block unless we requested a window from the current rep.
* subversion/include/private/svn_delta_private.h
(svn_txdelta__read_svndiff_window_sizes): Remove.
* subversion/libsvn_delta/svndiff.c
(svn_txdelta__read_svndiff_window_sizes): Remove.
Modified:
subversion/trunk/subversion/include/private/svn_delta_private.h
subversion/trunk/subversion/libsvn_delta/svndiff.c
subversion/trunk/subversion/libsvn_fs_fs/cached_data.c
Modified: subversion/trunk/subversion/include/private/svn_delta_private.h
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_delta_private.h?rev=1575453&r1=1575452&r2=1575453&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_delta_private.h (original)
+++ subversion/trunk/subversion/include/private/svn_delta_private.h Fri Mar 7
23:52:09 2014
@@ -101,16 +101,6 @@ svn_delta__delta_from_editor(const svn_d
struct svn_delta__extra_baton *exb,
apr_pool_t *pool);
-/**
- * Similar to #svn_txdelta_read_svndiff_window but only returns the window
- * header information, i.e. does not decode the window contents.
- */
-svn_error_t *
-svn_txdelta__read_svndiff_window_sizes(svn_txdelta_window_t **window,
- svn_stream_t *stream,
- int svndiff_version,
- apr_pool_t *pool);
-
#ifdef __cplusplus
}
Modified: subversion/trunk/subversion/libsvn_delta/svndiff.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_delta/svndiff.c?rev=1575453&r1=1575452&r2=1575453&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_delta/svndiff.c (original)
+++ subversion/trunk/subversion/libsvn_delta/svndiff.c Fri Mar 7 23:52:09 2014
@@ -872,23 +872,6 @@ svn_txdelta_read_svndiff_window(svn_txde
svn_error_t *
-svn_txdelta__read_svndiff_window_sizes(svn_txdelta_window_t **window,
- svn_stream_t *stream,
- int svndiff_version,
- apr_pool_t *pool)
-{
- apr_size_t inslen, newlen;
-
- *window = apr_pcalloc(pool, sizeof(**window));
- SVN_ERR(read_window_header(stream, &(*window)->sview_offset,
- &(*window)->sview_len, &(*window)->tview_len,
- &inslen, &newlen));
-
- return svn_error_trace(svn_stream_skip(stream, inslen + newlen));
-}
-
-
-svn_error_t *
svn_txdelta_skip_svndiff_window(apr_file_t *file,
int svndiff_version,
apr_pool_t *pool)
Modified: subversion/trunk/subversion/libsvn_fs_fs/cached_data.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/cached_data.c?rev=1575453&r1=1575452&r2=1575453&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/cached_data.c (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/cached_data.c Fri Mar 7 23:52:09
2014
@@ -2440,62 +2440,83 @@ init_rep_state(rep_state_t *rs,
return SVN_NO_ERROR;
}
+/* Implement svn_cache__partial_getter_func_t for txdelta windows.
+ * Instead of the whole window data, return only the
+ * svn_fs_fs__txdelta_cached_window_t wrapper containing the end-offset.
+ */
+static svn_error_t *
+get_window_header(void **out,
+ const void *data,
+ apr_size_t data_len,
+ void *baton,
+ apr_pool_t *result_pool)
+{
+ *out = apr_pmemdup(result_pool, data,
+ sizeof(svn_fs_fs__txdelta_cached_window_t));
+
+ return SVN_NO_ERROR;
+}
+
/* Walk through all windows in the representation addressed by RS in FS
* (excluding the delta bases) and put those not already cached into the
- * window caches. As a side effect, return the total sum of all expanded
- * window sizes in *FULLTEXT_LEN. Use POOL for temporary allocations.
+ * window caches. If MAX_OFFSET is not -1, don't read windows that start
+ * at or beyond that offset. Use POOL for temporary allocations.
*/
static svn_error_t *
-cache_windows(svn_filesize_t *fulltext_len,
- svn_fs_t *fs,
+cache_windows(svn_fs_t *fs,
rep_state_t *rs,
+ apr_off_t max_offset,
apr_pool_t *pool)
{
- *fulltext_len = 0;
-
while (rs->current < rs->size)
{
- svn_txdelta_window_t *window;
- apr_off_t start_offset = rs->start + rs->current;
- apr_off_t end_offset;
+ svn_fs_fs__txdelta_cached_window_t *cached_window;
svn_boolean_t found = FALSE;
- /* We don't need to read the data again, if it is already in cache.
+ if (max_offset != -1 && rs->start + rs->current >= max_offset)
+ return SVN_NO_ERROR;
+
+ /* We don't need to read the data again if it is already in cache.
*/
if (rs->window_cache)
{
- window_cache_key_t key = {0};
- SVN_ERR(svn_cache__has_key(&found, rs->window_cache,
- get_window_key(&key, rs), pool));
+ window_cache_key_t key = { 0 };
+ SVN_ERR(svn_cache__get_partial((void **) &cached_window, &found,
+ rs->window_cache,
+ get_window_key(&key, rs),
+ get_window_header, NULL, pool));
}
- /* navigate to the current window */
- SVN_ERR(rs_aligned_seek(rs, NULL, start_offset, pool));
-
- /* Skip or actually read the window - depending on cache status. */
if (found)
- SVN_ERR(svn_txdelta__read_svndiff_window_sizes(&window,
- rs->sfile->rfile->stream,
- rs->ver, pool));
+ {
+ /* Skip this window; we already have it. */
+ rs->current = cached_window->end_offset;
+ }
else
- SVN_ERR(svn_txdelta_read_svndiff_window(&window,
- rs->sfile->rfile->stream,
- rs->ver, pool));
-
- /* aggregate expanded window size */
- *fulltext_len += window->tview_len;
-
- /* determine on-disk window size */
- SVN_ERR(get_file_offset(&end_offset, rs, pool));
- rs->current = end_offset - rs->start;
+ {
+ /* Read, decode and cache the window. */
+ svn_txdelta_window_t *window;
+ apr_off_t start_offset = rs->start + rs->current;
+ apr_off_t end_offset;
+
+ /* navigate to the current window */
+ SVN_ERR(rs_aligned_seek(rs, NULL, start_offset, pool));
+ SVN_ERR(svn_txdelta_read_svndiff_window(&window,
+ rs->sfile->rfile->stream,
+ rs->ver, pool));
+
+ /* determine on-disk window size */
+ SVN_ERR(get_file_offset(&end_offset, rs, pool));
+ rs->current = end_offset - rs->start;
+
+ /* cache the window now */
+ SVN_ERR(set_cached_window(window, rs, pool));
+ }
+
if (rs->current > rs->size)
return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
- _("Reading one svndiff window read beyond "
- "the end of the representation"));
-
- /* cache the window now */
- if (!found)
- SVN_ERR(set_cached_window(window, rs, pool));
+ _("Reading one svndiff window read beyond "
+ "the end of the representation"));
rs->chunk_index++;
}
@@ -2505,7 +2526,8 @@ cache_windows(svn_filesize_t *fulltext_l
/* Read all txdelta / plain windows following REP_HEADER in FS as described
* by ENTRY. Read the data from the already open FILE and the wrapping
- * STREAM object. Use POOL for allocations.
+ * STREAM object. If MAX_OFFSET is not -1, don't read windows that start
+ * at or beyond that offset. Use POOL for allocations.
* If caching is not enabled, this is a no-op.
*/
static svn_error_t *
@@ -2513,6 +2535,7 @@ block_read_windows(svn_fs_fs__rep_header
svn_fs_t *fs,
svn_fs_fs__revision_file_t *rev_file,
svn_fs_fs__p2l_entry_t* entry,
+ apr_off_t max_offset,
apr_pool_t *pool)
{
fs_fs_data_t *ffd = fs->fsap_data;
@@ -2557,8 +2580,7 @@ block_read_windows(svn_fs_fs__rep_header
}
else
{
- svn_filesize_t fulltext_len;
- SVN_ERR(cache_windows(&fulltext_len, fs, &rs, pool));
+ SVN_ERR(cache_windows(fs, &rs, max_offset, pool));
}
return SVN_NO_ERROR;
@@ -2598,12 +2620,14 @@ read_rep_header(svn_fs_fs__rep_header_t
/* Fetch the representation data (header, txdelta / plain windows)
* addressed by ENTRY->ITEM in FS and cache it if caches are enabled.
* Read the data from the already open FILE and the wrapping
- * STREAM object. Use POOL for allocations.
+ * STREAM object. If MAX_OFFSET is not -1, don't read windows that start
+ * at or beyond that offset. Use POOL for allocations.
*/
static svn_error_t *
block_read_contents(svn_fs_t *fs,
svn_fs_fs__revision_file_t *rev_file,
svn_fs_fs__p2l_entry_t* entry,
+ apr_off_t max_offset,
apr_pool_t *pool)
{
pair_cache_key_t header_key = { 0 };
@@ -2614,7 +2638,8 @@ block_read_contents(svn_fs_t *fs,
SVN_ERR(read_rep_header(&rep_header, fs, rev_file->stream, &header_key,
pool));
- SVN_ERR(block_read_windows(rep_header, fs, rev_file, entry, pool));
+ SVN_ERR(block_read_windows(rep_header, fs, rev_file, entry, max_offset,
+ pool));
return SVN_NO_ERROR;
}
@@ -2822,7 +2847,7 @@ block_read(void **result,
/* read all items from the block */
for (i = 0; i < entries->nelts; ++i)
{
- svn_boolean_t is_result;
+ svn_boolean_t is_result, is_wanted;
apr_pool_t *pool;
svn_fs_fs__p2l_entry_t* entry;
@@ -2834,10 +2859,10 @@ block_read(void **result,
continue;
/* the item / container we were looking for? */
- is_result = result
- && entry->offset == wanted_offset
+ is_wanted = entry->offset == wanted_offset
&& entry->item.revision == revision
&& entry->item.number == item_index;
+ is_result = result && is_wanted;
/* select the pool that we want the item to be allocated in */
pool = is_result ? result_pool : iterpool;
@@ -2858,6 +2883,9 @@ block_read(void **result,
case SVN_FS_FS__ITEM_TYPE_FILE_PROPS:
case SVN_FS_FS__ITEM_TYPE_DIR_PROPS:
SVN_ERR(block_read_contents(fs, revision_file, entry,
+ is_wanted
+ ? -1
+ : block_start +
ffd->block_size,
pool));
break;