subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From i...@apache.org
Subject svn commit: r1636544 [7/13] - in /subversion/branches/remove-log-addressing: ./ subversion/bindings/javahl/tests/org/apache/subversion/javahl/ subversion/include/ subversion/include/private/ subversion/libsvn_client/ subversion/libsvn_delta/ subversion...
Date Tue, 04 Nov 2014 11:40:19 GMT
Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_x/index.h
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_x/index.h?rev=1636544&r1=1636543&r2=1636544&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_x/index.h (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_x/index.h Tue Nov  4 11:40:16 2014
@@ -24,6 +24,7 @@
 #define SVN_LIBSVN_FS__INDEX_H
 
 #include "fs.h"
+#include "rev_file.h"
 
 /* Per-defined item index values.  They are used to identify empty or
  * mandatory items.
@@ -65,7 +66,7 @@ typedef struct svn_fs_x__p2l_entry_t
   apr_off_t size;
 
   /* type of the item (see SVN_FS_X__ITEM_TYPE_*) defines */
-  unsigned type;
+  apr_uint32_t type;
 
   /* modified FNV-1a checksum.  0 if unknown checksum */
   apr_uint32_t fnv1_checksum;
@@ -86,20 +87,21 @@ svn_fs_x__p2l_entry_dup(const svn_fs_x__
                         apr_pool_t *pool);
 
 /* Open / create a log-to-phys index file with the full file path name
- * FILE_NAME.  Return the open file in *PROTO_INDEX and use POOL for
- * allocations.
+ * FILE_NAME.  Return the open file in *PROTO_INDEX allocated in
+ * RESULT_POOL.
  */
 svn_error_t *
 svn_fs_x__l2p_proto_index_open(apr_file_t **proto_index,
                                const char *file_name,
-                               apr_pool_t *pool);
+                               apr_pool_t *result_pool);
 
 /* Call this function before adding entries for the next revision to the
- * log-to-phys index file in PROTO_INDEX.  Use POOL for allocations.
+ * log-to-phys index file in PROTO_INDEX.  Use SCRATCH_POOL for temporary
+ * allocations.
  */
 svn_error_t *
 svn_fs_x__l2p_proto_index_add_revision(apr_file_t *proto_index,
-                                       apr_pool_t *pool);
+                                       apr_pool_t *scratch_pool);
 
 /* Add a new mapping, ITEM_INDEX to the (OFFSET, SUB_ITEM) pair, to log-to-
  * phys index file in PROTO_INDEX.  Please note that mappings may be added
@@ -109,72 +111,84 @@ svn_fs_x__l2p_proto_index_add_revision(a
  * that is already implied for all item indexes not explicitly given a
  * mapping.
  * 
- * Use POOL for allocations.
+ * Use SCRATCH_POOL for temporary allocations.
  */
 svn_error_t *
 svn_fs_x__l2p_proto_index_add_entry(apr_file_t *proto_index,
                                     apr_off_t offset,
                                     apr_uint32_t sub_item,
                                     apr_uint64_t item_index,
-                                    apr_pool_t *pool);
+                                    apr_pool_t *scratch_pool);
 
-/* Use the proto index file stored at PROTO_FILE_NAME and construct the
- * final log-to-phys index file at FILE_NAME.  The first revision will
+/* Use the proto index file stored at PROTO_FILE_NAME, construct the final
+ * log-to-phys index and append it to INDEX_FILE.  The first revision will
  * be REVISION, entries to the next revision will be assigned to REVISION+1
- * and so forth.  Use POOL for allocations.
+ * and so forth.  
+ *
+ * Return the MD5 checksum of the on-disk index data in *CHECKSUM, allocated
+ * in RESULT_POOL.  Use SCRATCH_POOL for temporary allocations.
  */
 svn_error_t *
-svn_fs_x__l2p_index_create(svn_fs_t *fs,
-                           const char *file_name,
+svn_fs_x__l2p_index_append(svn_checksum_t **checksum,
+                           svn_fs_t *fs,
+                           apr_file_t *index_file,
                            const char *proto_file_name,
                            svn_revnum_t revision,
-                           apr_pool_t *pool);
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool);
 
 /* Open / create a phys-to-log index file with the full file path name
- * FILE_NAME.  Return the open file in *PROTO_INDEX and use POOL for
- * allocations.
+ * FILE_NAME.  Return the open file in *PROTO_INDEX allocated in
+ * RESULT_POOL.
  */
 svn_error_t *
 svn_fs_x__p2l_proto_index_open(apr_file_t **proto_index,
                                const char *file_name,
-                               apr_pool_t *pool);
+                               apr_pool_t *result_pool);
 
 /* Add a new mapping ENTRY to the phys-to-log index file in PROTO_INDEX.
  * The entries must be added in ascending offset order and must not leave
  * intermittent ranges uncovered.  The revision value in ENTRY may be
- * SVN_INVALID_REVISION.  Use POOL for allocations.
+ * SVN_INVALID_REVISION.  Use SCRATCH_POOL for temporary allocations.
  */
 svn_error_t *
 svn_fs_x__p2l_proto_index_add_entry(apr_file_t *proto_index,
-                                    svn_fs_x__p2l_entry_t *entry,
-                                    apr_pool_t *pool);
+                                    const svn_fs_x__p2l_entry_t *entry,
+                                    apr_pool_t *scratch_pool);
 
 /* Set *NEXT_OFFSET to the first offset behind the last entry in the
  * phys-to-log proto index file PROTO_INDEX.  This will be 0 for empty
- * index files.  Use POOL for temporary allocations.
+ * index files.  Use SCRATCH_POOL for temporary allocations.
  */
 svn_error_t *
 svn_fs_x__p2l_proto_index_next_offset(apr_off_t *next_offset,
                                       apr_file_t *proto_index,
-                                      apr_pool_t *pool);
+                                      apr_pool_t *scratch_pool);
 
-/* Use the proto index file stored at PROTO_FILE_NAME and construct the
- * final phys-to-log index file at FILE_NAME.  Entries without a valid
+/* Use the proto index file stored at PROTO_FILE_NAME, construct the final
+ * phys-to-log index and append it to INDEX_FILE.  Entries without a valid
  * revision will be assigned to the REVISION given here.
- * Use POOL for allocations.
+ *
+ * Return the MD5 checksum of the on-disk index data in *CHECKSUM, allocated
+ * in RESULT_POOL.  Use SCRATCH_POOL for temporary allocations.
  */
 svn_error_t *
-svn_fs_x__p2l_index_create(svn_fs_t *fs,
-                           const char *file_name,
+svn_fs_x__p2l_index_append(svn_checksum_t **checksum,
+                           svn_fs_t *fs,
+                           apr_file_t *index_file,
                            const char *proto_file_name,
                            svn_revnum_t revision,
-                           apr_pool_t *pool);
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool);
 
 /* Use the phys-to-log mapping files in FS to build a list of entries
  * that (at least partly) overlap with the range given by BLOCK_START
  * offset and BLOCK_SIZE in the rep / pack file containing REVISION.
- * Return the array in *ENTRIES with svn_fs_fs__p2l_entry_t as elements.
- * Use POOL for allocations.
+ * Return the array in *ENTRIES with svn_fs_fs__p2l_entry_t as elements,
+ * allocated in RESULT_POOL.  REV_FILE determines whether to access single
+ * rev or pack file data.  If that is not available anymore (neither in
+ * cache nor on disk), return an error.  Use SCRATCH_POOL for temporary
+ * allocations.
  *
  * Note that (only) the first and the last mapping may cross a cluster
  * boundary.
@@ -182,69 +196,122 @@ svn_fs_x__p2l_index_create(svn_fs_t *fs,
 svn_error_t *
 svn_fs_x__p2l_index_lookup(apr_array_header_t **entries,
                            svn_fs_t *fs,
+                           svn_fs_x__revision_file_t *rev_file,
                            svn_revnum_t revision,
                            apr_off_t block_start,
                            apr_off_t block_size,
-                           apr_pool_t *pool);
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool);
 
 /* Use the phys-to-log mapping files in FS to return the entry for the
  * container or single item starting at global OFFSET in the rep file
- * containing REVISION in *ENTRY.  Sets *ENTRY to NULL if no item starts
- * at exactly that offset.  Use POOL for allocations.
+ * containing REVISION in*ENTRY, allocated in RESULT_POOL.  Sets *ENTRY
+ * to NULL if no item starts at exactly that offset.  REV_FILE determines
+ * whether to access single rev or pack file data.  If that is not available
+ * anymore (neither in cache nor on disk), return an error.
+ * Use SCRATCH_POOL for temporary allocations.
  */
 svn_error_t *
 svn_fs_x__p2l_entry_lookup(svn_fs_x__p2l_entry_t **entry,
                            svn_fs_t *fs,
+                           svn_fs_x__revision_file_t *rev_file,
                            svn_revnum_t revision,
                            apr_off_t offset,
-                           apr_pool_t *pool);
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool);
 
 /* Use the phys-to-log mapping files in FS to return the svn_fs_x__id_part_t
  * for the SUB_ITEM of the container starting at global OFFSET in the rep /
- * pack file containing REVISION in *ITEM.  Sets *ITEM to NULL if no element
- * starts at exactly that offset or if it contains no more than SUB_ITEM
- * sub-items.  Use POOL for allocations.
+ * pack file containing REVISION in *ITEM, allocated in RESULT_POOL.  Sets
+ * *ITEM to NULL if no element starts at exactly that offset or if it
+ * contains no more than SUB_ITEM sub-items.
+ *
+ * Use SCRATCH_POOL for temporary allocations.
  */
 svn_error_t *
 svn_fs_x__p2l_item_lookup(svn_fs_x__id_part_t **item,
                           svn_fs_t *fs,
+                          svn_fs_x__revision_file_t *rev_file,
                           svn_revnum_t revision,
                           apr_off_t offset,
                           apr_uint32_t sub_item,
-                          apr_pool_t *pool);
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool);
 
-/* Use the log-to-phys mapping files in FS to find the packed / non-packed /
- * proto-rev file offset and container sub-item of ITEM_ID.  *SUB_ITEM will
- * be 0 for non-container items.  Use POOL for allocations.
+/* For ITEM_ID in FS, return the position in the respective rev or pack file
+ * in *ABSOLUTE_POSITION and the *SUB_ITEM number within the object at that
+ * location. *SUB_ITEM will be 0 for non-container items.
+ *
+ * REV_FILE determines whether to access single rev or pack file data.
+ * If that is not available anymore (neither in cache nor on disk), re-open
+ * the rev / pack file and retry to open the index file.  For transaction
+ * content, REV_FILE may be NULL.
+ *
+ * Use SCRATCH_POOL for temporary allocations.
  */
 svn_error_t *
-svn_fs_x__item_offset(apr_off_t *offset,
+svn_fs_x__item_offset(apr_off_t *absolute_position,
                       apr_uint32_t *sub_item,
                       svn_fs_t *fs,
+                      svn_fs_x__revision_file_t *rev_file,
                       const svn_fs_x__id_part_t *item_id,
-                      apr_pool_t *pool);
+                      apr_pool_t *scratch_pool);
 
 /* Use the log-to-phys indexes in FS to determine the maximum item indexes
  * assigned to revision START_REV to START_REV + COUNT - 1.  That is a
  * close upper limit to the actual number of items in the respective revs.
- * Return the results in *MAX_IDS,  allocated in POOL.
+ * Return the results in *MAX_IDS,  allocated in RESULT_POOL.
+ * Use SCRATCH_POOL for temporary allocations.
  */
 svn_error_t *
 svn_fs_x__l2p_get_max_ids(apr_array_header_t **max_ids,
                           svn_fs_t *fs,
                           svn_revnum_t start_rev,
                           apr_size_t count,
-                          apr_pool_t *pool);
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool);
 
 /* In *OFFSET, return the first OFFSET in the pack / rev file containing
  * REVISION in FS not covered by the log-to-phys index.
- * Use POOL for allocations.
+ * Use SCRATCH_POOL for temporary allocations.
  */
 svn_error_t *
 svn_fs_x__p2l_get_max_offset(apr_off_t *offset,
                              svn_fs_t *fs,
+                             svn_fs_x__revision_file_t *rev_file,
                              svn_revnum_t revision,
-                             apr_pool_t *pool);
+                             apr_pool_t *scratch_pool);
+
+/* Index (re-)creation utilities.
+ */
+
+/* For FS, create a new L2P auto-deleting proto index file in POOL and return
+ * its name in *PROTONAME.  All entries to write are given in ENTRIES and
+ * entries are of type svn_fs_fs__p2l_entry_t* (sic!).  The ENTRIES array
+ * will be reordered.  Give the proto index file the lifetime of RESULT_POOL
+ * and use SCRATCH_POOL for temporary allocations.
+ */
+svn_error_t *
+svn_fs_x__l2p_index_from_p2l_entries(const char **protoname,
+                                     svn_fs_t *fs,
+                                     apr_array_header_t *entries,
+                                     apr_pool_t *result_pool,
+                                     apr_pool_t *scratch_pool);
+
+/* For FS, create a new P2L auto-deleting proto index file in POOL and return
+ * its name in *PROTONAME.  All entries to write are given in ENTRIES and
+ * of type svn_fs_fs__p2l_entry_t*.  The FVN1 checksums are not taken from
+ * ENTRIES but are begin calculated from the current contents of REV_FILE
+ * as we go.  Give the proto index file the lifetime of RESULT_POOL and use
+ * SCRATCH_POOL for temporary allocations.
+ */
+svn_error_t *
+svn_fs_x__p2l_index_from_p2l_entries(const char **protoname,
+                                     svn_fs_t *fs,
+                                     svn_fs_x__revision_file_t *rev_file,
+                                     apr_array_header_t *entries,
+                                     apr_pool_t *result_pool,
+                                     apr_pool_t *scratch_pool);
 
 /* Serialization and caching interface
  */

Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_x/low_level.c
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_x/low_level.c?rev=1636544&r1=1636543&r2=1636544&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_x/low_level.c (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_x/low_level.c Tue Nov  4 11:40:16 2014
@@ -27,6 +27,7 @@
 #include "private/svn_sorts_private.h"
 #include "private/svn_string_private.h"
 #include "private/svn_subr_private.h"
+#include "private/svn_fspath.h"
 
 #include "../libsvn_fs/fs-loader.h"
 
@@ -71,105 +72,115 @@
  * various flags. */
 #define MAX_CHANGE_LINE_LEN FSX_MAX_PATH_LEN + 256
 
-svn_error_t *
-svn_fs_x__parse_revision_trailer(apr_off_t *root_offset,
-                                 apr_off_t *changes_offset,
-                                 svn_stringbuf_t *trailer,
-                                 svn_revnum_t rev)
-{
-  int i, num_bytes;
-  const char *str;
-
-  /* This cast should be safe since the maximum amount read, 64, will
-     never be bigger than the size of an int. */
-  num_bytes = (int) trailer->len;
-
-  /* The last byte should be a newline. */
-  if (trailer->len == 0 || trailer->data[trailer->len - 1] != '\n')
+/* Convert the C string in *TEXT to a revision number and return it in *REV.
+ * Overflows, negative values other than -1 and terminating characters other
+ * than 0x20 or 0x0 will cause an error.  Set *TEXT to the first char after
+ * the initial separator or to EOS.
+ */
+static svn_error_t *
+parse_revnum(svn_revnum_t *rev,
+             const char **text)
+{
+  const char *string = *text;
+  if ((string[0] == '-') && (string[1] == '1'))
     {
-      return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
-                               _("Revision file (r%ld) lacks trailing newline"),
-                               rev);
+      *rev = SVN_INVALID_REVNUM;
+      string += 2;
     }
-
-  /* Look for the next previous newline. */
-  for (i = num_bytes - 2; i >= 0; i--)
+  else
     {
-      if (trailer->data[i] == '\n')
-        break;
+      SVN_ERR(svn_revnum_parse(rev, string, &string));
     }
 
-  if (i < 0)
-    {
-      return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
-                               _("Final line in revision file (r%ld) longer "
-                                 "than 64 characters"),
-                               rev);
-    }
+  if (*string == ' ')
+    ++string;
+  else if (*string != '\0')
+    return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
+                            _("Invalid character in revision number"));
 
-  i++;
-  str = &trailer->data[i];
+  *text = string;
+  return SVN_NO_ERROR;
+}
 
-  /* find the next space */
-  for ( ; i < (num_bytes - 2) ; i++)
-    if (trailer->data[i] == ' ')
-      break;
+svn_error_t *
+svn_fs_x__parse_footer(apr_off_t *l2p_offset,
+                       svn_checksum_t **l2p_checksum,
+                       apr_off_t *p2l_offset,
+                       svn_checksum_t **p2l_checksum,
+                       svn_stringbuf_t *footer,
+                       svn_revnum_t rev,
+                       apr_pool_t *result_pool)
+{
+  apr_int64_t val;
+  char *last_str = footer->data;
 
-  if (i == (num_bytes - 2))
-    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
-                             _("Final line in revision file r%ld missing space"),
-                             rev);
+  /* Get the L2P offset. */
+  const char *str = svn_cstring_tokenize(" ", &last_str);
+  if (str == NULL)
+    return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
+                            _("Invalid revision footer"));
 
-  if (root_offset)
-    {
-      apr_int64_t val;
+  SVN_ERR(svn_cstring_atoi64(&val, str));
+  *l2p_offset = (apr_off_t)val;
 
-      trailer->data[i] = '\0';
-      SVN_ERR(svn_cstring_atoi64(&val, str));
-      *root_offset = (apr_off_t)val;
-    }
+  /* Get the L2P checksum. */
+  str = svn_cstring_tokenize(" ", &last_str);
+  if (str == NULL)
+    return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
+                            _("Invalid revision footer"));
 
-  i++;
-  str = &trailer->data[i];
+  SVN_ERR(svn_checksum_parse_hex(l2p_checksum, svn_checksum_md5, str,
+                                 result_pool));
 
-  /* find the next newline */
-  for ( ; i < num_bytes; i++)
-    if (trailer->data[i] == '\n')
-      break;
+  /* Get the P2L offset. */
+  str = svn_cstring_tokenize(" ", &last_str);
+  if (str == NULL)
+    return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
+                            _("Invalid revision footer"));
 
-  if (changes_offset)
-    {
-      apr_int64_t val;
+  SVN_ERR(svn_cstring_atoi64(&val, str));
+  *p2l_offset = (apr_off_t)val;
 
-      trailer->data[i] = '\0';
-      SVN_ERR(svn_cstring_atoi64(&val, str));
-      *changes_offset = (apr_off_t)val;
-    }
+  /* Get the P2L checksum. */
+  str = svn_cstring_tokenize(" ", &last_str);
+  if (str == NULL)
+    return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
+                            _("Invalid revision footer"));
+
+  SVN_ERR(svn_checksum_parse_hex(p2l_checksum, svn_checksum_md5, str,
+                                 result_pool));
 
   return SVN_NO_ERROR;
 }
 
 svn_stringbuf_t *
-svn_fs_x__unparse_revision_trailer(apr_off_t root_offset,
-                                   apr_off_t changes_offset,
-                                   apr_pool_t *pool)
-{
-  return svn_stringbuf_createf(pool,
-                               "%" APR_OFF_T_FMT " %" APR_OFF_T_FMT "\n",
-                               root_offset,
-                               changes_offset);
+svn_fs_x__unparse_footer(apr_off_t l2p_offset,
+                         svn_checksum_t *l2p_checksum,
+                         apr_off_t p2l_offset,
+                         svn_checksum_t *p2l_checksum,
+                         apr_pool_t *result_pool,
+                         apr_pool_t *scratch_pool)
+{
+  return svn_stringbuf_createf(result_pool,
+                               "%" APR_OFF_T_FMT " %s %" APR_OFF_T_FMT " %s",
+                               l2p_offset,
+                               svn_checksum_to_cstring(l2p_checksum,
+                                                       scratch_pool),
+                               p2l_offset,
+                               svn_checksum_to_cstring(p2l_checksum,
+                                                       scratch_pool));
 }
 
 /* Given a revision file FILE that has been pre-positioned at the
    beginning of a Node-Rev header block, read in that header block and
    store it in the apr_hash_t HEADERS.  All allocations will be from
-   POOL. */
+   RESULT_POOL. */
 static svn_error_t *
 read_header_block(apr_hash_t **headers,
                   svn_stream_t *stream,
-                  apr_pool_t *pool)
+                  apr_pool_t *result_pool)
 {
-  *headers = svn_hash__make(pool);
+  *headers = svn_hash__make(result_pool);
 
   while (1)
     {
@@ -179,7 +190,8 @@ read_header_block(apr_hash_t **headers,
       apr_ssize_t name_len;
       svn_boolean_t eof;
 
-      SVN_ERR(svn_stream_readline(stream, &header_str, "\n", &eof, pool));
+      SVN_ERR(svn_stream_readline(stream, &header_str, "\n", &eof,
+                                  result_pool));
 
       if (eof || header_str->len == 0)
         break; /* end of header block */
@@ -226,7 +238,8 @@ read_header_block(apr_hash_t **headers,
 svn_error_t *
 svn_fs_x__parse_representation(representation_t **rep_p,
                                svn_stringbuf_t *text,
-                               apr_pool_t *pool)
+                               apr_pool_t *result_pool,
+                               apr_pool_t *scratch_pool)
 {
   representation_t *rep;
   char *str;
@@ -234,7 +247,7 @@ svn_fs_x__parse_representation(represent
   char *string = text->data;
   svn_checksum_t *checksum;
 
-  rep = apr_pcalloc(pool, sizeof(*rep));
+  rep = apr_pcalloc(result_pool, sizeof(*rep));
   *rep_p = rep;
 
   str = svn_cstring_tokenize(" ", &string);
@@ -283,7 +296,8 @@ svn_fs_x__parse_representation(represent
     return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
                             _("Malformed text representation offset line in node-rev"));
 
-  SVN_ERR(svn_checksum_parse_hex(&checksum, svn_checksum_md5, str, pool));
+  SVN_ERR(svn_checksum_parse_hex(&checksum, svn_checksum_md5, str,
+                                 scratch_pool));
   if (checksum)
     memcpy(rep->md5_digest, checksum->digest, sizeof(rep->md5_digest));
 
@@ -297,7 +311,8 @@ svn_fs_x__parse_representation(represent
     return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
                             _("Malformed text representation offset line in node-rev"));
 
-  SVN_ERR(svn_checksum_parse_hex(&checksum, svn_checksum_sha1, str, pool));
+  SVN_ERR(svn_checksum_parse_hex(&checksum, svn_checksum_sha1, str,
+                                 scratch_pool));
   rep->has_sha1 = checksum != NULL;
   if (checksum)
     memcpy(rep->sha1_digest, checksum->digest, sizeof(rep->sha1_digest));
@@ -311,17 +326,22 @@ static svn_error_t *
 read_rep_offsets(representation_t **rep_p,
                  char *string,
                  const svn_fs_id_t *noderev_id,
-                 apr_pool_t *pool)
+                 apr_pool_t *result_pool,
+                 apr_pool_t *scratch_pool)
 {
   svn_error_t *err
     = svn_fs_x__parse_representation(rep_p,
-                                     svn_stringbuf_create_wrap(string, pool),
-                                     pool);
+                                     svn_stringbuf_create_wrap(string,
+                                                               scratch_pool),
+                                     result_pool,
+                                     scratch_pool);
   if (err)
     {
-      const svn_string_t *id_unparsed = svn_fs_x__id_unparse(noderev_id, pool);
+      const svn_string_t *id_unparsed;
       const char *where;
-      where = apr_psprintf(pool,
+
+      id_unparsed = svn_fs_x__id_unparse(noderev_id, scratch_pool);
+      where = apr_psprintf(scratch_pool,
                            _("While reading representation offsets "
                              "for node-revision '%s':"),
                            noderev_id ? id_unparsed->data : "(null)");
@@ -387,27 +407,28 @@ auto_unescape_path(const char *path,
 svn_error_t *
 svn_fs_x__read_noderev(node_revision_t **noderev_p,
                        svn_stream_t *stream,
-                       apr_pool_t *pool)
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool)
 {
   apr_hash_t *headers;
   node_revision_t *noderev;
   char *value;
   const char *noderev_id;
 
-  SVN_ERR(read_header_block(&headers, stream, pool));
+  SVN_ERR(read_header_block(&headers, stream, scratch_pool));
 
-  noderev = apr_pcalloc(pool, sizeof(*noderev));
+  noderev = apr_pcalloc(result_pool, sizeof(*noderev));
 
   /* Read the node-rev id. */
   value = svn_hash_gets(headers, HEADER_ID);
   if (value == NULL)
-      /* ### More information: filename/offset coordinates */
-      return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
-                              _("Missing id field in node-rev"));
+     /* ### More information: filename/offset coordinates */
+     return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
+                             _("Missing id field in node-rev"));
 
   SVN_ERR(svn_stream_close(stream));
 
-  noderev->id = svn_fs_x__id_parse(value, strlen(value), pool);
+  SVN_ERR(svn_fs_x__id_parse(&noderev->id, value, result_pool));
   noderev_id = value; /* for error messages later */
 
   /* Read the type. */
@@ -437,7 +458,7 @@ svn_fs_x__read_noderev(node_revision_t *
   if (value)
     {
       SVN_ERR(read_rep_offsets(&noderev->prop_rep, value,
-                               noderev->id, pool));
+                               noderev->id, result_pool, scratch_pool));
     }
 
   /* Get the data location. */
@@ -445,7 +466,7 @@ svn_fs_x__read_noderev(node_revision_t *
   if (value)
     {
       SVN_ERR(read_rep_offsets(&noderev->data_rep, value,
-                               noderev->id, pool));
+                               noderev->id, result_pool, scratch_pool));
     }
 
   /* Get the created path. */
@@ -458,13 +479,21 @@ svn_fs_x__read_noderev(node_revision_t *
     }
   else
     {
-      noderev->created_path = auto_unescape_path(value, pool);
+      if (!svn_fspath__is_canonical(value))
+        return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                            _("Non-canonical cpath field in node-rev '%s'"),
+                            noderev_id);
+
+      noderev->created_path = auto_unescape_path(apr_pstrdup(result_pool,
+                                                              value),
+                                                 result_pool);
     }
 
   /* Get the predecessor ID. */
   value = svn_hash_gets(headers, HEADER_PRED);
   if (value)
-    noderev->predecessor_id = svn_fs_x__id_parse(value, strlen(value), pool);
+    SVN_ERR(svn_fs_x__id_parse(&noderev->predecessor_id, value,
+                               result_pool));
 
   /* Get the copyroot. */
   value = svn_hash_gets(headers, HEADER_COPYROOT);
@@ -475,21 +504,15 @@ svn_fs_x__read_noderev(node_revision_t *
     }
   else
     {
-      char *str;
+      SVN_ERR(parse_revnum(&noderev->copyroot_rev, (const char **)&value));
 
-      str = svn_cstring_tokenize(" ", &value);
-      if (str == NULL)
+      if (!svn_fspath__is_canonical(value))
         return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
                                  _("Malformed copyroot line in node-rev '%s'"),
                                  noderev_id);
-
-      noderev->copyroot_rev = SVN_STR_TO_REV(str);
-
-      if (*value == '\0')
-        return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
-                                 _("Malformed copyroot line in node-rev '%s'"),
-                                 noderev_id);
-      noderev->copyroot_path = auto_unescape_path(value, pool);
+      noderev->copyroot_path = auto_unescape_path(apr_pstrdup(result_pool,
+                                                              value),
+                                                  result_pool);
     }
 
   /* Get the copyfrom. */
@@ -501,19 +524,15 @@ svn_fs_x__read_noderev(node_revision_t *
     }
   else
     {
-      char *str = svn_cstring_tokenize(" ", &value);
-      if (str == NULL)
-        return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
-                                 _("Malformed copyfrom line in node-rev '%s'"),
-                                 noderev_id);
-
-      noderev->copyfrom_rev = SVN_STR_TO_REV(str);
+      SVN_ERR(parse_revnum(&noderev->copyfrom_rev, (const char **)&value));
 
       if (*value == 0)
         return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
                                  _("Malformed copyfrom line in node-rev '%s'"),
                                  noderev_id);
-      noderev->copyfrom_path = auto_unescape_path(value, pool);
+      noderev->copyfrom_path = auto_unescape_path(apr_pstrdup(result_pool,
+                                                              value),
+                                                  result_pool);
     }
 
   /* Get whether this is a fresh txn root. */
@@ -538,13 +557,13 @@ svn_fs_x__read_noderev(node_revision_t *
 
 /* Return a textual representation of the DIGEST of given KIND.
  * If IS_NULL is TRUE, no digest is available.
- * Use POOL for allocations.
+ * Allocate the result in RESULT_POOL.
  */
 static const char *
 format_digest(const unsigned char *digest,
               svn_checksum_kind_t kind,
               svn_boolean_t is_null,
-              apr_pool_t *pool)
+              apr_pool_t *result_pool)
 {
   svn_checksum_t checksum;
   checksum.digest = digest;
@@ -553,92 +572,96 @@ format_digest(const unsigned char *diges
   if (is_null)
     return "(null)";
 
-  return svn_checksum_to_cstring_display(&checksum, pool);
+  return svn_checksum_to_cstring_display(&checksum, result_pool);
 }
 
 svn_stringbuf_t *
 svn_fs_x__unparse_representation(representation_t *rep,
-                                 int format,
                                  svn_boolean_t mutable_rep_truncated,
-                                 apr_pool_t *pool)
+                                 apr_pool_t *result_pool,
+                                 apr_pool_t *scratch_pool)
 {
   if (!rep->has_sha1)
     return svn_stringbuf_createf
-            (pool,
+            (result_pool,
              "%" APR_INT64_T_FMT " %" APR_UINT64_T_FMT " %" SVN_FILESIZE_T_FMT
              " %" SVN_FILESIZE_T_FMT " %s",
              rep->id.change_set, rep->id.number, rep->size,
              rep->expanded_size,
-             format_digest(rep->md5_digest, svn_checksum_md5, FALSE, pool));
+             format_digest(rep->md5_digest, svn_checksum_md5, FALSE,
+                           scratch_pool));
 
   return svn_stringbuf_createf
-          (pool,
+          (result_pool,
            "%" APR_INT64_T_FMT " %" APR_UINT64_T_FMT " %" SVN_FILESIZE_T_FMT
            " %" SVN_FILESIZE_T_FMT " %s %s",
            rep->id.change_set, rep->id.number, rep->size,
            rep->expanded_size,
-           format_digest(rep->md5_digest, svn_checksum_md5, FALSE, pool),
+           format_digest(rep->md5_digest, svn_checksum_md5,
+                         FALSE, scratch_pool),
            format_digest(rep->sha1_digest, svn_checksum_sha1,
-                         !rep->has_sha1, pool));
+                         !rep->has_sha1, scratch_pool));
 }
 
 
 svn_error_t *
 svn_fs_x__write_noderev(svn_stream_t *outfile,
                         node_revision_t *noderev,
-                        int format,
-                        apr_pool_t *pool)
+                        apr_pool_t *scratch_pool)
 {
-  SVN_ERR(svn_stream_printf(outfile, pool, HEADER_ID ": %s\n",
-                            svn_fs_x__id_unparse(noderev->id, pool)->data));
+  SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_ID ": %s\n",
+                            svn_fs_x__id_unparse(noderev->id,
+                                                 scratch_pool)->data));
 
-  SVN_ERR(svn_stream_printf(outfile, pool, HEADER_TYPE ": %s\n",
+  SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_TYPE ": %s\n",
                             (noderev->kind == svn_node_file) ?
                             SVN_FS_X__KIND_FILE : SVN_FS_X__KIND_DIR));
 
   if (noderev->predecessor_id)
-    SVN_ERR(svn_stream_printf(outfile, pool, HEADER_PRED ": %s\n",
+    SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_PRED ": %s\n",
                               svn_fs_x__id_unparse(noderev->predecessor_id,
-                                                   pool)->data));
+                                                   scratch_pool)->data));
 
-  SVN_ERR(svn_stream_printf(outfile, pool, HEADER_COUNT ": %d\n",
+  SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_COUNT ": %d\n",
                             noderev->predecessor_count));
 
   if (noderev->data_rep)
-    SVN_ERR(svn_stream_printf(outfile, pool, HEADER_TEXT ": %s\n",
+    SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_TEXT ": %s\n",
                               svn_fs_x__unparse_representation
                                 (noderev->data_rep,
-                                 format,
                                  noderev->kind == svn_node_dir,
-                                 pool)->data));
+                                 scratch_pool, scratch_pool)->data));
 
   if (noderev->prop_rep)
-    SVN_ERR(svn_stream_printf(outfile, pool, HEADER_PROPS ": %s\n",
+    SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_PROPS ": %s\n",
                               svn_fs_x__unparse_representation
-                                (noderev->prop_rep, format,
-                                 TRUE, pool)->data));
+                                (noderev->prop_rep,
+                                 TRUE, scratch_pool, scratch_pool)->data));
 
-  SVN_ERR(svn_stream_printf(outfile, pool, HEADER_CPATH ": %s\n",
-                            auto_escape_path(noderev->created_path, pool)));
+  SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_CPATH ": %s\n",
+                            auto_escape_path(noderev->created_path,
+                                             scratch_pool)));
 
   if (noderev->copyfrom_path)
-    SVN_ERR(svn_stream_printf(outfile, pool, HEADER_COPYFROM ": %ld"
+    SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_COPYFROM ": %ld"
                               " %s\n",
                               noderev->copyfrom_rev,
-                              auto_escape_path(noderev->copyfrom_path, pool)));
+                              auto_escape_path(noderev->copyfrom_path,
+                                               scratch_pool)));
 
   if ((noderev->copyroot_rev != svn_fs_x__id_rev(noderev->id)) ||
       (strcmp(noderev->copyroot_path, noderev->created_path) != 0))
-    SVN_ERR(svn_stream_printf(outfile, pool, HEADER_COPYROOT ": %ld"
+    SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_COPYROOT ": %ld"
                               " %s\n",
                               noderev->copyroot_rev,
-                              auto_escape_path(noderev->copyroot_path, pool)));
+                              auto_escape_path(noderev->copyroot_path,
+                                               scratch_pool)));
 
   if (noderev->is_fresh_txn_root)
     SVN_ERR(svn_stream_puts(outfile, HEADER_FRESHTXNRT ": y\n"));
 
   if (noderev->mergeinfo_count > 0)
-    SVN_ERR(svn_stream_printf(outfile, pool, HEADER_MINFO_CNT ": %"
+    SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_MINFO_CNT ": %"
                               APR_INT64_T_FMT "\n",
                               noderev->mergeinfo_count));
 
@@ -651,16 +674,17 @@ svn_fs_x__write_noderev(svn_stream_t *ou
 svn_error_t *
 svn_fs_x__read_rep_header(svn_fs_x__rep_header_t **header,
                           svn_stream_t *stream,
-                          apr_pool_t *pool)
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool)
 {
   svn_stringbuf_t *buffer;
   char *str, *last_str;
   apr_int64_t val;
   svn_boolean_t eol = FALSE;
 
-  SVN_ERR(svn_stream_readline(stream, &buffer, "\n", &eol, pool));
+  SVN_ERR(svn_stream_readline(stream, &buffer, "\n", &eol, scratch_pool));
 
-  *header = apr_pcalloc(pool, sizeof(**header));
+  *header = apr_pcalloc(result_pool, sizeof(**header));
   (*header)->header_size = buffer->len + 1;
   if (strcmp(buffer->data, REP_DELTA) == 0)
     {
@@ -677,10 +701,7 @@ svn_fs_x__read_rep_header(svn_fs_x__rep_
   if (! str || (strcmp(str, REP_DELTA) != 0))
     goto error;
 
-  str = svn_cstring_tokenize(" ", &last_str);
-  if (! str)
-    goto error;
-  (*header)->base_revision = SVN_STR_TO_REV(str);
+  SVN_ERR(parse_revnum(&(*header)->base_revision, (const char **)&last_str));
 
   str = svn_cstring_tokenize(" ", &last_str);
   if (! str)
@@ -704,7 +725,7 @@ svn_fs_x__read_rep_header(svn_fs_x__rep_
 svn_error_t *
 svn_fs_x__write_rep_header(svn_fs_x__rep_header_t *header,
                            svn_stream_t *stream,
-                           apr_pool_t *pool)
+                           apr_pool_t *scratch_pool)
 {
   const char *text;
   
@@ -715,8 +736,8 @@ svn_fs_x__write_rep_header(svn_fs_x__rep
         break;
 
       default:
-        text = apr_psprintf(pool, REP_DELTA " %ld %" APR_OFF_T_FMT " %"
-                            SVN_FILESIZE_T_FMT "\n",
+        text = apr_psprintf(scratch_pool, REP_DELTA " %ld %" APR_OFF_T_FMT
+                                          " %" SVN_FILESIZE_T_FMT "\n",
                             header->base_revision, header->base_item_index,
                             header->base_length);
     }
@@ -730,7 +751,8 @@ svn_fs_x__write_rep_header(svn_fs_x__rep
 static svn_error_t *
 read_change(change_t **change_p,
             svn_stream_t *stream,
-            apr_pool_t *pool)
+            apr_pool_t *result_pool,
+            apr_pool_t *scratch_pool)
 {
   svn_stringbuf_t *line;
   svn_boolean_t eof = TRUE;
@@ -741,13 +763,13 @@ read_change(change_t **change_p,
   /* Default return value. */
   *change_p = NULL;
 
-  SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, pool));
+  SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, scratch_pool));
 
   /* Check for a blank line. */
   if (eof || (line->len == 0))
     return SVN_NO_ERROR;
 
-  change = apr_pcalloc(pool, sizeof(*change));
+  change = apr_pcalloc(result_pool, sizeof(*change));
   info = &change->info;
   last_str = line->data;
 
@@ -757,7 +779,7 @@ read_change(change_t **change_p,
     return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
                             _("Invalid changes line in rev-file"));
 
-  info->node_rev_id = svn_fs_x__id_parse(str, strlen(str), pool);
+  SVN_ERR(svn_fs_x__id_parse(&info->node_rev_id, str, result_pool));
   if (info->node_rev_id == NULL)
     return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
                             _("Invalid changes line in rev-file"));
@@ -873,13 +895,18 @@ read_change(change_t **change_p,
     }
 
   /* Get the changed path. */
-  change->path.data = auto_unescape_path(apr_pstrmemdup(pool, last_str,
+  if (!svn_fspath__is_canonical(last_str))
+    return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
+                            _("Invalid path in changes line"));
+
+  change->path.data = auto_unescape_path(apr_pstrmemdup(result_pool,
+                                                        last_str,
                                                         strlen(last_str)),
-                                         pool);
+                                         result_pool);
   change->path.len = strlen(change->path.data);
 
   /* Read the next line, the copyfrom line. */
-  SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, pool));
+  SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, result_pool));
   info->copyfrom_known = TRUE;
   if (eof || line->len == 0)
     {
@@ -889,17 +916,13 @@ read_change(change_t **change_p,
   else
     {
       last_str = line->data;
-      str = svn_cstring_tokenize(" ", &last_str);
-      if (! str)
-        return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
-                                _("Invalid changes line in rev-file"));
-      info->copyfrom_rev = SVN_STR_TO_REV(str);
+      SVN_ERR(parse_revnum(&info->copyfrom_rev, (const char **)&last_str));
 
-      if (! last_str)
+      if (!svn_fspath__is_canonical(last_str))
         return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
-                                _("Invalid changes line in rev-file"));
+                                _("Invalid copy-from path in changes line"));
 
-      info->copyfrom_path = auto_unescape_path(last_str, pool);
+      info->copyfrom_path = auto_unescape_path(last_str, result_pool);
     }
 
   *change_p = change;
@@ -910,33 +933,68 @@ read_change(change_t **change_p,
 svn_error_t *
 svn_fs_x__read_changes(apr_array_header_t **changes,
                        svn_stream_t *stream,
-                       apr_pool_t *pool)
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool)
 {
   change_t *change;
+  apr_pool_t *iterpool;
 
-  /* pre-allocate enough room for most change lists
-     (will be auto-expanded as necessary) */
-  *changes = apr_array_make(pool, 30, sizeof(change_t *));
-  
-  SVN_ERR(read_change(&change, stream, pool));
+  /* Pre-allocate enough room for most change lists.
+     (will be auto-expanded as necessary).
+
+     Chose the default to just below 2^N such that the doubling reallocs
+     will request roughly 2^M bytes from the OS without exceeding the
+     respective two-power by just a few bytes (leaves room array and APR
+     node overhead for large enough M).
+   */
+  *changes = apr_array_make(result_pool, 63, sizeof(change_t *));
+
+  SVN_ERR(read_change(&change, stream, result_pool, scratch_pool));
+  iterpool = svn_pool_create(scratch_pool);
   while (change)
     {
       APR_ARRAY_PUSH(*changes, change_t*) = change;
-      SVN_ERR(read_change(&change, stream, pool));
+      SVN_ERR(read_change(&change, stream, result_pool, iterpool));
+      svn_pool_clear(iterpool);
     }
+  svn_pool_destroy(iterpool);
 
   return SVN_NO_ERROR;
 }
 
-/* Write a single change entry, path PATH, change CHANGE, and copyfrom
-   string COPYFROM, into the file specified by FILE.  Only include the
-   node kind field if INCLUDE_NODE_KIND is true.  All temporary
-   allocations are in POOL. */
+svn_error_t *
+svn_fs_x__read_changes_incrementally(svn_stream_t *stream,
+                                     svn_fs_x__change_receiver_t
+                                       change_receiver,
+                                     void *change_receiver_baton,
+                                     apr_pool_t *scratch_pool)
+{
+  change_t *change;
+  apr_pool_t *iterpool;
+
+  iterpool = svn_pool_create(scratch_pool);
+  do
+    {
+      svn_pool_clear(iterpool);
+
+      SVN_ERR(read_change(&change, stream, iterpool, iterpool));
+      if (change)
+        SVN_ERR(change_receiver(change_receiver_baton, change, iterpool));
+    }
+  while (change);
+  svn_pool_destroy(iterpool);
+  
+  return SVN_NO_ERROR;
+}
+
+/* Write a single change entry, path PATH, change CHANGE, to STREAM.
+
+   All temporary allocations are in SCRATCH_POOL. */
 static svn_error_t *
 write_change_entry(svn_stream_t *stream,
                    const char *path,
                    svn_fs_path_change2_t *change,
-                   apr_pool_t *pool)
+                   apr_pool_t *scratch_pool)
 {
   const char *idstr;
   const char *change_string = NULL;
@@ -968,29 +1026,31 @@ write_change_entry(svn_stream_t *stream,
     }
 
   if (change->node_rev_id)
-    idstr = svn_fs_x__id_unparse(change->node_rev_id, pool)->data;
+    idstr = svn_fs_x__id_unparse(change->node_rev_id, scratch_pool)->data;
   else
     idstr = ACTION_RESET;
 
   SVN_ERR_ASSERT(change->node_kind == svn_node_dir
-                  || change->node_kind == svn_node_file);
-  kind_string = apr_psprintf(pool, "-%s",
-                              change->node_kind == svn_node_dir
-                              ? SVN_FS_X__KIND_DIR
-                              : SVN_FS_X__KIND_FILE);
-  buf = svn_stringbuf_createf(pool, "%s %s%s %s %s %s %s\n",
+                 || change->node_kind == svn_node_file);
+  kind_string = apr_psprintf(scratch_pool, "-%s",
+                             change->node_kind == svn_node_dir
+                             ? SVN_FS_X__KIND_DIR
+                             : SVN_FS_X__KIND_FILE);
+
+  buf = svn_stringbuf_createf(scratch_pool, "%s %s%s %s %s %s %s\n",
                               idstr, change_string, kind_string,
                               change->text_mod ? FLAG_TRUE : FLAG_FALSE,
                               change->prop_mod ? FLAG_TRUE : FLAG_FALSE,
                               change->mergeinfo_mod == svn_tristate_true
                                                ? FLAG_TRUE : FLAG_FALSE,
-                              auto_escape_path(path, pool));
+                              auto_escape_path(path, scratch_pool));
 
   if (SVN_IS_VALID_REVNUM(change->copyfrom_rev))
     {
-      svn_stringbuf_appendcstr(buf, apr_psprintf(pool, "%ld %s",
-                             change->copyfrom_rev,
-                             auto_escape_path(change->copyfrom_path, pool)));
+      svn_stringbuf_appendcstr(buf, apr_psprintf(scratch_pool, "%ld %s",
+                               change->copyfrom_rev,
+                               auto_escape_path(change->copyfrom_path,
+                                                scratch_pool)));
     }
 
   svn_stringbuf_appendbyte(buf, '\n');
@@ -1005,17 +1065,24 @@ svn_fs_x__write_changes(svn_stream_t *st
                         svn_fs_t *fs,
                         apr_hash_t *changes,
                         svn_boolean_t terminate_list,
-                        apr_pool_t *pool)
+                        apr_pool_t *scratch_pool)
 {
-  apr_pool_t *iterpool = svn_pool_create(pool);
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
   apr_array_header_t *sorted_changed_paths;
   int i;
 
   /* For the sake of the repository administrator sort the changes so
      that the final file is deterministic and repeatable, however the
-     rest of the FSX code doesn't require any particular order here. */
+     rest of the FSX code doesn't require any particular order here.
+
+     Also, this sorting is only effective in writing all entries with
+     a single call as write_final_changed_path_info() does.  For the
+     list being written incrementally during transaction, we actually
+     *must not* change the order of entries from different calls.
+   */
   sorted_changed_paths = svn_sort__hash(changes,
-                                        svn_sort_compare_items_lexically, pool);
+                                        svn_sort_compare_items_lexically,
+                                        scratch_pool);
 
   /* Write all items to disk in the new order. */
   for (i = 0; i < sorted_changed_paths->nelts; ++i)
@@ -1034,7 +1101,7 @@ svn_fs_x__write_changes(svn_stream_t *st
 
   if (terminate_list)
     svn_stream_puts(stream, "\n");
-  
+
   svn_pool_destroy(iterpool);
 
   return SVN_NO_ERROR;

Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_x/low_level.h
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_x/low_level.h?rev=1636544&r1=1636543&r2=1636544&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_x/low_level.h (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_x/low_level.h Tue Nov  4 11:40:16 2014
@@ -36,62 +36,81 @@ extern "C" {
 #define SVN_FS_X__KIND_FILE          "file"
 #define SVN_FS_X__KIND_DIR           "dir"
 
-/* Given the last "few" bytes (should be at least 40) of revision REV in
- * TRAILER,  parse the last line and return the offset of the root noderev
- * in *ROOT_OFFSET and the offset of the changed paths list in
- * *CHANGES_OFFSET.  Offsets are relative to the revision's start offset.
- * ROOT_OFFSET and / or CHANGES_OFFSET may be NULL.
+/* The functions are grouped as follows:
+ *
+ * - revision footer
+ * - representation (as in "text:" and "props:" lines)
+ * - node revision
+ * - representation header ("DELTA" lines)
+ * - changed path list
+ */
+
+/* Given the FSX revision / pack FOOTER, parse it destructively
+ * and return the start offsets of the index data in *L2P_OFFSET and
+ * *P2L_OFFSET, respectively.  Also, return the expected checksums in
+ * in *L2P_CHECKSUM and *P2L_CHECKSUM.
  * 
- * Note that REV is only used to construct nicer error objects.
+ * Note that REV is only used to construct nicer error objects that
+ * mention this revision.  Allocate the checksums in RESULT_POOL.
  */
 svn_error_t *
-svn_fs_x__parse_revision_trailer(apr_off_t *root_offset,
-                                 apr_off_t *changes_offset,
-                                 svn_stringbuf_t *trailer,
-                                 svn_revnum_t rev);
-
-/* Given the offset of the root noderev in ROOT_OFFSET and the offset of
- * the changed paths list in CHANGES_OFFSET,  return the corresponding
- * revision's trailer.  Allocate it in POOL.
+svn_fs_x__parse_footer(apr_off_t *l2p_offset,
+                       svn_checksum_t **l2p_checksum,
+                       apr_off_t *p2l_offset,
+                       svn_checksum_t **p2l_checksum,
+                       svn_stringbuf_t *footer,
+                       svn_revnum_t rev,
+                       apr_pool_t *result_pool);
+
+/* Given the offset of the L2P index data in L2P_OFFSET, the content
+ * checksum in L2P_CHECKSUM and the offset plus checksum of the P2L
+ * index data in P2L_OFFSET and P2L_CHECKSUM.
+ *
+ * Return the corresponding format 7+ revision / pack file footer.
+ * Allocate it in RESULT_POOL and use SCRATCH_POOL for temporary.
  */
 svn_stringbuf_t *
-svn_fs_x__unparse_revision_trailer(apr_off_t root_offset,
-                                   apr_off_t changes_offset,
-                                   apr_pool_t *pool);
+svn_fs_x__unparse_footer(apr_off_t l2p_offset,
+                         svn_checksum_t *l2p_checksum,
+                         apr_off_t p2l_offset,
+                         svn_checksum_t *p2l_checksum,
+                         apr_pool_t *result_pool,
+                         apr_pool_t *scratch_pool);
 
 /* Parse the description of a representation from TEXT and store it
-   into *REP_P.  Allocate *REP_P in POOL. */
+   into *REP_P.  TEXT will be invalidated by this call.  Allocate *REP_P in
+   RESULT_POOL and use SCRATCH_POOL for temporaries. */
 svn_error_t *
 svn_fs_x__parse_representation(representation_t **rep_p,
                                svn_stringbuf_t *text,
-                               apr_pool_t *pool);
+                               apr_pool_t *result_pool,
+                               apr_pool_t *scratch_pool);
 
-/* Return a formatted string, compatible with filesystem format FORMAT,
-   that represents the location of representation REP.  If
-   MUTABLE_REP_TRUNCATED is given, the rep is for props or dir contents,
-   and only a "-1" revision number will be given for a mutable rep.
-   If MAY_BE_CORRUPT is true, guard for NULL when constructing the string.
-   Perform the allocation from POOL.  */
+/* Return a formatted string that represents the location of representation
+ * REP.  If MUTABLE_REP_TRUNCATED is given, the rep is for props or dir
+ * contents, and only a "-1" revision number will be given for a mutable rep.
+ * If MAY_BE_CORRUPT is true, guard for NULL when constructing the string.
+ * Allocate the result in RESULT_POOL and temporaries in SCRATCH_POOL. */
 svn_stringbuf_t *
 svn_fs_x__unparse_representation(representation_t *rep,
-                                 int format,
                                  svn_boolean_t mutable_rep_truncated,
-                                 apr_pool_t *pool);
+                                 apr_pool_t *result_pool,
+                                 apr_pool_t *scratch_pool);
 
 /* Read a node-revision from STREAM. Set *NODEREV to the new structure,
-   allocated in POOL. */
+   allocated in RESULT_POOL. */
 svn_error_t *
 svn_fs_x__read_noderev(node_revision_t **noderev,
                        svn_stream_t *stream,
-                       apr_pool_t *pool);
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool);
 
-/* Write the node-revision NODEREV into the stream OUTFILE, compatible with
-   filesystem format FORMAT.  Temporary allocations are from POOL. */
+/* Write the node-revision NODEREV into the stream OUTFILE.
+   Temporary allocations are from SCRATCH_POOL. */
 svn_error_t *
 svn_fs_x__write_noderev(svn_stream_t *outfile,
                         node_revision_t *noderev,
-                        int format,
-                        apr_pool_t *pool);
+                        apr_pool_t *scratch_pool);
 
 /* This type enumerates all forms of representations that we support. */
 typedef enum svn_fs_x__rep_type_t
@@ -132,39 +151,61 @@ typedef struct svn_fs_x__rep_header_t
   apr_size_t header_size;
 } svn_fs_x__rep_header_t;
 
-/* Read the next line from file FILE and parse it as a text
-   representation entry.  Return the parsed entry in *REP_ARGS_P.
-   Perform all allocations in POOL. */
+/* Read the next line from STREAM and parse it as a text
+   representation header.  Return the parsed entry in *HEADER, allocated
+   in RESULT_POOL. Perform temporary allocations in SCRATCH_POOL. */
 svn_error_t *
 svn_fs_x__read_rep_header(svn_fs_x__rep_header_t **header,
                           svn_stream_t *stream,
-                          apr_pool_t *pool);
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool);
 
-/* Write the representation HEADER to STREAM.  Use POOL for allocations. */
+/* Write the representation HEADER to STREAM. 
+ * Use SCRATCH_POOL for allocations. */
 svn_error_t *
 svn_fs_x__write_rep_header(svn_fs_x__rep_header_t *header,
                            svn_stream_t *stream,
-                           apr_pool_t *pool);
+                           apr_pool_t *scratch_pool);
 
-/* Read all the changes from STREAM and store them in *CHANGES.  Do all
-   allocations in POOL. */
+/* Read all the changes from STREAM and store them in *CHANGES,
+   allocated in RESULT_POOL. Do temporary allocations in SCRATCH_POOL. */
 svn_error_t *
 svn_fs_x__read_changes(apr_array_header_t **changes,
                        svn_stream_t *stream,
-                       apr_pool_t *pool);
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool);
+
+/* Callback function used by svn_fs_fs__read_changes_incrementally(),
+ * asking the receiver to process to process CHANGE using BATON.  CHANGE
+ * and SCRATCH_POOL will not be valid beyond the current callback invocation.
+ */
+typedef svn_error_t *(*svn_fs_x__change_receiver_t)(
+  void *baton,
+  change_t *change,
+  apr_pool_t *scratch_pool);
+
+/* Read all the changes from STREAM and invoke CHANGE_RECEIVER on each change.
+   Do all allocations in SCRATCH_POOL. */
+svn_error_t *
+svn_fs_x__read_changes_incrementally(svn_stream_t *stream,
+                                     svn_fs_x__change_receiver_t
+                                       change_receiver,
+                                     void *change_receiver_baton,
+                                     apr_pool_t *scratch_pool);
 
 /* Write the changed path info from CHANGES in filesystem FS to the
    output stream STREAM.  You may call this function multiple time on
-   the same stream but the last call should set TERMINATE_LIST to write
-   an extra empty line that marks the end of the changed paths list.
-   Perform temporary allocations in POOL.
+   the same stream.  If you are writing to a (proto-)revision file,
+   the last call must set TERMINATE_LIST to write an extra empty line
+   that marks the end of the changed paths list.
+   Perform temporary allocations in SCRATCH_POOL.
  */
 svn_error_t *
 svn_fs_x__write_changes(svn_stream_t *stream,
                         svn_fs_t *fs,
                         apr_hash_t *changes,
                         svn_boolean_t terminate_list,
-                        apr_pool_t *pool);
+                        apr_pool_t *scratch_pool);
 
 #ifdef __cplusplus
 }

Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_x/pack.c
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_x/pack.c?rev=1636544&r1=1636543&r2=1636544&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_x/pack.c (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_x/pack.c Tue Nov  4 11:40:16 2014
@@ -357,12 +357,6 @@ static svn_error_t *
 close_pack_context(pack_context_t *context,
                    apr_pool_t *pool)
 {
-  const char *l2p_index_path
-    = apr_pstrcat(pool, context->pack_file_path, PATH_EXT_L2P_INDEX,
-                  SVN_VA_NULL);
-  const char *p2l_index_path
-    = apr_pstrcat(pool, context->pack_file_path, PATH_EXT_P2L_INDEX,
-                  SVN_VA_NULL);
   const char *proto_l2p_index_path;
   const char *proto_p2l_index_path;
 
@@ -371,18 +365,17 @@ close_pack_context(pack_context_t *conte
                                context->proto_l2p_index, pool));
   SVN_ERR(svn_io_file_name_get(&proto_p2l_index_path,
                                context->proto_p2l_index, pool));
-  
+
   /* finalize proto index files */
   SVN_ERR(svn_io_file_close(context->proto_l2p_index, pool));
   SVN_ERR(svn_io_file_close(context->proto_p2l_index, pool));
 
-  /* Create the actual index files*/
-  SVN_ERR(svn_fs_x__l2p_index_create(context->fs, l2p_index_path,
-                                     proto_l2p_index_path,
-                                     context->shard_rev, pool));
-  SVN_ERR(svn_fs_x__p2l_index_create(context->fs, p2l_index_path,
-                                     proto_p2l_index_path,
-                                     context->shard_rev, pool));
+  /* Append the actual index data to the pack file. */
+  SVN_ERR(svn_fs_x__add_index_data(context->fs, context->pack_file,
+                                    proto_l2p_index_path,
+                                    proto_p2l_index_path,
+                                    context->shard_rev, 
+                                    pool));
 
   /* remove proto index files */
   SVN_ERR(svn_io_remove_file2(proto_l2p_index_path, FALSE, pool));
@@ -476,7 +469,7 @@ static svn_error_t *
 copy_item_to_temp(pack_context_t *context,
                   apr_array_header_t *entries,
                   apr_file_t *temp_file,
-                  apr_file_t *rev_file,
+                  svn_fs_x__revision_file_t *rev_file,
                   svn_fs_x__p2l_entry_t *entry,
                   apr_pool_t *pool)
 {
@@ -486,7 +479,8 @@ copy_item_to_temp(pack_context_t *contex
   SVN_ERR(svn_io_file_seek(temp_file, APR_CUR, &new_entry->offset, pool));
   APR_ARRAY_PUSH(entries, svn_fs_x__p2l_entry_t *) = new_entry;
   
-  SVN_ERR(copy_file_data(context, temp_file, rev_file, entry->size, pool));
+  SVN_ERR(copy_file_data(context, temp_file, rev_file->file, entry->size,
+                         pool));
   
   return SVN_NO_ERROR;
 }
@@ -561,12 +555,11 @@ get_item(pack_context_t *context,
  */
 static svn_error_t *
 copy_rep_to_temp(pack_context_t *context,
-                 apr_file_t *rev_file,
+                 svn_fs_x__revision_file_t *rev_file,
                  svn_fs_x__p2l_entry_t *entry,
                  apr_pool_t *pool)
 {
   svn_fs_x__rep_header_t *rep_header;
-  svn_stream_t *stream;
   apr_off_t source_offset = entry->offset;
 
   /* create a copy of ENTRY, make it point to the copy destination and
@@ -578,9 +571,8 @@ copy_rep_to_temp(pack_context_t *context
   add_item_rep_mapping(context, entry);
 
   /* read & parse the representation header */
-  stream = svn_stream_from_aprfile2(rev_file, TRUE, pool);
-  SVN_ERR(svn_fs_x__read_rep_header(&rep_header, stream, pool));
-  svn_stream_close(stream);
+  SVN_ERR(svn_fs_x__read_rep_header(&rep_header, rev_file->stream, pool,
+                                    pool));
 
   /* if the representation is a delta against some other rep, link the two */
   if (   rep_header->type == svn_fs_x__rep_delta
@@ -596,9 +588,9 @@ copy_rep_to_temp(pack_context_t *context
     }
 
   /* copy the whole rep (including header!) to our temp file */
-  SVN_ERR(svn_io_file_seek(rev_file, APR_SET, &source_offset, pool));
-  SVN_ERR(copy_file_data(context, context->reps_file, rev_file, entry->size,
-                         pool));
+  SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &source_offset, pool));
+  SVN_ERR(copy_file_data(context, context->reps_file, rev_file->file,
+                         entry->size, pool));
 
   return SVN_NO_ERROR;
 }
@@ -679,7 +671,7 @@ tweak_path_for_ordering(const char *orig
  */
 static svn_error_t *
 copy_node_to_temp(pack_context_t *context,
-                  apr_file_t *rev_file,
+                  svn_fs_x__revision_file_t *rev_file,
                   svn_fs_x__p2l_entry_t *entry,
                   apr_pool_t *pool)
 {
@@ -687,13 +679,10 @@ copy_node_to_temp(pack_context_t *contex
                                          sizeof(*path_order));
   node_revision_t *noderev;
   const char *sort_path;
-  svn_stream_t *stream;
   apr_off_t source_offset = entry->offset;
 
   /* read & parse noderev */
-  stream = svn_stream_from_aprfile2(rev_file, TRUE, pool);
-  SVN_ERR(svn_fs_x__read_noderev(&noderev, stream, pool));
-  svn_stream_close(stream);
+  SVN_ERR(svn_fs_x__read_noderev(&noderev, rev_file->stream, pool, pool));
 
   /* create a copy of ENTRY, make it point to the copy destination and
    * store it in CONTEXT */
@@ -704,9 +693,9 @@ copy_node_to_temp(pack_context_t *contex
   add_item_rep_mapping(context, entry);
 
   /* copy the noderev to our temp file */
-  SVN_ERR(svn_io_file_seek(rev_file, APR_SET, &source_offset, pool));
-  SVN_ERR(copy_file_data(context, context->reps_file, rev_file, entry->size,
-                         pool));
+  SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &source_offset, pool));
+  SVN_ERR(copy_file_data(context, context->reps_file, rev_file->file,
+                         entry->size, pool));
 
   /* if the node has a data representation, make that the node's "base".
    * This will (often) cause the noderev to be placed right in front of
@@ -768,58 +757,6 @@ sort_items(apr_array_header_t *entries)
                   (int (*)(const void *, const void *))compare_p2l_info);
 }
 
-/* Decorator for svn_fs_x__p2l_entry_t that associates it with a sorted
- * variant of its ITEMS array.
- */
-typedef struct sub_item_ordered_t
-{
-  /* ENTRY that got wrapped */
-  svn_fs_x__p2l_entry_t *entry;
-
-  /* Array of pointers into ENTRY->ITEMS, sorted by their revision member
-   * _descending_ order.  May be NULL if ENTRY->ITEM_COUNT < 2. */
-  svn_fs_x__id_part_t **order;
-} sub_item_ordered_t;
-
-/* implements compare_fn_t. Place LHS before RHS, if the latter is younger.
- * Used to sort sub_item_ordered_t::order
- */
-static int
-compare_sub_items(const svn_fs_x__id_part_t * const * lhs,
-                  const svn_fs_x__id_part_t * const * rhs)
-{
-  return (*lhs)->change_set < (*rhs)->change_set
-       ? 1
-       : ((*lhs)->change_set > (*rhs)->change_set ? -1 : 0);
-}
-
-/* implements compare_fn_t. Place LHS before RHS, if the latter belongs to
- * a newer revision.
- */
-static int
-compare_p2l_info_rev(const sub_item_ordered_t * lhs,
-                     const sub_item_ordered_t * rhs)
-{
-  svn_fs_x__id_part_t *lhs_part;
-  svn_fs_x__id_part_t *rhs_part;
-  
-  assert(lhs != rhs);
-  if (lhs->entry->item_count == 0)
-    return rhs->entry->item_count == 0 ? 0 : -1;
-  if (rhs->entry->item_count == 0)
-    return 1;
-
-  lhs_part = lhs->order ? lhs->order[lhs->entry->item_count - 1]
-                        : &lhs->entry->items[0];
-  rhs_part = rhs->order ? rhs->order[rhs->entry->item_count - 1]
-                        : &rhs->entry->items[0];
-
-  if (lhs_part->change_set == rhs_part->change_set)
-    return 0;
-
-  return lhs_part->change_set < rhs_part->change_set ? -1 : 1;
-}
-
 /* implements compare_fn_t.  Sort descending by PATH, NODE_ID and REVISION.
  */
 static int
@@ -1207,7 +1144,7 @@ store_nodes(pack_context_t *context,
 
       /* item will fit into the block. */
       SVN_ERR(svn_io_file_seek(temp_file, APR_SET, &entry->offset, iterpool));
-      SVN_ERR(svn_fs_x__read_noderev(&noderev, stream, iterpool));
+      SVN_ERR(svn_fs_x__read_noderev(&noderev, stream, iterpool, iterpool));
       svn_fs_x__noderevs_add(*container, noderev);
 
       container_size += entry->size;
@@ -1284,8 +1221,9 @@ write_reps_containers(pack_context_t *co
     = svn_fs_x__reps_builder_create(context->fs, container_pool);
   apr_array_header_t *sub_items
     = apr_array_make(pool, 64, sizeof(svn_fs_x__id_part_t));
-  svn_stream_t *temp_stream
-    = svn_stream_from_aprfile2(temp_file, TRUE, pool);
+  svn_fs_x__revision_file_t *file;
+
+  SVN_ERR(svn_fs_x__wrap_temp_rev_file(&file, context->fs, temp_file, pool));
 
   /* copy all items in strict order */
   for (i = entries->nelts-1; i >= 0; --i)
@@ -1331,8 +1269,8 @@ write_reps_containers(pack_context_t *co
                                iterpool));
       SVN_ERR(svn_fs_x__get_representation_length(&representation.size,
                                              &representation.expanded_size,
-                                             context->fs, temp_file,
-                                             temp_stream, entry, iterpool));
+                                             context->fs, file,
+                                             entry, iterpool));
       SVN_ERR(svn_fs_x__get_contents(&stream, context->fs, &representation,
                                      FALSE, iterpool));
       contents = svn_stringbuf_create_ensure(representation.expanded_size,
@@ -1656,7 +1594,7 @@ write_changes_containers(pack_context_t 
        * the container */
       SVN_ERR(svn_io_file_seek(temp_file, APR_SET, &entry->offset,
                                iterpool));
-      SVN_ERR(svn_fs_x__read_changes(&changes, temp_stream, iterpool));
+      SVN_ERR(svn_fs_x__read_changes(&changes, temp_stream, pool, iterpool));
       SVN_ERR(svn_fs_x__changes_append_list(&list_index, container, changes));
       SVN_ERR_ASSERT(list_index == sub_items->nelts);
       block_left -= estimated_size;
@@ -1720,13 +1658,10 @@ static svn_error_t *
 write_l2p_index(pack_context_t *context,
                 apr_pool_t *pool)
 {
-  apr_pool_t *iterpool = svn_pool_create(pool);
-  svn_revnum_t prev_rev = SVN_INVALID_REVNUM;
-  int i;
-  apr_uint32_t k;
-  svn_priority_queue__t *queue;
-  apr_size_t count = 0;
-  apr_array_header_t *sub_item_orders;
+  apr_pool_t *scratch_pool = svn_pool_create(pool);
+  const char *temp_name;
+  const char *proto_index;
+  apr_off_t offset = 0;
 
   /* lump all items into one bucket.  As target, use the bucket that
    * probably has the most entries already. */
@@ -1734,88 +1669,24 @@ write_l2p_index(pack_context_t *context,
   append_entries(context->reps, context->file_props);
   append_entries(context->reps, context->dir_props);
 
-  /* wrap P2L entries such that we have access to the sub-items in revision
-     order.  The ENTRY_COUNT member will point to the next item to read+1. */
-  sub_item_orders
-    = apr_array_make(pool, context->reps->nelts, sizeof(sub_item_ordered_t));
-  sub_item_orders->nelts = context->reps->nelts;
-
-  for (i = 0; i < context->reps->nelts; ++i)
-    {
-      svn_fs_x__p2l_entry_t *entry
-        = APR_ARRAY_IDX(context->reps, i, svn_fs_x__p2l_entry_t *);
-      sub_item_ordered_t *ordered
-        = &APR_ARRAY_IDX(sub_item_orders, i, sub_item_ordered_t);
-
-      /* skip unused regions (e.g. padding) */
-      if (entry->item_count == 0)
-        continue;
-
-      assert(entry);
-      ordered->entry = entry;
-      count += entry->item_count;
-
-      if (entry->item_count > 1)
-        {
-          ordered->order
-            = apr_palloc(pool, sizeof(*ordered->order) * entry->item_count);
-          for (k = 0; k < entry->item_count; ++k)
-            ordered->order[k] = &entry->items[k];
-
-          qsort(ordered->order, entry->item_count, sizeof(*ordered->order),
-                (int (*)(const void *, const void *))compare_sub_items);
-        }
-    }
-
-  /* we need to write the index in ascending revision order */
-  queue = svn_priority_queue__create
-            (sub_item_orders,
-             (int (*)(const void *, const void *))compare_p2l_info_rev);
-
-  /* write index entries */
-  for (i = 0; i < count; ++i)
-    {
-      svn_fs_x__id_part_t *sub_item;
-      sub_item_ordered_t *ordered = svn_priority_queue__peek(queue);
-
-      if (ordered->entry->item_count > 0)
-        {
-          /* if there is only one item, we skip the overhead of having an
-             extra array for the item order */
-          sub_item = ordered->order
-                   ? ordered->order[ordered->entry->item_count - 1]
-                   : &ordered->entry->items[0];
-
-          /* next revision? */
-          if (prev_rev != svn_fs_x__get_revnum(sub_item->change_set))
-            {
-              prev_rev = svn_fs_x__get_revnum(sub_item->change_set);
-              SVN_ERR(svn_fs_x__l2p_proto_index_add_revision
-                          (context->proto_l2p_index, iterpool));
-            }
-
-          /* add entry */
-          SVN_ERR(svn_fs_x__l2p_proto_index_add_entry
-                      (context->proto_l2p_index, ordered->entry->offset,
-                      (apr_uint32_t)(sub_item - ordered->entry->items),
-                      sub_item->number, iterpool));
-
-          /* make ITEM_COUNT point the next sub-item to use+1 */
-          --ordered->entry->item_count;
-        }
-
-      /* process remaining sub-items (if any) of that container later */
-      if (ordered->entry->item_count)
-        svn_priority_queue__update(queue);
-      else
-        svn_priority_queue__pop(queue);
-
-      /* keep memory usage in check */
-      if (i % 256 == 0)
-        svn_pool_clear(iterpool);
-    }
+  /* Let the index code do the expensive L2P -> P2L transformation. */
+  SVN_ERR(svn_fs_x__l2p_index_from_p2l_entries(&temp_name,
+                                               context->fs,
+                                               context->reps,
+                                               pool, scratch_pool));
+
+  /* Append newly written segment to exisiting proto index file. */
+  SVN_ERR(svn_io_file_name_get(&proto_index, context->proto_l2p_index,
+                               scratch_pool));
+
+  SVN_ERR(svn_io_file_flush(context->proto_l2p_index, scratch_pool));
+  SVN_ERR(svn_io_append_file(temp_name, proto_index, scratch_pool));
+  SVN_ERR(svn_io_remove_file2(temp_name, FALSE, scratch_pool));
+  SVN_ERR(svn_io_file_seek(context->proto_l2p_index, APR_END, &offset,
+                           scratch_pool));
 
-  svn_pool_destroy(iterpool);
+  /* Done. */
+  svn_pool_destroy(scratch_pool);
 
   return SVN_NO_ERROR;
 }
@@ -1836,26 +1707,19 @@ pack_range(pack_context_t *context,
   for (revision = context->start_rev; revision < context->end_rev; ++revision)
     {
       apr_off_t offset = 0;
-      apr_finfo_t finfo;
-      apr_file_t *rev_file;
+      svn_fs_x__revision_file_t *rev_file;
 
-      /* Get the size of the file. */
-      const char *path = svn_dirent_join(context->shard_dir,
-                                         apr_psprintf(revpool, "%ld",
-                                                      revision),
-                                         revpool);
-      SVN_ERR(svn_io_stat(&finfo, path, APR_FINFO_SIZE, revpool));
-
-      SVN_ERR(svn_io_file_open(&rev_file, path,
-                               APR_READ | APR_BUFFERED | APR_BINARY,
-                               APR_OS_DEFAULT, revpool));
+      /* Get the rev file dimensions (mainly index locations). */
+      SVN_ERR(svn_fs_x__open_pack_or_rev_file(&rev_file, context->fs,
+                                              revision, revpool, iterpool));
+      SVN_ERR(svn_fs_x__auto_read_footer(rev_file));
 
       /* store the indirect array index */
       APR_ARRAY_PUSH(context->rev_offsets, int) = context->reps->nelts;
   
       /* read the phys-to-log index file until we covered the whole rev file.
        * That index contains enough info to build both target indexes from it. */
-      while (offset < finfo.size)
+      while (offset < rev_file->l2p_offset)
         {
           /* read one cluster */
           int i;
@@ -1863,8 +1727,9 @@ pack_range(pack_context_t *context,
           svn_pool_clear(iterpool);
 
           SVN_ERR(svn_fs_x__p2l_index_lookup(&entries, context->fs,
-                                             revision, offset,
-                                             ffd->p2l_page_size, iterpool));
+                                             rev_file, revision, offset,
+                                             ffd->p2l_page_size, iterpool,
+                                             iterpool));
 
           for (i = 0; i < entries->nelts; ++i)
             {
@@ -1878,9 +1743,9 @@ pack_range(pack_context_t *context,
 
               /* process entry while inside the rev file */
               offset = entry->offset;
-              if (offset < finfo.size)
+              if (offset < rev_file->l2p_offset)
                 {
-                  SVN_ERR(svn_io_file_seek(rev_file, APR_SET, &offset,
+                  SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &offset,
                                            iterpool));
 
                   if (entry->type == SVN_FS_X__ITEM_TYPE_CHANGES)
@@ -1962,7 +1827,7 @@ append_revision(pack_context_t *context,
   fs_x_data_t *ffd = context->fs->fsap_data;
   apr_off_t offset = 0;
   apr_pool_t *iterpool = svn_pool_create(pool);
-  apr_file_t *rev_file;
+  svn_fs_x__revision_file_t *rev_file;
   apr_finfo_t finfo;
 
   /* Get the size of the file. */
@@ -1973,11 +1838,11 @@ append_revision(pack_context_t *context,
   SVN_ERR(svn_io_stat(&finfo, path, APR_FINFO_SIZE, pool));
 
   /* Copy all the bits from the rev file to the end of the pack file. */
-  SVN_ERR(svn_io_file_open(&rev_file, path,
-                           APR_READ | APR_BUFFERED | APR_BINARY,
-                           APR_OS_DEFAULT, pool));
-  SVN_ERR(copy_file_data(context, context->pack_file, rev_file, finfo.size, 
-                         iterpool));
+  SVN_ERR(svn_fs_x__open_pack_or_rev_file(&rev_file, context->fs,
+                                          context->start_rev, pool,
+                                          iterpool));
+  SVN_ERR(copy_file_data(context, context->pack_file, rev_file->file,
+                         finfo.size, iterpool));
 
   /* mark the start of a new revision */
   SVN_ERR(svn_fs_x__l2p_proto_index_add_revision(context->proto_l2p_index,
@@ -1990,9 +1855,10 @@ append_revision(pack_context_t *context,
       /* read one cluster */
       int i;
       apr_array_header_t *entries;
-      SVN_ERR(svn_fs_x__p2l_index_lookup(&entries, context->fs,
-                                          context->start_rev, offset,
-                                          ffd->p2l_page_size, iterpool));
+      SVN_ERR(svn_fs_x__p2l_index_lookup(&entries, context->fs, rev_file,
+                                         context->start_rev, offset,
+                                         ffd->p2l_page_size, iterpool,
+                                         iterpool));
 
       for (i = 0; i < entries->nelts; ++i)
         {
@@ -2075,7 +1941,7 @@ pack_log_addressed(svn_fs_t *fs,
   /* phase 1: determine the size of the revisions to pack */
   SVN_ERR(svn_fs_x__l2p_get_max_ids(&max_ids, fs, shard_rev,
                                     context.shard_end_rev - shard_rev,
-                                    pool));
+                                    pool, pool));
 
   /* pack revisions in ranges that don't exceed MAX_MEM */
   for (i = 0; i < max_ids->nelts; ++i)

Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_x/recovery.c
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_x/recovery.c?rev=1636544&r1=1636543&r2=1636544&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_x/recovery.c (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_x/recovery.c Tue Nov  4 11:40:16 2014
@@ -55,10 +55,11 @@ recover_get_largest_revision(svn_fs_t *f
   while (1)
     {
       svn_error_t *err;
-      apr_file_t *file;
+      svn_fs_x__revision_file_t *file;
       svn_pool_clear(iterpool);
 
-      err = svn_fs_x__open_pack_or_rev_file(&file, fs, right, iterpool);
+      err = svn_fs_x__open_pack_or_rev_file(&file, fs, right, iterpool,
+                                            iterpool);
       if (err && err->apr_err == SVN_ERR_FS_NO_SUCH_REVISION)
         {
           svn_error_clear(err);
@@ -78,10 +79,11 @@ recover_get_largest_revision(svn_fs_t *f
     {
       svn_revnum_t probe = left + ((right - left) / 2);
       svn_error_t *err;
-      apr_file_t *file;
+      svn_fs_x__revision_file_t *file;
       svn_pool_clear(iterpool);
 
-      err = svn_fs_x__open_pack_or_rev_file(&file, fs, probe, iterpool);
+      err = svn_fs_x__open_pack_or_rev_file(&file, fs, probe, iterpool,
+                                            iterpool);
       if (err && err->apr_err == SVN_ERR_FS_NO_SUCH_REVISION)
         {
           svn_error_clear(err);
@@ -122,7 +124,7 @@ recover_body(void *baton, apr_pool_t *po
   svn_node_kind_t youngest_revprops_kind;
 
   /* Lose potentially corrupted data in temp files */
-  SVN_ERR(svn_fs_x__cleanup_revprop_namespace(fs));
+  SVN_ERR(svn_fs_x__reset_revprop_generation_file(fs, pool));
 
   /* We need to know the largest revision in the filesystem. */
   SVN_ERR(recover_get_largest_revision(fs, &max_rev, pool));



Mime
View raw message