Modified: 
subversion/branches/move-tracking-2/subversion/libsvn_fs_x/cached_data.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_x/cached_data.c?rev=1641647&r1=1641646&r2=1641647&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_x/cached_data.c 
(original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_x/cached_data.c 
Tue Nov 25 16:26:48 2014
@@ -48,12 +48,12 @@
 
 #include "svn_private_config.h"
 
-/* forward-declare */
+/* forward-declare. See implementation for the docstring */
 static svn_error_t *
 block_read(void **result,
            svn_fs_t *fs,
            const svn_fs_x__id_part_t *id,
-           apr_file_t *revision_file,
+           svn_fs_x__revision_file_t *revision_file,
            apr_pool_t *result_pool,
            apr_pool_t *scratch_pool);
 
@@ -70,7 +70,7 @@ static svn_error_t *
 dgb__log_access(svn_fs_t *fs,
                 const svn_fs_x__id_part_t *id,
                 void *item,
-                int item_type,
+                apr_uint32_t item_type,
                 apr_pool_t *scratch_pool)
 {
   /* no-op if this macro is not defined */
@@ -192,21 +192,21 @@ aligned_seek(svn_fs_t *fs,
    store the newly opened file in FILE.  Seek to the item's location before
    returning.  Perform temporary allocations in POOL. */
 static svn_error_t *
-open_and_seek_revision(apr_file_t **file,
+open_and_seek_revision(svn_fs_x__revision_file_t **file,
                        svn_fs_t *fs,
                        const svn_fs_x__id_part_t *id,
                        apr_pool_t *pool)
 {
-  apr_file_t *rev_file;
+  svn_fs_x__revision_file_t *rev_file;
   apr_off_t offset = -1;
   apr_uint32_t sub_item = 0;
   svn_revnum_t rev = svn_fs_x__get_revnum(id->change_set);
 
   SVN_ERR(svn_fs_x__ensure_revision_exists(rev, fs, pool));
 
-  SVN_ERR(svn_fs_x__open_pack_or_rev_file(&rev_file, fs, rev, pool));
-  SVN_ERR(svn_fs_x__item_offset(&offset, &sub_item, fs, id, pool));
-  SVN_ERR(aligned_seek(fs, rev_file, NULL, offset, pool));
+  SVN_ERR(svn_fs_x__open_pack_or_rev_file(&rev_file, fs, rev, pool, pool));
+  SVN_ERR(svn_fs_x__item_offset(&offset, &sub_item, fs, rev_file, id, pool));
+  SVN_ERR(aligned_seek(fs, rev_file->file, NULL, offset, pool));
 
   *file = rev_file;
 
@@ -217,24 +217,20 @@ open_and_seek_revision(apr_file_t **file
    to its position and store the newly opened file in FILE.  Perform
    temporary allocations in POOL. */
 static svn_error_t *
-open_and_seek_transaction(apr_file_t **file,
+open_and_seek_transaction(svn_fs_x__revision_file_t **file,
                           svn_fs_t *fs,
                           representation_t *rep,
                           apr_pool_t *pool)
 {
-  apr_file_t *rev_file;
   apr_off_t offset;
   apr_uint32_t sub_item = 0;
   apr_int64_t txn_id = svn_fs_x__get_txn_id(rep->id.change_set);
 
-  SVN_ERR(svn_io_file_open(&rev_file,
-                           svn_fs_x__path_txn_proto_rev(fs, txn_id, pool),
-                           APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool));
+  SVN_ERR(svn_fs_x__open_proto_rev_file(file, fs, txn_id, pool, pool));
 
-  SVN_ERR(svn_fs_x__item_offset(&offset, &sub_item, fs, &rep->id, pool));
-  SVN_ERR(aligned_seek(fs, rev_file, NULL, offset, pool));
-
-  *file = rev_file;
+  SVN_ERR(svn_fs_x__item_offset(&offset, &sub_item, fs, *file, &rep->id,
+                                pool));
+  SVN_ERR(aligned_seek(fs, (*file)->file, NULL, offset, pool));
 
   return SVN_NO_ERROR;
 }
@@ -243,7 +239,7 @@ open_and_seek_transaction(apr_file_t **f
    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_fs_x__revision_file_t **file_p,
                              svn_fs_t *fs,
                              representation_t *rep,
                              apr_pool_t *pool)
@@ -274,20 +270,24 @@ static svn_error_t *
 get_node_revision_body(node_revision_t **noderev_p,
                        svn_fs_t *fs,
                        const svn_fs_id_t *id,
-                       apr_pool_t *pool)
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool)
 {
-  apr_file_t *revision_file;
   svn_error_t *err;
   svn_boolean_t is_cached = FALSE;
   fs_x_data_t *ffd = fs->fsap_data;
 
   if (svn_fs_x__id_is_txn(id))
     {
+      apr_file_t *file;
+
       /* This is a transaction node-rev.  Its storage logic is very
          different from that of rev / pack files. */
-      err = svn_io_file_open(&revision_file,
-                             svn_fs_x__path_txn_node_rev(fs, id, pool),
-                             APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool);
+      err = svn_io_file_open(&file,
+                             svn_fs_x__path_txn_node_rev(fs, id,
+                                                         scratch_pool),
+                             APR_READ | APR_BUFFERED, APR_OS_DEFAULT,
+                             scratch_pool);
       if (err)
         {
           if (APR_STATUS_IS_ENOENT(err->apr_err))
@@ -300,33 +300,38 @@ get_node_revision_body(node_revision_t *
         }
 
       SVN_ERR(svn_fs_x__read_noderev(noderev_p,
-                                     svn_stream_from_aprfile2(revision_file,
+                                     svn_stream_from_aprfile2(file,
                                                               FALSE,
-                                                              pool),
-                                     pool));
+                                                              scratch_pool),
+                                     result_pool, scratch_pool));
     }
   else
     {
+      svn_fs_x__revision_file_t *revision_file;
+
       /* noderevs in rev / pack files can be cached */
       const svn_fs_x__id_part_t *noderev_id = svn_fs_x__id_noderev_id(id);
       svn_revnum_t revision = svn_fs_x__get_revnum(noderev_id->change_set);
       pair_cache_key_t key;
 
+      SVN_ERR(svn_fs_x__open_pack_or_rev_file(&revision_file, fs, revision,
+                                              scratch_pool, scratch_pool));
+
       /* First, try a noderevs container cache lookup. */
       if (   svn_fs_x__is_packed_rev(fs, revision)
           && ffd->noderevs_container_cache)
         {
           apr_off_t offset;
           apr_uint32_t sub_item;
-          SVN_ERR(svn_fs_x__item_offset(&offset, &sub_item, fs, noderev_id,
-                                        pool));
+          SVN_ERR(svn_fs_x__item_offset(&offset, &sub_item, fs, revision_file,
+                                        noderev_id, scratch_pool));
           key.revision = svn_fs_x__packed_base_rev(fs, revision);
           key.second = offset;
 
           SVN_ERR(svn_cache__get_partial((void **)noderev_p, &is_cached,
                                          ffd->noderevs_container_cache, &key, 
                                          svn_fs_x__noderevs_get_func,
-                                         &sub_item, pool));
+                                         &sub_item, result_pool));
           if (is_cached)
             return SVN_NO_ERROR;
         }
@@ -342,22 +347,23 @@ get_node_revision_body(node_revision_t *
                                  &is_cached,
                                  ffd->node_revision_cache,
                                  &key,
-                                 pool));
+                                 result_pool));
           if (is_cached)
             return SVN_NO_ERROR;
         }
 
-      /* someone needs to read the data from this file: */
-      err = open_and_seek_revision(&revision_file, fs, noderev_id, pool);
+      /* read the data from disk */
+      SVN_ERR(open_and_seek_revision(&revision_file, fs, noderev_id,
+                                     scratch_pool));
 
       /* block-read will parse the whole block and will also return
-          the one noderev that we need right now. */
+         the one noderev that we need right now. */
       SVN_ERR(block_read((void **)noderev_p, fs,
                          noderev_id,
                          revision_file,
-                         pool,
-                         pool));
-      SVN_ERR(svn_io_file_close(revision_file, pool));
+                         result_pool,
+                         scratch_pool));
+      SVN_ERR(svn_fs_x__close_revision_file(revision_file));
     }
 
   return SVN_NO_ERROR;
@@ -367,21 +373,23 @@ svn_error_t *
 svn_fs_x__get_node_revision(node_revision_t **noderev_p,
                             svn_fs_t *fs,
                             const svn_fs_id_t *id,
-                            apr_pool_t *pool)
+                            apr_pool_t *result_pool,
+                            apr_pool_t *scratch_pool)
 {
   const svn_fs_x__id_part_t *noderev_id = svn_fs_x__id_noderev_id(id);
 
-  svn_error_t *err = get_node_revision_body(noderev_p, fs, id, pool);
+  svn_error_t *err = get_node_revision_body(noderev_p, fs, id,
+                                            result_pool, scratch_pool);
   if (err && err->apr_err == SVN_ERR_FS_CORRUPT)
     {
-      svn_string_t *id_string = svn_fs_x__id_unparse(id, pool);
+      svn_string_t *id_string = svn_fs_x__id_unparse(id, scratch_pool);
       return svn_error_createf(SVN_ERR_FS_CORRUPT, err,
                                "Corrupt node-revision '%s'",
                                id_string->data);
     }
 
   SVN_ERR(dgb__log_access(fs, noderev_id, *noderev_p,
-                          SVN_FS_X__ITEM_TYPE_NODEREV, pool));
+                          SVN_FS_X__ITEM_TYPE_NODEREV, scratch_pool));
 
   return svn_error_trace(err);
 }
@@ -407,6 +415,10 @@ svn_fs_x__get_mergeinfo_count(apr_int64_
       fs_x_data_t *ffd = fs->fsap_data;
       svn_revnum_t revision = svn_fs_x__get_revnum(noderev_id->change_set);
 
+      svn_fs_x__revision_file_t *rev_file;
+      SVN_ERR(svn_fs_x__open_pack_or_rev_file(&rev_file, fs, revision, pool,
+                                              pool));
+
       if (   svn_fs_x__is_packed_rev(fs, revision)
           && ffd->noderevs_container_cache)
         {
@@ -415,7 +427,7 @@ svn_fs_x__get_mergeinfo_count(apr_int64_
           apr_uint32_t sub_item;
           svn_boolean_t is_cached;
 
-          SVN_ERR(svn_fs_x__item_offset(&offset, &sub_item, fs,
+          SVN_ERR(svn_fs_x__item_offset(&offset, &sub_item, fs, rev_file,
                                         noderev_id, pool));
           key.revision = svn_fs_x__packed_base_rev(fs, revision);
           key.second = offset;
@@ -431,7 +443,7 @@ svn_fs_x__get_mergeinfo_count(apr_int64_
 #endif
 
   /* fallback to the naive implementation handling all edge cases */
-  SVN_ERR(svn_fs_x__get_node_revision(&noderev, fs, id, pool));
+  SVN_ERR(svn_fs_x__get_node_revision(&noderev, fs, id, pool, pool));
   *count = noderev->mergeinfo_count;
 
   return SVN_NO_ERROR;
@@ -442,10 +454,11 @@ svn_error_t *
 svn_fs_x__rev_get_root(svn_fs_id_t **root_id_p,
                        svn_fs_t *fs,
                        svn_revnum_t rev,
-                       apr_pool_t *pool)
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool)
 {
-  SVN_ERR(svn_fs_x__ensure_revision_exists(rev, fs, pool));
-  *root_id_p = svn_fs_x__id_create_root(rev, pool);
+  SVN_ERR(svn_fs_x__ensure_revision_exists(rev, fs, scratch_pool));
+  *root_id_p = svn_fs_x__id_create_root(rev, result_pool);
 
   return SVN_NO_ERROR;
 }
@@ -455,15 +468,13 @@ svn_fs_x__rev_get_root(svn_fs_id_t **roo
 typedef struct shared_file_t
 {
   /* The opened file. NULL while file is not open, yet. */
-  apr_file_t *file;
-
-  /* Stream wrapper around FILE. NULL while file is not open, yet. */
-  svn_stream_t *stream;
+  svn_fs_x__revision_file_t *rfile;
 
   /* file system to open the file in */
   svn_fs_t *fs;
 
-  /* revision contained in the file */
+  /* a revision contained in the FILE.  Since this file may be shared,
+     that value may be different from REP_STATE_T->REVISION. */
   svn_revnum_t revision;
 
   /* pool to use when creating the FILE.  This guarantees that the file
@@ -477,7 +488,7 @@ typedef struct shared_file_t
 typedef struct rep_state_t
 {
                     /* shared lazy-open rev/pack file structure */
-  shared_file_t *file;
+  shared_file_t *sfile;
                     /* The txdelta window cache to use or NULL. */
   svn_cache__t *window_cache;
                     /* Caches un-deltified windows. May be NULL. */
@@ -490,16 +501,96 @@ typedef struct rep_state_t
   apr_size_t header_size;
   apr_off_t start;  /* The starting offset for the raw
                        svndiff data minus header.
-                       -1 if the offset is yet unknwon. */
+                       -1 if the offset is yet unknown. */
                     /* sub-item index in case the rep is containered */
   apr_uint32_t sub_item;
-  apr_off_t current;/* The current offset relative to start. */
-  apr_off_t size;   /* Final value of CURRENT. */
+  apr_off_t current;/* The current offset relative to START. */
+  apr_off_t size;   /* The on-disk size of the representation. */
   int ver;          /* If a delta, what svndiff version? 
                        -1 for unknown delta version. */
   int chunk_index;  /* number of the window to read */
 } rep_state_t;
 
+/* Simple wrapper around svn_fs_x__get_file_offset to simplify callers. */
+static svn_error_t *
+get_file_offset(apr_off_t *offset,
+                rep_state_t *rs,
+                apr_pool_t *pool)
+{
+  return svn_error_trace(svn_fs_x__get_file_offset(offset,
+                                                   rs->sfile->rfile->file,
+                                                   pool));
+}
+
+/* Simple wrapper around svn_io_file_aligned_seek to simplify callers. */
+static svn_error_t *
+rs_aligned_seek(rep_state_t *rs,
+                apr_off_t *buffer_start,
+                apr_off_t offset,
+                apr_pool_t *pool)
+{
+  fs_x_data_t *ffd = rs->sfile->fs->fsap_data;
+  return svn_error_trace(svn_io_file_aligned_seek(rs->sfile->rfile->file,
+                                                  ffd->block_size,
+                                                  buffer_start, offset,
+                                                  pool));
+}
+
+/* Open FILE->FILE and FILE->STREAM if they haven't been opened, yet. */
+static svn_error_t*
+auto_open_shared_file(shared_file_t *file)
+{
+  if (file->rfile == NULL)
+    SVN_ERR(svn_fs_x__open_pack_or_rev_file(&file->rfile, file->fs,
+                                            file->revision, file->pool,
+                                            file->pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* Set RS->START to the begin of the representation raw in RS->SFILE->RFILE,
+   if that hasn't been done yet.  Use POOL for temporary allocations. */
+static svn_error_t*
+auto_set_start_offset(rep_state_t *rs, apr_pool_t *pool)
+{
+  if (rs->start == -1)
+    {
+      SVN_ERR(svn_fs_x__item_offset(&rs->start, &rs->sub_item,
+                                    rs->sfile->fs, rs->sfile->rfile,
+                                    &rs->rep_id, pool));
+      rs->start += rs->header_size;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Set RS->VER depending on what is found in the already open RS->FILE->FILE
+   if the diff version is still unknown.  Use POOL for temporary allocations.
+ */
+static svn_error_t*
+auto_read_diff_version(rep_state_t *rs, apr_pool_t *pool)
+{
+  if (rs->ver == -1)
+    {
+      char buf[4];
+      SVN_ERR(rs_aligned_seek(rs, NULL, rs->start, pool));
+      SVN_ERR(svn_io_file_read_full2(rs->sfile->rfile->file, buf,
+                                     sizeof(buf), NULL, NULL, pool));
+
+      /* ### Layering violation */
+      if (! ((buf[0] == 'S') && (buf[1] == 'V') && (buf[2] == 'N')))
+        return svn_error_create
+          (SVN_ERR_FS_CORRUPT, NULL,
+           _("Malformed svndiff data in representation"));
+      rs->ver = buf[3];
+
+      rs->chunk_index = 0;
+      rs->current = 4;
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* See create_rep_state, which wraps this and adds another error. */
 static svn_error_t *
 create_rep_state_body(rep_state_t **rep_state,
@@ -507,10 +598,11 @@ create_rep_state_body(rep_state_t **rep_
                       shared_file_t **shared_file,
                       representation_t *rep,
                       svn_fs_t *fs,
-                      apr_pool_t *pool)
+                      apr_pool_t *result_pool,
+                      apr_pool_t *scratch_pool)
 {
   fs_x_data_t *ffd = fs->fsap_data;
-  rep_state_t *rs = apr_pcalloc(pool, sizeof(*rs));
+  rep_state_t *rs = apr_pcalloc(result_pool, sizeof(*rs));
   svn_fs_x__rep_header_t *rh;
   svn_boolean_t is_cached = FALSE;
   svn_revnum_t revision = svn_fs_x__get_revnum(rep->id.change_set);
@@ -525,7 +617,7 @@ create_rep_state_body(rep_state_t **rep_
    * we can re-use the same, already open file object
    */
   svn_boolean_t reuse_shared_file
-    =    shared_file && *shared_file && (*shared_file)->file
+    =    shared_file && *shared_file && (*shared_file)->rfile
       && SVN_IS_VALID_REVNUM((*shared_file)->revision)
       && (*shared_file)->revision < ffd->min_unpacked_rev
       && revision < ffd->min_unpacked_rev
@@ -567,116 +659,109 @@ create_rep_state_body(rep_state_t **rep_
   /* cache lookup, i.e. skip reading the rep header if possible */
   if (ffd->rep_header_cache && SVN_IS_VALID_REVNUM(revision))
     SVN_ERR(svn_cache__get((void **) &rh, &is_cached,
-                           ffd->rep_header_cache, &key, pool));
+                           ffd->rep_header_cache, &key, result_pool));
 
-  if (is_cached)
+  /* initialize the (shared) FILE member in RS */
+  if (reuse_shared_file)
     {
-      if (reuse_shared_file)
-        {
-          rs->file = *shared_file;
-        }
-      else
-        {
-          shared_file_t *file = apr_pcalloc(pool, sizeof(*file));
-          SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(revision));
-
-          file->revision = revision;
-          file->pool = pool;
-          file->fs = fs;
-          rs->file = file;
-
-          /* remember the current file, if suggested by the caller */
-          if (shared_file)
-            *shared_file = file;
-        }
+      rs->sfile = *shared_file;
     }
   else
     {
+      shared_file_t *file = apr_pcalloc(result_pool, sizeof(*file));
+      file->revision = revision;
+      file->pool = result_pool;
+      file->fs = fs;
+      rs->sfile = file;
+
+      /* remember the current file, if suggested by the caller */
+      if (shared_file)
+        *shared_file = file;
+    }
+
+  /* read rep header, if necessary */
+  if (!is_cached)
+    {
       /* we will need the on-disk location for non-txn reps */
       apr_off_t offset;
-      apr_uint32_t sub_item;
+      svn_boolean_t in_container = TRUE;
 
-      if (SVN_IS_VALID_REVNUM(revision))
-        SVN_ERR(svn_fs_x__item_offset(&offset, &sub_item, fs, &rep->id, pool));
+      /* ensure file is open and navigate to the start of rep header */
+      if (reuse_shared_file)
+        {
+          /* ... we can re-use the same, already open file object.
+           * This implies that we don't read from a txn.
+           */
+          rs->sfile = *shared_file;
+          SVN_ERR(auto_open_shared_file(rs->sfile));
+        }
+      else
+        {
+          /* otherwise, create a new file object.  May or may not be
+           * an in-txn file.
+           */
+          SVN_ERR(open_and_seek_representation(&rs->sfile->rfile, fs, rep,
+                                               result_pool));
+        }
 
-      /* is rep stored in some star-deltified container? */
       if (SVN_IS_VALID_REVNUM(revision))
         {
-          svn_boolean_t in_container = TRUE;
+          apr_uint32_t sub_item;
+
+          SVN_ERR(svn_fs_x__item_offset(&offset, &sub_item, fs,
+                                        rs->sfile->rfile, &rep->id,
+                                        scratch_pool));
+
+          /* is rep stored in some star-deltified container? */
           if (sub_item == 0)
             {
               svn_fs_x__p2l_entry_t *entry;
-              SVN_ERR(svn_fs_x__p2l_entry_lookup(&entry, fs, revision,
-                                                 offset, pool));
+              SVN_ERR(svn_fs_x__p2l_entry_lookup(&entry, fs, rs->sfile->rfile,
+                                                 revision, offset,
+                                                 scratch_pool, scratch_pool));
               in_container = entry->type == SVN_FS_X__ITEM_TYPE_REPS_CONT;
             }
 
           if (in_container)
             {
               /* construct a container rep header */
-              *rep_header = apr_pcalloc(pool, sizeof(**rep_header));
+              *rep_header = apr_pcalloc(result_pool, sizeof(**rep_header));
               (*rep_header)->type = svn_fs_x__rep_container;
 
-              /* provide an empty shared file struct */
-              rs->file = apr_pcalloc(pool, sizeof(*rs->file));
-              rs->file->revision = revision;
-              rs->file->pool = pool;
-              rs->file->fs = fs;
-
               /* exit to caller */
               *rep_state = rs;
               return SVN_NO_ERROR;
             }
-        }
-
-      if (reuse_shared_file)
-        {
-          /* ... we can re-use the same, already open file object
-           */
-          SVN_ERR_ASSERT(sub_item == 0);
-          SVN_ERR(aligned_seek(fs, (*shared_file)->file, NULL, offset, pool));
 
-          rs->file = *shared_file;
+          SVN_ERR(rs_aligned_seek(rs, NULL, offset, scratch_pool));
         }
-      else
-        {
-          shared_file_t *file = apr_pcalloc(pool, sizeof(*file));
-          file->revision = revision;
-          file->pool = pool;
-          file->fs = fs;
 
-          /* otherwise, create a new file object
-           */
-          SVN_ERR(open_and_seek_representation(&file->file, fs, rep, pool));
-          file->stream = svn_stream_from_aprfile2(file->file, TRUE,
-                                                  file->pool);
-          rs->file = file;
-
-          /* remember the current file, if suggested by the caller */
-          if (shared_file)
-            *shared_file = file;
-        }
-
-      SVN_ERR(svn_fs_x__read_rep_header(&rh, rs->file->stream, pool));
-      SVN_ERR(svn_fs_x__get_file_offset(&rs->start, rs->file->file, pool));
+      SVN_ERR(svn_fs_x__read_rep_header(&rh, rs->sfile->rfile->stream,
+                                        result_pool, scratch_pool));
+      SVN_ERR(get_file_offset(&rs->start, rs, result_pool));
 
+      /* populate the cache if appropriate */
       if (SVN_IS_VALID_REVNUM(revision))
         {
-          SVN_ERR(block_read(NULL, fs, &rs->rep_id, rs->file->file, pool, 
pool));
+          SVN_ERR(block_read(NULL, fs, &rs->rep_id, rs->sfile->rfile,
+                             result_pool, scratch_pool));
           if (ffd->rep_header_cache)
-            SVN_ERR(svn_cache__set(ffd->rep_header_cache, &key, rh, pool));
+            SVN_ERR(svn_cache__set(ffd->rep_header_cache, &key, rh,
+                                   scratch_pool));
         }
     }
 
+  /* finalize */
   SVN_ERR(dgb__log_access(fs, &rs->rep_id, rh, SVN_FS_X__ITEM_TYPE_ANY_REP,
-                          pool));
+                          scratch_pool));
 
   rs->header_size = rh->header_size;
   *rep_state = rs;
   *rep_header = rh;
 
-  /* We are dealing with a delta, find out what version. */
   rs->chunk_index = 0;
+
+  /* skip "SVNx" diff marker */
   rs->current = 4;
 
   return SVN_NO_ERROR;
@@ -699,14 +784,14 @@ create_rep_state(rep_state_t **rep_state
                  shared_file_t **shared_file,
                  representation_t *rep,
                  svn_fs_t *fs,
-                 apr_pool_t *pool)
+                 apr_pool_t *result_pool,
+                 apr_pool_t *scratch_pool)
 {
   svn_error_t *err = create_rep_state_body(rep_state, rep_header,
-                                           shared_file, rep, fs, pool);
+                                           shared_file, rep, fs,
+                                           result_pool, scratch_pool);
   if (err && err->apr_err == SVN_ERR_FS_CORRUPT)
     {
-      fs_x_data_t *ffd = fs->fsap_data;
-
       /* ### This always returns "-1" for transaction reps, because
          ### this particular bit of code doesn't know if the rep is
          ### stored in the protorev or in the mutable area (for props
@@ -718,7 +803,8 @@ create_rep_state(rep_state_t **rep_state
                                "Corrupt representation '%s'",
                                rep
                                ? svn_fs_x__unparse_representation
-                                   (rep, ffd->format, TRUE, pool)->data
+                                   (rep, TRUE, scratch_pool,
+                                    scratch_pool)->data
                                : "(null)");
     }
   /* ### Call representation_string() ? */
@@ -728,18 +814,24 @@ create_rep_state(rep_state_t **rep_state
 svn_error_t *
 svn_fs_x__check_rep(representation_t *rep,
                     svn_fs_t *fs,
-                    apr_pool_t *pool)
+                    apr_pool_t *scratch_pool)
 {
   apr_off_t offset;
   apr_uint32_t sub_item;
   svn_fs_x__p2l_entry_t *entry;
   svn_revnum_t revision = svn_fs_x__get_revnum(rep->id.change_set);
 
+  svn_fs_x__revision_file_t *rev_file;
+  SVN_ERR(svn_fs_x__open_pack_or_rev_file(&rev_file, fs, revision,
+                                          scratch_pool, scratch_pool));
+
   /* Does REP->ID refer to an actual item? Which one is it? */
-  SVN_ERR(svn_fs_x__item_offset(&offset, &sub_item, fs, &rep->id, pool));
+  SVN_ERR(svn_fs_x__item_offset(&offset, &sub_item, fs, rev_file, &rep->id,
+                                scratch_pool));
 
   /* What is the type of that item? */
-  SVN_ERR(svn_fs_x__p2l_entry_lookup(&entry, fs, revision, offset, pool));
+  SVN_ERR(svn_fs_x__p2l_entry_lookup(&entry, fs, rev_file, revision, offset,
+                                     scratch_pool, scratch_pool));
 
   /* Verify that we've got an item that is actually a representation. */
   if (   entry == NULL
@@ -751,8 +843,8 @@ svn_fs_x__check_rep(representation_t *re
     return svn_error_createf(SVN_ERR_REPOS_CORRUPTED, NULL,
                              _("No representation found at offset %s "
                                "for item %s in revision %ld"),
-                             apr_off_t_toa(pool, offset),
-                             apr_psprintf(pool, "%" APR_UINT64_T_FMT,
+                             apr_off_t_toa(scratch_pool, offset),
+                             apr_psprintf(scratch_pool, "%" APR_UINT64_T_FMT,
                                           rep->id.number),
                              revision);
 
@@ -766,12 +858,10 @@ svn_fs_x__rep_chain_length(int *chain_le
                            int *shard_count,
                            representation_t *rep,
                            svn_fs_t *fs,
-                           apr_pool_t *pool)
+                           apr_pool_t *scratch_pool)
 {
   fs_x_data_t *ffd = fs->fsap_data;
-  svn_revnum_t shard_size = ffd->max_files_per_dir
-                          ? ffd->max_files_per_dir
-                          : 1;
+  svn_revnum_t shard_size = ffd->max_files_per_dir;
   svn_boolean_t is_delta = FALSE;
   int count = 0;
   int shards = 1;
@@ -782,7 +872,7 @@ svn_fs_x__rep_chain_length(int *chain_le
    * To reuse open file handles between iterations (e.g. while within the
    * same pack file), we only clear this pool once in a while instead of
    * at the start of each iteration. */
-  apr_pool_t *iterpool = svn_pool_create(pool);
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
   /* Check whether the length of the deltification chain is acceptable.
    * Otherwise, shared reps may form a non-skipping delta chain in
@@ -811,6 +901,7 @@ svn_fs_x__rep_chain_length(int *chain_le
                                     &file_hint,
                                     &base_rep,
                                     fs,
+                                    iterpool,
                                     iterpool));
 
       base_rep.id.change_set
@@ -970,9 +1061,14 @@ get_cached_window_sizes_func(void **out,
   return SVN_NO_ERROR;
 }
 
-/* Return the packed & expanded sizes of the window addressed by RS.  If the
- * window cannot be found in the window cache, set *IS_CACHED to FALSE.
- * Otherwise, set it to TRUE and return the data in *SIZES, allocated in POOL.
+/* Read the WINDOW_P number CHUNK_INDEX for the representation given in
+ * rep state RS from the current FSFS session's cache.  This will be a
+ * no-op and IS_CACHED will be set to FALSE if no cache has been given.
+ * If a cache is available IS_CACHED will inform the caller about the
+ * success of the lookup. Allocations of the window in will be made
+ * from RESULT_POOL. Use SCRATCH_POOL for temporary allocations.
+ *
+ * If the information could be found, put RS to CHUNK_INDEX.
  */
 static svn_error_t *
 get_cached_window_sizes(window_sizes_t **sizes,
@@ -1005,7 +1101,8 @@ get_cached_window(svn_txdelta_window_t *
                   rep_state_t *rs,
                   int chunk_index,
                   svn_boolean_t *is_cached,
-                  apr_pool_t *pool)
+                  apr_pool_t *result_pool,
+                  apr_pool_t *scratch_pool)
 {
   if (! rs->window_cache)
     {
@@ -1023,7 +1120,7 @@ get_cached_window(svn_txdelta_window_t *
                              is_cached,
                              rs->window_cache,
                              &key,
-                             pool));
+                             result_pool));
 
       if (*is_cached)
         {
@@ -1146,19 +1243,23 @@ build_rep_list(apr_array_header_t **list
   svn_fs_x__rep_header_t *rep_header;
   svn_boolean_t is_cached = FALSE;
   shared_file_t *shared_file = NULL;
+  apr_pool_t *iterpool = svn_pool_create(pool);
 
   *list = apr_array_make(pool, 1, sizeof(rep_state_t *));
   rep = *first_rep;
 
   /* for the top-level rep, we need the rep_args */
-  SVN_ERR(create_rep_state(&rs, &rep_header, &shared_file, &rep, fs, pool));
+  SVN_ERR(create_rep_state(&rs, &rep_header, &shared_file, &rep, fs, pool,
+                           iterpool));
 
   while (1)
     {
+      svn_pool_clear(iterpool);
+
       /* fetch state, if that has not been done already */
       if (!rs)
         SVN_ERR(create_rep_state(&rs, &rep_header, &shared_file,
-                                 &rep, fs, pool));
+                                 &rep, fs, pool, iterpool));
 
       /* for txn reps and containered reps, there won't be a cached
        * combined window */
@@ -1174,14 +1275,14 @@ build_rep_list(apr_array_header_t **list
           rs->current = 0;
           rs->size = (*window_p)->len;
           *src_state = rs;
-          return SVN_NO_ERROR;
+          break;
         }
 
       if (rep_header->type == svn_fs_x__rep_container)
         {
           /* This is a container item, so just return the current rep_state. */
           *src_state = rs;
-          return SVN_NO_ERROR;
+          break;
         }
 
       /* Push this rep onto the list.  If it's self-compressed, we're done. */
@@ -1189,7 +1290,7 @@ build_rep_list(apr_array_header_t **list
       if (rep_header->type == svn_fs_x__rep_self_delta)
         {
           *src_state = NULL;
-          return SVN_NO_ERROR;
+          break;
         }
 
       rep.id.change_set
@@ -1199,6 +1300,9 @@ build_rep_list(apr_array_header_t **list
 
       rs = NULL;
     }
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
 }
 
 
@@ -1240,68 +1344,12 @@ rep_read_get_baton(struct rep_read_baton
   return SVN_NO_ERROR;
 }
 
-/* Open FILE->FILE and FILE->STREAM if they haven't been opened, yet. */
-static svn_error_t*
-auto_open_shared_file(shared_file_t *file)
-{
-  if (file->file == NULL)
-    {
-      SVN_ERR(svn_fs_x__open_pack_or_rev_file(&file->file, file->fs,
-                                              file->revision, file->pool));
-      file->stream = svn_stream_from_aprfile2(file->file, TRUE, file->pool);
-    }
-
-  return SVN_NO_ERROR;
-}
-
-/* Set RS->START to the begin of the representation raw in RS->FILE->FILE,
-   if that hasn't been done yet.  Use POOL for temporary allocations. */
-static svn_error_t*
-auto_set_start_offset(rep_state_t *rs, apr_pool_t *pool)
-{
-  if (rs->start == -1)
-    {
-      SVN_ERR(svn_fs_x__item_offset(&rs->start, &rs->sub_item,
-                                    rs->file->fs, &rs->rep_id, pool));
-      rs->start += rs->header_size;
-    }
-
-  return SVN_NO_ERROR;
-}
-
-/* Set RS->VER depending on what is found in the already open RS->FILE->FILE
-   if the diff version is still unknown.  Use POOL for temporary allocations.
- */
-static svn_error_t*
-auto_read_diff_version(rep_state_t *rs, apr_pool_t *pool)
-{
-  if (rs->ver == -1)
-    {
-      char buf[4];
-      SVN_ERR(aligned_seek(rs->file->fs, rs->file->file, NULL, rs->start,
-                           pool));
-      SVN_ERR(svn_io_file_read_full2(rs->file->file, buf, sizeof(buf),
-                                     NULL, NULL, pool));
-
-      /* ### Layering violation */
-      if (! ((buf[0] == 'S') && (buf[1] == 'V') && (buf[2] == 'N')))
-        return svn_error_create
-          (SVN_ERR_FS_CORRUPT, NULL,
-           _("Malformed svndiff data in representation"));
-      rs->ver = buf[3];
-
-      rs->chunk_index = 0;
-      rs->current = 4;
-    }
-
-  return SVN_NO_ERROR;
-}
-
 /* Skip forwards to THIS_CHUNK in REP_STATE and then read the next delta
    window into *NWIN. */
 static svn_error_t *
 read_delta_window(svn_txdelta_window_t **nwin, int this_chunk,
-                  rep_state_t *rs, apr_pool_t *pool)
+                  rep_state_t *rs, apr_pool_t *result_pool,
+                  apr_pool_t *scratch_pool)
 {
   svn_boolean_t is_cached;
   apr_off_t start_offset;
@@ -1310,16 +1358,17 @@ read_delta_window(svn_txdelta_window_t *
 
   SVN_ERR_ASSERT(rs->chunk_index <= this_chunk);
 
-  SVN_ERR(dgb__log_access(rs->file->fs, &rs->rep_id, NULL,
-                          SVN_FS_X__ITEM_TYPE_ANY_REP, pool));
+  SVN_ERR(dgb__log_access(rs->sfile->fs, &rs->rep_id, NULL,
+                          SVN_FS_X__ITEM_TYPE_ANY_REP, scratch_pool));
 
   /* Read the next window.  But first, try to find it in the cache. */
-  SVN_ERR(get_cached_window(nwin, rs, this_chunk, &is_cached, pool));
+  SVN_ERR(get_cached_window(nwin, rs, this_chunk, &is_cached,
+                            result_pool, scratch_pool));
   if (is_cached)
     return SVN_NO_ERROR;
 
   /* someone has to actually read the data from file.  Open it */
-  SVN_ERR(auto_open_shared_file(rs->file));
+  SVN_ERR(auto_open_shared_file(rs->sfile));
 
   /* invoke the 'block-read' feature for non-txn data.
      However, don't do that if we are in the middle of some representation,
@@ -1328,37 +1377,38 @@ read_delta_window(svn_txdelta_window_t *
       && svn_fs_x__is_revision(rs->rep_id.change_set)
       && rs->window_cache)
     {
-      SVN_ERR(block_read(NULL, rs->file->fs, &rs->rep_id, rs->file->file,
-                         pool, pool));
+      SVN_ERR(block_read(NULL, rs->sfile->fs, &rs->rep_id,
+                         rs->sfile->rfile, result_pool, scratch_pool));
 
       /* reading the whole block probably also provided us with the
          desired txdelta window */
-      SVN_ERR(get_cached_window(nwin, rs, this_chunk, &is_cached, pool));
+      SVN_ERR(get_cached_window(nwin, rs, this_chunk, &is_cached,
+                                result_pool, scratch_pool));
       if (is_cached)
         return SVN_NO_ERROR;
     }
 
   /* data is still not cached -> we need to read it.
      Make sure we have all the necessary info. */
-  SVN_ERR(auto_set_start_offset(rs, pool));
-  SVN_ERR(auto_read_diff_version(rs, pool));
+  SVN_ERR(auto_set_start_offset(rs, scratch_pool));
+  SVN_ERR(auto_read_diff_version(rs, scratch_pool));
 
   /* RS->FILE may be shared between RS instances -> make sure we point
    * to the right data. */
   start_offset = rs->start + rs->current;
-  SVN_ERR(aligned_seek(rs->file->fs, rs->file->file, NULL, start_offset,
-                       pool));
+  SVN_ERR(rs_aligned_seek(rs, NULL, start_offset, scratch_pool));
 
   /* Skip windows to reach the current chunk if we aren't there yet. */
-  iterpool = svn_pool_create(pool);
+  iterpool = svn_pool_create(scratch_pool);
   while (rs->chunk_index < this_chunk)
     {
+      apr_file_t *file = rs->sfile->rfile->file;
       svn_pool_clear(iterpool);
-      SVN_ERR(svn_txdelta_skip_svndiff_window(rs->file->file, rs->ver,
-                                              iterpool));
+
+      SVN_ERR(svn_txdelta_skip_svndiff_window(file, rs->ver, iterpool));
       rs->chunk_index++;
-      SVN_ERR(svn_fs_x__get_file_offset(&start_offset, rs->file->file,
-                                        iterpool));
+      SVN_ERR(svn_fs_x__get_file_offset(&start_offset, file, iterpool));
+
       rs->current = start_offset - rs->start;
       if (rs->current >= rs->size)
         return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
@@ -1369,9 +1419,9 @@ read_delta_window(svn_txdelta_window_t *
   svn_pool_destroy(iterpool);
 
   /* Actually read the next window. */
-  SVN_ERR(svn_txdelta_read_svndiff_window(nwin, rs->file->stream, rs->ver,
-                                          pool));
-  SVN_ERR(svn_fs_x__get_file_offset(&end_offset, rs->file->file, pool));
+  SVN_ERR(svn_txdelta_read_svndiff_window(nwin, rs->sfile->rfile->stream,
+                                          rs->ver, result_pool));
+  SVN_ERR(get_file_offset(&end_offset, rs, scratch_pool));
   rs->current = end_offset - rs->start;
   if (rs->current > rs->size)
     return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
@@ -1381,7 +1431,7 @@ read_delta_window(svn_txdelta_window_t *
   /* the window has not been cached before, thus cache it now
    * (if caching is used for them at all) */
   if (svn_fs_x__is_revision(rs->rep_id.change_set))
-    SVN_ERR(set_cached_window(*nwin, rs, start_offset, pool));
+    SVN_ERR(set_cached_window(*nwin, rs, start_offset, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -1391,15 +1441,16 @@ static svn_error_t *
 read_container_window(svn_stringbuf_t **nwin,
                       rep_state_t *rs,
                       apr_size_t size,
-                      apr_pool_t *pool)
+                      apr_pool_t *result_pool,
+                      apr_pool_t *scratch_pool)
 {
   svn_fs_x__rep_extractor_t *extractor = NULL;
-  svn_fs_t *fs = rs->file->fs;
+  svn_fs_t *fs = rs->sfile->fs;
   fs_x_data_t *ffd = fs->fsap_data;
   pair_cache_key_t key;
   svn_revnum_t revision = svn_fs_x__get_revnum(rs->rep_id.change_set);
 
-  SVN_ERR(auto_set_start_offset(rs, pool));
+  SVN_ERR(auto_set_start_offset(rs, scratch_pool));
   key.revision = svn_fs_x__packed_base_rev(fs, revision);
   key.second = rs->start;
 
@@ -1414,19 +1465,19 @@ read_container_window(svn_stringbuf_t **
       SVN_ERR(svn_cache__get_partial((void**)&extractor, &is_cached,
                                      ffd->reps_container_cache, &key,
                                      svn_fs_x__reps_get_func, &baton,
-                                     pool));
+                                     result_pool));
     }
 
   /* read from disk, if necessary */
   if (extractor == NULL)
     {
-      SVN_ERR(auto_open_shared_file(rs->file));
+      SVN_ERR(auto_open_shared_file(rs->sfile));
       SVN_ERR(block_read((void **)&extractor, fs, &rs->rep_id,
-                         rs->file->file, pool, pool));
+                         rs->sfile->rfile, result_pool, scratch_pool));
     }
 
   SVN_ERR(svn_fs_x__extractor_drive(nwin, extractor, rs->current, size,
-                                    pool, pool));
+                                    result_pool, scratch_pool));
 
   /* Update RS. */
   rs->current += (apr_off_t)size;
@@ -1446,6 +1497,7 @@ get_combined_window(svn_stringbuf_t **re
   apr_array_header_t *windows;
   svn_stringbuf_t *source, *buf = rb->base_window;
   rep_state_t *rs;
+  apr_pool_t *iterpool;
 
   /* Read all windows that we need to combine. This is fine because
      the size of each window is relatively small (100kB) and skip-
@@ -1453,12 +1505,16 @@ get_combined_window(svn_stringbuf_t **re
      Stop early if one of them does not depend on its predecessors. */
   window_pool = svn_pool_create(rb->pool);
   windows = apr_array_make(window_pool, 0, sizeof(svn_txdelta_window_t *));
+  iterpool = svn_pool_create(rb->pool);
   for (i = 0; i < rb->rs_list->nelts; ++i)
     {
       svn_txdelta_window_t *window;
 
+      svn_pool_clear(iterpool);
+
       rs = APR_ARRAY_IDX(rb->rs_list, i, rep_state_t *);
-      SVN_ERR(read_delta_window(&window, rb->chunk_index, rs, window_pool));
+      SVN_ERR(read_delta_window(&window, rb->chunk_index, rs, window_pool,
+                                iterpool));
 
       APR_ARRAY_PUSH(windows, svn_txdelta_window_t *) = window;
       if (window->src_ops == 0)
@@ -1474,6 +1530,8 @@ get_combined_window(svn_stringbuf_t **re
     {
       svn_txdelta_window_t *window;
 
+      svn_pool_clear(iterpool);
+
       rs = APR_ARRAY_IDX(rb->rs_list, i, rep_state_t *);
       window = APR_ARRAY_IDX(windows, i, svn_txdelta_window_t *);
 
@@ -1484,7 +1542,7 @@ get_combined_window(svn_stringbuf_t **re
       source = buf;
       if (source == NULL && rb->src_state != NULL)
         SVN_ERR(read_container_window(&source, rb->src_state,
-                                      window->sview_len, pool));
+                                      window->sview_len, pool, iterpool));
 
       /* Combine this window with the current one. */
       new_pool = svn_pool_create(rb->pool);
@@ -1511,6 +1569,7 @@ get_combined_window(svn_stringbuf_t **re
       svn_pool_destroy(pool);
       pool = new_pool;
     }
+  svn_pool_destroy(iterpool);
 
   svn_pool_destroy(window_pool);
 
@@ -1549,8 +1608,7 @@ static svn_error_t *
 init_rep_state(rep_state_t *rs,
                svn_fs_x__rep_header_t *rep_header,
                svn_fs_t *fs,
-               apr_file_t *file,
-               svn_stream_t *stream,
+               svn_fs_x__revision_file_t *rev_file,
                svn_fs_x__p2l_entry_t* entry,
                apr_pool_t *pool)
 {
@@ -1562,13 +1620,12 @@ init_rep_state(rep_state_t *rs,
                  && entry->type <= SVN_FS_X__ITEM_TYPE_DIR_PROPS);
   SVN_ERR_ASSERT(entry->item_count == 1);
 
-  shared_file->file = file;
-  shared_file->stream = stream;
+  shared_file->rfile = rev_file;
   shared_file->fs = fs;
   shared_file->revision = svn_fs_x__get_revnum(entry->items[0].change_set);
   shared_file->pool = pool;
 
-  rs->file = shared_file;
+  rs->sfile = shared_file;
   rs->rep_id = entry->items[0];
   rs->header_size = rep_header->header_size;
   rs->start = entry->offset + rs->header_size;
@@ -1627,16 +1684,17 @@ cache_windows(svn_filesize_t *fulltext_l
           apr_off_t block_start;
 
           /* navigate to & read the current window */
-          SVN_ERR(aligned_seek(fs, rs->file->file, &block_start,
-                               start_offset, pool));
-          SVN_ERR(svn_txdelta_read_svndiff_window(&window, rs->file->stream,
+          SVN_ERR(rs_aligned_seek(rs, &block_start, start_offset, pool));
+          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(svn_fs_x__get_file_offset(&end_offset, rs->file->file,
+          SVN_ERR(svn_fs_x__get_file_offset(&end_offset,
+                                            rs->sfile->rfile->file,
                                             pool));
           rs->current = end_offset - rs->start;
           if (rs->current > rs->size)
@@ -1681,7 +1739,7 @@ read_rep_header(svn_fs_x__rep_header_t *
         return SVN_NO_ERROR;
     }
 
-  SVN_ERR(svn_fs_x__read_rep_header(rep_header, stream, pool));
+  SVN_ERR(svn_fs_x__read_rep_header(rep_header, stream, pool, pool));
 
   if (ffd->rep_header_cache)
     SVN_ERR(svn_cache__set(ffd->rep_header_cache, key, *rep_header, pool));
@@ -1693,8 +1751,7 @@ svn_error_t *
 svn_fs_x__get_representation_length(svn_filesize_t *packed_len,
                                     svn_filesize_t *expanded_len,
                                     svn_fs_t *fs,
-                                    apr_file_t *file,
-                                    svn_stream_t *stream,
+                                    svn_fs_x__revision_file_t *rev_file,
                                     svn_fs_x__p2l_entry_t* entry,
                                     apr_pool_t *pool)
 {
@@ -1711,12 +1768,12 @@ svn_fs_x__get_representation_length(svn_
   key.revision = svn_fs_x__get_revnum(entry->items[0].change_set);
   key.is_packed = svn_fs_x__is_packed_rev(fs, key.revision);
   key.item_index = entry->items[0].number;
-  SVN_ERR(read_rep_header(&rep_header, fs, stream, &key, pool));
+  SVN_ERR(read_rep_header(&rep_header, fs, rev_file->stream, &key, pool));
 
   /* prepare representation reader state (rs) structure */
-  SVN_ERR(init_rep_state(&rs, rep_header, fs, file, stream, entry, pool));
+  SVN_ERR(init_rep_state(&rs, rep_header, fs, rev_file, entry, pool));
   
-  /* RS->FILE may be shared between RS instances -> make sure we point
+  /* RS->SFILE may be shared between RS instances -> make sure we point
    * to the right data. */
   *packed_len = rs.size;
   SVN_ERR(cache_windows(expanded_len, fs, &rs, -1, pool));
@@ -1749,7 +1806,7 @@ get_contents_from_windows(struct rep_rea
            * the delta rep size _before_ putting the data into a
            * a container. */
           SVN_ERR(read_container_window(&rb->base_window, rs,
-                                        rb->len, rb->pool));
+                                        rb->len, rb->pool, rb->pool));
           rs->current -= rb->base_window->len;
         }
 
@@ -2221,14 +2278,18 @@ delta_read_next_window(svn_txdelta_windo
                        apr_pool_t *pool)
 {
   struct delta_read_baton *drb = baton;
+  apr_pool_t *scratch_pool = svn_pool_create(pool);
 
   *window = NULL;
   if (drb->rs->current < drb->rs->size)
     {
-      SVN_ERR(read_delta_window(window, drb->rs->chunk_index, drb->rs, pool));
+      SVN_ERR(read_delta_window(window, drb->rs->chunk_index, drb->rs, pool,
+                                scratch_pool));
       drb->rs->chunk_index++;
     }
 
+  svn_pool_destroy(scratch_pool);
+
   return SVN_NO_ERROR;
 }
 
@@ -2276,7 +2337,7 @@ svn_fs_x__get_file_delta_stream(svn_txde
     {
       /* Read target's base rep if any. */
       SVN_ERR(create_rep_state(&rep_state, &rep_header, NULL,
-                                target->data_rep, fs, pool));
+                                target->data_rep, fs, pool, pool));
 
       /* Try a shortcut: if the target is stored as a delta against the source,
          then just use that delta. */
@@ -2307,10 +2368,10 @@ svn_fs_x__get_file_delta_stream(svn_txde
         }
 
       /* Don't keep file handles open for longer than necessary. */
-      if (rep_state->file->file)
+      if (rep_state->sfile->rfile)
         {
-          SVN_ERR(svn_io_file_close(rep_state->file->file, pool));
-          rep_state->file->file = NULL;
+          SVN_ERR(svn_fs_x__close_revision_file(rep_state->sfile->rfile));
+          rep_state->sfile->rfile = NULL;
         }
     }
 
@@ -2446,7 +2507,7 @@ read_dir_entries(apr_array_header_t *ent
                            _("Directory entry corrupt in '%s'"),
                            svn_fs_x__id_unparse(id, scratch_pool)->data);
 
-      dirent->id = svn_fs_x__id_parse(str, strlen(str), result_pool);
+      SVN_ERR(svn_fs_x__id_parse(&dirent->id, str, result_pool));
 
       /* In incremental mode, update the hash; otherwise, write to the
        * final array. */
@@ -2502,26 +2563,22 @@ get_dir_contents(apr_array_header_t **en
     }
   else if (noderev->data_rep)
     {
-      /* use a temporary pool for temp objects.
-       * Also undeltify content before parsing it. Otherwise, we could only
+      /* Undeltify content before parsing it. Otherwise, we could only
        * parse it byte-by-byte.
        */
-      apr_pool_t *text_pool = svn_pool_create(scratch_pool);
       apr_size_t len = noderev->data_rep->expanded_size;
       svn_stringbuf_t *text;
 
       /* The representation is immutable.  Read it normally. */
       SVN_ERR(svn_fs_x__get_contents(&contents, fs, noderev->data_rep,
-                                     FALSE, text_pool));
-      SVN_ERR(svn_stringbuf_from_stream(&text, contents, len, text_pool));
+                                     FALSE, scratch_pool));
+      SVN_ERR(svn_stringbuf_from_stream(&text, contents, len, scratch_pool));
       SVN_ERR(svn_stream_close(contents));
 
       /* de-serialize hash */
-      contents = svn_stream_from_stringbuf(text, text_pool);
+      contents = svn_stream_from_stringbuf(text, scratch_pool);
       SVN_ERR(read_dir_entries(*entries, contents, FALSE,  noderev->id,
                                result_pool, scratch_pool));
-
-      svn_pool_destroy(text_pool);
     }
 
   return SVN_NO_ERROR;
@@ -2723,7 +2780,7 @@ svn_fs_x__get_changes(apr_array_header_t
                       svn_revnum_t rev,
                       apr_pool_t *result_pool)
 {
-  apr_file_t *revision_file;
+  svn_fs_x__revision_file_t *revision_file;
   svn_boolean_t found;
   fs_x_data_t *ffd = fs->fsap_data;
   apr_pool_t *scratch_pool = svn_pool_create(result_pool);
@@ -2732,6 +2789,12 @@ svn_fs_x__get_changes(apr_array_header_t
   id.change_set = svn_fs_x__change_set_by_rev(rev);
   id.number = SVN_FS_X__ITEM_INDEX_CHANGES;
 
+  /* Provide revision file. */
+
+  SVN_ERR(svn_fs_x__ensure_revision_exists(rev, fs, scratch_pool));
+  SVN_ERR(svn_fs_x__open_pack_or_rev_file(&revision_file, fs, rev,
+                                          scratch_pool, scratch_pool));
+
   /* try cache lookup first */
 
   if (ffd->changes_container_cache && svn_fs_x__is_packed_rev(fs, rev))
@@ -2740,8 +2803,8 @@ svn_fs_x__get_changes(apr_array_header_t
       apr_uint32_t sub_item;
       pair_cache_key_t key;
 
-      SVN_ERR(svn_fs_x__item_offset(&offset, &sub_item, fs, &id,
-                                    scratch_pool));
+      SVN_ERR(svn_fs_x__item_offset(&offset, &sub_item, fs, revision_file,
+                                    &id, scratch_pool));
       key.revision = svn_fs_x__packed_base_rev(fs, rev);
       key.second = offset;
 
@@ -2762,17 +2825,11 @@ svn_fs_x__get_changes(apr_array_header_t
 
   if (!found)
     {
-      /* read changes from revision file */
-
-      SVN_ERR(svn_fs_x__ensure_revision_exists(rev, fs, scratch_pool));
-      SVN_ERR(svn_fs_x__open_pack_or_rev_file(&revision_file, fs, rev,
-                                              scratch_pool));
-
       /* 'block-read' will also provide us with the desired data */
       SVN_ERR(block_read((void **)changes, fs, &id, revision_file,
                          result_pool, scratch_pool));
 
-      SVN_ERR(svn_io_file_close(revision_file, scratch_pool));
+      SVN_ERR(svn_fs_x__close_revision_file(revision_file));
     }
 
   SVN_ERR(dgb__log_access(fs, &id, *changes, SVN_FS_X__ITEM_TYPE_CHANGES,
@@ -2790,8 +2847,7 @@ svn_fs_x__get_changes(apr_array_header_t
  */
 static svn_error_t *
 block_read_contents(svn_fs_t *fs,
-                    apr_file_t *file,
-                    svn_stream_t *stream,
+                    svn_fs_x__revision_file_t *rev_file,
                     svn_fs_x__p2l_entry_t* entry,
                     pair_cache_key_t *key,
                     apr_off_t max_offset,
@@ -2810,40 +2866,59 @@ block_read_contents(svn_fs_t *fs,
   header_key.is_packed = svn_fs_x__is_packed_rev(fs, header_key.revision);
   header_key.item_index = key->second;
 
-  SVN_ERR(read_rep_header(&rep_header, fs, stream, &header_key,
+  SVN_ERR(read_rep_header(&rep_header, fs, rev_file->stream, &header_key,
                           scratch_pool));
-  SVN_ERR(init_rep_state(&rs, rep_header, fs, file, stream, entry,
-                         scratch_pool));
+  SVN_ERR(init_rep_state(&rs, rep_header, fs, rev_file, entry, scratch_pool));
   SVN_ERR(cache_windows(&fulltext_len, fs, &rs, max_offset, scratch_pool));
 
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *
-auto_select_stream(svn_stream_t **stream,
-                   svn_fs_t *fs,
-                   apr_file_t *file,
-                   svn_stream_t *file_stream,
-                   svn_fs_x__p2l_entry_t* entry,
-                   apr_pool_t *pool)
-{
-  fs_x_data_t *ffd = fs->fsap_data;
+/* For the given REV_FILE in FS, in *STREAM return a stream covering the
+ * item specified by ENTRY.  Also, verify the item's content by low-level
+ * checksum.  Allocate the result in POOL.
+ */
+static svn_error_t *
+read_item(svn_stream_t **stream,
+          svn_fs_t *fs,
+          svn_fs_x__revision_file_t *rev_file,
+          svn_fs_x__p2l_entry_t* entry,
+          apr_pool_t *pool)
+{
+  apr_uint32_t digest;
+  svn_checksum_t *expected, *actual;
+  apr_uint32_t plain_digest;
+
+  /* Read item into string buffer. */
+  svn_stringbuf_t *text = svn_stringbuf_create_ensure(entry->size, pool);
+  text->len = entry->size;
+  text->data[text->len] = 0;
+  SVN_ERR(svn_io_file_read_full2(rev_file->file, text->data, text->len,
+                                 NULL, NULL, pool));
+
+  /* Return (construct, calculate) stream and checksum. */
+  *stream = svn_stream_from_stringbuf(text, pool);
+  digest = svn__fnv1a_32x4(text->data, text->len);
 
-  if (((entry->offset + entry->size) ^ entry->offset) >= ffd->block_size)
-    {
-      svn_stringbuf_t *text = svn_stringbuf_create_ensure(entry->size, pool);
-      text->len = entry->size;
-      text->data[text->len] = 0;
-      SVN_ERR(svn_io_file_read_full2(file, text->data, text->len, NULL,
-                                     NULL, pool));
-      *stream = svn_stream_from_stringbuf(text, pool);
-    }
-  else
-    {
-      *stream = file_stream;
-    }
+  /* Checksums will match most of the time. */
+  if (entry->fnv1_checksum == digest)
+    return SVN_NO_ERROR;
 
-  return SVN_NO_ERROR;
+  /* Construct proper checksum objects from their digests to allow for
+   * nice error messages. */
+  plain_digest = htonl(entry->fnv1_checksum);
+  expected = svn_checksum__from_digest_fnv1a_32x4(
+                (const unsigned char *)&plain_digest, pool);
+  plain_digest = htonl(digest);
+  actual = svn_checksum__from_digest_fnv1a_32x4(
+                (const unsigned char *)&plain_digest, pool);
+
+  /* Construct the full error message with all the info we have. */
+  return svn_checksum_mismatch_err(expected, actual, pool,
+                 _("Low-level checksum mismatch while reading\n"
+                   "%s bytes of meta data at offset %s "),
+                 apr_psprintf(pool, "%" APR_OFF_T_FMT, entry->size),
+                 apr_psprintf(pool, "%" APR_OFF_T_FMT, entry->offset));
 }
 
 /* Read all txdelta / plain windows following REP_HEADER in FS as described
@@ -2855,8 +2930,7 @@ auto_select_stream(svn_stream_t **stream
 static svn_error_t *
 block_read_changes(apr_array_header_t **changes,
                    svn_fs_t *fs,
-                   apr_file_t *file,
-                   svn_stream_t *file_stream,
+                   svn_fs_x__revision_file_t *rev_file,
                    svn_fs_x__p2l_entry_t* entry,
                    svn_boolean_t must_read,
                    apr_pool_t *result_pool,
@@ -2881,18 +2955,27 @@ block_read_changes(apr_array_header_t **
         return SVN_NO_ERROR;
     }
 
-  SVN_ERR(auto_select_stream(&stream, fs, file, file_stream, entry,
-                             scratch_pool));
+  SVN_ERR(read_item(&stream, fs, rev_file, entry, scratch_pool));
 
   /* read changes from revision file */
 
-  SVN_ERR(svn_fs_x__read_changes(changes, stream, result_pool));
+  SVN_ERR(svn_fs_x__read_changes(changes, stream, result_pool, scratch_pool));
 
   /* cache for future reference */
 
   if (ffd->changes_cache)
-    SVN_ERR(svn_cache__set(ffd->changes_cache, &revision, *changes,
-                           scratch_pool));
+    {
+      /* Guesstimate for the size of the in-cache representation. */
+      apr_size_t estimated_size = (apr_size_t)250 * (*changes)->nelts;
+
+      /* Don't even serialize data that probably won't fit into the
+        * cache.  This often implies that either CHANGES is very
+        * large, memory is scarce or both.  Having a huge temporary
+        * copy would not be a good thing in either case. */
+      if (svn_cache__is_cachable(ffd->changes_cache, estimated_size))
+        SVN_ERR(svn_cache__set(ffd->changes_cache, &revision, *changes,
+                               scratch_pool));
+    }
 
   return SVN_NO_ERROR;
 }
@@ -2900,8 +2983,7 @@ block_read_changes(apr_array_header_t **
 static svn_error_t *
 block_read_changes_container(apr_array_header_t **changes,
                              svn_fs_t *fs,
-                             apr_file_t *file,
-                             svn_stream_t *file_stream,
+                             svn_fs_x__revision_file_t *rev_file,
                              svn_fs_x__p2l_entry_t* entry,
                              apr_uint32_t sub_item,
                              svn_boolean_t must_read,
@@ -2927,8 +3009,7 @@ block_read_changes_container(apr_array_h
         return SVN_NO_ERROR;
     }
 
-  SVN_ERR(auto_select_stream(&stream, fs, file, file_stream, entry,
-                             scratch_pool));
+  SVN_ERR(read_item(&stream, fs, rev_file, entry, scratch_pool));
 
   /* read changes from revision file */
 
@@ -2951,8 +3032,7 @@ block_read_changes_container(apr_array_h
 static svn_error_t *
 block_read_noderev(node_revision_t **noderev_p,
                    svn_fs_t *fs,
-                   apr_file_t *file,
-                   svn_stream_t *file_stream,
+                   svn_fs_x__revision_file_t *rev_file,
                    svn_fs_x__p2l_entry_t* entry,
                    pair_cache_key_t *key,
                    svn_boolean_t must_read,
@@ -2977,12 +3057,12 @@ block_read_noderev(node_revision_t **nod
         return SVN_NO_ERROR;
     }
 
-  SVN_ERR(auto_select_stream(&stream, fs, file, file_stream, entry,
-                             scratch_pool));
+  SVN_ERR(read_item(&stream, fs, rev_file, entry, scratch_pool));
 
   /* read node rev from revision file */
 
-  SVN_ERR(svn_fs_x__read_noderev(noderev_p, stream, result_pool));
+  SVN_ERR(svn_fs_x__read_noderev(noderev_p, stream, result_pool,
+                                 scratch_pool));
 
   /* Workaround issue #4031: is-fresh-txn-root in revision files. */
   (*noderev_p)->is_fresh_txn_root = FALSE;
@@ -2997,8 +3077,7 @@ block_read_noderev(node_revision_t **nod
 static svn_error_t *
 block_read_noderevs_container(node_revision_t **noderev_p,
                               svn_fs_t *fs,
-                              apr_file_t *file,
-                              svn_stream_t *file_stream,
+                              svn_fs_x__revision_file_t *rev_file,
                               svn_fs_x__p2l_entry_t* entry,
                               apr_uint32_t sub_item,
                               svn_boolean_t must_read,
@@ -3024,16 +3103,13 @@ block_read_noderevs_container(node_revis
         return SVN_NO_ERROR;
     }
 
-  SVN_ERR(auto_select_stream(&stream, fs, file, file_stream, entry,
-                             scratch_pool));
+  SVN_ERR(read_item(&stream, fs, rev_file, entry, scratch_pool));
 
   /* read noderevs from revision file */
-
   SVN_ERR(svn_fs_x__read_noderevs_container(&container, stream, scratch_pool,
                                             scratch_pool));
 
   /* extract requested data */
-
   if (must_read)
     SVN_ERR(svn_fs_x__noderevs_get(noderev_p, container, sub_item,
                                    result_pool));
@@ -3048,8 +3124,7 @@ block_read_noderevs_container(node_revis
 static svn_error_t *
 block_read_reps_container(svn_fs_x__rep_extractor_t **extractor,
                           svn_fs_t *fs,
-                          apr_file_t *file,
-                          svn_stream_t *file_stream,
+                          svn_fs_x__revision_file_t *rev_file,
                           svn_fs_x__p2l_entry_t* entry,
                           apr_uint32_t sub_item,
                           svn_boolean_t must_read,
@@ -3075,11 +3150,9 @@ block_read_reps_container(svn_fs_x__rep_
         return SVN_NO_ERROR;
     }
 
-  SVN_ERR(auto_select_stream(&stream, fs, file, file_stream, entry,
-                             scratch_pool));
+  SVN_ERR(read_item(&stream, fs, rev_file, entry, scratch_pool));
 
   /* read noderevs from revision file */
-
   SVN_ERR(svn_fs_x__read_reps_container(&container, stream, result_pool,
                                         scratch_pool));
 
@@ -3100,7 +3173,7 @@ static svn_error_t *
 block_read(void **result,
            svn_fs_t *fs,
            const svn_fs_x__id_part_t *id,
-           apr_file_t *revision_file,
+           svn_fs_x__revision_file_t *revision_file,
            apr_pool_t *result_pool,
            apr_pool_t *scratch_pool)
 {
@@ -3113,24 +3186,25 @@ block_read(void **result,
   int run_count = 0;
   int i;
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
-  svn_stream_t *stream = svn_stream_from_aprfile2(revision_file, TRUE,
-                                                  scratch_pool);
 
   /* don't try this on transaction protorev files */
   SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(revision));
 
   /* index lookup: find the OFFSET of the item we *must* read plus (in the
    * "do-while" block) the list of items in the same block. */
-  SVN_ERR(svn_fs_x__item_offset(&wanted_offset, &wanted_sub_item, fs, id,
-                                iterpool));
+  SVN_ERR(svn_fs_x__item_offset(&wanted_offset, &wanted_sub_item, fs,
+                                revision_file, id, iterpool));
 
   offset = wanted_offset;
   do
     {
       /* fetch list of items in the block surrounding OFFSET */
-      SVN_ERR(aligned_seek(fs, revision_file, &block_start, offset, iterpool));
-      SVN_ERR(svn_fs_x__p2l_index_lookup(&entries, fs, revision, block_start,
-                                         ffd->block_size, scratch_pool));
+      SVN_ERR(aligned_seek(fs, revision_file->file, &block_start, offset,
+                           iterpool));
+      SVN_ERR(svn_fs_x__p2l_index_lookup(&entries, fs, revision_file,
+                                         revision, block_start,
+                                         ffd->block_size, scratch_pool,
+                                         scratch_pool));
 
       /* read all items from the block */
       for (i = 0; i < entries->nelts; ++i)
@@ -3166,7 +3240,7 @@ block_read(void **result,
               key.revision = svn_fs_x__get_revnum(entry->items[0].change_set);
               key.second = entry->items[0].number;
 
-              SVN_ERR(svn_io_file_seek(revision_file, APR_SET,
+              SVN_ERR(svn_io_file_seek(revision_file->file, SEEK_SET,
                                        &entry->offset, iterpool));
               switch (entry->type)
                 {
@@ -3174,7 +3248,7 @@ block_read(void **result,
                   case SVN_FS_X__ITEM_TYPE_DIR_REP:
                   case SVN_FS_X__ITEM_TYPE_FILE_PROPS:
                   case SVN_FS_X__ITEM_TYPE_DIR_PROPS:
-                    SVN_ERR(block_read_contents(fs, revision_file, stream,
+                    SVN_ERR(block_read_contents(fs, revision_file,
                                                 entry, &key,
                                                 is_wanted
                                                   ? -1
@@ -3185,14 +3259,14 @@ block_read(void **result,
                   case SVN_FS_X__ITEM_TYPE_NODEREV:
                     if (ffd->node_revision_cache || is_result)
                       SVN_ERR(block_read_noderev((node_revision_t **)&item,
-                                                 fs, revision_file, stream,
+                                                 fs, revision_file,
                                                  entry, &key, is_result,
                                                  pool, iterpool));
                     break;
 
                   case SVN_FS_X__ITEM_TYPE_CHANGES:
                     SVN_ERR(block_read_changes((apr_array_header_t **)&item,
-                                               fs, revision_file,  stream,
+                                               fs, revision_file,
                                                entry, is_result,
                                                pool, iterpool));
                     break;
@@ -3200,7 +3274,7 @@ block_read(void **result,
                   case SVN_FS_X__ITEM_TYPE_CHANGES_CONT:
                     SVN_ERR(block_read_changes_container
                                             ((apr_array_header_t **)&item,
-                                             fs, revision_file,  stream,
+                                             fs, revision_file,
                                              entry, wanted_sub_item,
                                              is_result, pool, iterpool));
                     break;
@@ -3208,7 +3282,7 @@ block_read(void **result,
                   case SVN_FS_X__ITEM_TYPE_NODEREVS_CONT:
                     SVN_ERR(block_read_noderevs_container
                                             ((node_revision_t **)&item,
-                                             fs, revision_file,  stream,
+                                             fs, revision_file,
                                              entry, wanted_sub_item,
                                              is_result, pool, iterpool));
                     break;
@@ -3216,7 +3290,7 @@ block_read(void **result,
                   case SVN_FS_X__ITEM_TYPE_REPS_CONT:
                     SVN_ERR(block_read_reps_container
                                       ((svn_fs_x__rep_extractor_t **)&item,
-                                       fs, revision_file,  stream,
+                                       fs, revision_file,
                                        entry, wanted_sub_item,
                                        is_result, pool, iterpool));
                     break;
@@ -3243,7 +3317,6 @@ block_read(void **result,
 
   /* if the caller requested a result, we must have provided one by now */
   assert(!result || *result);
-  SVN_ERR(svn_stream_close(stream));
   svn_pool_destroy(iterpool);
 
   return SVN_NO_ERROR;

Modified: 
subversion/branches/move-tracking-2/subversion/libsvn_fs_x/cached_data.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_x/cached_data.h?rev=1641647&r1=1641646&r2=1641647&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_x/cached_data.h 
(original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_x/cached_data.h 
Tue Nov 25 16:26:48 2014
@@ -37,7 +37,8 @@ svn_error_t *
 svn_fs_x__get_node_revision(node_revision_t **noderev_p,
                             svn_fs_t *fs,
                             const svn_fs_id_t *id,
-                            apr_pool_t *pool);
+                            apr_pool_t *result_pool,
+                            apr_pool_t *scratch_pool);
 
 /* Set *COUNT to the value of the mergeinfo_count member of the node-
    revision for the node ID in FS.  Do any allocations in POOL. */
@@ -53,25 +54,26 @@ svn_error_t *
 svn_fs_x__rev_get_root(svn_fs_id_t **root_id,
                        svn_fs_t *fs,
                        svn_revnum_t rev,
-                       apr_pool_t *pool);
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool);
 
 /* Verify that representation REP in FS can be accessed.
-   Do any allocations in POOL. */
+   Do any allocations in SCRATCH_POOL. */
 svn_error_t *
 svn_fs_x__check_rep(representation_t *rep,
                     svn_fs_t *fs,
-                    apr_pool_t *pool);
+                    apr_pool_t *scratch_pool);
 
 /* Follow the representation delta chain in FS starting with REP.  The
    number of reps (including REP) in the chain will be returned in
    *CHAIN_LENGTH.  *SHARD_COUNT will be set to the number of shards
-   accessed.  Do any allocations in POOL. */
+   accessed.  Do any allocations in SCRATCH_POOL. */
 svn_error_t *
 svn_fs_x__rep_chain_length(int *chain_length,
                            int *shard_count,
                            representation_t *rep,
                            svn_fs_t *fs,
-                           apr_pool_t *pool);
+                           apr_pool_t *scratch_pool);
 
 /* Set *CONTENTS to be a readable svn_stream_t that receives the text
    representation REP as seen in filesystem FS.  If CACHE_FULLTEXT is
@@ -95,8 +97,7 @@ svn_error_t *
 svn_fs_x__get_representation_length(svn_filesize_t *packed_len,
                                     svn_filesize_t *expanded_len,
                                     svn_fs_t *fs,
-                                    apr_file_t *file,
-                                    svn_stream_t *stream,
+                                    svn_fs_x__revision_file_t *rev_file,
                                     svn_fs_x__p2l_entry_t* entry,
                                     apr_pool_t *pool);
 

Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_x/dag.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_x/dag.c?rev=1641647&r1=1641646&r2=1641647&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_x/dag.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_x/dag.c Tue Nov 25 
16:26:48 2014
@@ -160,10 +160,13 @@ get_node_revision(node_revision_t **node
   if (! node->node_revision)
     {
       node_revision_t *noderev;
+      apr_pool_t *scratch_pool = svn_pool_create(node->node_pool);
 
       SVN_ERR(svn_fs_x__get_node_revision(&noderev, node->fs,
-                                          node->id, node->node_pool));
+                                          node->id, node->node_pool,
+                                          scratch_pool));
       node->node_revision = noderev;
+      svn_pool_destroy(scratch_pool);
     }
 
   /* Now NODE->node_revision is set.  */
@@ -613,7 +616,7 @@ svn_fs_x__dag_revision_root(dag_node_t *
   /* Construct the node. */
   new_node = apr_pcalloc(pool, sizeof(*new_node));
   new_node->fs = fs;
-  SVN_ERR(svn_fs_x__rev_get_root(&new_node->id, fs, rev, pool));
+  SVN_ERR(svn_fs_x__rev_get_root(&new_node->id, fs, rev, pool, pool));
 
   /* Grab the contents so we can inspect the node's kind and created path. */
   new_node->node_pool = pool;

Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_x/fs.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_x/fs.c?rev=1641647&r1=1641646&r2=1641647&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_x/fs.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_x/fs.c Tue Nov 25 
16:26:48 2014
@@ -45,6 +45,7 @@
 #include "revprops.h"
 #include "rep-cache.h"
 #include "transaction.h"
+#include "util.h"
 #include "svn_private_config.h"
 #include "private/svn_fs_util.h"
 
@@ -72,20 +73,28 @@ x_serialized_init(svn_fs_t *fs, apr_pool
      each separate repository opened during the lifetime of the
      svn_fs_initialize pool.  It's unlikely that anyone will notice
      the modest expenditure; the alternative is to allocate each structure
-     in a subpool, add a reference-count, and add a serialized deconstructor
+     in a subpool, add a reference-count, and add a serialized destructor
      to the FS vtable.  That's more machinery than it's worth.
 
-     Using the uuid to obtain the lock creates a corner case if a
-     caller uses svn_fs_set_uuid on the repository in a process where
-     other threads might be using the same repository through another
-     FS object.  The only real-world consumer of svn_fs_set_uuid is
-     "svnadmin load", so this is a low-priority problem, and we don't
-     know of a better way of associating such data with the
-     repository. */
+     Picking an appropriate key for the shared data is tricky, because,
+     unfortunately, a filesystem UUID is not really unique.  It is implicitly
+     shared between hotcopied (1), dump / loaded (2) or naively copied (3)
+     filesystems.  We tackle this problem by using a combination of the UUID
+     and an instance ID as the key.  This allows us to avoid key clashing
+     in (1) and (2).
+
+     Speaking of (3), there is not so much we can do about it, except maybe
+     provide a convenient way of fixing things.  Naively copied filesystems
+     have identical filesystem UUIDs *and* instance IDs.  With the key being
+     a combination of these two, clashes can be fixed by changing either of
+     them (or both), e.g. with svn_fs_set_uuid(). */
+
 
   SVN_ERR_ASSERT(fs->uuid);
-  key = apr_pstrcat(pool, SVN_FSX_SHARED_USERDATA_PREFIX, fs->uuid,
-                    SVN_VA_NULL);
+  SVN_ERR_ASSERT(ffd->instance_id);
+
+  key = apr_pstrcat(pool, SVN_FSX_SHARED_USERDATA_PREFIX,
+                    fs->uuid, ":", ffd->instance_id, SVN_VA_NULL);
   status = apr_pool_userdata_get(&val, key, common_pool);
   if (status)
     return svn_error_wrap_apr(status, _("Can't fetch FSX shared data"));
@@ -99,13 +108,16 @@ x_serialized_init(svn_fs_t *fs, apr_pool
       /* POSIX fcntl locks are per-process, so we need a mutex for
          intra-process synchronization when grabbing the repository write
          lock. */
-      SVN_ERR(svn_mutex__init(&ffsd->fs_write_lock, TRUE, common_pool));
+      SVN_ERR(svn_mutex__init(&ffsd->fs_write_lock,
+                              SVN_FS_X__USE_LOCK_MUTEX, common_pool));
 
       /* ... the pack lock ... */
-      SVN_ERR(svn_mutex__init(&ffsd->fs_pack_lock, TRUE, common_pool));
+      SVN_ERR(svn_mutex__init(&ffsd->fs_pack_lock,
+                              SVN_FS_X__USE_LOCK_MUTEX, common_pool));
 
       /* ... not to mention locking the txn-current file. */
-      SVN_ERR(svn_mutex__init(&ffsd->txn_current_lock, TRUE, common_pool));
+      SVN_ERR(svn_mutex__init(&ffsd->txn_current_lock,
+                              SVN_FS_X__USE_LOCK_MUTEX, common_pool));
 
       /* We also need a mutex for synchronizing access to the active
          transaction list and free transaction pointer. */
@@ -158,6 +170,16 @@ x_freeze_body(void *baton,
 }
 
 static svn_error_t *
+x_freeze_body2(void *baton,
+               apr_pool_t *pool)
+{
+  struct x_freeze_baton_t *b = baton;
+  SVN_ERR(svn_fs_x__with_write_lock(b->fs, x_freeze_body, baton, pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
 x_freeze(svn_fs_t *fs,
          svn_fs_freeze_func_t freeze_func,
          void *freeze_baton,
@@ -170,7 +192,7 @@ x_freeze(svn_fs_t *fs,
   b.freeze_baton = freeze_baton;
 
   SVN_ERR(svn_fs__check_fs(fs, TRUE));
-  SVN_ERR(svn_fs_x__with_write_lock(fs, x_freeze_body, &b, pool));
+  SVN_ERR(svn_fs_x__with_pack_lock(fs, x_freeze_body2, &b, pool));
 
   return SVN_NO_ERROR;
 }
@@ -203,6 +225,18 @@ x_revision_proplist(apr_hash_t **proplis
                                                          rev, FALSE, pool));
 }
 
+/* Wrapper around svn_fs_x__set_uuid() adapting between function
+   signatures. */
+static svn_error_t *
+x_set_uuid(svn_fs_t *fs,
+           const char *uuid,
+           apr_pool_t *pool)
+{
+  /* Whenever we set a new UUID, imply that FS will also be a different
+   * instance (on formats that support this). */
+  return svn_error_trace(svn_fs_x__set_uuid(fs, uuid, NULL, pool));
+}
+
 
 
 /* The vtable associated with a specific open filesystem. */
@@ -211,7 +245,7 @@ static fs_vtable_t fs_vtable = {
   svn_fs_x__revision_prop,
   x_revision_proplist,
   svn_fs_x__change_rev_prop,
-  svn_fs_x__set_uuid,
+  x_set_uuid,
   svn_fs_x__revision_root,
   svn_fs_x__begin_txn,
   svn_fs_x__open_txn,
@@ -244,6 +278,15 @@ initialize_fs_struct(svn_fs_t *fs)
   return SVN_NO_ERROR;
 }
 
+/* Reset vtable and fsap_data fields in FS such that the FS is basically
+ * closed now.  Note that FS must not hold locks when you call this. */
+static void
+uninitialize_fs_struct(svn_fs_t *fs)
+{
+  fs->vtable = NULL;
+  fs->fsap_data = NULL;
+}
+
 /* This implements the fs_library_vtable_t.create() API.  Create a new
    fsx-backed Subversion filesystem at path PATH and link it into
    *FS.  Perform temporary allocations in POOL, and fs-global allocations
@@ -311,20 +354,53 @@ x_open_for_recovery(svn_fs_t *fs,
                     apr_pool_t *pool,
                     apr_pool_t *common_pool)
 {
-  /* Recovery for FSX is currently limited to recreating the 'current'
+  svn_error_t * err;
+  svn_revnum_t youngest_rev;
+  apr_pool_t * subpool = svn_pool_create(pool);
+
+  /* Recovery for FSFS is currently limited to recreating the 'current'
      file from the latest revision. */
 
   /* The only thing we have to watch out for is that the 'current' file
-     might not exist.  So we'll try to create it here unconditionally,
-     and just ignore any errors that might indicate that it's already
-     present. (We'll need it to exist later anyway as a source for the
-     new file's permissions). */
+     might not exist or contain garbage.  So we'll try to read it here
+     and provide or replace the existing file if we couldn't read it.
+     (We'll also need it to exist later anyway as a source for the new
+     file's permissions). */
 
-  /* Use a partly-filled fs pointer first to create 'current'.  This will fail
-     if 'current' already exists, but we don't care about that. */
+  /* Use a partly-filled fs pointer first to create 'current'. */
   fs->path = apr_pstrdup(fs->pool, path);
-  svn_error_clear(svn_io_file_create(svn_fs_x__path_current(fs, pool),
-                                     "0 1 1\n", pool));
+
+  SVN_ERR(initialize_fs_struct(fs));
+
+  /* Figure out the repo format and check that we can even handle it. */
+  SVN_ERR(svn_fs_x__read_format_file(fs, subpool));
+
+  /* Now, read 'current' and try to patch it if necessary. */
+  err = svn_fs_x__youngest_rev(&youngest_rev, fs, subpool);
+  if (err)
+    {
+      const char *file_path;
+
+      /* 'current' file is missing or contains garbage.  Since we are trying
+       * to recover from whatever problem there is, being picky about the
+       * error code here won't do us much good.  If there is a persistent
+       * problem that we can't fix, it will show up when we try rewrite the
+       * file a few lines further below and we will report the failure back
+       * to the caller.
+       *
+       * Start recovery with HEAD = 0. */
+      svn_error_clear(err);
+      file_path = svn_fs_x__path_current(fs, subpool);
+
+      /* Best effort to ensure the file exists and is valid.
+       * This may fail for r/o filesystems etc. */
+      SVN_ERR(svn_io_remove_file2(file_path, TRUE, subpool));
+      SVN_ERR(svn_io_file_create_empty(file_path, subpool));
+      SVN_ERR(svn_fs_x__write_current(fs, 0, subpool));
+    }
+
+  uninitialize_fs_struct(fs);
+  svn_pool_destroy(subpool);
 
   /* Now open the filesystem properly by calling the vtable method directly. */
   return x_open(fs, path, common_pool_lock, pool, common_pool);
@@ -412,11 +488,13 @@ x_hotcopy(svn_fs_t *src_fs,
   if (cancel_func)
     SVN_ERR(cancel_func(cancel_baton));
 
-  /* Provide FFD for DST_FS, test / initialize target repo, remove FFD. */
+  /* Test target repo when in INCREMENTAL mode, initialize it when not.
+   * For this, we need our FS internal data structures to be temporarily
+   * available. */
   SVN_ERR(initialize_fs_struct(dst_fs));
   SVN_ERR(svn_fs_x__hotcopy_prepare_target(src_fs, dst_fs, dst_path,
                                            incremental, pool));
-  dst_fs->fsap_data = NULL;
+  uninitialize_fs_struct(dst_fs);
 
   /* Now, the destination repo should open just fine. */
   SVN_ERR(x_open(dst_fs, dst_path, common_pool_lock, pool, common_pool));
@@ -424,8 +502,9 @@ x_hotcopy(svn_fs_t *src_fs,
     SVN_ERR(cancel_func(cancel_baton));
 
   /* Now, we may copy data as needed ... */
-  return svn_fs_x__hotcopy(src_fs, dst_fs,
-                           incremental, cancel_func, cancel_baton, pool);
+  return svn_fs_x__hotcopy(src_fs, dst_fs, incremental,
+                           notify_func, notify_baton,
+                           cancel_func, cancel_baton, pool);
 }
 
 
@@ -456,7 +535,7 @@ x_delete_fs(const char *path,
             apr_pool_t *pool)
 {
   /* Remove everything. */
-  return svn_io_remove_dir2(path, FALSE, NULL, NULL, pool);
+  return svn_error_trace(svn_io_remove_dir2(path, FALSE, NULL, NULL, pool));
 }
 
 static const svn_version_t *

Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_x/fs.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_x/fs.h?rev=1641647&r1=1641646&r2=1641647&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_x/fs.h (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_x/fs.h Tue Nov 25 
16:26:48 2014
@@ -126,6 +126,16 @@ extern "C" {
  */
 #define SVN_FS_X__FORMAT_NUMBER   1
 
+/* On most operating systems apr implements file locks per process, not
+   per file.  On Windows apr implements the locking as per file handle
+   locks, so we don't have to add our own mutex for just in-process
+   synchronization. */
+#if APR_HAS_THREADS && !defined(WIN32)
+#define SVN_FS_X__USE_LOCK_MUTEX 1
+#else
+#define SVN_FS_X__USE_LOCK_MUTEX 0
+#endif
+
 /* Private FSX-specific data shared between all svn_txn_t objects that
    relate to a particular transaction in a filesystem (as identified
    by transaction id and filesystem UUID).  Objects of this type are
@@ -245,9 +255,11 @@ typedef struct fs_x_data_t
   /* The maximum number of files to store per directory. */
   int max_files_per_dir;
 
-  /* Rev / pack file read granularity. */
+  /* Rev / pack file read granularity in bytes. */
   apr_int64_t block_size;
 
+  /* Rev / pack file granularity (in bytes) covered by a single phys-to-log
+   * index page. */
   /* Capacity in entries of log-to-phys index pages */
   apr_int64_t l2p_page_size;
 
@@ -400,6 +412,12 @@ typedef struct fs_x_data_t
   /* Pack after every commit. */
   svn_boolean_t pack_after_commit;
 
+  /* Per-instance filesystem ID, which provides an additional level of
+     uniqueness for filesystems that share the same UUID, but should
+     still be distinguishable (e.g. backups produced by svn_fs_hotcopy()
+     or dump / load cycles). */
+  const char *instance_id;
+
   /* Pointer to svn_fs_open. */
   svn_error_t *(*svn_fs_open_)(svn_fs_t **, const char *, apr_hash_t *,
                                apr_pool_t *, apr_pool_t *);


Reply via email to