You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2010/08/05 00:23:35 UTC

svn commit: r982417 - /subversion/branches/performance/subversion/libsvn_fs_fs/fs_fs.c

Author: stefan2
Date: Wed Aug  4 22:23:34 2010
New Revision: 982417

URL: http://svn.apache.org/viewvc?rev=982417&view=rev
Log:
Instead of using plain APR files, use cached file handles for FSFS
read operations.

* subversion/libsvn_fs_fs/fs_fs.c
  (DEFAULT_FILE_COOKIE, REF_FILE_COOKIE): define file cookies
  (svn_fs_fs__path_rev_absolute): use cache lookup to increase performance
  (sync_file_handle_cache): new utility function
  (open_pack_or_rev_file, open_and_seek_revision, open_and_seek_transaction,
  open_and_seek_representation):
  use cached file handles instead of APR file handles; add / change parameters
  (get_node_revision_body, svn_fs_fs__rev_get_root, svn_fs_fs__paths_changed,
   recover_get_largest_revision, recover_body): implement using file handle cache
  (svn_fs_fs__put_node_revision, write_next_ids, svn_fs_fs__set_entry,
   svn_fs_fs__add_change, rep_write_contents_close, svn_fs_fs__set_proplist,
   commit_body, commit_obliteration_body): clear cache after DB modification
  (rep_state): add  cached file handle member
  (create_rep_state_body, read_window, get_contents, 
   svn_fs_fs__get_file_delta_stream): read reps from cached file handles

Modified:
    subversion/branches/performance/subversion/libsvn_fs_fs/fs_fs.c

Modified: subversion/branches/performance/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_fs_fs/fs_fs.c?rev=982417&r1=982416&r2=982417&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/performance/subversion/libsvn_fs_fs/fs_fs.c Wed Aug  4 22:23:34 2010
@@ -113,6 +113,17 @@
 #define REP_PLAIN          "PLAIN"
 #define REP_DELTA          "DELTA"
 
+/* Cookies used to classify cached file handle usage */
+/* Used whenever no other specific region of the rev file is being read. */
+#define DEFAULT_FILE_COOKIE 0
+
+/* Used when reading representation data.
+ * Since this is often interleaved with other reads, use a separate 
+ * cookie (hence a separate file handle) for the reps.  That way, rep
+ * access can often be satisfied from the APR read buffer.  The same
+ * applies to the meta data because it is not rep data. */
+#define REP_FILE_COOKIE     1
+
 /* Notes:
 
 To avoid opening and closing the rev-files all the time, it would
@@ -252,11 +263,18 @@ svn_fs_fs__path_rev_absolute(const char 
 {
   if (! is_packed_rev(fs, rev))
     {
+      fs_fs_data_t *ffd = fs->fsap_data;
       svn_node_kind_t kind;
 
       /* Initialize the return variable. */
       *path = path_rev(fs, rev, pool);
 
+      /* quick check the path. For revs close to HEAD, this will often
+       * be effective (and, hence, efficient). */
+      if (svn_file_handle_cache__has_file(ffd->file_handle_cache, *path))
+        return SVN_NO_ERROR;
+
+      /* the expensive standard lookup check */
       SVN_ERR(svn_io_check_path(*path, &kind, pool));
       if (kind == svn_node_file)
         {
@@ -644,6 +662,17 @@ with_txn_current_lock(svn_fs_t *fs,
                         pool);
 }
 
+/* A frequently used utility method: close all cached, idle file handles.
+ * Call this at the end of write transactions to ensure that successive
+ * reads will see the new file content.
+ */
+static svn_error_t *
+sync_file_handle_cache(svn_fs_t *fs)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+  return svn_file_handle_cache__flush(ffd->file_handle_cache);
+}
+
 /* A structure used by unlock_proto_rev() and unlock_proto_rev_body(),
    which see. */
 struct unlock_proto_rev_baton
@@ -1780,21 +1809,40 @@ ensure_revision_exists(svn_fs_t *fs,
 /* Open the correct revision file for REV.  If the filesystem FS has
    been packed, *FILE will be set to the packed file; otherwise, set *FILE
    to the revision file for REV.  Return SVN_ERR_FS_NO_SUCH_REVISION if the
-   file doesn't exist.  Use POOL for allocations. */
+   file doesn't exist.  Move the file pointer of OFFSET, if the latter is
+   not -1.  Prefer cached file handles that share the same COOKIE (again,
+   if not -1).  Use POOL for allocations. */
 static svn_error_t *
-open_pack_or_rev_file(apr_file_t **file,
+open_pack_or_rev_file(svn_file_handle_cache__handle_t **file,
                       svn_fs_t *fs,
                       svn_revnum_t rev,
+                      apr_off_t offset,
+                      int cookie,
                       apr_pool_t *pool)
 {
   svn_error_t *err;
   const char *path;
 
+  /* make sure file has a defined state */
+  *file = NULL;
   err = svn_fs_fs__path_rev_absolute(&path, fs, rev, pool);
 
   if (! err)
-    err = svn_io_file_open(file, path,
-                           APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool);
+    {
+      /* open the revision file in buffered r/o mode */
+      fs_fs_data_t *ffd = fs->fsap_data;
+      err = svn_file_handle_cache__open(file,
+                                        ffd->file_handle_cache,
+                                        path,
+                                        APR_READ | APR_BUFFERED,
+                                        APR_OS_DEFAULT,
+                                        offset,
+                                        cookie,
+                                        pool);
+
+      /* if that succeeded, there must be an underlying APR file */
+      assert(err || svn_file_handle_cache__get_apr_handle(*file));
+    }
 
   if (err && APR_STATUS_IS_ENOENT(err->apr_err))
     {
@@ -1870,20 +1918,18 @@ get_packed_offset(apr_off_t *rev_offset,
 
 /* Open the revision file for revision REV in filesystem FS and store
    the newly opened file in FILE.  Seek to location OFFSET before
-   returning.  Perform temporary allocations in POOL. */
+   returning.  Prefer cached file handles with the specified COOKIE
+   (if not -1).  Perform temporary allocations in POOL. */
 static svn_error_t *
-open_and_seek_revision(apr_file_t **file,
+open_and_seek_revision(svn_file_handle_cache__handle_t **file,
                        svn_fs_t *fs,
                        svn_revnum_t rev,
                        apr_off_t offset,
+                       int cookie,
                        apr_pool_t *pool)
 {
-  apr_file_t *rev_file;
-
+  /* none of the following requires the file handle */
   SVN_ERR(ensure_revision_exists(fs, rev, pool));
-
-  SVN_ERR(open_pack_or_rev_file(&rev_file, fs, rev, pool));
-
   if (is_packed_rev(fs, rev))
     {
       apr_off_t rev_offset;
@@ -1892,53 +1938,55 @@ open_and_seek_revision(apr_file_t **file
       offset += rev_offset;
     }
 
-  SVN_ERR(svn_io_file_seek(rev_file, APR_SET, &offset, pool));
-
-  *file = rev_file;
-
-  return SVN_NO_ERROR;
+  /* So, open the revision file and position the pointer here in one go. */
+  return open_pack_or_rev_file(file, fs, rev, offset, cookie, pool);
 }
 
 /* Open the representation for a node-revision in transaction TXN_ID
    in filesystem FS and store the newly opened file in FILE.  Seek to
-   location OFFSET before returning.  Perform temporary allocations in
+   location OFFSET before returning.  Prefer cached file handles witt
+   the specified COOKIE (if not -1).  Perform temporary allocations in
    POOL.  Only appropriate for file contents, nor props or directory
    contents. */
 static svn_error_t *
-open_and_seek_transaction(apr_file_t **file,
+open_and_seek_transaction(svn_file_handle_cache__handle_t **file,
                           svn_fs_t *fs,
                           const char *txn_id,
                           representation_t *rep,
+                          int cookie,
                           apr_pool_t *pool)
 {
-  apr_file_t *rev_file;
-  apr_off_t offset;
-
-  SVN_ERR(svn_io_file_open(&rev_file, path_txn_proto_rev(fs, txn_id, pool),
-                           APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool));
-
-  offset = rep->offset;
-  SVN_ERR(svn_io_file_seek(rev_file, APR_SET, &offset, pool));
-
-  *file = rev_file;
+  fs_fs_data_t *ffd = fs->fsap_data;
 
-  return SVN_NO_ERROR;
+  /* open & seek in one call */
+  return svn_file_handle_cache__open(file,
+                                     ffd->file_handle_cache,
+                                     path_txn_proto_rev(fs, txn_id, pool),
+                                     APR_READ | APR_BUFFERED, 
+                                     APR_OS_DEFAULT, 
+                                     rep->offset,
+                                     cookie,
+                                     pool);
 }
 
 /* Given a node-id ID, and a representation REP in filesystem FS, open
    the correct file and seek to the correction location.  Store this
    file in *FILE_P.  Perform any allocations in POOL. */
 static svn_error_t *
-open_and_seek_representation(apr_file_t **file_p,
+open_and_seek_representation(svn_file_handle_cache__handle_t **file_p,
                              svn_fs_t *fs,
                              representation_t *rep,
                              apr_pool_t *pool)
 {
+  /* representation headers tend to cluster. Therefore, use separate
+   * file handles for them (controlled by the cookie) to maximize APR 
+   * buffer effectiveness. */
   if (! rep->txn_id)
     return open_and_seek_revision(file_p, fs, rep->revision, rep->offset,
-                                  pool);
+                                  REP_FILE_COOKIE, pool);
   else
-    return open_and_seek_transaction(file_p, fs, rep->txn_id, rep, pool);
+    return open_and_seek_transaction(file_p, fs, rep->txn_id, rep, 
+                                     REP_FILE_COOKIE, pool);
 }
 
 /* Parse the description of a representation from STRING and store it
@@ -2039,14 +2087,21 @@ get_node_revision_body(node_revision_t *
                        const svn_fs_id_t *id,
                        apr_pool_t *pool)
 {
-  apr_file_t *revision_file;
+  svn_file_handle_cache__handle_t *revision_file;
   svn_error_t *err;
 
   if (svn_fs_fs__id_txn_id(id))
     {
       /* This is a transaction node-rev. */
-      err = svn_io_file_open(&revision_file, path_txn_node_rev(fs, id, pool),
-                             APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool);
+      fs_fs_data_t *ffd = fs->fsap_data;
+      err = svn_file_handle_cache__open(&revision_file,
+                                        ffd->file_handle_cache,
+                                        path_txn_node_rev(fs, id, pool),
+                                        APR_READ | APR_BUFFERED,
+                                        APR_OS_DEFAULT,
+                                        0,
+                                        DEFAULT_FILE_COOKIE,
+                                        pool);
     }
   else
     {
@@ -2054,6 +2109,7 @@ get_node_revision_body(node_revision_t *
       err = open_and_seek_revision(&revision_file, fs,
                                    svn_fs_fs__id_rev(id),
                                    svn_fs_fs__id_offset(id),
+                                   DEFAULT_FILE_COOKIE,
                                    pool);
     }
 
@@ -2069,8 +2125,10 @@ get_node_revision_body(node_revision_t *
     }
 
   return svn_fs_fs__read_noderev(noderev_p,
-                                 svn_stream_from_aprfile2(revision_file, FALSE,
-                                                          pool),
+                                 svn_stream_from_cached_file_handle
+                                     (revision_file,
+                                      FALSE,
+                                      pool),
                                  pool);
 }
 
@@ -2360,7 +2418,10 @@ svn_fs_fs__put_node_revision(svn_fs_t *f
                                    svn_fs_fs__fs_supports_mergeinfo(fs),
                                    pool));
 
-  return svn_io_file_close(noderev_file, pool);
+  SVN_ERR(svn_io_file_close(noderev_file, pool));
+
+  /* we wrote to the db -> sync file contents */
+  return sync_file_handle_cache(fs);
 }
 
 
@@ -2652,7 +2713,8 @@ svn_fs_fs__rev_get_root(svn_fs_id_t **ro
                         apr_pool_t *pool)
 {
   fs_fs_data_t *ffd = fs->fsap_data;
-  apr_file_t *revision_file;
+  svn_file_handle_cache__handle_t *revision_file;
+  apr_file_t *apr_rev_file;
   apr_off_t root_offset;
   svn_fs_id_t *root_id;
   svn_boolean_t is_cached;
@@ -2664,14 +2726,19 @@ svn_fs_fs__rev_get_root(svn_fs_id_t **ro
   if (is_cached)
     return SVN_NO_ERROR;
 
-  SVN_ERR(open_pack_or_rev_file(&revision_file, fs, rev, pool));
-  SVN_ERR(get_root_changes_offset(&root_offset, NULL, revision_file, fs, rev,
+  /* we don't care about the file pointer position */
+  SVN_ERR(open_pack_or_rev_file(&revision_file, fs, rev, -1,
+                                DEFAULT_FILE_COOKIE, pool));
+  apr_rev_file = svn_file_handle_cache__get_apr_handle(revision_file);
+
+  /* it will moved here anyways */
+  SVN_ERR(get_root_changes_offset(&root_offset, NULL, apr_rev_file, fs, rev,
                                   pool));
 
-  SVN_ERR(get_fs_id_at_offset(&root_id, revision_file, fs, rev,
-                              root_offset, pool));
+  SVN_ERR(get_fs_id_at_offset(&root_id, apr_rev_file, fs, rev, root_offset, 
+                              pool));
 
-  SVN_ERR(svn_io_file_close(revision_file, pool));
+  SVN_ERR(svn_file_handle_cache__close(revision_file));
 
   SVN_ERR(svn_cache__set(ffd->rev_root_id_cache, &rev, root_id, pool));
 
@@ -2842,7 +2909,10 @@ svn_fs_fs__revision_proplist(apr_hash_t 
    representation is. */
 struct rep_state
 {
-  apr_file_t *file;
+  svn_file_handle_cache__handle_t *file;
+                    /* For convenience, store the APR file handle
+                       along with the surrounding cached file handle. */
+  apr_file_t *apr_file;
   apr_off_t start;  /* The starting offset for the raw
                        svndiff/plaintext data minus header. */
   apr_off_t off;    /* The current offset into the file. */
@@ -2864,8 +2934,10 @@ create_rep_state_body(struct rep_state *
   unsigned char buf[4];
 
   SVN_ERR(open_and_seek_representation(&rs->file, fs, rep, pool));
-  SVN_ERR(read_rep_line(&ra, rs->file, pool));
-  SVN_ERR(get_file_offset(&rs->start, rs->file, pool));
+  rs->apr_file = svn_file_handle_cache__get_apr_handle(rs->file);
+
+  SVN_ERR(read_rep_line(&ra, rs->apr_file, pool));
+  SVN_ERR(get_file_offset(&rs->start, rs->apr_file, pool));
   rs->off = rs->start;
   rs->end = rs->start + rep->size;
   *rep_state = rs;
@@ -2876,7 +2948,7 @@ create_rep_state_body(struct rep_state *
     return SVN_NO_ERROR;
 
   /* We are dealing with a delta, find out what version. */
-  SVN_ERR(svn_io_file_read_full(rs->file, buf, sizeof(buf), NULL, pool));
+  SVN_ERR(svn_io_file_read_full(rs->apr_file, buf, sizeof(buf), NULL, pool));
   if (! ((buf[0] == 'S') && (buf[1] == 'V') && (buf[2] == 'N')))
     return svn_error_create
       (SVN_ERR_FS_CORRUPT, NULL,
@@ -3067,9 +3139,9 @@ read_window(svn_txdelta_window_t **nwin,
   /* Skip windows to reach the current chunk if we aren't there yet. */
   while (rs->chunk_index < this_chunk)
     {
-      SVN_ERR(svn_txdelta_skip_svndiff_window(rs->file, rs->ver, pool));
+      SVN_ERR(svn_txdelta_skip_svndiff_window(rs->apr_file, rs->ver, pool));
       rs->chunk_index++;
-      SVN_ERR(get_file_offset(&rs->off, rs->file, pool));
+      SVN_ERR(get_file_offset(&rs->off, rs->apr_file, pool));
       if (rs->off >= rs->end)
         return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
                                 _("Reading one svndiff window read "
@@ -3078,10 +3150,10 @@ read_window(svn_txdelta_window_t **nwin,
     }
 
   /* Read the next window. */
-  stream = svn_stream_from_aprfile2(rs->file, TRUE, pool);
+  stream = svn_stream_from_cached_file_handle(rs->file, TRUE, pool);
   SVN_ERR(svn_txdelta_read_svndiff_window(nwin, stream, rs->ver, pool));
   rs->chunk_index++;
-  SVN_ERR(get_file_offset(&rs->off, rs->file, pool));
+  SVN_ERR(get_file_offset(&rs->off, rs->apr_file, pool));
 
   if (rs->off > rs->end)
     return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
@@ -3154,7 +3226,7 @@ get_contents(struct rep_read_baton *rb,
   char *sbuf, *tbuf, *cur = buf;
   struct rep_state *rs;
   svn_txdelta_window_t *cwindow, *lwindow;
-
+  
   /* Special case for when there are no delta reps, only a plain
      text. */
   if (rb->rs_list->nelts == 0)
@@ -3163,7 +3235,7 @@ get_contents(struct rep_read_baton *rb,
       rs = rb->src_state;
       if (((apr_off_t) copy_len) > rs->end - rs->off)
         copy_len = (apr_size_t) (rs->end - rs->off);
-      SVN_ERR(svn_io_file_read_full(rs->file, cur, copy_len, NULL,
+      SVN_ERR(svn_io_file_read_full(rs->apr_file, cur, copy_len, NULL,
                                     rb->pool));
       rs->off += copy_len;
       *len = copy_len;
@@ -3236,10 +3308,10 @@ get_contents(struct rep_read_baton *rb,
                   if ((rs->start + lwindow->sview_offset) != rs->off)
                     {
                       rs->off = rs->start + lwindow->sview_offset;
-                      SVN_ERR(svn_io_file_seek(rs->file, APR_SET, &rs->off,
+                      SVN_ERR(svn_io_file_seek(rs->apr_file, APR_SET, &rs->off,
                                                rb->pool));
                     }
-                  SVN_ERR(svn_io_file_read_full(rs->file, sbuf,
+                  SVN_ERR(svn_io_file_read_full(rs->apr_file, sbuf,
                                                 lwindow->sview_len,
                                                 NULL, rb->pool));
                   rs->off += lwindow->sview_len;
@@ -3485,7 +3557,7 @@ svn_fs_fs__get_file_delta_stream(svn_txd
           return SVN_NO_ERROR;
         }
       else
-        SVN_ERR(svn_io_file_close(rep_state->file, pool));
+        SVN_ERR(svn_file_handle_cache__close(rep_state->file));
     }
 
   /* Read both fulltexts and construct a delta. */
@@ -4272,24 +4344,29 @@ svn_fs_fs__paths_changed(apr_hash_t **ch
 {
   apr_off_t changes_offset;
   apr_hash_t *changed_paths;
-  apr_file_t *revision_file;
+  svn_file_handle_cache__handle_t *revision_file;
+  apr_file_t *apr_revision_file;
 
   SVN_ERR(ensure_revision_exists(fs, rev, pool));
 
-  SVN_ERR(open_pack_or_rev_file(&revision_file, fs, rev, pool));
+  /* we don't care about the file pointer position */
+  SVN_ERR(open_pack_or_rev_file(&revision_file, fs, rev, -1, 
+                                DEFAULT_FILE_COOKIE, pool));
+  apr_revision_file = svn_file_handle_cache__get_apr_handle(revision_file);
+
+  /* it will moved here anyways */
+  SVN_ERR(get_root_changes_offset(NULL, &changes_offset, apr_revision_file, 
+                                  fs, rev, pool));
 
-  SVN_ERR(get_root_changes_offset(NULL, &changes_offset, revision_file, fs,
-                                  rev, pool));
-
-  SVN_ERR(svn_io_file_seek(revision_file, APR_SET, &changes_offset, pool));
+  SVN_ERR(svn_io_file_seek(apr_revision_file, APR_SET, &changes_offset, pool));
 
   changed_paths = apr_hash_make(pool);
 
-  SVN_ERR(fetch_all_changes(changed_paths, copyfrom_cache, revision_file,
+  SVN_ERR(fetch_all_changes(changed_paths, copyfrom_cache, apr_revision_file,
                             TRUE, pool));
 
   /* Close the revision file. */
-  SVN_ERR(svn_io_file_close(revision_file, pool));
+  SVN_ERR(svn_file_handle_cache__close(revision_file));
 
   *changed_paths_p = changed_paths;
 
@@ -4709,7 +4786,10 @@ write_next_ids(svn_fs_t *fs,
   SVN_ERR(svn_stream_printf(out_stream, pool, "%s %s\n", node_id, copy_id));
 
   SVN_ERR(svn_stream_close(out_stream));
-  return svn_io_file_close(file, pool);
+  SVN_ERR(svn_io_file_close(file, pool));
+
+  /* we wrote to the db -> sync file contents */
+  return sync_file_handle_cache(fs);
 }
 
 /* Find out what the next unique node-id and copy-id are for
@@ -4921,7 +5001,10 @@ svn_fs_fs__set_entry(svn_fs_t *fs,
                                 strlen(name), name));
     }
 
-  return svn_io_file_close(file, pool);
+  SVN_ERR(svn_io_file_close(file, pool));
+
+  /* we wrote to the db -> sync file contents */
+  return sync_file_handle_cache(fs);
 }
 
 /* Write a single change entry, path PATH, change CHANGE, and copyfrom
@@ -5021,7 +5104,10 @@ svn_fs_fs__add_change(svn_fs_t *fs,
 
   SVN_ERR(write_change_entry(file, path, change, TRUE, pool));
 
-  return svn_io_file_close(file, pool);
+  SVN_ERR(svn_io_file_close(file, pool));
+
+  /* we wrote to the db -> sync file contents */
+  return sync_file_handle_cache(fs);
 }
 
 /* This baton is used by the representation writing streams.  It keeps
@@ -5276,7 +5362,8 @@ rep_write_contents_close(void *baton)
   SVN_ERR(unlock_proto_rev(b->fs, rep->txn_id, b->lockcookie, b->pool));
   svn_pool_destroy(b->pool);
 
-  return SVN_NO_ERROR;
+  /* we wrote to the db -> sync file contents */
+  return sync_file_handle_cache(b->fs);
 }
 
 /* Store a writable stream in *CONTENTS_P that will receive all data
@@ -5377,7 +5464,8 @@ svn_fs_fs__set_proplist(svn_fs_t *fs,
       SVN_ERR(svn_fs_fs__put_node_revision(fs, noderev->id, noderev, FALSE, pool));
     }
 
-  return SVN_NO_ERROR;
+  /* we wrote to the db -> sync file contents */
+  return sync_file_handle_cache(fs);
 }
 
 /* Read the 'current' file for filesystem FS and store the next
@@ -5920,6 +6008,9 @@ commit_body(void *baton, apr_pool_t *poo
   SVN_ERR(svn_io_file_flush_to_disk(proto_file, pool));
   SVN_ERR(svn_io_file_close(proto_file, pool));
 
+  /* we wrote to the db -> sync file contents */
+  SVN_ERR(sync_file_handle_cache(cb->fs));
+
   /* We don't unlock the prototype revision file immediately to avoid a
      race with another caller writing to the prototype revision file
      before we commit it. */
@@ -6091,6 +6182,9 @@ commit_obliteration_body(void *baton, ap
   SVN_ERR(svn_io_file_flush_to_disk(proto_file, pool));
   SVN_ERR(svn_io_file_close(proto_file, pool));
 
+  /* we wrote to the db -> sync file contents */
+  SVN_ERR(sync_file_handle_cache(cb->fs));
+
   /* We don't unlock the prototype revision file immediately to avoid a
      race with another caller writing to the prototype revision file
      before we commit it. */
@@ -6428,9 +6522,12 @@ recover_get_largest_revision(svn_fs_t *f
   while (1)
     {
       svn_error_t *err;
-      apr_file_t *file;
+      svn_file_handle_cache__handle_t *file;
 
-      err = open_pack_or_rev_file(&file, fs, right, iterpool);
+      /* We don't care about the file pointer position as long as the file 
+         itself exists. */
+      err = open_pack_or_rev_file(&file, fs, right, -1, 
+                                  DEFAULT_FILE_COOKIE, iterpool);
       svn_pool_clear(iterpool);
 
       if (err && err->apr_err == SVN_ERR_FS_NO_SUCH_REVISION)
@@ -6452,9 +6549,11 @@ recover_get_largest_revision(svn_fs_t *f
     {
       svn_revnum_t probe = left + ((right - left) / 2);
       svn_error_t *err;
-      apr_file_t *file;
+      svn_file_handle_cache__handle_t *file;
 
-      err = open_pack_or_rev_file(&file, fs, probe, iterpool);
+      /* Again, ignore the file pointer position. */
+      err = open_pack_or_rev_file(&file, fs, probe, -1, 
+                                  DEFAULT_FILE_COOKIE, iterpool);
       svn_pool_clear(iterpool);
 
       if (err && err->apr_err == SVN_ERR_FS_NO_SUCH_REVISION)
@@ -6738,7 +6837,8 @@ recover_body(void *baton, apr_pool_t *po
 
       for (rev = 0; rev <= max_rev; rev++)
         {
-          apr_file_t *rev_file;
+          svn_file_handle_cache__handle_t *rev_file;
+          apr_file_t *apr_rev_file;
           apr_off_t root_offset;
 
           svn_pool_clear(iterpool);
@@ -6746,12 +6846,18 @@ recover_body(void *baton, apr_pool_t *po
           if (b->cancel_func)
             SVN_ERR(b->cancel_func(b->cancel_baton));
 
-          SVN_ERR(open_pack_or_rev_file(&rev_file, fs, rev, iterpool));
-          SVN_ERR(get_root_changes_offset(&root_offset, NULL, rev_file, fs, rev,
+          /* Any file pointer position will do ... */
+          SVN_ERR(open_pack_or_rev_file(&rev_file, fs, rev, -1,
+                                        DEFAULT_FILE_COOKIE, iterpool));
+          apr_rev_file = svn_file_handle_cache__get_apr_handle(rev_file);
+
+          /* ... because it gets set here explicitly */
+          SVN_ERR(get_root_changes_offset(&root_offset, NULL, 
+                                          apr_rev_file, fs, rev,
                                           iterpool));
-          SVN_ERR(recover_find_max_ids(fs, rev, rev_file, root_offset,
+          SVN_ERR(recover_find_max_ids(fs, rev, apr_rev_file, root_offset,
                                        max_node_id, max_copy_id, iterpool));
-          SVN_ERR(svn_io_file_close(rev_file, iterpool));
+          SVN_ERR(svn_file_handle_cache__close(rev_file));
         }
       svn_pool_destroy(iterpool);