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 2013/07/16 14:45:04 UTC

svn commit: r1503692 [2/2] - in /subversion/branches/fsfs-improvements: subversion/libsvn_fs_fs/ tools/server-side/

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs_fs.c?rev=1503692&r1=1503691&r2=1503692&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs_fs.c Tue Jul 16 12:45:03 2013
@@ -51,6 +51,7 @@
 #include "svn_ctype.h"
 #include "svn_version.h"
 
+#include "cached_data.h"
 #include "fs.h"
 #include "tree.h"
 #include "lock.h"
@@ -1342,1633 +1343,81 @@ svn_fs_fs__revision_exists(svn_revnum_t 
   return SVN_NO_ERROR;
 }
 
-/* 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. */
-static svn_error_t *
-open_and_seek_revision(apr_file_t **file,
-                       svn_fs_t *fs,
-                       svn_revnum_t rev,
-                       apr_off_t offset,
-                       apr_pool_t *pool)
-{
-  apr_file_t *rev_file;
-
-  SVN_ERR(svn_fs_fs__revision_exists(rev, fs, pool));
-
-  SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&rev_file, fs, rev, pool));
-
-  if (svn_fs_fs__is_packed_rev(fs, rev))
-    {
-      apr_off_t rev_offset;
-
-      SVN_ERR(svn_fs_fs__get_packed_offset(&rev_offset, fs, rev, pool));
-      offset += rev_offset;
-    }
-
-  SVN_ERR(svn_io_file_seek(rev_file, APR_SET, &offset, pool));
-
-  *file = rev_file;
-
-  return SVN_NO_ERROR;
-}
-
-/* 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
-   POOL.  Only appropriate for file contents, nor props or directory
-   contents. */
-static svn_error_t *
-open_and_seek_transaction(apr_file_t **file,
-                          svn_fs_t *fs,
-                          const char *txn_id,
-                          representation_t *rep,
-                          apr_pool_t *pool)
-{
-  apr_file_t *rev_file;
-  apr_off_t offset;
-
-  SVN_ERR(svn_io_file_open(&rev_file,
-                           svn_fs_fs__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;
-
-  return SVN_NO_ERROR;
-}
-
-/* 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,
-                             svn_fs_t *fs,
-                             representation_t *rep,
-                             apr_pool_t *pool)
-{
-  if (! rep->txn_id)
-    return open_and_seek_revision(file_p, fs, rep->revision, rep->offset,
-                                  pool);
-  else
-    return open_and_seek_transaction(file_p, fs, rep->txn_id, rep, pool);
-}
-
-static svn_error_t *
-err_dangling_id(svn_fs_t *fs, const svn_fs_id_t *id)
-{
-  svn_string_t *id_str = svn_fs_fs__id_unparse(id, fs->pool);
-  return svn_error_createf
-    (SVN_ERR_FS_ID_NOT_FOUND, 0,
-     _("Reference to non-existent node '%s' in filesystem '%s'"),
-     id_str->data, fs->path);
-}
-
-/* Look up the NODEREV_P for ID in FS' node revsion cache. If noderev
- * caching has been enabled and the data can be found, IS_CACHED will
- * be set to TRUE. The noderev will be allocated from POOL.
- *
- * Non-permanent ids (e.g. ids within a TXN) will not be cached.
- */
-static svn_error_t *
-get_cached_node_revision_body(node_revision_t **noderev_p,
-                              svn_fs_t *fs,
-                              const svn_fs_id_t *id,
-                              svn_boolean_t *is_cached,
-                              apr_pool_t *pool)
-{
-  fs_fs_data_t *ffd = fs->fsap_data;
-  if (! ffd->node_revision_cache || svn_fs_fs__id_txn_id(id))
-    {
-      *is_cached = FALSE;
-    }
-  else
-    {
-      pair_cache_key_t key = { 0 };
-
-      key.revision = svn_fs_fs__id_rev(id);
-      key.second = svn_fs_fs__id_offset(id);
-      SVN_ERR(svn_cache__get((void **) noderev_p,
-                            is_cached,
-                            ffd->node_revision_cache,
-                            &key,
-                            pool));
-    }
-
-  return SVN_NO_ERROR;
-}
-
-/* If noderev caching has been enabled, store the NODEREV_P for the given ID
- * in FS' node revsion cache. SCRATCH_POOL is used for temporary allcations.
- *
- * Non-permanent ids (e.g. ids within a TXN) will not be cached.
- */
-static svn_error_t *
-set_cached_node_revision_body(node_revision_t *noderev_p,
-                              svn_fs_t *fs,
-                              const svn_fs_id_t *id,
-                              apr_pool_t *scratch_pool)
-{
-  fs_fs_data_t *ffd = fs->fsap_data;
-
-  if (ffd->node_revision_cache && !svn_fs_fs__id_txn_id(id))
-    {
-      pair_cache_key_t key = { 0 };
-
-      key.revision = svn_fs_fs__id_rev(id);
-      key.second = svn_fs_fs__id_offset(id);
-      return svn_cache__set(ffd->node_revision_cache,
-                            &key,
-                            noderev_p,
-                            scratch_pool);
-    }
-
-  return SVN_NO_ERROR;
-}
-
-/* Get the node-revision for the node ID in FS.
-   Set *NODEREV_P to the new node-revision structure, allocated in POOL.
-   See svn_fs_fs__get_node_revision, which wraps this and adds another
-   error. */
-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_file_t *revision_file;
-  svn_error_t *err;
-  svn_boolean_t is_cached = FALSE;
-
-  /* First, try a cache lookup. If that succeeds, we are done here. */
-  SVN_ERR(get_cached_node_revision_body(noderev_p, fs, id, &is_cached, pool));
-  if (is_cached)
-    return SVN_NO_ERROR;
-
-  if (svn_fs_fs__id_txn_id(id))
-    {
-      /* This is a transaction node-rev. */
-      err = svn_io_file_open(&revision_file,
-                             svn_fs_fs__path_txn_node_rev(fs, id, pool),
-                             APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool);
-    }
-  else
-    {
-      /* This is a revision node-rev. */
-      err = open_and_seek_revision(&revision_file, fs,
-                                   svn_fs_fs__id_rev(id),
-                                   svn_fs_fs__id_offset(id),
-                                   pool);
-    }
-
-  if (err)
-    {
-      if (APR_STATUS_IS_ENOENT(err->apr_err))
-        {
-          svn_error_clear(err);
-          return svn_error_trace(err_dangling_id(fs, id));
-        }
-
-      return svn_error_trace(err);
-    }
-
-  SVN_ERR(svn_fs_fs__read_noderev(noderev_p,
-                                  svn_stream_from_aprfile2(revision_file, FALSE,
-                                                           pool),
-                                  pool));
-
-  /* The noderev is not in cache, yet. Add it, if caching has been enabled. */
-  return set_cached_node_revision_body(*noderev_p, fs, id, pool);
-}
-
-svn_error_t *
-svn_fs_fs__get_node_revision(node_revision_t **noderev_p,
-                             svn_fs_t *fs,
-                             const svn_fs_id_t *id,
-                             apr_pool_t *pool)
-{
-  svn_error_t *err = get_node_revision_body(noderev_p, fs, id, pool);
-  if (err && err->apr_err == SVN_ERR_FS_CORRUPT)
-    {
-      svn_string_t *id_string = svn_fs_fs__id_unparse(id, pool);
-      return svn_error_createf(SVN_ERR_FS_CORRUPT, err,
-                               "Corrupt node-revision '%s'",
-                               id_string->data);
-    }
-  return svn_error_trace(err);
-}
-
-
-svn_error_t *
-svn_fs_fs__put_node_revision(svn_fs_t *fs,
-                             const svn_fs_id_t *id,
-                             node_revision_t *noderev,
-                             svn_boolean_t fresh_txn_root,
-                             apr_pool_t *pool)
-{
-  fs_fs_data_t *ffd = fs->fsap_data;
-  apr_file_t *noderev_file;
-  const char *txn_id = svn_fs_fs__id_txn_id(id);
-
-  noderev->is_fresh_txn_root = fresh_txn_root;
-
-  if (! txn_id)
-    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
-                             _("Attempted to write to non-transaction '%s'"),
-                             svn_fs_fs__id_unparse(id, pool)->data);
-
-  SVN_ERR(svn_io_file_open(&noderev_file,
-                           svn_fs_fs__path_txn_node_rev(fs, id, pool),
-                           APR_WRITE | APR_CREATE | APR_TRUNCATE
-                           | APR_BUFFERED, APR_OS_DEFAULT, pool));
-
-  SVN_ERR(svn_fs_fs__write_noderev(svn_stream_from_aprfile2(noderev_file, TRUE,
-                                                            pool),
-                                   noderev, ffd->format,
-                                   svn_fs_fs__fs_supports_mergeinfo(fs),
-                                   pool));
-
-  SVN_ERR(svn_io_file_close(noderev_file, pool));
-
-  return SVN_NO_ERROR;
-}
-
-/* For the in-transaction NODEREV within FS, write the sha1->rep mapping
- * file in the respective transaction, if rep sharing has been enabled etc.
- * Use POOL for temporary allocations.
- */
-static svn_error_t *
-store_sha1_rep_mapping(svn_fs_t *fs,
-                       node_revision_t *noderev,
-                       apr_pool_t *pool)
-{
-  fs_fs_data_t *ffd = fs->fsap_data;
-
-  /* if rep sharing has been enabled and the noderev has a data rep and
-   * its SHA-1 is known, store the rep struct under its SHA1. */
-  if (   ffd->rep_sharing_allowed
-      && noderev->data_rep
-      && noderev->data_rep->sha1_checksum)
-    {
-      apr_file_t *rep_file;
-      const char *file_name = path_txn_sha1(fs,
-                                            svn_fs_fs__id_txn_id(noderev->id),
-                                            noderev->data_rep->sha1_checksum,
-                                            pool);
-      svn_stringbuf_t *rep_string
-        = svn_fs_fs__unparse_representation(noderev->data_rep,
-                                            ffd->format,
-                                            (noderev->kind == svn_node_dir),
-                                            FALSE,
-                                            pool);
-      SVN_ERR(svn_io_file_open(&rep_file, file_name,
-                               APR_WRITE | APR_CREATE | APR_TRUNCATE
-                               | APR_BUFFERED, APR_OS_DEFAULT, pool));
-
-      SVN_ERR(svn_io_file_write_full(rep_file, rep_string->data,
-                                     rep_string->len, NULL, pool));
-
-      SVN_ERR(svn_io_file_close(rep_file, pool));
-    }
-
-  return SVN_NO_ERROR;
-}
-
-
-/* Given a revision file REV_FILE, opened to REV in FS, find the Node-ID
-   of the header located at OFFSET and store it in *ID_P.  Allocate
-   temporary variables from POOL. */
-static svn_error_t *
-get_fs_id_at_offset(svn_fs_id_t **id_p,
-                    apr_file_t *rev_file,
-                    svn_fs_t *fs,
-                    svn_revnum_t rev,
-                    apr_off_t offset,
-                    apr_pool_t *pool)
-{
-  node_revision_t *noderev;
-
-  SVN_ERR(svn_io_file_seek(rev_file, APR_SET, &offset, pool));
-  SVN_ERR(svn_fs_fs__read_noderev(&noderev,
-                                  svn_stream_from_aprfile2(rev_file, TRUE,
-                                                           pool),
-                                  pool));
-
-  /* noderev->id is const, get rid of that */
-  *id_p = svn_fs_fs__id_copy(noderev->id, pool);
-
-  /* assert that the txn_id is REV
-   * (asserting on offset would be harder because we the rev_offset is not
-   * known here) */
-  assert(svn_fs_fs__id_rev(*id_p) == rev);
-
-  return SVN_NO_ERROR;
-}
-
-
-/* Given an open revision file REV_FILE in FS for REV, locate the trailer that
-   specifies the offset to the root node-id and to the changed path
-   information.  Store the root node offset in *ROOT_OFFSET and the
-   changed path offset in *CHANGES_OFFSET.  If either of these
-   pointers is NULL, do nothing with it.
-
-   If PACKED is true, REV_FILE should be a packed shard file.
-   ### There is currently no such parameter.  This function assumes that
-       svn_fs_fs__is_packed_rev(FS, REV) will indicate whether REV_FILE is
-       a packed file.  Therefore FS->fsap_data->min_unpacked_rev must not
-       have been refreshed since REV_FILE was opened if there is a
-       possibility that revision REV may have become packed since then.
-       TODO: Take an IS_PACKED parameter instead, in order to remove this
-       requirement.
-
-   Allocate temporary variables from POOL. */
-static svn_error_t *
-get_root_changes_offset(apr_off_t *root_offset,
-                        apr_off_t *changes_offset,
-                        apr_file_t *rev_file,
-                        svn_fs_t *fs,
-                        svn_revnum_t rev,
-                        apr_pool_t *pool)
-{
-  fs_fs_data_t *ffd = fs->fsap_data;
-  apr_off_t offset;
-  apr_off_t rev_offset;
-  apr_seek_where_t seek_relative;
-  svn_stringbuf_t *trailer = svn_stringbuf_create_ensure(64, pool);
-
-  /* Determine where to seek to in the file.
-
-     If we've got a pack file, we want to seek to the end of the desired
-     revision.  But we don't track that, so we seek to the beginning of the
-     next revision.
-
-     Unless the next revision is in a different file, in which case, we can
-     just seek to the end of the pack file -- just like we do in the
-     non-packed case. */
-  if (svn_fs_fs__is_packed_rev(fs, rev)
-      && ((rev + 1) % ffd->max_files_per_dir != 0))
-    {
-      SVN_ERR(svn_fs_fs__get_packed_offset(&offset, fs, rev + 1, pool));
-      seek_relative = APR_SET;
-    }
-  else
-    {
-      seek_relative = APR_END;
-      offset = 0;
-    }
-
-  /* Offset of the revision from the start of the pack file, if applicable. */
-  if (svn_fs_fs__is_packed_rev(fs, rev))
-    SVN_ERR(svn_fs_fs__get_packed_offset(&rev_offset, fs, rev, pool));
-  else
-    rev_offset = 0;
-
-  /* We will assume that the last line containing the two offsets
-     will never be longer than 64 characters. */
-  SVN_ERR(svn_io_file_seek(rev_file, seek_relative, &offset, pool));
-
-  trailer->len = trailer->blocksize-1;
-  offset -= trailer->len;
-  SVN_ERR(svn_io_file_seek(rev_file, APR_SET, &offset, pool));
-
-  /* Read in this last block, from which we will identify the last line. */
-  SVN_ERR(svn_io_file_read(rev_file, trailer->data, &trailer->len, pool));
-  trailer->data[trailer->len] = 0;
-
-  /* Parse the last line. */
-  SVN_ERR(svn_fs_fs__parse_revision_trailer(root_offset,
-                                            changes_offset,
-                                            trailer,
-                                            rev));
-
-  /* return absolute offsets */
-  if (root_offset)
-    *root_offset += rev_offset;
-  if (changes_offset)
-    *changes_offset += rev_offset;
-
-  return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_fs_fs__rev_get_root(svn_fs_id_t **root_id_p,
-                        svn_fs_t *fs,
-                        svn_revnum_t rev,
-                        apr_pool_t *pool)
-{
-  fs_fs_data_t *ffd = fs->fsap_data;
-  apr_file_t *revision_file;
-  apr_off_t root_offset;
-  svn_fs_id_t *root_id = NULL;
-  svn_boolean_t is_cached;
-
-  SVN_ERR(svn_fs_fs__revision_exists(rev, fs, pool));
-
-  SVN_ERR(svn_cache__get((void **) root_id_p, &is_cached,
-                         ffd->rev_root_id_cache, &rev, pool));
-  if (is_cached)
-    return SVN_NO_ERROR;
-
-  SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&revision_file, fs, rev, pool));
-  SVN_ERR(get_root_changes_offset(&root_offset, NULL, revision_file, fs, rev,
-                                  pool));
-
-  SVN_ERR(get_fs_id_at_offset(&root_id, revision_file, fs, rev,
-                              root_offset, pool));
-
-  SVN_ERR(svn_io_file_close(revision_file, pool));
-
-  SVN_ERR(svn_cache__set(ffd->rev_root_id_cache, &rev, root_id, pool));
-
-  *root_id_p = root_id;
-
-  return SVN_NO_ERROR;
-}
-
-/* Represents where in the current svndiff data block each
-   representation is. */
-typedef struct rep_state_t
-{
-  apr_file_t *file;
-                    /* The txdelta window cache to use or NULL. */
-  svn_cache__t *window_cache;
-                    /* Caches un-deltified windows. May be NULL. */
-  svn_cache__t *combined_cache;
-  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. */
-  apr_off_t end;    /* The end offset of the raw data. */
-  int ver;          /* If a delta, what svndiff version? */
-  int chunk_index;
-} rep_state_t;
-
-/* See create_rep_state, which wraps this and adds another error. */
-static svn_error_t *
-create_rep_state_body(rep_state_t **rep_state,
-                      svn_fs_fs__rep_header_t **rep_header,
-                      apr_file_t **file_hint,
-                      svn_revnum_t *rev_hint,
-                      representation_t *rep,
-                      svn_fs_t *fs,
-                      apr_pool_t *pool)
-{
-  fs_fs_data_t *ffd = fs->fsap_data;
-  rep_state_t *rs = apr_pcalloc(pool, sizeof(*rs));
-  svn_fs_fs__rep_header_t *rh;
-  unsigned char buf[4];
-
-  /* If the hint is
-   * - given,
-   * - refers to a valid revision,
-   * - refers to a packed revision,
-   * - as does the rep we want to read, and
-   * - refers to the same pack file as the rep
-   * ...
-   */
-  if (   file_hint && rev_hint && *file_hint
-      && SVN_IS_VALID_REVNUM(*rev_hint)
-      && *rev_hint < ffd->min_unpacked_rev
-      && rep->revision < ffd->min_unpacked_rev
-      && (   (*rev_hint / ffd->max_files_per_dir)
-          == (rep->revision / ffd->max_files_per_dir)))
-    {
-      /* ... we can re-use the same, already open file object
-       */
-      apr_off_t offset;
-      SVN_ERR(svn_fs_fs__get_packed_offset(&offset, fs, rep->revision, pool));
-
-      offset += rep->offset;
-      SVN_ERR(svn_io_file_seek(*file_hint, APR_SET, &offset, pool));
-
-      rs->file = *file_hint;
-    }
-  else
-    {
-      /* otherwise, create a new file object
-       */
-      SVN_ERR(open_and_seek_representation(&rs->file, fs, rep, pool));
-    }
-
-  /* remember the current file, if suggested by the caller */
-  if (file_hint)
-    *file_hint = rs->file;
-  if (rev_hint)
-    *rev_hint = rep->revision;
-
-  /* continue constructing RS and RA */
-  rs->window_cache = ffd->txdelta_window_cache;
-  rs->combined_cache = ffd->combined_window_cache;
-
-  SVN_ERR(svn_fs_fs__read_rep_header(&rh,
-                           svn_stream_from_aprfile2(rs->file, FALSE, pool),
-                           pool));
-  SVN_ERR(svn_fs_fs__get_file_offset(&rs->start, rs->file, pool));
-  rs->off = rs->start;
-  rs->end = rs->start + rep->size;
-  *rep_state = rs;
-  *rep_header = rh;
-
-  if (rh->type == svn_fs_fs__rep_plain)
-    /* This is a plaintext, so just return the current rep_state. */
-    return SVN_NO_ERROR;
-
-  /* We are dealing with a delta, find out what version. */
-  SVN_ERR(svn_io_file_read_full2(rs->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->off += 4;
-
-  return SVN_NO_ERROR;
-}
-
-/* Read the rep args for REP in filesystem FS and create a rep_state
-   for reading the representation.  Return the rep_state_t in *REP_STATE
-   and the rep header in *REP_HEADER, both allocated in POOL.
-
-   When reading multiple reps, i.e. a skip delta chain, you may provide
-   non-NULL FILE_HINT and REV_HINT.  (If FILE_HINT is not NULL, in the first
-   call it should be a pointer to NULL.)  The function will use these variables
-   to store the previous call results and tries to re-use them.  This may
-   result in significant savings in I/O for packed files.
- */
-static svn_error_t *
-create_rep_state(rep_state_t **rep_state,
-                 svn_fs_fs__rep_header_t **rep_header,
-                 apr_file_t **file_hint,
-                 svn_revnum_t *rev_hint,
-                 representation_t *rep,
-                 svn_fs_t *fs,
-                 apr_pool_t *pool)
-{
-  svn_error_t *err = create_rep_state_body(rep_state, rep_header,
-                                           file_hint, rev_hint,
-                                           rep, fs, pool);
-  if (err && err->apr_err == SVN_ERR_FS_CORRUPT)
-    {
-      fs_fs_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
-         ### or dir contents).  It is pretty rare for FSFS to *read*
-         ### from the protorev file, though, so this is probably OK.
-         ### And anyone going to debug corruption errors is probably
-         ### going to jump straight to this comment anyway! */
-      return svn_error_createf(SVN_ERR_FS_CORRUPT, err,
-                               "Corrupt representation '%s'",
-                               rep
-                               ? svn_fs_fs__unparse_representation
-                                   (rep, ffd->format, TRUE, TRUE, pool)->data
-                               : "(null)");
-    }
-  /* ### Call representation_string() ? */
-  return svn_error_trace(err);
-}
-
-/* Check that the presentation REP actually exists in FS.  Use POOL for
-   allocations.
-
-   When reading multiple reps, i.e. a skip delta chain, you may provide
-   non-NULL FILE_HINT and REV_HINT.  (If FILE_HINT is not NULL, in the
-   first call it should be a pointer to NULL.)  The function will use these
-   variables to store the previous call results and tries to re-use them.
-   This may result in significant I/O reduction for packed files.
- */
-static svn_error_t *
-check_rep(representation_t *rep,
-          svn_fs_t *fs,
-          apr_file_t **file_hint,
-          svn_revnum_t *rev_hint,
-          apr_pool_t *pool)
-{
-  rep_state_t *rs;
-  svn_fs_fs__rep_header_t *rep_header;
-
-  /* ### Should this be using read_rep_line() directly? */
-  SVN_ERR(create_rep_state(&rs, &rep_header, file_hint, rev_hint, rep,
-                           fs, pool));
-
-  return SVN_NO_ERROR;
-}
-
-/* In FS, determine the number of base representations in REP's delta
-   chain and return the value in *CHAIN_LENGTH.  Use POOL for allocations.
- */
-static svn_error_t *
-rep_chain_length(int *chain_length,
-                 representation_t *rep,
-                 svn_fs_t *fs,
-                 apr_pool_t *pool)
-{
-  int count = 0;
-  apr_pool_t *sub_pool = svn_pool_create(pool);
-  svn_boolean_t is_delta = FALSE;
-  
-  /* Check whether the length of the deltification chain is acceptable.
-   * Otherwise, shared reps may form a non-skipping delta chain in
-   * extreme cases. */
-  representation_t base_rep = *rep;
-
-  /* re-use open files between iterations */
-  apr_file_t *file_hint = NULL;
-  svn_revnum_t rev_hint = SVN_INVALID_REVNUM;
-
-  svn_fs_fs__rep_header_t *header;
-
-  /* follow the delta chain towards the end but for at most
-   * MAX_CHAIN_LENGTH steps. */
-  do
-    {
-      rep_state_t *rep_state;
-      SVN_ERR(create_rep_state_body(&rep_state,
-                                    &header,
-                                    &file_hint,
-                                    &rev_hint,
-                                    &base_rep,
-                                    fs,
-                                    sub_pool));
-
-      base_rep.revision = header->base_revision;
-      base_rep.offset = header->base_offset;
-      base_rep.size = header->base_length;
-      base_rep.txn_id = NULL;
-      is_delta = header->type == svn_fs_fs__rep_delta;
-
-      ++count;
-      if (count % 16 == 0)
-        {
-          file_hint = NULL;
-          svn_pool_clear(sub_pool);
-        }
-    }
-  while (is_delta && base_rep.revision);
-
-  *chain_length = count;
-  svn_pool_destroy(sub_pool);
-
-  return SVN_NO_ERROR;
-}
-
-struct rep_read_baton
-{
-  /* The FS from which we're reading. */
-  svn_fs_t *fs;
-
-  /* If not NULL, this is the base for the first delta window in rs_list */
-  svn_stringbuf_t *base_window;
-
-  /* The state of all prior delta representations. */
-  apr_array_header_t *rs_list;
-
-  /* The plaintext state, if there is a plaintext. */
-  rep_state_t *src_state;
-
-  /* The index of the current delta chunk, if we are reading a delta. */
-  int chunk_index;
-
-  /* The buffer where we store undeltified data. */
-  char *buf;
-  apr_size_t buf_pos;
-  apr_size_t buf_len;
-
-  /* A checksum context for summing the data read in order to verify it.
-     Note: we don't need to use the sha1 checksum because we're only doing
-     data verification, for which md5 is perfectly safe.  */
-  svn_checksum_ctx_t *md5_checksum_ctx;
-
-  svn_boolean_t checksum_finalized;
-
-  /* The stored checksum of the representation we are reading, its
-     length, and the amount we've read so far.  Some of this
-     information is redundant with rs_list and src_state, but it's
-     convenient for the checksumming code to have it here. */
-  svn_checksum_t *md5_checksum;
-
-  svn_filesize_t len;
-  svn_filesize_t off;
-
-  /* The key for the fulltext cache for this rep, if there is a
-     fulltext cache. */
-  pair_cache_key_t fulltext_cache_key;
-  /* The text we've been reading, if we're going to cache it. */
-  svn_stringbuf_t *current_fulltext;
-
-  /* Used for temporary allocations during the read. */
-  apr_pool_t *pool;
-
-  /* Pool used to store file handles and other data that is persistant
-     for the entire stream read. */
-  apr_pool_t *filehandle_pool;
-};
-
-/* Combine the name of the rev file in RS with the given OFFSET to form
- * a cache lookup key.  Allocations will be made from POOL.  May return
- * NULL if the key cannot be constructed. */
-static const char*
-get_window_key(rep_state_t *rs, apr_off_t offset, apr_pool_t *pool)
-{
-  const char *name;
-  const char *last_part;
-  const char *name_last;
-
-  /* the rev file name containing the txdelta window.
-   * If this fails we are in serious trouble anyways.
-   * And if nobody else detects the problems, the file content checksum
-   * comparison _will_ find them.
-   */
-  if (apr_file_name_get(&name, rs->file))
-    return NULL;
-
-  /* Handle packed files as well by scanning backwards until we find the
-   * revision or pack number. */
-  name_last = name + strlen(name) - 1;
-  while (! svn_ctype_isdigit(*name_last))
-    --name_last;
-
-  last_part = name_last;
-  while (svn_ctype_isdigit(*last_part))
-    --last_part;
-
-  /* We must differentiate between packed files (as of today, the number
-   * is being followed by a dot) and non-packed files (followed by \0).
-   * Otherwise, there might be overlaps in the numbering range if the
-   * repo gets packed after caching the txdeltas of non-packed revs.
-   * => add the first non-digit char to the packed number. */
-  if (name_last[1] != '\0')
-    ++name_last;
-
-  /* copy one char MORE than the actual number to mark packed files,
-   * i.e. packed revision file content uses different key space then
-   * non-packed ones: keys for packed rev file content ends with a dot
-   * for non-packed rev files they end with a digit. */
-  name = apr_pstrndup(pool, last_part + 1, name_last - last_part);
-  return svn_fs_fs__combine_number_and_string(offset, name, pool);
-}
-
-/* Read the WINDOW_P for the 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 particualar) will be made from POOL.
- *
- * If the information could be found, put RS and the position within the
- * rev file into the same state as if the data had just been read from it.
- */
-static svn_error_t *
-get_cached_window(svn_txdelta_window_t **window_p,
-                  rep_state_t *rs,
-                  svn_boolean_t *is_cached,
-                  apr_pool_t *pool)
-{
-  if (! rs->window_cache)
-    {
-      /* txdelta window has not been enabled */
-      *is_cached = FALSE;
-    }
-  else
-    {
-      /* ask the cache for the desired txdelta window */
-      svn_fs_fs__txdelta_cached_window_t *cached_window;
-      SVN_ERR(svn_cache__get((void **) &cached_window,
-                             is_cached,
-                             rs->window_cache,
-                             get_window_key(rs, rs->off, pool),
-                             pool));
-
-      if (*is_cached)
-        {
-          /* found it. Pass it back to the caller. */
-          *window_p = cached_window->window;
-
-          /* manipulate the RS as if we just read the data */
-          rs->chunk_index++;
-          rs->off = cached_window->end_offset;
-
-          /* manipulate the rev file as if we just read from it */
-          SVN_ERR(svn_io_file_seek(rs->file, APR_SET, &rs->off, pool));
-        }
-    }
-
-  return SVN_NO_ERROR;
-}
-
-/* Store the WINDOW read at OFFSET for the rep state RS in the current
- * FSFS session's cache. This will be a no-op if no cache has been given.
- * Temporary allocations will be made from SCRATCH_POOL. */
-static svn_error_t *
-set_cached_window(svn_txdelta_window_t *window,
-                  rep_state_t *rs,
-                  apr_off_t offset,
-                  apr_pool_t *scratch_pool)
-{
-  if (rs->window_cache)
-    {
-      /* store the window and the first offset _past_ it */
-      svn_fs_fs__txdelta_cached_window_t cached_window;
-
-      cached_window.window = window;
-      cached_window.end_offset = rs->off;
-
-      /* but key it with the start offset because that is the known state
-       * when we will look it up */
-      return svn_cache__set(rs->window_cache,
-                            get_window_key(rs, offset, scratch_pool),
-                            &cached_window,
-                            scratch_pool);
-    }
-
-  return SVN_NO_ERROR;
-}
-
-/* Read the WINDOW_P for the 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 particualar) will be made from POOL.
- */
-static svn_error_t *
-get_cached_combined_window(svn_stringbuf_t **window_p,
-                           rep_state_t *rs,
-                           svn_boolean_t *is_cached,
-                           apr_pool_t *pool)
-{
-  if (! rs->combined_cache)
-    {
-      /* txdelta window has not been enabled */
-      *is_cached = FALSE;
-    }
-  else
-    {
-      /* ask the cache for the desired txdelta window */
-      return svn_cache__get((void **)window_p,
-                            is_cached,
-                            rs->combined_cache,
-                            get_window_key(rs, rs->start, pool),
-                            pool);
-    }
-
-  return SVN_NO_ERROR;
-}
-
-/* Store the WINDOW read at OFFSET for the rep state RS in the current
- * FSFS session's cache. This will be a no-op if no cache has been given.
- * Temporary allocations will be made from SCRATCH_POOL. */
-static svn_error_t *
-set_cached_combined_window(svn_stringbuf_t *window,
-                           rep_state_t *rs,
-                           apr_off_t offset,
-                           apr_pool_t *scratch_pool)
-{
-  if (rs->combined_cache)
-    {
-      /* but key it with the start offset because that is the known state
-       * when we will look it up */
-      return svn_cache__set(rs->combined_cache,
-                            get_window_key(rs, offset, scratch_pool),
-                            window,
-                            scratch_pool);
-    }
-
-  return SVN_NO_ERROR;
-}
-
-/* Build an array of rep_state_t structures in *LIST giving the delta
-   reps from first_rep to a plain-text or self-compressed rep.  Set
-   *SRC_STATE to the plain-text rep we find at the end of the chain,
-   or to NULL if the final delta representation is self-compressed.
-   The representation to start from is designated by filesystem FS, id
-   ID, and representation REP.
-   Also, set *WINDOW_P to the base window content for *LIST, if it
-   could be found in cache. Otherwise, *LIST will contain the base
-   representation for the whole delta chain.
-   Finally, return the expanded size of the representation in
-   *EXPANDED_SIZE. It will take care of cases where only the on-disk
-   size is known.  */
-static svn_error_t *
-build_rep_list(apr_array_header_t **list,
-               svn_stringbuf_t **window_p,
-               rep_state_t **src_state,
-               svn_filesize_t *expanded_size,
-               svn_fs_t *fs,
-               representation_t *first_rep,
-               apr_pool_t *pool)
-{
-  representation_t rep;
-  rep_state_t *rs = NULL;
-  svn_fs_fs__rep_header_t *rep_header;
-  svn_boolean_t is_cached = FALSE;
-  apr_file_t *last_file = NULL;
-  svn_revnum_t last_revision;
-
-  *list = apr_array_make(pool, 1, sizeof(rep_state_t *));
-  rep = *first_rep;
-
-  /* The value as stored in the data struct.
-     0 is either for unknown length or actually zero length. */
-  *expanded_size = first_rep->expanded_size;
-
-  /* for the top-level rep, we need the rep_args */
-  SVN_ERR(create_rep_state(&rs, &rep_header, &last_file,
-                           &last_revision, &rep, fs, pool));
-
-  /* Unknown size or empty representation?
-     That implies the this being the first iteration.
-     Usually size equals on-disk size, except for empty,
-     compressed representations (delta, size = 4).
-     Please note that for all non-empty deltas have
-     a 4-byte header _plus_ some data. */
-  if (*expanded_size == 0)
-    if (rep_header->type == svn_fs_fs__rep_plain || first_rep->size != 4)
-      *expanded_size = first_rep->size;
-
-  while (1)
-    {
-      /* fetch state, if that has not been done already */
-      if (!rs)
-        SVN_ERR(create_rep_state(&rs, &rep_header, &last_file,
-                                 &last_revision, &rep, fs, pool));
-
-      SVN_ERR(get_cached_combined_window(window_p, rs, &is_cached, pool));
-      if (is_cached)
-        {
-          /* We already have a reconstructed window in our cache.
-             Write a pseudo rep_state_t with the full length. */
-          rs->off = rs->start;
-          rs->end = rs->start + (*window_p)->len;
-          *src_state = rs;
-          return SVN_NO_ERROR;
-        }
-
-      if (rep_header->type == svn_fs_fs__rep_plain)
-        {
-          /* This is a plaintext, so just return the current rep_state. */
-          *src_state = rs;
-          return SVN_NO_ERROR;
-        }
-
-      /* Push this rep onto the list.  If it's self-compressed, we're done. */
-      APR_ARRAY_PUSH(*list, rep_state_t *) = rs;
-      if (rep_header->type == svn_fs_fs__rep_self_delta)
-        {
-          *src_state = NULL;
-          return SVN_NO_ERROR;
-        }
-
-      rep.revision = rep_header->base_revision;
-      rep.offset = rep_header->base_offset;
-      rep.size = rep_header->base_length;
-      rep.txn_id = NULL;
-
-      rs = NULL;
-    }
-}
-
-
-/* Create a rep_read_baton structure for node revision NODEREV in
-   filesystem FS and store it in *RB_P.  If FULLTEXT_CACHE_KEY is not
-   NULL, it is the rep's key in the fulltext cache, and a stringbuf
-   must be allocated to store the text.  Perform all allocations in
-   POOL.  If rep is mutable, it must be for file contents. */
-static svn_error_t *
-rep_read_get_baton(struct rep_read_baton **rb_p,
-                   svn_fs_t *fs,
-                   representation_t *rep,
-                   pair_cache_key_t fulltext_cache_key,
-                   apr_pool_t *pool)
-{
-  struct rep_read_baton *b;
-
-  b = apr_pcalloc(pool, sizeof(*b));
-  b->fs = fs;
-  b->base_window = NULL;
-  b->chunk_index = 0;
-  b->buf = NULL;
-  b->md5_checksum_ctx = svn_checksum_ctx_create(svn_checksum_md5, pool);
-  b->checksum_finalized = FALSE;
-  b->md5_checksum = svn_checksum_dup(rep->md5_checksum, pool);
-  b->len = rep->expanded_size;
-  b->off = 0;
-  b->fulltext_cache_key = fulltext_cache_key;
-  b->pool = svn_pool_create(pool);
-  b->filehandle_pool = svn_pool_create(pool);
-
-  SVN_ERR(build_rep_list(&b->rs_list, &b->base_window,
-                         &b->src_state, &b->len, fs, rep,
-                         b->filehandle_pool));
-
-  if (SVN_IS_VALID_REVNUM(fulltext_cache_key.revision))
-    b->current_fulltext = svn_stringbuf_create_ensure
-                            ((apr_size_t)b->len,
-                             b->filehandle_pool);
-  else
-    b->current_fulltext = NULL;
-
-  /* Save our output baton. */
-  *rb_p = b;
-
-  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)
-{
-  svn_stream_t *stream;
-  svn_boolean_t is_cached;
-  apr_off_t old_offset;
-
-  SVN_ERR_ASSERT(rs->chunk_index <= this_chunk);
-
-  /* RS->FILE may be shared between RS instances -> make sure we point
-   * to the right data. */
-  SVN_ERR(svn_io_file_seek(rs->file, APR_SET, &rs->off, pool));
-
-  /* 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));
-      rs->chunk_index++;
-      SVN_ERR(svn_fs_fs__get_file_offset(&rs->off, rs->file, pool));
-      if (rs->off >= rs->end)
-        return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
-                                _("Reading one svndiff window read "
-                                  "beyond the end of the "
-                                  "representation"));
-    }
-
-  /* Read the next window. But first, try to find it in the cache. */
-  SVN_ERR(get_cached_window(nwin, rs, &is_cached, pool));
-  if (is_cached)
-    return SVN_NO_ERROR;
-
-  /* Actually read the next window. */
-  old_offset = rs->off;
-  stream = svn_stream_from_aprfile2(rs->file, TRUE, pool);
-  SVN_ERR(svn_txdelta_read_svndiff_window(nwin, stream, rs->ver, pool));
-  rs->chunk_index++;
-  SVN_ERR(svn_fs_fs__get_file_offset(&rs->off, rs->file, pool));
-
-  if (rs->off > rs->end)
-    return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
-                            _("Reading one svndiff window read beyond "
-                              "the end of the representation"));
-
-  /* the window has not been cached before, thus cache it now
-   * (if caching is used for them at all) */
-  return set_cached_window(*nwin, rs, old_offset, pool);
-}
-
-/* Read SIZE bytes from the representation RS and return it in *NWIN. */
-static svn_error_t *
-read_plain_window(svn_stringbuf_t **nwin, rep_state_t *rs,
-                  apr_size_t size, apr_pool_t *pool)
-{
-  /* RS->FILE may be shared between RS instances -> make sure we point
-   * to the right data. */
-  SVN_ERR(svn_io_file_seek(rs->file, APR_SET, &rs->off, pool));
-
-  /* Read the plain data. */
-  *nwin = svn_stringbuf_create_ensure(size, pool);
-  SVN_ERR(svn_io_file_read_full2(rs->file, (*nwin)->data, size, NULL, NULL,
-                                 pool));
-  (*nwin)->data[size] = 0;
-
-  /* Update RS. */
-  rs->off += (apr_off_t)size;
-
-  return SVN_NO_ERROR;
-}
-
-/* Get the undeltified window that is a result of combining all deltas
-   from the current desired representation identified in *RB with its
-   base representation.  Store the window in *RESULT. */
-static svn_error_t *
-get_combined_window(svn_stringbuf_t **result,
-                    struct rep_read_baton *rb)
-{
-  apr_pool_t *pool, *new_pool, *window_pool;
-  int i;
-  apr_array_header_t *windows;
-  svn_stringbuf_t *source, *buf = rb->base_window;
-  rep_state_t *rs;
-
-  /* Read all windows that we need to combine. This is fine because
-     the size of each window is relatively small (100kB) and skip-
-     delta limits the number of deltas in a chain to well under 100.
-     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 *));
-  for (i = 0; i < rb->rs_list->nelts; ++i)
-    {
-      svn_txdelta_window_t *window;
-
-      rs = APR_ARRAY_IDX(rb->rs_list, i, rep_state_t *);
-      SVN_ERR(read_delta_window(&window, rb->chunk_index, rs, window_pool));
-
-      APR_ARRAY_PUSH(windows, svn_txdelta_window_t *) = window;
-      if (window->src_ops == 0)
-        {
-          ++i;
-          break;
-        }
-    }
-
-  /* Combine in the windows from the other delta reps. */
-  pool = svn_pool_create(rb->pool);
-  for (--i; i >= 0; --i)
-    {
-      svn_txdelta_window_t *window;
-
-      rs = APR_ARRAY_IDX(rb->rs_list, i, rep_state_t *);
-      window = APR_ARRAY_IDX(windows, i, svn_txdelta_window_t *);
-
-      /* Maybe, we've got a PLAIN start representation.  If we do, read
-         as much data from it as the needed for the txdelta window's source
-         view.
-         Note that BUF / SOURCE may only be NULL in the first iteration. */
-      source = buf;
-      if (source == NULL && rb->src_state != NULL)
-        SVN_ERR(read_plain_window(&source, rb->src_state, window->sview_len,
-                                  pool));
-
-      /* Combine this window with the current one. */
-      new_pool = svn_pool_create(rb->pool);
-      buf = svn_stringbuf_create_ensure(window->tview_len, new_pool);
-      buf->len = window->tview_len;
-
-      svn_txdelta_apply_instructions(window, source ? source->data : NULL,
-                                     buf->data, &buf->len);
-      if (buf->len != window->tview_len)
-        return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
-                                _("svndiff window length is "
-                                  "corrupt"));
-
-      /* Cache windows only if the whole rep content could be read as a
-         single chunk.  Only then will no other chunk need a deeper RS
-         list than the cached chunk. */
-      if ((rb->chunk_index == 0) && (rs->off == rs->end))
-        SVN_ERR(set_cached_combined_window(buf, rs, rs->start, new_pool));
-
-      /* Cycle pools so that we only need to hold three windows at a time. */
-      svn_pool_destroy(pool);
-      pool = new_pool;
-    }
-
-  svn_pool_destroy(window_pool);
-
-  *result = buf;
-  return SVN_NO_ERROR;
-}
-
-/* Returns whether or not the expanded fulltext of the file is cachable
- * based on its size SIZE.  The decision depends on the cache used by RB.
- */
-static svn_boolean_t
-fulltext_size_is_cachable(fs_fs_data_t *ffd, svn_filesize_t size)
-{
-  return (size < APR_SIZE_MAX)
-      && svn_cache__is_cachable(ffd->fulltext_cache, (apr_size_t)size);
-}
-
-/* Close method used on streams returned by read_representation().
- */
-static svn_error_t *
-rep_read_contents_close(void *baton)
-{
-  struct rep_read_baton *rb = baton;
-
-  svn_pool_destroy(rb->pool);
-  svn_pool_destroy(rb->filehandle_pool);
-
-  return SVN_NO_ERROR;
-}
-
-/* Return the next *LEN bytes of the rep and store them in *BUF. */
-static svn_error_t *
-get_contents(struct rep_read_baton *rb,
-             char *buf,
-             apr_size_t *len)
-{
-  apr_size_t copy_len, remaining = *len;
-  char *cur = buf;
-  rep_state_t *rs;
-
-  /* Special case for when there are no delta reps, only a plain
-     text. */
-  if (rb->rs_list->nelts == 0)
-    {
-      copy_len = remaining;
-      rs = rb->src_state;
-
-      if (rb->base_window != NULL)
-        {
-          /* We got the desired rep directly from the cache.
-             This is where we need the pseudo rep_state_t created
-             by build_rep_list(). */
-          apr_size_t offset = (apr_size_t)(rs->off - rs->start);
-          if (copy_len + offset > rb->base_window->len)
-            copy_len = offset < rb->base_window->len
-                     ? rb->base_window->len - offset
-                     : 0ul;
-
-          memcpy (cur, rb->base_window->data + offset, copy_len);
-        }
-      else
-        {
-          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_full2(rs->file, cur, copy_len, NULL,
-                                         NULL, rb->pool));
-        }
-
-      rs->off += copy_len;
-      *len = copy_len;
-      return SVN_NO_ERROR;
-    }
-
-  while (remaining > 0)
-    {
-      /* If we have buffered data from a previous chunk, use that. */
-      if (rb->buf)
-        {
-          /* Determine how much to copy from the buffer. */
-          copy_len = rb->buf_len - rb->buf_pos;
-          if (copy_len > remaining)
-            copy_len = remaining;
-
-          /* Actually copy the data. */
-          memcpy(cur, rb->buf + rb->buf_pos, copy_len);
-          rb->buf_pos += copy_len;
-          cur += copy_len;
-          remaining -= copy_len;
-
-          /* If the buffer is all used up, clear it and empty the
-             local pool. */
-          if (rb->buf_pos == rb->buf_len)
-            {
-              svn_pool_clear(rb->pool);
-              rb->buf = NULL;
-            }
-        }
-      else
-        {
-          svn_stringbuf_t *sbuf = NULL;
-
-          rs = APR_ARRAY_IDX(rb->rs_list, 0, rep_state_t *);
-          if (rs->off == rs->end)
-            break;
-
-          /* Get more buffered data by evaluating a chunk. */
-          SVN_ERR(get_combined_window(&sbuf, rb));
-
-          rb->chunk_index++;
-          rb->buf_len = sbuf->len;
-          rb->buf = sbuf->data;
-          rb->buf_pos = 0;
-        }
-    }
-
-  *len = cur - buf;
-
-  return SVN_NO_ERROR;
-}
-
-/* BATON is of type `rep_read_baton'; read the next *LEN bytes of the
-   representation and store them in *BUF.  Sum as we read and verify
-   the MD5 sum at the end. */
-static svn_error_t *
-rep_read_contents(void *baton,
-                  char *buf,
-                  apr_size_t *len)
-{
-  struct rep_read_baton *rb = baton;
-
-  /* Get the next block of data. */
-  SVN_ERR(get_contents(rb, buf, len));
-
-  if (rb->current_fulltext)
-    svn_stringbuf_appendbytes(rb->current_fulltext, buf, *len);
-
-  /* Perform checksumming.  We want to check the checksum as soon as
-     the last byte of data is read, in case the caller never performs
-     a short read, but we don't want to finalize the MD5 context
-     twice. */
-  if (!rb->checksum_finalized)
-    {
-      SVN_ERR(svn_checksum_update(rb->md5_checksum_ctx, buf, *len));
-      rb->off += *len;
-      if (rb->off == rb->len)
-        {
-          svn_checksum_t *md5_checksum;
-
-          rb->checksum_finalized = TRUE;
-          SVN_ERR(svn_checksum_final(&md5_checksum, rb->md5_checksum_ctx,
-                                     rb->pool));
-          if (!svn_checksum_match(md5_checksum, rb->md5_checksum))
-            return svn_error_create(SVN_ERR_FS_CORRUPT,
-                    svn_checksum_mismatch_err(rb->md5_checksum, md5_checksum,
-                        rb->pool,
-                        _("Checksum mismatch while reading representation")),
-                    NULL);
-        }
-    }
-
-  if (rb->off == rb->len && rb->current_fulltext)
-    {
-      fs_fs_data_t *ffd = rb->fs->fsap_data;
-      SVN_ERR(svn_cache__set(ffd->fulltext_cache, &rb->fulltext_cache_key,
-                             rb->current_fulltext, rb->pool));
-      rb->current_fulltext = NULL;
-    }
-
-  return SVN_NO_ERROR;
-}
-
-
-/* Return a stream in *CONTENTS_P that will read the contents of a
-   representation stored at the location given by REP.  Appropriate
-   for any kind of immutable representation, but only for file
-   contents (not props or directory contents) in mutable
-   representations.
-
-   If REP is NULL, the representation is assumed to be empty, and the
-   empty stream is returned.
-*/
-static svn_error_t *
-read_representation(svn_stream_t **contents_p,
-                    svn_fs_t *fs,
-                    representation_t *rep,
-                    apr_pool_t *pool)
-{
-  if (! rep)
-    {
-      *contents_p = svn_stream_empty(pool);
-    }
-  else
-    {
-      fs_fs_data_t *ffd = fs->fsap_data;
-      pair_cache_key_t fulltext_cache_key = { 0 };
-      svn_filesize_t len = rep->expanded_size ? rep->expanded_size : rep->size;
-      struct rep_read_baton *rb;
-
-      fulltext_cache_key.revision = rep->revision;
-      fulltext_cache_key.second = rep->offset;
-      if (ffd->fulltext_cache && SVN_IS_VALID_REVNUM(rep->revision)
-          && fulltext_size_is_cachable(ffd, len))
-        {
-          svn_stringbuf_t *fulltext;
-          svn_boolean_t is_cached;
-          SVN_ERR(svn_cache__get((void **) &fulltext, &is_cached,
-                                 ffd->fulltext_cache, &fulltext_cache_key,
-                                 pool));
-          if (is_cached)
-            {
-              *contents_p = svn_stream_from_stringbuf(fulltext, pool);
-              return SVN_NO_ERROR;
-            }
-        }
-      else
-        fulltext_cache_key.revision = SVN_INVALID_REVNUM;
-
-      SVN_ERR(rep_read_get_baton(&rb, fs, rep, fulltext_cache_key, pool));
-
-      *contents_p = svn_stream_create(rb, pool);
-      svn_stream_set_read(*contents_p, rep_read_contents);
-      svn_stream_set_close(*contents_p, rep_read_contents_close);
-    }
-
-  return SVN_NO_ERROR;
-}
-
 svn_error_t *
-svn_fs_fs__get_contents(svn_stream_t **contents_p,
-                        svn_fs_t *fs,
-                        node_revision_t *noderev,
-                        apr_pool_t *pool)
-{
-  return read_representation(contents_p, fs, noderev->data_rep, pool);
-}
-
-/* Baton used when reading delta windows. */
-struct delta_read_baton
-{
-  rep_state_t *rs;
-  svn_checksum_t *checksum;
-};
-
-/* This implements the svn_txdelta_next_window_fn_t interface. */
-static svn_error_t *
-delta_read_next_window(svn_txdelta_window_t **window, void *baton,
-                       apr_pool_t *pool)
+svn_fs_fs__put_node_revision(svn_fs_t *fs,
+                             const svn_fs_id_t *id,
+                             node_revision_t *noderev,
+                             svn_boolean_t fresh_txn_root,
+                             apr_pool_t *pool)
 {
-  struct delta_read_baton *drb = baton;
-
-  if (drb->rs->off == drb->rs->end)
-    {
-      *window = NULL;
-      return SVN_NO_ERROR;
-    }
-
-  return read_delta_window(window, drb->rs->chunk_index, drb->rs, pool);
-}
+  fs_fs_data_t *ffd = fs->fsap_data;
+  apr_file_t *noderev_file;
+  const char *txn_id = svn_fs_fs__id_txn_id(id);
 
-/* This implements the svn_txdelta_md5_digest_fn_t interface. */
-static const unsigned char *
-delta_read_md5_digest(void *baton)
-{
-  struct delta_read_baton *drb = baton;
+  noderev->is_fresh_txn_root = fresh_txn_root;
 
-  if (drb->checksum->kind == svn_checksum_md5)
-    return drb->checksum->digest;
-  else
-    return NULL;
-}
+  if (! txn_id)
+    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                             _("Attempted to write to non-transaction '%s'"),
+                             svn_fs_fs__id_unparse(id, pool)->data);
 
-svn_error_t *
-svn_fs_fs__get_file_delta_stream(svn_txdelta_stream_t **stream_p,
-                                 svn_fs_t *fs,
-                                 node_revision_t *source,
-                                 node_revision_t *target,
-                                 apr_pool_t *pool)
-{
-  svn_stream_t *source_stream, *target_stream;
-
-  /* Try a shortcut: if the target is stored as a delta against the source,
-     then just use that delta. */
-  if (source && source->data_rep && target->data_rep)
-    {
-      rep_state_t *rep_state;
-      svn_fs_fs__rep_header_t *rep_header;
-
-      /* Read target's base rep if any. */
-      SVN_ERR(create_rep_state(&rep_state, &rep_header, NULL, NULL,
-                               target->data_rep, fs, pool));
-      /* If that matches source, then use this delta as is. */
-      if (rep_header->type == svn_fs_fs__rep_self_delta
-          || (rep_header->type == svn_fs_fs__rep_delta
-              && rep_header->base_revision == source->data_rep->revision
-              && rep_header->base_offset == source->data_rep->offset))
-        {
-          /* Create the delta read baton. */
-          struct delta_read_baton *drb = apr_pcalloc(pool, sizeof(*drb));
-          drb->rs = rep_state;
-          drb->checksum = svn_checksum_dup(target->data_rep->md5_checksum,
-                                           pool);
-          *stream_p = svn_txdelta_stream_create(drb, delta_read_next_window,
-                                                delta_read_md5_digest, pool);
-          return SVN_NO_ERROR;
-        }
-      else
-        SVN_ERR(svn_io_file_close(rep_state->file, pool));
-    }
+  SVN_ERR(svn_io_file_open(&noderev_file,
+                           svn_fs_fs__path_txn_node_rev(fs, id, pool),
+                           APR_WRITE | APR_CREATE | APR_TRUNCATE
+                           | APR_BUFFERED, APR_OS_DEFAULT, pool));
 
-  /* Read both fulltexts and construct a delta. */
-  if (source)
-    SVN_ERR(read_representation(&source_stream, fs, source->data_rep, pool));
-  else
-    source_stream = svn_stream_empty(pool);
-  SVN_ERR(read_representation(&target_stream, fs, target->data_rep, pool));
+  SVN_ERR(svn_fs_fs__write_noderev(svn_stream_from_aprfile2(noderev_file, TRUE,
+                                                            pool),
+                                   noderev, ffd->format,
+                                   svn_fs_fs__fs_supports_mergeinfo(fs),
+                                   pool));
 
-  /* Because source and target stream will already verify their content,
-   * there is no need to do this once more.  In particular if the stream
-   * content is being fetched from cache. */
-  svn_txdelta2(stream_p, source_stream, target_stream, FALSE, pool);
+  SVN_ERR(svn_io_file_close(noderev_file, pool));
 
   return SVN_NO_ERROR;
 }
 
-/* Baton for cache_access_wrapper. Wraps the original parameters of
- * svn_fs_fs__try_process_file_content().
- */
-typedef struct cache_access_wrapper_baton_t
-{
-  svn_fs_process_contents_func_t func;
-  void* baton;
-} cache_access_wrapper_baton_t;
-
-/* Wrapper to translate between svn_fs_process_contents_func_t and
- * svn_cache__partial_getter_func_t.
+/* For the in-transaction NODEREV within FS, write the sha1->rep mapping
+ * file in the respective transaction, if rep sharing has been enabled etc.
+ * Use POOL for temporary allocations.
  */
 static svn_error_t *
-cache_access_wrapper(void **out,
-                     const void *data,
-                     apr_size_t data_len,
-                     void *baton,
-                     apr_pool_t *pool)
-{
-  cache_access_wrapper_baton_t *wrapper_baton = baton;
-
-  SVN_ERR(wrapper_baton->func((const unsigned char *)data,
-                              data_len - 1, /* cache adds terminating 0 */
-                              wrapper_baton->baton,
-                              pool));
-
-  /* non-NULL value to signal the calling cache that all went well */
-  *out = baton;
-
-  return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_fs_fs__try_process_file_contents(svn_boolean_t *success,
-                                     svn_fs_t *fs,
-                                     node_revision_t *noderev,
-                                     svn_fs_process_contents_func_t processor,
-                                     void* baton,
-                                     apr_pool_t *pool)
-{
-  representation_t *rep = noderev->data_rep;
-  if (rep)
-    {
-      fs_fs_data_t *ffd = fs->fsap_data;
-      pair_cache_key_t fulltext_cache_key = { 0 };
-
-      fulltext_cache_key.revision = rep->revision;
-      fulltext_cache_key.second = rep->offset;
-      if (ffd->fulltext_cache && SVN_IS_VALID_REVNUM(rep->revision)
-          && fulltext_size_is_cachable(ffd, rep->expanded_size))
-        {
-          cache_access_wrapper_baton_t wrapper_baton;
-          void *dummy = NULL;
-
-          wrapper_baton.func = processor;
-          wrapper_baton.baton = baton;
-          return svn_cache__get_partial(&dummy, success,
-                                        ffd->fulltext_cache,
-                                        &fulltext_cache_key,
-                                        cache_access_wrapper,
-                                        &wrapper_baton,
-                                        pool);
-        }
-    }
-
-  *success = FALSE;
-  return SVN_NO_ERROR;
-}
-
-/* Fetch the contents of a directory into ENTRIES.  Values are stored
-   as filename to string mappings; further conversion is necessary to
-   convert them into svn_fs_dirent_t values. */
-static svn_error_t *
-get_dir_contents(apr_hash_t *entries,
-                 svn_fs_t *fs,
-                 node_revision_t *noderev,
-                 apr_pool_t *pool)
+store_sha1_rep_mapping(svn_fs_t *fs,
+                       node_revision_t *noderev,
+                       apr_pool_t *pool)
 {
-  svn_stream_t *contents;
+  fs_fs_data_t *ffd = fs->fsap_data;
 
-  if (noderev->data_rep && noderev->data_rep->txn_id)
+  /* if rep sharing has been enabled and the noderev has a data rep and
+   * its SHA-1 is known, store the rep struct under its SHA1. */
+  if (   ffd->rep_sharing_allowed
+      && noderev->data_rep
+      && noderev->data_rep->sha1_checksum)
     {
-      const char *filename
-        = svn_fs_fs__path_txn_node_children(fs, noderev->id, pool);
+      apr_file_t *rep_file;
+      const char *file_name = path_txn_sha1(fs,
+                                            svn_fs_fs__id_txn_id(noderev->id),
+                                            noderev->data_rep->sha1_checksum,
+                                            pool);
+      svn_stringbuf_t *rep_string
+        = svn_fs_fs__unparse_representation(noderev->data_rep,
+                                            ffd->format,
+                                            (noderev->kind == svn_node_dir),
+                                            FALSE,
+                                            pool);
+      SVN_ERR(svn_io_file_open(&rep_file, file_name,
+                               APR_WRITE | APR_CREATE | APR_TRUNCATE
+                               | APR_BUFFERED, APR_OS_DEFAULT, pool));
 
-      /* The representation is mutable.  Read the old directory
-         contents from the mutable children file, followed by the
-         changes we've made in this transaction. */
-      SVN_ERR(svn_stream_open_readonly(&contents, filename, pool, pool));
-      SVN_ERR(svn_hash_read2(entries, contents, SVN_HASH_TERMINATOR, pool));
-      SVN_ERR(svn_hash_read_incremental(entries, contents, NULL, pool));
-      SVN_ERR(svn_stream_close(contents));
-    }
-  else if (noderev->data_rep)
-    {
-      /* use a temporary pool for temp objects.
-       * Also undeltify content before parsing it. Otherwise, we could only
-       * parse it byte-by-byte.
-       */
-      apr_pool_t *text_pool = svn_pool_create(pool);
-      apr_size_t len = noderev->data_rep->expanded_size
-                     ? (apr_size_t)noderev->data_rep->expanded_size
-                     : (apr_size_t)noderev->data_rep->size;
-      svn_stringbuf_t *text = svn_stringbuf_create_ensure(len, text_pool);
-      text->len = len;
-
-      /* The representation is immutable.  Read it normally. */
-      SVN_ERR(read_representation(&contents, fs, noderev->data_rep, text_pool));
-      SVN_ERR(svn_stream_read(contents, text->data, &text->len));
-      SVN_ERR(svn_stream_close(contents));
-
-      /* de-serialize hash */
-      contents = svn_stream_from_stringbuf(text, text_pool);
-      SVN_ERR(svn_hash_read2(entries, contents, SVN_HASH_TERMINATOR, pool));
+      SVN_ERR(svn_io_file_write_full(rep_file, rep_string->data,
+                                     rep_string->len, NULL, pool));
 
-      svn_pool_destroy(text_pool);
+      SVN_ERR(svn_io_file_close(rep_file, pool));
     }
 
   return SVN_NO_ERROR;
 }
 
-
 static const char *
 unparse_dir_entry(svn_node_kind_t kind, const svn_fs_id_t *id,
                   apr_pool_t *pool)
@@ -3016,223 +1465,6 @@ unparse_dir_entries(apr_hash_t **str_ent
 }
 
 
-/* Given a hash STR_ENTRIES with values as svn_string_t as specified
-   in an FSFS directory contents listing, return a hash of dirents in
-   *ENTRIES_P.  Perform allocations in POOL. */
-static svn_error_t *
-parse_dir_entries(apr_hash_t **entries_p,
-                  apr_hash_t *str_entries,
-                  const char *unparsed_id,
-                  apr_pool_t *pool)
-{
-  apr_hash_index_t *hi;
-
-  *entries_p = apr_hash_make(pool);
-
-  /* Translate the string dir entries into real entries. */
-  for (hi = apr_hash_first(pool, str_entries); hi; hi = apr_hash_next(hi))
-    {
-      const char *name = svn__apr_hash_index_key(hi);
-      svn_string_t *str_val = svn__apr_hash_index_val(hi);
-      char *str, *last_str;
-      svn_fs_dirent_t *dirent = apr_pcalloc(pool, sizeof(*dirent));
-
-      last_str = apr_pstrdup(pool, str_val->data);
-      dirent->name = apr_pstrdup(pool, name);
-
-      str = svn_cstring_tokenize(" ", &last_str);
-      if (str == NULL)
-        return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
-                                 _("Directory entry corrupt in '%s'"),
-                                 unparsed_id);
-
-      if (strcmp(str, SVN_FS_FS__KIND_FILE) == 0)
-        {
-          dirent->kind = svn_node_file;
-        }
-      else if (strcmp(str, SVN_FS_FS__KIND_DIR) == 0)
-        {
-          dirent->kind = svn_node_dir;
-        }
-      else
-        {
-          return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
-                                   _("Directory entry corrupt in '%s'"),
-                                   unparsed_id);
-        }
-
-      str = svn_cstring_tokenize(" ", &last_str);
-      if (str == NULL)
-          return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
-                                   _("Directory entry corrupt in '%s'"),
-                                   unparsed_id);
-
-      dirent->id = svn_fs_fs__id_parse(str, strlen(str), pool);
-
-      svn_hash_sets(*entries_p, dirent->name, dirent);
-    }
-
-  return SVN_NO_ERROR;
-}
-
-/* Return the cache object in FS responsible to storing the directory
- * the NODEREV. If none exists, return NULL. */
-static svn_cache__t *
-locate_dir_cache(svn_fs_t *fs,
-                 node_revision_t *noderev)
-{
-  fs_fs_data_t *ffd = fs->fsap_data;
-  return svn_fs_fs__id_txn_id(noderev->id)
-      ? ffd->txn_dir_cache
-      : ffd->dir_cache;
-}
-
-svn_error_t *
-svn_fs_fs__rep_contents_dir(apr_hash_t **entries_p,
-                            svn_fs_t *fs,
-                            node_revision_t *noderev,
-                            apr_pool_t *pool)
-{
-  const char *unparsed_id = NULL;
-  apr_hash_t *unparsed_entries, *parsed_entries;
-
-  /* find the cache we may use */
-  svn_cache__t *cache = locate_dir_cache(fs, noderev);
-  if (cache)
-    {
-      svn_boolean_t found;
-
-      unparsed_id = svn_fs_fs__id_unparse(noderev->id, pool)->data;
-      SVN_ERR(svn_cache__get((void **) entries_p, &found, cache,
-                             unparsed_id, pool));
-      if (found)
-        return SVN_NO_ERROR;
-    }
-
-  /* Read in the directory hash. */
-  unparsed_entries = apr_hash_make(pool);
-  SVN_ERR(get_dir_contents(unparsed_entries, fs, noderev, pool));
-  SVN_ERR(parse_dir_entries(&parsed_entries, unparsed_entries,
-                            unparsed_id, pool));
-
-  /* Update the cache, if we are to use one. */
-  if (cache)
-    SVN_ERR(svn_cache__set(cache, unparsed_id, parsed_entries, pool));
-
-  *entries_p = parsed_entries;
-  return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_fs_fs__rep_contents_dir_entry(svn_fs_dirent_t **dirent,
-                                  svn_fs_t *fs,
-                                  node_revision_t *noderev,
-                                  const char *name,
-                                  apr_pool_t *result_pool,
-                                  apr_pool_t *scratch_pool)
-{
-  svn_boolean_t found = FALSE;
-
-  /* find the cache we may use */
-  svn_cache__t *cache = locate_dir_cache(fs, noderev);
-  if (cache)
-    {
-      const char *unparsed_id =
-        svn_fs_fs__id_unparse(noderev->id, scratch_pool)->data;
-
-      /* Cache lookup. */
-      SVN_ERR(svn_cache__get_partial((void **)dirent,
-                                     &found,
-                                     cache,
-                                     unparsed_id,
-                                     svn_fs_fs__extract_dir_entry,
-                                     (void*)name,
-                                     result_pool));
-    }
-
-  /* fetch data from disk if we did not find it in the cache */
-  if (! found)
-    {
-      apr_hash_t *entries;
-      svn_fs_dirent_t *entry;
-      svn_fs_dirent_t *entry_copy = NULL;
-
-      /* read the dir from the file system. It will probably be put it
-         into the cache for faster lookup in future calls. */
-      SVN_ERR(svn_fs_fs__rep_contents_dir(&entries, fs, noderev,
-                                          scratch_pool));
-
-      /* find desired entry and return a copy in POOL, if found */
-      entry = svn_hash_gets(entries, name);
-      if (entry != NULL)
-        {
-          entry_copy = apr_palloc(result_pool, sizeof(*entry_copy));
-          entry_copy->name = apr_pstrdup(result_pool, entry->name);
-          entry_copy->id = svn_fs_fs__id_copy(entry->id, result_pool);
-          entry_copy->kind = entry->kind;
-        }
-
-      *dirent = entry_copy;
-    }
-
-  return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_fs_fs__get_proplist(apr_hash_t **proplist_p,
-                        svn_fs_t *fs,
-                        node_revision_t *noderev,
-                        apr_pool_t *pool)
-{
-  apr_hash_t *proplist;
-  svn_stream_t *stream;
-
-  if (noderev->prop_rep && noderev->prop_rep->txn_id)
-    {
-      const char *filename
-        = svn_fs_fs__path_txn_node_props(fs, noderev->id, pool);
-      proplist = apr_hash_make(pool);
-
-      SVN_ERR(svn_stream_open_readonly(&stream, filename, pool, pool));
-      SVN_ERR(svn_hash_read2(proplist, stream, SVN_HASH_TERMINATOR, pool));
-      SVN_ERR(svn_stream_close(stream));
-    }
-  else if (noderev->prop_rep)
-    {
-      fs_fs_data_t *ffd = fs->fsap_data;
-      representation_t *rep = noderev->prop_rep;
-      pair_cache_key_t key = { 0 };
-
-      key.revision = rep->revision;
-      key.second = rep->offset;
-      if (ffd->properties_cache && SVN_IS_VALID_REVNUM(rep->revision))
-        {
-          svn_boolean_t is_cached;
-          SVN_ERR(svn_cache__get((void **) proplist_p, &is_cached,
-                                 ffd->properties_cache, &key, pool));
-          if (is_cached)
-            return SVN_NO_ERROR;
-        }
-
-      proplist = apr_hash_make(pool);
-      SVN_ERR(read_representation(&stream, fs, noderev->prop_rep, pool));
-      SVN_ERR(svn_hash_read2(proplist, stream, SVN_HASH_TERMINATOR, pool));
-      SVN_ERR(svn_stream_close(stream));
-
-      if (ffd->properties_cache && SVN_IS_VALID_REVNUM(rep->revision))
-        SVN_ERR(svn_cache__set(ffd->properties_cache, &key, proplist, pool));
-    }
-  else
-    {
-      /* return an empty prop list if the node doesn't have any props */
-      proplist = apr_hash_make(pool);
-    }
-
-  *proplist_p = proplist;
-
-  return SVN_NO_ERROR;
-}
-
 svn_error_t *
 svn_fs_fs__file_length(svn_filesize_t *length,
                        node_revision_t *noderev,
@@ -3615,54 +1847,6 @@ svn_fs_fs__txn_changes_fetch(apr_hash_t 
   return SVN_NO_ERROR;
 }
 
-/* Fetch the list of change in revision REV in FS and return it in *CHANGES.
- * Allocate the result in POOL.
- */
-static svn_error_t *
-get_changes(apr_array_header_t **changes,
-            svn_fs_t *fs,
-            svn_revnum_t rev,
-            apr_pool_t *pool)
-{
-  apr_off_t changes_offset;
-  apr_file_t *revision_file;
-  fs_fs_data_t *ffd = fs->fsap_data;
-
-  /* try cache lookup first */
-
-  if (ffd->changes_cache)
-    {
-      svn_boolean_t found;
-      SVN_ERR(svn_cache__get((void **) changes, &found, ffd->changes_cache,
-                             &rev, pool));
-      if (found)
-        return SVN_NO_ERROR;
-    }
-
-  /* read changes from revision file */
-
-  SVN_ERR(svn_fs_fs__revision_exists(rev, fs, pool));
-  SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&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_fs_fs__read_changes(changes,
-                      svn_stream_from_aprfile2(revision_file, TRUE, pool),
-                                  pool));
-
-  SVN_ERR(svn_io_file_close(revision_file, pool));
-
-  /* cache for future reference */
-
-  if (ffd->changes_cache)
-    SVN_ERR(svn_cache__set(ffd->changes_cache, &rev, *changes, pool));
-
-  return SVN_NO_ERROR;
-}
-
-
 svn_error_t *
 svn_fs_fs__paths_changed(apr_hash_t **changed_paths_p,
                          svn_fs_t *fs,
@@ -3674,7 +1858,7 @@ svn_fs_fs__paths_changed(apr_hash_t **ch
   apr_array_header_t *changes;
   apr_pool_t *scratch_pool = svn_pool_create(pool);
 
-  SVN_ERR(get_changes(&changes, fs, rev, scratch_pool));
+  SVN_ERR(svn_fs_fs__get_changes(&changes, fs, rev, scratch_pool));
 
   changed_paths = svn_hash__make(pool);
 
@@ -4457,7 +2641,7 @@ choose_delta_base(representation_t **rep
        * Otherwise, shared reps may form a non-skipping delta chain in
        * extreme cases. */
       int chain_length = 0;
-      SVN_ERR(rep_chain_length(&chain_length, *rep, fs, pool));
+      SVN_ERR(svn_fs_fs__rep_chain_length(&chain_length, *rep, fs, pool));
 
       /* Some reasonable limit, depending on how acceptable longer linear
        * chains are in this repo.  Also, allow for some minimal chain. */
@@ -4543,7 +2727,7 @@ rep_write_get_baton(struct rep_write_bat
 
   /* Get the base for this delta. */
   SVN_ERR(choose_delta_base(&base_rep, fs, noderev, FALSE, b->pool));
-  SVN_ERR(read_representation(&source, fs, base_rep, b->pool));
+  SVN_ERR(svn_fs_fs__get_contents(&source, fs, base_rep, b->pool));
 
   /* Write out the rep header. */
   if (base_rep)
@@ -5028,7 +3212,7 @@ write_hash_delta_rep(representation_t *r
 
   /* Get the base for this delta. */
   SVN_ERR(choose_delta_base(&base_rep, fs, noderev, props, pool));
-  SVN_ERR(read_representation(&source, fs, base_rep, pool));
+  SVN_ERR(svn_fs_fs__get_contents(&source, fs, base_rep, pool));
 
   SVN_ERR(svn_fs_fs__get_file_offset(&rep->offset, file, pool));
 
@@ -6973,8 +5157,9 @@ verify_walker(representation_t *rep,
 
       /* access the repo data */
       previous_file = walker_baton->file_hint;
-      SVN_ERR(check_rep(rep, fs, &walker_baton->file_hint,
-                        &walker_baton->rev_hint, walker_baton->pool));
+      SVN_ERR(svn_fs_fs__check_rep(rep, fs, &walker_baton->file_hint,
+                                   &walker_baton->rev_hint,
+                                   walker_baton->pool));
 
       /* update resource usage counters */
       walker_baton->iteration_count++;
@@ -6984,7 +5169,7 @@ verify_walker(representation_t *rep,
   else
     {
       /* ### Should this be using read_rep_line() directly? */
-      SVN_ERR(check_rep(rep, fs, NULL, NULL, scratch_pool));
+      SVN_ERR(svn_fs_fs__check_rep(rep, fs, NULL, NULL, scratch_pool));
     }
 
   return SVN_NO_ERROR;

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs_fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs_fs.h?rev=1503692&r1=1503691&r2=1503692&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs_fs.h (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs_fs.h Tue Jul 16 12:45:03 2013
@@ -79,13 +79,6 @@ svn_error_t *svn_fs_fs__recover(svn_fs_t
                                 void *cancel_baton,
                                 apr_pool_t *pool);
 
-/* Set *NODEREV_P to the node-revision for the node ID in FS.  Do any
-   allocations in POOL. */
-svn_error_t *svn_fs_fs__get_node_revision(node_revision_t **noderev_p,
-                                          svn_fs_t *fs,
-                                          const svn_fs_id_t *id,
-                                          apr_pool_t *pool);
-
 /* Store NODEREV as the node-revision for the node whose id is ID in
    FS, after setting its is_fresh_txn_root to FRESH_TXN_ROOT.  Do any
    necessary temporary allocation in POOL. */
@@ -107,73 +100,6 @@ svn_fs_fs__revision_exists(svn_revnum_t 
                            svn_fs_t *fs,
                            apr_pool_t *pool);
 
-/* Set *ROOT_ID to the node-id for the root of revision REV in
-   filesystem FS.  Do any allocations in POOL. */
-svn_error_t *svn_fs_fs__rev_get_root(svn_fs_id_t **root_id,
-                                     svn_fs_t *fs,
-                                     svn_revnum_t rev,
-                                     apr_pool_t *pool);
-
-/* Set *ENTRIES to an apr_hash_t of dirent structs that contain the
-   directory entries of node-revision NODEREV in filesystem FS.  The
-   returned table (and its keys and values) is allocated in POOL,
-   which is also used for temporary allocations. */
-svn_error_t *svn_fs_fs__rep_contents_dir(apr_hash_t **entries,
-                                         svn_fs_t *fs,
-                                         node_revision_t *noderev,
-                                         apr_pool_t *pool);
-
-/* Set *DIRENT to the entry identified by NAME in the directory given
-   by NODEREV in filesystem FS.  If no such entry exits, *DIRENT will
-   be NULL. The returned object is allocated in RESULT_POOL; SCRATCH_POOL
-   used for temporary allocations. */
-svn_error_t *
-svn_fs_fs__rep_contents_dir_entry(svn_fs_dirent_t **dirent,
-                                  svn_fs_t *fs,
-                                  node_revision_t *noderev,
-                                  const char *name,
-                                  apr_pool_t *result_pool,
-                                  apr_pool_t *scratch_pool);
-
-/* Set *CONTENTS to be a readable svn_stream_t that receives the text
-   representation of node-revision NODEREV as seen in filesystem FS.
-   Use POOL for temporary allocations. */
-svn_error_t *svn_fs_fs__get_contents(svn_stream_t **contents,
-                                     svn_fs_t *fs,
-                                     node_revision_t *noderev,
-                                     apr_pool_t *pool);
-
-/* Attempt to fetch the text representation of node-revision NODEREV as
-   seen in filesystem FS and pass it along with the BATON to the PROCESSOR.
-   Set *SUCCESS only of the data could be provided and the processing
-   had been called.
-   Use POOL for all allocations.
- */
-svn_error_t *
-svn_fs_fs__try_process_file_contents(svn_boolean_t *success,
-                                     svn_fs_t *fs,
-                                     node_revision_t *noderev,
-                                     svn_fs_process_contents_func_t processor,
-                                     void* baton,
-                                     apr_pool_t *pool);
-
-/* Set *STREAM_P to a delta stream turning the contents of the file SOURCE into
-   the contents of the file TARGET, allocated in POOL.
-   If SOURCE is null, the empty string will be used. */
-svn_error_t *svn_fs_fs__get_file_delta_stream(svn_txdelta_stream_t **stream_p,
-                                              svn_fs_t *fs,
-                                              node_revision_t *source,
-                                              node_revision_t *target,
-                                              apr_pool_t *pool);
-
-/* Set *PROPLIST to be an apr_hash_t containing the property list of
-   node-revision NODEREV as seen in filesystem FS.  Use POOL for
-   temporary allocations. */
-svn_error_t *svn_fs_fs__get_proplist(apr_hash_t **proplist,
-                                     svn_fs_t *fs,
-                                     node_revision_t *noderev,
-                                     apr_pool_t *pool);
-
 /* Set *LENGTH to the be fulltext length of the node revision
    specified by NODEREV.  Use POOL for temporary allocations. */
 svn_error_t *svn_fs_fs__file_length(svn_filesize_t *length,

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/tree.c?rev=1503692&r1=1503691&r2=1503692&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/tree.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/tree.c Tue Jul 16 12:45:03 2013
@@ -52,6 +52,7 @@
 
 #include "fs.h"
 #include "key-gen.h"
+#include "cached_data.h"
 #include "dag.h"
 #include "lock.h"
 #include "tree.h"

Modified: subversion/branches/fsfs-improvements/tools/server-side/svn-rep-sharing-stats.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/tools/server-side/svn-rep-sharing-stats.c?rev=1503692&r1=1503691&r2=1503692&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/tools/server-side/svn-rep-sharing-stats.c (original)
+++ subversion/branches/fsfs-improvements/tools/server-side/svn-rep-sharing-stats.c Tue Jul 16 12:45:03 2013
@@ -33,6 +33,7 @@
 #include "../../subversion/libsvn_fs_fs/fs_fs.h"
 /* for svn_fs_fs__id_* (used in assertions only) */
 #include "../../subversion/libsvn_fs_fs/id.h"
+#include "../../subversion/libsvn_fs_fs/cached_data.h"
 
 #include "private/svn_cmdline_private.h"