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;
 


Reply via email to