You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by iv...@apache.org on 2014/06/25 20:16:51 UTC

svn commit: r1605535 [2/3] - in /subversion/branches/remove-log-addressing: ./ subversion/bindings/javahl/native/ subversion/bindings/javahl/src/org/apache/subversion/javahl/ subversion/bindings/javahl/tests/org/apache/subversion/javahl/ subversion/bin...

Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/low_level.c
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/low_level.c?rev=1605535&r1=1605534&r2=1605535&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/low_level.c (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/low_level.c Wed Jun 25 18:16:50 2014
@@ -150,14 +150,49 @@ svn_fs_fs__parse_revision_trailer(apr_of
 svn_stringbuf_t *
 svn_fs_fs__unparse_revision_trailer(apr_off_t root_offset,
                                     apr_off_t changes_offset,
-                                    apr_pool_t *pool)
+                                    apr_pool_t *result_pool)
 {
-  return svn_stringbuf_createf(pool,
+  return svn_stringbuf_createf(result_pool,
                                "%" APR_OFF_T_FMT " %" APR_OFF_T_FMT "\n",
                                root_offset,
                                changes_offset);
 }
 
+svn_error_t *
+svn_fs_fs__parse_footer(apr_off_t *l2p_offset,
+                        apr_off_t *p2l_offset,
+                        svn_stringbuf_t *footer,
+                        svn_revnum_t rev)
+{
+  apr_int64_t val;
+
+  /* Split the footer into the 2 number strings. */
+  char *seperator = strchr(footer->data, ' ');
+  if (!seperator)
+    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                             _("Revision file (r%ld) has corrupt footer"),
+                             rev);
+  *seperator = '\0';
+
+  /* Convert offset values. */
+  SVN_ERR(svn_cstring_atoi64(&val, footer->data));
+  *l2p_offset = (apr_off_t)val;
+  SVN_ERR(svn_cstring_atoi64(&val, seperator + 1));
+  *p2l_offset = (apr_off_t)val;
+
+  return SVN_NO_ERROR;
+}
+
+svn_stringbuf_t *
+svn_fs_fs__unparse_footer(apr_off_t l2p_offset,
+                          apr_off_t p2l_offset,
+                          apr_pool_t *result_pool)
+{
+  return svn_stringbuf_createf(result_pool,
+                               "%" APR_OFF_T_FMT " %" APR_OFF_T_FMT,
+                               l2p_offset,
+                               p2l_offset);
+}
 
 /* Read the next entry in the changes record from file FILE and store
    the resulting change in *CHANGE_P.  If there is no next record,
@@ -165,7 +200,8 @@ svn_fs_fs__unparse_revision_trailer(apr_
 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;
@@ -176,13 +212,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;
 
@@ -192,7 +228,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_fs__id_parse(str, strlen(str), pool);
+  info->node_rev_id = svn_fs_fs__id_parse(str, result_pool);
   if (info->node_rev_id == NULL)
     return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
                             _("Invalid changes line in rev-file"));
@@ -313,10 +349,10 @@ read_change(change_t **change_p,
   
   /* Get the changed path. */
   change->path.len = strlen(last_str);
-  change->path.data = apr_pstrmemdup(pool, last_str, change->path.len);
+  change->path.data = apr_pstrdup(result_pool, last_str);
 
   /* 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, scratch_pool));
   info->copyfrom_known = TRUE;
   if (eof || line->len == 0)
     {
@@ -336,7 +372,7 @@ read_change(change_t **change_p,
         return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
                                 _("Invalid changes line in rev-file"));
 
-      info->copyfrom_path = apr_pstrdup(pool, last_str);
+      info->copyfrom_path = apr_pstrdup(result_pool, last_str);
     }
 
   *change_p = change;
@@ -347,36 +383,72 @@ read_change(change_t **change_p,
 svn_error_t *
 svn_fs_fs__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 *));
+  /* Pre-allocate enough room for most change lists.
+     (will be auto-expanded as necessary).
 
-  SVN_ERR(read_change(&change, stream, pool));
+     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;
 }
 
+svn_error_t *
+svn_fs_fs__read_changes_incrementally(svn_stream_t *stream,
+                                      svn_fs_fs__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, and copyfrom
    string COPYFROM, into the file specified by FILE.  Only include the
    node kind field if INCLUDE_NODE_KIND is true.  Only include the
    mergeinfo-mod field if INCLUDE_MERGEINFO_MODS is true.  All temporary
-   allocations are in POOL. */
+   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,
                    svn_boolean_t include_node_kind,
                    svn_boolean_t include_mergeinfo_mods,
-                   apr_pool_t *pool)
+                   apr_pool_t *scratch_pool)
 {
   const char *idstr;
   const char *change_string = NULL;
@@ -409,7 +481,7 @@ write_change_entry(svn_stream_t *stream,
     }
 
   if (change->node_rev_id)
-    idstr = svn_fs_fs__id_unparse(change->node_rev_id, pool)->data;
+    idstr = svn_fs_fs__id_unparse(change->node_rev_id, scratch_pool)->data;
   else
     idstr = ACTION_RESET;
 
@@ -417,19 +489,19 @@ write_change_entry(svn_stream_t *stream,
     {
       SVN_ERR_ASSERT(change->node_kind == svn_node_dir
                      || change->node_kind == svn_node_file);
-      kind_string = apr_psprintf(pool, "-%s",
+      kind_string = apr_psprintf(scratch_pool, "-%s",
                                  change->node_kind == svn_node_dir
                                  ? SVN_FS_FS__KIND_DIR
                                   : SVN_FS_FS__KIND_FILE);
     }
 
   if (include_mergeinfo_mods && change->mergeinfo_mod != svn_tristate_unknown)
-    mergeinfo_string = apr_psprintf(pool, " %s",
+    mergeinfo_string = apr_psprintf(scratch_pool, " %s",
                                     change->mergeinfo_mod == svn_tristate_true
                                       ? FLAG_TRUE
                                       : FLAG_FALSE);
 
-  buf = svn_stringbuf_createf(pool, "%s %s%s %s %s%s %s\n",
+  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,
@@ -438,7 +510,7 @@ write_change_entry(svn_stream_t *stream,
 
   if (SVN_IS_VALID_REVNUM(change->copyfrom_rev))
     {
-      svn_stringbuf_appendcstr(buf, apr_psprintf(pool, "%ld %s",
+      svn_stringbuf_appendcstr(buf, apr_psprintf(scratch_pool, "%ld %s",
                                                  change->copyfrom_rev,
                                                  change->copyfrom_path));
     }
@@ -455,9 +527,9 @@ svn_fs_fs__write_changes(svn_stream_t *s
                          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);
   fs_fs_data_t *ffd = fs->fsap_data;
   svn_boolean_t include_node_kinds =
       ffd->format >= SVN_FS_FS__MIN_KIND_IN_CHANGED_FORMAT;
@@ -470,7 +542,8 @@ svn_fs_fs__write_changes(svn_stream_t *s
      that the final file is deterministic and repeatable, however the
      rest of the FSFS code doesn't require any particular order here. */
   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)
@@ -499,13 +572,13 @@ svn_fs_fs__write_changes(svn_stream_t *s
 /* 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)
     {
@@ -515,7 +588,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 */
@@ -562,7 +636,8 @@ read_header_block(apr_hash_t **headers,
 svn_error_t *
 svn_fs_fs__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;
@@ -571,7 +646,7 @@ svn_fs_fs__parse_representation(represen
   svn_checksum_t *checksum;
   const char *end;
 
-  rep = apr_pcalloc(pool, sizeof(*rep));
+  rep = apr_pcalloc(result_pool, sizeof(*rep));
   *rep_p = rep;
 
   str = svn_cstring_tokenize(" ", &string);
@@ -620,7 +695,8 @@ svn_fs_fs__parse_representation(represen
     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));
   memcpy(rep->md5_digest, checksum->digest, sizeof(rep->md5_digest));
 
   /* The remaining fields are only used for formats >= 4, so check that. */
@@ -633,7 +709,8 @@ svn_fs_fs__parse_representation(represen
     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;
   memcpy(rep->sha1_digest, checksum->digest, sizeof(rep->sha1_digest));
 
@@ -666,17 +743,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_fs__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_fs__id_unparse(noderev_id, pool);
+      const svn_string_t *id_unparsed;
       const char *where;
-      where = apr_psprintf(pool,
+
+      id_unparsed = svn_fs_fs__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)");
@@ -694,16 +776,17 @@ read_rep_offsets(representation_t **rep_
 svn_error_t *
 svn_fs_fs__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);
@@ -714,7 +797,7 @@ svn_fs_fs__read_noderev(node_revision_t 
 
   SVN_ERR(svn_stream_close(stream));
 
-  noderev->id = svn_fs_fs__id_parse(value, strlen(value), pool);
+  noderev->id = svn_fs_fs__id_parse(value, result_pool);
   noderev_id = value; /* for error messages later */
 
   /* Read the type. */
@@ -744,7 +827,7 @@ svn_fs_fs__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. */
@@ -752,7 +835,7 @@ svn_fs_fs__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. */
@@ -765,20 +848,19 @@ svn_fs_fs__read_noderev(node_revision_t 
     }
   else
     {
-      noderev->created_path = apr_pstrdup(pool, value);
+      noderev->created_path = apr_pstrdup(result_pool, value);
     }
 
   /* Get the predecessor ID. */
   value = svn_hash_gets(headers, HEADER_PRED);
   if (value)
-    noderev->predecessor_id = svn_fs_fs__id_parse(value, strlen(value),
-                                                  pool);
+    noderev->predecessor_id = svn_fs_fs__id_parse(value, result_pool);
 
   /* Get the copyroot. */
   value = svn_hash_gets(headers, HEADER_COPYROOT);
   if (value == NULL)
     {
-      noderev->copyroot_path = apr_pstrdup(pool, noderev->created_path);
+      noderev->copyroot_path = apr_pstrdup(result_pool, noderev->created_path);
       noderev->copyroot_rev = svn_fs_fs__id_rev(noderev->id);
     }
   else
@@ -797,7 +879,7 @@ svn_fs_fs__read_noderev(node_revision_t 
         return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
                                  _("Malformed copyroot line in node-rev '%s'"),
                                  noderev_id);
-      noderev->copyroot_path = apr_pstrdup(pool, value);
+      noderev->copyroot_path = apr_pstrdup(result_pool, value);
     }
 
   /* Get the copyfrom. */
@@ -821,7 +903,7 @@ svn_fs_fs__read_noderev(node_revision_t 
         return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
                                  _("Malformed copyfrom line in node-rev '%s'"),
                                  noderev_id);
-      noderev->copyfrom_path = apr_pstrdup(pool, value);
+      noderev->copyfrom_path = apr_pstrdup(result_pool, value);
     }
 
   /* Get whether this is a fresh txn root. */
@@ -846,13 +928,13 @@ svn_fs_fs__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;
@@ -861,37 +943,41 @@ 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_fs__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)
 {
   char buffer[SVN_INT64_BUFFER_SIZE];
   if (svn_fs_fs__id_txn_used(&rep->txn_id) && mutable_rep_truncated)
-    return svn_stringbuf_ncreate("-1", 2, pool);
+    return svn_stringbuf_ncreate("-1", 2, result_pool);
 
   if (format < SVN_FS_FS__MIN_REP_SHARING_FORMAT || !rep->has_sha1)
     return svn_stringbuf_createf
-            (pool, "%ld %" APR_UINT64_T_FMT " %" SVN_FILESIZE_T_FMT
+            (result_pool, "%ld %" APR_UINT64_T_FMT " %" SVN_FILESIZE_T_FMT
              " %" SVN_FILESIZE_T_FMT " %s",
              rep->revision, rep->item_index, 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));
 
   svn__ui64tobase36(buffer, rep->uniquifier.number);
   return svn_stringbuf_createf
-          (pool, "%ld %" APR_UINT64_T_FMT " %" SVN_FILESIZE_T_FMT
+          (result_pool, "%ld %" APR_UINT64_T_FMT " %" SVN_FILESIZE_T_FMT
            " %" SVN_FILESIZE_T_FMT " %s %s %s/_%s",
            rep->revision, rep->item_index, 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),
-           svn_fs_fs__id_txn_unparse(&rep->uniquifier.noderev_txn_id, pool),
+                         !rep->has_sha1, scratch_pool),
+           svn_fs_fs__id_txn_unparse(&rep->uniquifier.noderev_txn_id,
+                                     scratch_pool),
            buffer);
 }
 
@@ -901,50 +987,50 @@ svn_fs_fs__write_noderev(svn_stream_t *o
                          node_revision_t *noderev,
                          int format,
                          svn_boolean_t include_mergeinfo,
-                         apr_pool_t *pool)
+                         apr_pool_t *scratch_pool)
 {
-  SVN_ERR(svn_stream_printf(outfile, pool, HEADER_ID ": %s\n",
+  SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_ID ": %s\n",
                             svn_fs_fs__id_unparse(noderev->id,
-                                                  pool)->data));
+                                                  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_FS__KIND_FILE : SVN_FS_FS__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_fs__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_fs__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_fs__unparse_representation
                                 (noderev->prop_rep, format,
-                                 TRUE, pool)->data));
+                                 TRUE, scratch_pool, scratch_pool)->data));
 
-  SVN_ERR(svn_stream_printf(outfile, pool, HEADER_CPATH ": %s\n",
+  SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_CPATH ": %s\n",
                             noderev->created_path));
 
   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,
                               noderev->copyfrom_path));
 
   if ((noderev->copyroot_rev != svn_fs_fs__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,
                               noderev->copyroot_path));
@@ -955,8 +1041,8 @@ svn_fs_fs__write_noderev(svn_stream_t *o
   if (include_mergeinfo)
     {
       if (noderev->mergeinfo_count > 0)
-        SVN_ERR(svn_stream_printf(outfile, pool, HEADER_MINFO_CNT ": %"
-                                  APR_INT64_T_FMT "\n",
+        SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_MINFO_CNT
+                                  ": %" APR_INT64_T_FMT "\n",
                                   noderev->mergeinfo_count));
 
       if (noderev->has_mergeinfo)
@@ -969,16 +1055,17 @@ svn_fs_fs__write_noderev(svn_stream_t *o
 svn_error_t *
 svn_fs_fs__read_rep_header(svn_fs_fs__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_PLAIN) == 0)
     {
@@ -1028,7 +1115,7 @@ svn_fs_fs__read_rep_header(svn_fs_fs__re
 svn_error_t *
 svn_fs_fs__write_rep_header(svn_fs_fs__rep_header_t *header,
                             svn_stream_t *stream,
-                            apr_pool_t *pool)
+                            apr_pool_t *scratch_pool)
 {
   const char *text;
   
@@ -1043,8 +1130,8 @@ svn_fs_fs__write_rep_header(svn_fs_fs__r
         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);
     }

Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/low_level.h
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/low_level.h?rev=1605535&r1=1605534&r2=1605535&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/low_level.h (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/low_level.h Wed Jun 25 18:16:50 2014
@@ -31,7 +31,8 @@
 
 /* The functions are grouped as follows:
  *
- * - revision trailer
+ * - revision trailer (up to format 6)
+ * - revision footer (since format 7)
  * - changed path list
  * - node revision
  * - representation (as in "text:" and "props:" lines)
@@ -54,68 +55,113 @@ svn_fs_fs__parse_revision_trailer(apr_of
 
 /* 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.
+ * revision's trailer.  Allocate it in RESULT_POOL.
  */
 svn_stringbuf_t *
 svn_fs_fs__unparse_revision_trailer(apr_off_t root_offset,
                                     apr_off_t changes_offset,
-                                    apr_pool_t *pool);
+                                    apr_pool_t *result_pool);
 
-/* Read all the changes from STREAM and store them in *CHANGES.  Do all
-   allocations in POOL. */
+/* Given the format 7+ revision / pack FOOTER, parse it destructively
+ * and return the start offsets of the index data in *L2P_OFFSET and
+ * *P2L_OFFSET, respectively.
+ * 
+ * Note that REV is only used to construct nicer error objects that
+ * mention this revision.
+ */
+svn_error_t *
+svn_fs_fs__parse_footer(apr_off_t *l2p_offset,
+                        apr_off_t *p2l_offset,
+                        svn_stringbuf_t *footer,
+                        svn_revnum_t rev);
+
+/* Given the offset of the L2P index data in L2P_OFFSET and the offset of
+ * the P2L index data in P2L_OFFSET,  return the corresponding format 7+
+ * revision / pack file footer.  Allocate it in RESULT_POOL.
+ */
+svn_stringbuf_t *
+svn_fs_fs__unparse_footer(apr_off_t l2p_offset,
+                          apr_off_t p2l_offset,
+                          apr_pool_t *result_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_fs__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_fs__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_fs__read_changes_incrementally(svn_stream_t *stream,
+                                      svn_fs_fs__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.
+   Perform temporary allocations in SCRATCH_POOL.
  */
 svn_error_t *
 svn_fs_fs__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);
 
 /* Read a node-revision from STREAM. Set *NODEREV to the new structure,
-   allocated in POOL. */
+   allocated in RESULT_POOL. */
 svn_error_t *
 svn_fs_fs__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.  Only write mergeinfo-related metadata if
-   INCLUDE_MERGEINFO is true.  Temporary allocations are from POOL. */
+   INCLUDE_MERGEINFO is true.  Temporary allocations are from SCRATCH_POOL. */
 svn_error_t *
 svn_fs_fs__write_noderev(svn_stream_t *outfile,
                          node_revision_t *noderev,
                          int format,
                          svn_boolean_t include_mergeinfo,
-                         apr_pool_t *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_fs__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.  */
+   Allocate the result in RESULT_POOL and temporaries in SCRATCH_POOL. */
 svn_stringbuf_t *
 svn_fs_fs__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);
 
 /* This type enumerates all forms of representations that we support. */
 typedef enum svn_fs_fs__rep_type_t
@@ -156,16 +202,18 @@ typedef struct svn_fs_fs__rep_header_t
   apr_size_t header_size;
 } svn_fs_fs__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_fs__read_rep_header(svn_fs_fs__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 temporary allocations. */
 svn_error_t *
 svn_fs_fs__write_rep_header(svn_fs_fs__rep_header_t *header,
                             svn_stream_t *stream,
-                            apr_pool_t *pool);
+                            apr_pool_t *scratch_pool);

Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/recovery.c
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/recovery.c?rev=1605535&r1=1605534&r2=1605535&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/recovery.c (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/recovery.c Wed Jun 25 18:16:50 2014
@@ -161,7 +161,7 @@ recover_find_max_ids(svn_fs_t *fs,
 
   baton.stream = rev_file->stream;
   SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &offset, pool));
-  SVN_ERR(svn_fs_fs__read_noderev(&noderev, baton.stream, pool));
+  SVN_ERR(svn_fs_fs__read_noderev(&noderev, baton.stream, pool, pool));
 
   /* Check that this is a directory.  It should be. */
   if (noderev->kind != svn_node_dir)
@@ -184,7 +184,7 @@ recover_find_max_ids(svn_fs_t *fs,
   SVN_ERR(svn_fs_fs__item_offset(&offset, fs, rev_file, rev, NULL,
                                  noderev->data_rep->item_index, pool));
   SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &offset, pool));
-  SVN_ERR(svn_fs_fs__read_rep_header(&header, baton.stream, pool));
+  SVN_ERR(svn_fs_fs__read_rep_header(&header, baton.stream, pool, pool));
   if (header->type != svn_fs_fs__rep_plain)
     return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
                             _("Recovery encountered a deltified directory "
@@ -244,7 +244,7 @@ recover_find_max_ids(svn_fs_t *fs,
         return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
                                 _("Directory entry corrupt"));
 
-      id = svn_fs_fs__id_parse(str, strlen(str), iterpool);
+      id = svn_fs_fs__id_parse(str, iterpool);
 
       rev_item = svn_fs_fs__id_rev_item(id);
       if (rev_item->revision != rev)

Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/rev_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/rev_file.c?rev=1605535&r1=1605534&r2=1605535&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/rev_file.c (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/rev_file.c Wed Jun 25 18:16:50 2014
@@ -22,17 +22,18 @@
 
 #include "rev_file.h"
 #include "fs_fs.h"
+#include "low_level.h"
 #include "util.h"
 
 #include "../libsvn_fs/fs-loader.h"
 
 #include "svn_private_config.h"
 
-void
-svn_fs_fs__init_revision_file(svn_fs_fs__revision_file_t *file,
-                              svn_fs_t *fs,
-                              svn_revnum_t revision,
-                              apr_pool_t *pool)
+static void
+init_revision_file(svn_fs_fs__revision_file_t *file,
+                   svn_fs_t *fs,
+                   svn_revnum_t revision,
+                   apr_pool_t *pool)
 {
   fs_fs_data_t *ffd = fs->fsap_data;
 
@@ -118,23 +119,12 @@ svn_fs_fs__open_pack_or_rev_file(svn_fs_
                                  apr_pool_t *pool)
 {
   *file = apr_palloc(pool, sizeof(**file));
-  svn_fs_fs__init_revision_file(*file, fs, rev, pool);
+  init_revision_file(*file, fs, rev, pool);
 
   return svn_error_trace(open_pack_or_rev_file(*file, fs, rev, pool));
 }
 
 svn_error_t *
-svn_fs_fs__reopen_revision_file(svn_fs_fs__revision_file_t *file,
-                                svn_fs_t *fs,
-                                svn_revnum_t rev)
-{
-  if (file->file)
-    svn_fs_fs__close_revision_file(file);
-
-  return svn_error_trace(open_pack_or_rev_file(file, fs, rev, file->pool));
-}
-
-svn_error_t *
 svn_fs_fs__open_proto_rev_file(svn_fs_fs__revision_file_t **file,
                                svn_fs_t *fs,
                                const svn_fs_fs__id_part_t *txn_id,

Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/rev_file.h
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/rev_file.h?rev=1605535&r1=1605534&r2=1605535&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/rev_file.h (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/rev_file.h Wed Jun 25 18:16:50 2014
@@ -38,7 +38,9 @@
 typedef struct svn_fs_fs__packed_number_stream_t
   svn_fs_fs__packed_number_stream_t;
 
-/* All files and associated properties for START_REVISION.
+/* Data file, including indexes data, and associated properties for
+ * START_REVISION.  As the FILE is kept open, background pack operations
+ * will not cause access to this file to fail.
  */
 typedef struct svn_fs_fs__revision_file_t
 {
@@ -49,7 +51,7 @@ typedef struct svn_fs_fs__revision_file_
   /* the revision was packed when the first file / stream got opened */
   svn_boolean_t is_packed;
 
-  /* rev / pack file or NULL if not opened, yet */
+  /* rev / pack file */
   apr_file_t *file;
 
   /* stream based on FILE and not NULL exactly when FILE is not NULL */
@@ -59,15 +61,6 @@ typedef struct svn_fs_fs__revision_file_
   apr_pool_t *pool;
 } svn_fs_fs__revision_file_t;
 
-/* Initialize the FILE data structure for REVISION in FS without actually
- * opening any files.  Use POOL for all future allocations in FILE.
- */
-void
-svn_fs_fs__init_revision_file(svn_fs_fs__revision_file_t *file,
-                              svn_fs_t *fs,
-                              svn_revnum_t revision,
-                              apr_pool_t *pool);
-
 /* Open the correct revision file for REV.  If the filesystem FS has
  * been packed, *FILE will be set to the packed file; otherwise, set *FILE
  * to the revision file for REV.  Return SVN_ERR_FS_NO_SUCH_REVISION if the

Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/temp_serializer.c
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/temp_serializer.c?rev=1605535&r1=1605534&r2=1605535&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/temp_serializer.c (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/temp_serializer.c Wed Jun 25 18:16:50 2014
@@ -1148,18 +1148,15 @@ svn_fs_fs__serialize_changes(void **data
   svn_stringbuf_t *serialized;
   int i;
 
-  /* initialize our auxiliary data structure */
+  /* initialize our auxiliary data structure and link it to the
+   * array elements */
   changes.count = array->nelts;
-  changes.changes = apr_palloc(pool, sizeof(change_t*) * changes.count);
-
-  /* populate it with the array elements */
-  for (i = 0; i < changes.count; ++i)
-    changes.changes[i] = APR_ARRAY_IDX(array, i, change_t*);
+  changes.changes = (change_t **)array->elts;
 
   /* serialize it and all its elements */
   context = svn_temp_serializer__init(&changes,
                                       sizeof(changes),
-                                      changes.count * 100,
+                                      changes.count * 250,
                                       pool);
 
   svn_temp_serializer__push(context,
@@ -1188,19 +1185,21 @@ svn_fs_fs__deserialize_changes(void **ou
 {
   int i;
   changes_data_t *changes = (changes_data_t *)data;
-  apr_array_header_t *array = apr_array_make(pool, changes->count,
-                                             sizeof(change_t *));
+  apr_array_header_t *array = apr_array_make(pool, 0, sizeof(change_t *));
 
   /* de-serialize our auxiliary data structure */
   svn_temp_deserializer__resolve(changes, (void**)&changes->changes);
 
   /* de-serialize each entry and add it to the array */
   for (i = 0; i < changes->count; ++i)
-    {
-      deserialize_change(changes->changes,
-                         (change_t **)&changes->changes[i]);
-      APR_ARRAY_PUSH(array, change_t *) = changes->changes[i];
-    }
+    deserialize_change(changes->changes,
+                       (change_t **)&changes->changes[i]);
+
+  /* Use the changes buffer as the array's data buffer
+   * (DATA remains valid for at least as long as POOL). */
+  array->elts = (char *)changes->changes;
+  array->nelts = changes->count;
+  array->nalloc = changes->count;
 
   /* done */
   *out = array;

Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/transaction.c
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/transaction.c?rev=1605535&r1=1605534&r2=1605535&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/transaction.c (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/transaction.c Wed Jun 25 18:16:50 2014
@@ -43,6 +43,7 @@
 #include "rep-cache.h"
 
 #include "private/svn_fs_util.h"
+#include "private/svn_fspath.h"
 #include "private/svn_sorts_private.h"
 #include "private/svn_subr_private.h"
 #include "private/svn_string_private.h"
@@ -487,12 +488,12 @@ svn_fs_fs__put_node_revision(svn_fs_t *f
 
 /* 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.
+ * Use SCATCH_POOL for temporary allocations.
  */
 static svn_error_t *
 store_sha1_rep_mapping(svn_fs_t *fs,
                        node_revision_t *noderev,
-                       apr_pool_t *pool)
+                       apr_pool_t *scratch_pool)
 {
   fs_fs_data_t *ffd = fs->fsap_data;
 
@@ -506,20 +507,20 @@ store_sha1_rep_mapping(svn_fs_t *fs,
       const char *file_name = path_txn_sha1(fs,
                                             &noderev->data_rep->txn_id,
                                             noderev->data_rep->sha1_digest,
-                                            pool);
+                                            scratch_pool);
       svn_stringbuf_t *rep_string
         = svn_fs_fs__unparse_representation(noderev->data_rep,
                                             ffd->format,
                                             (noderev->kind == svn_node_dir),
-                                            pool);
+                                            scratch_pool, scratch_pool);
       SVN_ERR(svn_io_file_open(&rep_file, file_name,
                                APR_WRITE | APR_CREATE | APR_TRUNCATE
-                               | APR_BUFFERED, APR_OS_DEFAULT, pool));
+                               | APR_BUFFERED, APR_OS_DEFAULT, scratch_pool));
 
       SVN_ERR(svn_io_file_write_full(rep_file, rep_string->data,
-                                     rep_string->len, NULL, pool));
+                                     rep_string->len, NULL, scratch_pool));
 
-      SVN_ERR(svn_io_file_close(rep_file, pool));
+      SVN_ERR(svn_io_file_close(rep_file, scratch_pool));
     }
 
   return SVN_NO_ERROR;
@@ -724,84 +725,72 @@ fold_change(apr_hash_t *changed_paths,
   return SVN_NO_ERROR;
 }
 
-/* Examine all the changed path entries in CHANGES and store them in
+/* An implementation of svn_fs_fs__change_receiver_t.
+   Examine all the changed path entries in CHANGES and store them in
    *CHANGED_PATHS.  Folding is done to remove redundant or unnecessary
    data. Do all allocations in POOL. */
 static svn_error_t *
-process_changes(apr_hash_t *changed_paths,
-                apr_array_header_t *changes,
-                apr_pool_t *pool)
-{
-  apr_pool_t *iterpool = svn_pool_create(pool);
-  int i;
-
-  /* Read in the changes one by one, folding them into our local hash
-     as necessary. */
-
-  for (i = 0; i < changes->nelts; ++i)
-    {
-      /* The ITERPOOL will be cleared at the end of this function
-       * since it is only used rarely and for a single hash iterator.
-       */
-      change_t *change = APR_ARRAY_IDX(changes, i, change_t *);
-
-      SVN_ERR(fold_change(changed_paths, change));
-
-      /* Now, if our change was a deletion or replacement, we have to
-         blow away any changes thus far on paths that are (or, were)
-         children of this path.
-         ### i won't bother with another iteration pool here -- at
-         most we talking about a few extra dups of paths into what
-         is already a temporary subpool.
+process_changes(void *baton,
+                change_t *change,
+                apr_pool_t *scratch_pool)
+{
+  apr_hash_t *changed_paths = baton;
+
+  SVN_ERR(fold_change(changed_paths, change));
+
+  /* Now, if our change was a deletion or replacement, we have to
+     blow away any changes thus far on paths that are (or, were)
+     children of this path.
+     ### i won't bother with another iteration pool here -- at
+     most we talking about a few extra dups of paths into what
+     is already a temporary subpool.
+  */
+
+  if ((change->info.change_kind == svn_fs_path_change_delete)
+       || (change->info.change_kind == svn_fs_path_change_replace))
+    {
+      apr_hash_index_t *hi;
+
+      /* a potential child path must contain at least 2 more chars
+         (the path separator plus at least one char for the name).
+         Also, we should not assume that all paths have been normalized
+         i.e. some might have trailing path separators.
       */
-
-      if ((change->info.change_kind == svn_fs_path_change_delete)
-           || (change->info.change_kind == svn_fs_path_change_replace))
-        {
-          apr_hash_index_t *hi;
-
-          /* a potential child path must contain at least 2 more chars
-             (the path separator plus at least one char for the name).
-             Also, we should not assume that all paths have been normalized
-             i.e. some might have trailing path separators.
-          */
-          apr_ssize_t path_len = change->path.len;
-          apr_ssize_t min_child_len = path_len == 0
-                                    ? 1
-                                    : change->path.data[path_len-1] == '/'
-                                        ? path_len + 1
-                                        : path_len + 2;
-
-          /* CAUTION: This is the inner loop of an O(n^2) algorithm.
-             The number of changes to process may be >> 1000.
-             Therefore, keep the inner loop as tight as possible.
-          */
-          for (hi = apr_hash_first(iterpool, changed_paths);
-               hi;
-               hi = apr_hash_next(hi))
+      apr_ssize_t path_len = change->path.len;
+      apr_ssize_t min_child_len = path_len == 0
+                                ? 1
+                                : change->path.data[path_len-1] == '/'
+                                    ? path_len + 1
+                                    : path_len + 2;
+
+      /* CAUTION: This is the inner loop of an O(n^2) algorithm.
+         The number of changes to process may be >> 1000.
+         Therefore, keep the inner loop as tight as possible.
+      */
+      for (hi = apr_hash_first(scratch_pool, changed_paths);
+           hi;
+           hi = apr_hash_next(hi))
+        {
+          /* KEY is the path. */
+          const void *path;
+          apr_ssize_t klen;
+          apr_hash_this(hi, &path, &klen, NULL);
+
+          /* If we come across a child of our path, remove it.
+             Call svn_fspath__skip_ancestor only if there is a chance that
+             this is actually a sub-path.
+           */
+          if (klen >= min_child_len)
             {
-              /* KEY is the path. */
-              const void *path;
-              apr_ssize_t klen;
-              apr_hash_this(hi, &path, &klen, NULL);
-
-              /* If we come across a child of our path, remove it.
-                 Call svn_dirent_is_child only if there is a chance that
-                 this is actually a sub-path.
-               */
-              if (   klen >= min_child_len
-                  && svn_dirent_is_child(change->path.data, path, iterpool))
+              const char *child;
+
+              child = svn_fspath__skip_ancestor(change->path.data, path);
+              if (child && child[0] != '\0')
                 apr_hash_set(changed_paths, path, klen, NULL);
             }
-
-          /* Clear the per-iteration subpool. */
-          svn_pool_clear(iterpool);
         }
     }
 
-  /* Destroy the per-iteration subpool. */
-  svn_pool_destroy(iterpool);
-
   return SVN_NO_ERROR;
 }
 
@@ -813,7 +802,6 @@ svn_fs_fs__txn_changes_fetch(apr_hash_t 
 {
   apr_file_t *file;
   apr_hash_t *changed_paths = apr_hash_make(pool);
-  apr_array_header_t *changes;
   apr_pool_t *scratch_pool = svn_pool_create(pool);
 
   SVN_ERR(svn_io_file_open(&file,
@@ -821,11 +809,11 @@ svn_fs_fs__txn_changes_fetch(apr_hash_t 
                            APR_READ | APR_BUFFERED, APR_OS_DEFAULT,
                            scratch_pool));
 
-  SVN_ERR(svn_fs_fs__read_changes(&changes,
+  SVN_ERR(svn_fs_fs__read_changes_incrementally(
                                   svn_stream_from_aprfile2(file, TRUE,
                                                            scratch_pool),
+                                  process_changes, changed_paths,
                                   scratch_pool));
-  SVN_ERR(process_changes(changed_paths, changes, pool));
   svn_pool_destroy(scratch_pool);
 
   *changed_paths_p = changed_paths;
@@ -871,7 +859,7 @@ create_new_txn_noderev_from_rev(svn_fs_t
   node_revision_t *noderev;
   const svn_fs_fs__id_part_t *node_id, *copy_id;
 
-  SVN_ERR(svn_fs_fs__get_node_revision(&noderev, fs, src, pool));
+  SVN_ERR(svn_fs_fs__get_node_revision(&noderev, fs, src, pool, pool));
 
   if (svn_fs_fs__id_is_txn(noderev->id))
     return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
@@ -1047,7 +1035,7 @@ svn_fs_fs__create_txn(svn_fs_txn_t **txn
   *txn_p = txn;
 
   /* Create a new root node for this transaction. */
-  SVN_ERR(svn_fs_fs__rev_get_root(&root_id, fs, rev, pool));
+  SVN_ERR(svn_fs_fs__rev_get_root(&root_id, fs, rev, pool, pool));
   SVN_ERR(create_new_txn_noderev_from_rev(fs, &ftd->txn_id, root_id, pool));
 
   /* Create an empty rev file. */
@@ -1195,7 +1183,7 @@ svn_fs_fs__get_txn(transaction_t **txn_p
   SVN_ERR(get_txn_proplist(txn->proplist, fs, txn_id, pool));
   root_id = svn_fs_fs__id_txn_create_root(txn_id, pool);
 
-  SVN_ERR(svn_fs_fs__get_node_revision(&noderev, fs, root_id, pool));
+  SVN_ERR(svn_fs_fs__get_node_revision(&noderev, fs, root_id, pool, pool));
 
   txn->root_id = svn_fs_fs__id_copy(noderev->id, pool);
   txn->base_id = svn_fs_fs__id_copy(noderev->predecessor_id, pool);
@@ -1595,9 +1583,11 @@ struct rep_write_baton
   svn_checksum_ctx_t *md5_checksum_ctx;
   svn_checksum_ctx_t *sha1_checksum_ctx;
 
-  apr_pool_t *pool;
+  /* Local / scratch pool, available for temporary allocations. */
+  apr_pool_t *scratch_pool;
 
-  apr_pool_t *parent_pool;
+  /* Outer / result pool. */
+  apr_pool_t *result_pool;
 };
 
 /* Handler for the write method of the representation writable stream.
@@ -1633,13 +1623,17 @@ shards_spanned(int *spanned,
 {
   fs_fs_data_t *ffd = fs->fsap_data;
   int shard_size = ffd->max_files_per_dir ? ffd->max_files_per_dir : 1;
+  apr_pool_t *iterpool;
 
   int count = walk ? 1 : 0; /* The start of a walk already touches a shard. */
   svn_revnum_t shard, last_shard = ffd->youngest_rev_cache / shard_size;
+  iterpool = svn_pool_create(pool);
   while (walk-- && noderev->predecessor_count)
     {
+      svn_pool_clear(iterpool);
       SVN_ERR(svn_fs_fs__get_node_revision(&noderev, fs,
-                                           noderev->predecessor_id, pool));
+                                           noderev->predecessor_id, pool,
+                                           iterpool));
       shard = svn_fs_fs__id_rev(noderev->id) / shard_size;
       if (shard != last_shard)
         {
@@ -1647,6 +1641,7 @@ shards_spanned(int *spanned,
           last_shard = shard;
         }
     }
+  svn_pool_destroy(iterpool);
 
   *spanned = count;
   return SVN_NO_ERROR;
@@ -1673,6 +1668,7 @@ choose_delta_base(representation_t **rep
   int walk;
   node_revision_t *base;
   fs_fs_data_t *ffd = fs->fsap_data;
+  apr_pool_t *iterpool;
 
   /* If we have no predecessors, or that one is empty, then use the empty
    * stream as a base. */
@@ -1719,9 +1715,15 @@ choose_delta_base(representation_t **rep
      if noderev has ten predecessors and we want the eighth file rev,
      walk back two predecessors.) */
   base = noderev;
+  iterpool = svn_pool_create(pool);
   while ((count++) < noderev->predecessor_count)
-    SVN_ERR(svn_fs_fs__get_node_revision(&base, fs,
-                                         base->predecessor_id, pool));
+    {
+      svn_pool_clear(iterpool);
+      SVN_ERR(svn_fs_fs__get_node_revision(&base, fs,
+                                           base->predecessor_id, pool,
+                                           iterpool));
+    }
+  svn_pool_destroy(iterpool);
 
   /* return a suitable base representation */
   *rep = props ? base->prop_rep : base->data_rep;
@@ -1779,8 +1781,9 @@ rep_write_cleanup(void *data)
   svn_error_t *err;
 
   /* Truncate and close the protorevfile. */
-  err = svn_io_file_trunc(b->file, b->rep_offset, b->pool);
-  err = svn_error_compose_create(err, svn_io_file_close(b->file, b->pool));
+  err = svn_io_file_trunc(b->file, b->rep_offset, b->scratch_pool);
+  err = svn_error_compose_create(err, svn_io_file_close(b->file,
+                                                        b->scratch_pool));
 
   /* Remove our lock regardless of any preceding errors so that the
      being_written flag is always removed and stays consistent with the
@@ -1789,7 +1792,7 @@ rep_write_cleanup(void *data)
   err = svn_error_compose_create(err,
                                  unlock_proto_rev(b->fs,
                                      svn_fs_fs__id_txn_id(b->noderev->id),
-                                     b->lockcookie, b->pool));
+                                     b->lockcookie, b->scratch_pool));
   if (err)
     {
       apr_status_t rc = err->apr_err;
@@ -1826,24 +1829,25 @@ rep_write_get_baton(struct rep_write_bat
   b->md5_checksum_ctx = svn_checksum_ctx_create(svn_checksum_md5, pool);
 
   b->fs = fs;
-  b->parent_pool = pool;
-  b->pool = svn_pool_create(pool);
+  b->result_pool = pool;
+  b->scratch_pool = svn_pool_create(pool);
   b->rep_size = 0;
   b->noderev = noderev;
 
   /* Open the prototype rev file and seek to its end. */
   SVN_ERR(get_writable_proto_rev(&file, &b->lockcookie,
                                  fs, svn_fs_fs__id_txn_id(noderev->id),
-                                 b->pool));
+                                 b->scratch_pool));
 
   b->file = file;
-  b->rep_stream = svn_stream_from_aprfile2(file, TRUE, b->pool);
+  b->rep_stream = svn_stream_from_aprfile2(file, TRUE, b->scratch_pool);
 
-  SVN_ERR(svn_fs_fs__get_file_offset(&b->rep_offset, file, b->pool));
+  SVN_ERR(svn_fs_fs__get_file_offset(&b->rep_offset, file, b->scratch_pool));
 
   /* Get the base for this delta. */
-  SVN_ERR(choose_delta_base(&base_rep, fs, noderev, FALSE, b->pool));
-  SVN_ERR(svn_fs_fs__get_contents(&source, fs, base_rep, TRUE, b->pool));
+  SVN_ERR(choose_delta_base(&base_rep, fs, noderev, FALSE, b->scratch_pool));
+  SVN_ERR(svn_fs_fs__get_contents(&source, fs, base_rep, TRUE,
+                                  b->scratch_pool));
 
   /* Write out the rep header. */
   if (base_rep)
@@ -1857,13 +1861,15 @@ rep_write_get_baton(struct rep_write_bat
     {
       header.type = svn_fs_fs__rep_self_delta;
     }
-  SVN_ERR(svn_fs_fs__write_rep_header(&header, b->rep_stream, b->pool));
+  SVN_ERR(svn_fs_fs__write_rep_header(&header, b->rep_stream,
+                                      b->scratch_pool));
 
   /* Now determine the offset of the actual svndiff data. */
-  SVN_ERR(svn_fs_fs__get_file_offset(&b->delta_start, file, b->pool));
+  SVN_ERR(svn_fs_fs__get_file_offset(&b->delta_start, file,
+                                     b->scratch_pool));
 
   /* Cleanup in case something goes wrong. */
-  apr_pool_cleanup_register(b->pool, b, rep_write_cleanup,
+  apr_pool_cleanup_register(b->scratch_pool, b, rep_write_cleanup,
                             apr_pool_cleanup_null);
 
   /* Prepare to write the svndiff data. */
@@ -1874,7 +1880,8 @@ rep_write_get_baton(struct rep_write_bat
                           ffd->delta_compression_level,
                           pool);
 
-  b->delta_stream = svn_txdelta_target_push(wh, whb, source, b->pool);
+  b->delta_stream = svn_txdelta_target_push(wh, whb, source,
+                                            b->scratch_pool);
 
   *wb_p = b;
 
@@ -1887,15 +1894,16 @@ rep_write_get_baton(struct rep_write_bat
    there may be new duplicate representations within the same uncommitted
    revision, those can be passed in REPS_HASH (maps a sha1 digest onto
    representation_t*), otherwise pass in NULL for REPS_HASH.
-   POOL will be used for allocations. The lifetime of the returned rep is
-   limited by both, POOL and REP lifetime.
+   Use RESULT_POOL for *OLD_REP  allocations and SCRATCH_POOL for temporaries.
+   The lifetime of *OLD_REP is limited by both, RESULT_POOL and REP lifetime.
  */
 static svn_error_t *
 get_shared_rep(representation_t **old_rep,
                svn_fs_t *fs,
                representation_t *rep,
                apr_hash_t *reps_hash,
-               apr_pool_t *pool)
+               apr_pool_t *result_pool,
+               apr_pool_t *scratch_pool)
 {
   svn_error_t *err;
   fs_fs_data_t *ffd = fs->fsap_data;
@@ -1919,12 +1927,12 @@ get_shared_rep(representation_t **old_re
       svn_checksum_t checksum;
       checksum.digest = rep->sha1_digest;
       checksum.kind = svn_checksum_sha1;
-      err = svn_fs_fs__get_rep_reference(old_rep, fs, &checksum, pool);
+      err = svn_fs_fs__get_rep_reference(old_rep, fs, &checksum, result_pool);
       /* ### Other error codes that we shouldn't mask out? */
       if (err == SVN_NO_ERROR)
         {
           if (*old_rep)
-            SVN_ERR(svn_fs_fs__check_rep(*old_rep, fs, NULL, pool));
+            SVN_ERR(svn_fs_fs__check_rep(*old_rep, fs, NULL, scratch_pool));
         }
       else if (err->apr_err == SVN_ERR_FS_CORRUPT
                || SVN_ERROR_IN_CATEGORY(err->apr_err,
@@ -1957,17 +1965,19 @@ get_shared_rep(representation_t **old_re
     {
       svn_node_kind_t kind;
       const char *file_name
-        = path_txn_sha1(fs, &rep->txn_id, rep->sha1_digest, pool);
+        = path_txn_sha1(fs, &rep->txn_id, rep->sha1_digest, scratch_pool);
 
       /* in our txn, is there a rep file named with the wanted SHA1?
          If so, read it and use that rep.
        */
-      SVN_ERR(svn_io_check_path(file_name, &kind, pool));
+      SVN_ERR(svn_io_check_path(file_name, &kind, scratch_pool));
       if (kind == svn_node_file)
         {
           svn_stringbuf_t *rep_string;
-          SVN_ERR(svn_stringbuf_from_file2(&rep_string, file_name, pool));
-          SVN_ERR(svn_fs_fs__parse_representation(old_rep, rep_string, pool));
+          SVN_ERR(svn_stringbuf_from_file2(&rep_string, file_name,
+                                           scratch_pool));
+          SVN_ERR(svn_fs_fs__parse_representation(old_rep, rep_string,
+                                                  result_pool, scratch_pool));
         }
     }
 
@@ -2014,7 +2024,7 @@ rep_write_contents_close(void *baton)
   representation_t *old_rep;
   apr_off_t offset;
 
-  rep = apr_pcalloc(b->parent_pool, sizeof(*rep));
+  rep = apr_pcalloc(b->result_pool, sizeof(*rep));
 
   /* Close our delta stream so the last bits of svndiff are written
      out. */
@@ -2022,27 +2032,28 @@ rep_write_contents_close(void *baton)
     SVN_ERR(svn_stream_close(b->delta_stream));
 
   /* Determine the length of the svndiff data. */
-  SVN_ERR(svn_fs_fs__get_file_offset(&offset, b->file, b->pool));
+  SVN_ERR(svn_fs_fs__get_file_offset(&offset, b->file, b->scratch_pool));
   rep->size = offset - b->delta_start;
 
   /* Fill in the rest of the representation field. */
   rep->expanded_size = b->rep_size;
   rep->txn_id = *svn_fs_fs__id_txn_id(b->noderev->id);
-  SVN_ERR(set_uniquifier(b->fs, rep, b->pool));
+  SVN_ERR(set_uniquifier(b->fs, rep, b->scratch_pool));
   rep->revision = SVN_INVALID_REVNUM;
 
   /* Finalize the checksum. */
   SVN_ERR(digests_final(rep, b->md5_checksum_ctx, b->sha1_checksum_ctx,
-                        b->parent_pool));
+                        b->result_pool));
 
   /* Check and see if we already have a representation somewhere that's
      identical to the one we just wrote out. */
-  SVN_ERR(get_shared_rep(&old_rep, b->fs, rep, NULL, b->parent_pool));
+  SVN_ERR(get_shared_rep(&old_rep, b->fs, rep, NULL, b->result_pool,
+                         b->scratch_pool));
 
   if (old_rep)
     {
       /* We need to erase from the protorev the data we just wrote. */
-      SVN_ERR(svn_io_file_trunc(b->file, b->rep_offset, b->pool));
+      SVN_ERR(svn_io_file_trunc(b->file, b->rep_offset, b->scratch_pool));
 
       /* Use the old rep for this content. */
       b->noderev->data_rep = old_rep;
@@ -2057,19 +2068,20 @@ rep_write_contents_close(void *baton)
     }
 
   /* Remove cleanup callback. */
-  apr_pool_cleanup_kill(b->pool, b, rep_write_cleanup);
+  apr_pool_cleanup_kill(b->scratch_pool, b, rep_write_cleanup);
 
   /* Write out the new node-rev information. */
   SVN_ERR(svn_fs_fs__put_node_revision(b->fs, b->noderev->id, b->noderev,
-                                       FALSE, b->pool));
+                                       FALSE, b->scratch_pool));
   if (!old_rep)
     {
-      SVN_ERR(store_sha1_rep_mapping(b->fs, b->noderev, b->pool));
+      SVN_ERR(store_sha1_rep_mapping(b->fs, b->noderev, b->scratch_pool));
     }
 
-  SVN_ERR(svn_io_file_close(b->file, b->pool));
-  SVN_ERR(unlock_proto_rev(b->fs, &rep->txn_id, b->lockcookie, b->pool));
-  svn_pool_destroy(b->pool);
+  SVN_ERR(svn_io_file_close(b->file, b->scratch_pool));
+  SVN_ERR(unlock_proto_rev(b->fs, &rep->txn_id, b->lockcookie,
+                           b->scratch_pool));
+  svn_pool_destroy(b->scratch_pool);
 
   return SVN_NO_ERROR;
 }
@@ -2247,7 +2259,7 @@ write_directory_to_stream(svn_stream_t *
    found, we will truncate the one just written from the file and return
    the existing rep.  If FINAL_REVISION is not SVN_INVALID_REVNUM, use it
    to determine whether to write to the proto-index files.
-   Perform temporary allocations in POOL. */
+   Perform temporary allocations in SCRATCH_POOL. */
 static svn_error_t *
 write_container_rep(representation_t *rep,
                     apr_file_t *file,
@@ -2257,40 +2269,41 @@ write_container_rep(representation_t *re
                     apr_hash_t *reps_hash,
                     int item_type,
                     svn_revnum_t final_revision,
-                    apr_pool_t *pool)
+                    apr_pool_t *scratch_pool)
 {
   svn_stream_t *stream;
   struct write_container_baton *whb;
   representation_t *old_rep;
   apr_off_t offset = 0;
 
-  SVN_ERR(svn_fs_fs__get_file_offset(&offset, file, pool));
+  SVN_ERR(svn_fs_fs__get_file_offset(&offset, file, scratch_pool));
 
-  whb = apr_pcalloc(pool, sizeof(*whb));
+  whb = apr_pcalloc(scratch_pool, sizeof(*whb));
 
-  whb->stream = svn_stream_from_aprfile2(file, TRUE, pool);
+  whb->stream = svn_stream_from_aprfile2(file, TRUE, scratch_pool);
   whb->size = 0;
-  whb->md5_ctx = svn_checksum_ctx_create(svn_checksum_md5, pool);
-  whb->sha1_ctx = svn_checksum_ctx_create(svn_checksum_sha1, pool);
+  whb->md5_ctx = svn_checksum_ctx_create(svn_checksum_md5, scratch_pool);
+  whb->sha1_ctx = svn_checksum_ctx_create(svn_checksum_sha1, scratch_pool);
 
-  stream = svn_stream_create(whb, pool);
+  stream = svn_stream_create(whb, scratch_pool);
   svn_stream_set_write(stream, write_container_handler);
 
   SVN_ERR(svn_stream_puts(whb->stream, "PLAIN\n"));
 
-  SVN_ERR(writer(stream, collection, pool));
+  SVN_ERR(writer(stream, collection, scratch_pool));
 
   /* Store the results. */
-  SVN_ERR(digests_final(rep, whb->md5_ctx, whb->sha1_ctx, pool));
+  SVN_ERR(digests_final(rep, whb->md5_ctx, whb->sha1_ctx, scratch_pool));
 
   /* Check and see if we already have a representation somewhere that's
      identical to the one we just wrote out. */
-  SVN_ERR(get_shared_rep(&old_rep, fs, rep, reps_hash, pool));
+  SVN_ERR(get_shared_rep(&old_rep, fs, rep, reps_hash, scratch_pool,
+                         scratch_pool));
 
   if (old_rep)
     {
       /* We need to erase from the protorev the data we just wrote. */
-      SVN_ERR(svn_io_file_trunc(file, offset, pool));
+      SVN_ERR(svn_io_file_trunc(file, offset, scratch_pool));
 
       /* Use the old rep for this content. */
       memcpy(rep, old_rep, sizeof (*rep));
@@ -2321,7 +2334,8 @@ write_container_rep(representation_t *re
    If ITEM_TYPE is IS_PROPS equals SVN_FS_FS__ITEM_TYPE_*_PROPS, assume
    that we want to a props representation as the base for our delta.
    If FINAL_REVISION is not SVN_INVALID_REVNUM, use it to determine whether
-   to write to the proto-index files.  Perform temporary allocations in POOL.
+   to write to the proto-index files.
+   Perform temporary allocations in SCRATCH_POOL.
  */
 static svn_error_t *
 write_container_delta_rep(representation_t *rep,
@@ -2333,7 +2347,7 @@ write_container_delta_rep(representation
                           apr_hash_t *reps_hash,
                           int item_type,
                           svn_revnum_t final_revision,
-                          apr_pool_t *pool)
+                          apr_pool_t *scratch_pool)
 {
   svn_txdelta_window_handler_t diff_wh;
   void *diff_whb;
@@ -2356,10 +2370,10 @@ write_container_delta_rep(representation
                         || (item_type == SVN_FS_FS__ITEM_TYPE_DIR_PROPS);
 
   /* Get the base for this delta. */
-  SVN_ERR(choose_delta_base(&base_rep, fs, noderev, is_props, pool));
-  SVN_ERR(svn_fs_fs__get_contents(&source, fs, base_rep, FALSE, pool));
+  SVN_ERR(choose_delta_base(&base_rep, fs, noderev, is_props, scratch_pool));
+  SVN_ERR(svn_fs_fs__get_contents(&source, fs, base_rep, FALSE, scratch_pool));
 
-  SVN_ERR(svn_fs_fs__get_file_offset(&offset, file, pool));
+  SVN_ERR(svn_fs_fs__get_file_offset(&offset, file, scratch_pool));
 
   /* Write out the rep header. */
   if (base_rep)
@@ -2374,9 +2388,9 @@ write_container_delta_rep(representation
       header.type = svn_fs_fs__rep_self_delta;
     }
 
-  file_stream = svn_stream_from_aprfile2(file, TRUE, pool);
-  SVN_ERR(svn_fs_fs__write_rep_header(&header, file_stream, pool));
-  SVN_ERR(svn_fs_fs__get_file_offset(&delta_start, file, pool));
+  file_stream = svn_stream_from_aprfile2(file, TRUE, scratch_pool);
+  SVN_ERR(svn_fs_fs__write_rep_header(&header, file_stream, scratch_pool));
+  SVN_ERR(svn_fs_fs__get_file_offset(&delta_start, file, scratch_pool));
 
   /* Prepare to write the svndiff data. */
   svn_txdelta_to_svndiff3(&diff_wh,
@@ -2384,32 +2398,34 @@ write_container_delta_rep(representation
                           file_stream,
                           diff_version,
                           ffd->delta_compression_level,
-                          pool);
+                          scratch_pool);
 
-  whb = apr_pcalloc(pool, sizeof(*whb));
-  whb->stream = svn_txdelta_target_push(diff_wh, diff_whb, source, pool);
+  whb = apr_pcalloc(scratch_pool, sizeof(*whb));
+  whb->stream = svn_txdelta_target_push(diff_wh, diff_whb, source,
+                                        scratch_pool);
   whb->size = 0;
-  whb->md5_ctx = svn_checksum_ctx_create(svn_checksum_md5, pool);
-  whb->sha1_ctx = svn_checksum_ctx_create(svn_checksum_sha1, pool);
+  whb->md5_ctx = svn_checksum_ctx_create(svn_checksum_md5, scratch_pool);
+  whb->sha1_ctx = svn_checksum_ctx_create(svn_checksum_sha1, scratch_pool);
 
   /* serialize the hash */
-  stream = svn_stream_create(whb, pool);
+  stream = svn_stream_create(whb, scratch_pool);
   svn_stream_set_write(stream, write_container_handler);
 
-  SVN_ERR(writer(stream, collection, pool));
+  SVN_ERR(writer(stream, collection, scratch_pool));
   SVN_ERR(svn_stream_close(whb->stream));
 
   /* Store the results. */
-  SVN_ERR(digests_final(rep, whb->md5_ctx, whb->sha1_ctx, pool));
+  SVN_ERR(digests_final(rep, whb->md5_ctx, whb->sha1_ctx, scratch_pool));
 
   /* Check and see if we already have a representation somewhere that's
      identical to the one we just wrote out. */
-  SVN_ERR(get_shared_rep(&old_rep, fs, rep, reps_hash, pool));
+  SVN_ERR(get_shared_rep(&old_rep, fs, rep, reps_hash, scratch_pool,
+                         scratch_pool));
 
   if (old_rep)
     {
       /* We need to erase from the protorev the data we just wrote. */
-      SVN_ERR(svn_io_file_trunc(file, offset, pool));
+      SVN_ERR(svn_io_file_trunc(file, offset, scratch_pool));
 
       /* Use the old rep for this content. */
       memcpy(rep, old_rep, sizeof (*rep));
@@ -2417,7 +2433,7 @@ write_container_delta_rep(representation
   else
     {
       /* Write out our cosmetic end marker. */
-      SVN_ERR(svn_fs_fs__get_file_offset(&rep_end, file, pool));
+      SVN_ERR(svn_fs_fs__get_file_offset(&rep_end, file, scratch_pool));
       SVN_ERR(svn_stream_puts(file_stream, "ENDREP\n"));
 
       /* update the representation */
@@ -2456,8 +2472,7 @@ validate_root_noderev(svn_fs_t *fs,
     SVN_ERR(svn_fs_fs__revision_root(&head_revision, fs, head_revnum, pool));
     SVN_ERR(svn_fs_fs__node_id(&head_root_id, head_revision, "/", pool));
     SVN_ERR(svn_fs_fs__get_node_revision(&head_root_noderev, fs, head_root_id,
-                                         pool));
-
+                                         pool, pool));
     head_predecessor_count = head_root_noderev->predecessor_count;
   }
 
@@ -2561,6 +2576,7 @@ write_final_rev(const svn_fs_id_t **new_
   svn_fs_fs__id_part_t node_id, copy_id, rev_item;
   fs_fs_data_t *ffd = fs->fsap_data;
   svn_stream_t *file_stream;
+  apr_pool_t *subpool;
 
   *new_id_p = NULL;
 
@@ -2568,16 +2584,15 @@ write_final_rev(const svn_fs_id_t **new_
   if (! svn_fs_fs__id_is_txn(id))
     return SVN_NO_ERROR;
 
-  SVN_ERR(svn_fs_fs__get_node_revision(&noderev, fs, id, pool));
+  subpool = svn_pool_create(pool);
+  SVN_ERR(svn_fs_fs__get_node_revision(&noderev, fs, id, pool, subpool));
 
   if (noderev->kind == svn_node_dir)
     {
-      apr_pool_t *subpool;
       apr_array_header_t *entries;
       int i;
 
       /* This is a directory.  Write out all the children first. */
-      subpool = svn_pool_create(pool);
 
       SVN_ERR(svn_fs_fs__rep_contents_dir(&entries, fs, noderev, pool,
                                           subpool));
@@ -2594,7 +2609,6 @@ write_final_rev(const svn_fs_id_t **new_
           if (new_id && (svn_fs_fs__id_rev(new_id) == rev))
             dirent->id = svn_fs_fs__id_copy(new_id, pool);
         }
-      svn_pool_destroy(subpool);
 
       if (noderev->data_rep && is_txn_rep(noderev->data_rep))
         {
@@ -2637,6 +2651,8 @@ write_final_rev(const svn_fs_id_t **new_
         }
     }
 
+  svn_pool_destroy(subpool);
+
   /* Fix up the property reps. */
   if (noderev->prop_rep && is_txn_rep(noderev->prop_rep))
     {
@@ -2840,36 +2856,37 @@ write_final_current(svn_fs_t *fs,
 static svn_error_t *
 verify_locks(svn_fs_t *fs,
              const svn_fs_fs__id_part_t *txn_id,
+             apr_hash_t *changed_paths,
              apr_pool_t *pool)
 {
   apr_pool_t *subpool = svn_pool_create(pool);
-  apr_hash_t *changes;
   apr_hash_index_t *hi;
-  apr_array_header_t *changed_paths;
+  apr_array_header_t *changed_paths_sorted;
   svn_stringbuf_t *last_recursed = NULL;
   int i;
 
-  /* Fetch the changes for this transaction. */
-  SVN_ERR(svn_fs_fs__txn_changes_fetch(&changes, fs, txn_id, pool));
-
   /* Make an array of the changed paths, and sort them depth-first-ily.  */
-  changed_paths = apr_array_make(pool, apr_hash_count(changes) + 1,
-                                 sizeof(const char *));
-  for (hi = apr_hash_first(pool, changes); hi; hi = apr_hash_next(hi))
-    APR_ARRAY_PUSH(changed_paths, const char *) = svn__apr_hash_index_key(hi);
-  svn_sort__array(changed_paths, svn_sort_compare_paths);
+  changed_paths_sorted = apr_array_make(pool,
+                                        apr_hash_count(changed_paths) + 1,
+                                        sizeof(const char *));
+  for (hi = apr_hash_first(pool, changed_paths); hi; hi = apr_hash_next(hi))
+    {
+      APR_ARRAY_PUSH(changed_paths_sorted, const char *) =
+        svn__apr_hash_index_key(hi);
+    }
+  svn_sort__array(changed_paths_sorted, svn_sort_compare_paths);
 
   /* Now, traverse the array of changed paths, verify locks.  Note
      that if we need to do a recursive verification a path, we'll skip
      over children of that path when we get to them. */
-  for (i = 0; i < changed_paths->nelts; i++)
+  for (i = 0; i < changed_paths_sorted->nelts; i++)
     {
       const char *path;
       svn_fs_path_change2_t *change;
       svn_boolean_t recurse = TRUE;
 
       svn_pool_clear(subpool);
-      path = APR_ARRAY_IDX(changed_paths, i, const char *);
+      path = APR_ARRAY_IDX(changed_paths_sorted, i, const char *);
 
       /* If this path has already been verified as part of a recursive
          check of one of its parents, no need to do it again.  */
@@ -2878,7 +2895,7 @@ verify_locks(svn_fs_t *fs,
         continue;
 
       /* Fetch the change associated with our path.  */
-      change = svn_hash_gets(changes, path);
+      change = svn_hash_gets(changed_paths, path);
 
       /* What does it mean to succeed at lock verification for a given
          path?  For an existing file or directory getting modified
@@ -3030,17 +3047,17 @@ commit_body(void *baton, apr_pool_t *poo
     return svn_error_create(SVN_ERR_FS_TXN_OUT_OF_DATE, NULL,
                             _("Transaction out of date"));
 
-  /* Locks may have been added (or stolen) between the calling of
-     previous svn_fs.h functions and svn_fs_commit_txn(), so we need
-     to re-examine every changed-path in the txn and re-verify all
-     discovered locks. */
-  SVN_ERR(verify_locks(cb->fs, txn_id, pool));
-
   /* We need the changes list for verification as well as for writing it
      to the final rev file. */
   SVN_ERR(svn_fs_fs__txn_changes_fetch(&changed_paths, cb->fs, txn_id,
                                        pool));
 
+  /* Locks may have been added (or stolen) between the calling of
+     previous svn_fs.h functions and svn_fs_commit_txn(), so we need
+     to re-examine every changed-path in the txn and re-verify all
+     discovered locks. */
+  SVN_ERR(verify_locks(cb->fs, txn_id, changed_paths, pool));
+
   /* We are going to be one better than this puny old revision. */
   new_rev = old_rev + 1;
 
@@ -3335,7 +3352,7 @@ svn_fs_fs__delete_node_revision(svn_fs_t
 {
   node_revision_t *noderev;
 
-  SVN_ERR(svn_fs_fs__get_node_revision(&noderev, fs, id, pool));
+  SVN_ERR(svn_fs_fs__get_node_revision(&noderev, fs, id, pool, pool));
 
   /* Delete any mutable property representation. */
   if (noderev->prop_rep && is_txn_rep(noderev->prop_rep))

Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/transaction.h
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/transaction.h?rev=1605535&r1=1605534&r2=1605535&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/transaction.h (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/transaction.h Wed Jun 25 18:16:50 2014
@@ -198,6 +198,18 @@ svn_fs_fs__set_proplist(svn_fs_t *fs,
                         apr_hash_t *proplist,
                         apr_pool_t *pool);
 
+/* Append the L2P and P2L indexes given by their proto index file names
+ * L2P_PROTO_INDEX and P2L_PROTO_INDEX to the revision / pack FILE.
+ * The latter contains revision(s) starting at REVISION in FS.
+ * Use POOL for temporary allocations.  */
+svn_error_t *
+svn_fs_fs__add_index_data(svn_fs_t *fs,
+                          apr_file_t *file,
+                          const char *l2p_proto_index,
+                          const char *p2l_proto_index,
+                          svn_revnum_t revision,
+                          apr_pool_t *pool);
+
 /* Commit the transaction TXN in filesystem FS and return its new
    revision number in *REV.  If the transaction is out of date, return
    the error SVN_ERR_FS_TXN_OUT_OF_DATE. Use POOL for temporary

Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/tree.c?rev=1605535&r1=1605534&r2=1605535&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/tree.c (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/tree.c Wed Jun 25 18:16:50 2014
@@ -416,7 +416,9 @@ cache_lookup( fs_fs_dag_cache_t *cache
 /* 2nd level cache */
 
 /* Find and return the DAG node cache for ROOT and the key that
-   should be used for PATH. */
+   should be used for PATH.
+
+   Pool will only be used for allocating a new keys if necessary */
 static void
 locate_cache(svn_cache__t **cache,
              const char **key,
@@ -427,15 +429,20 @@ locate_cache(svn_cache__t **cache,
   if (root->is_txn_root)
     {
       fs_txn_root_data_t *frd = root->fsap_data;
-      if (cache) *cache = frd->txn_node_cache;
-      if (key && path) *key = path;
+
+      if (cache)
+        *cache = frd->txn_node_cache;
+      if (key && path)
+        *key = path;
     }
   else
     {
       fs_fs_data_t *ffd = root->fs->fsap_data;
-      if (cache) *cache = ffd->rev_node_cache;
-      if (key && path) *key
-        = svn_fs_fs__combine_number_and_string(root->rev, path, pool);
+
+      if (cache)
+        *cache = ffd->rev_node_cache;
+      if (key && path)
+        *key = svn_fs_fs__combine_number_and_string(root->rev, path, pool);
     }
 }
 
@@ -1856,11 +1863,19 @@ merge(svn_stringbuf_t *conflict_p,
   {
     node_revision_t *tgt_nr, *anc_nr, *src_nr;
     svn_boolean_t same;
+    apr_pool_t *scratch_pool;
 
     /* Get node revisions for our id's. */
-    SVN_ERR(svn_fs_fs__get_node_revision(&tgt_nr, fs, target_id, pool));
-    SVN_ERR(svn_fs_fs__get_node_revision(&anc_nr, fs, ancestor_id, pool));
-    SVN_ERR(svn_fs_fs__get_node_revision(&src_nr, fs, source_id, pool));
+    scratch_pool = svn_pool_create(pool);
+    SVN_ERR(svn_fs_fs__get_node_revision(&tgt_nr, fs, target_id, pool,
+                                         scratch_pool));
+    svn_pool_clear(scratch_pool);
+    SVN_ERR(svn_fs_fs__get_node_revision(&anc_nr, fs, ancestor_id, pool,
+                                         scratch_pool));
+    svn_pool_clear(scratch_pool);
+    SVN_ERR(svn_fs_fs__get_node_revision(&src_nr, fs, source_id, pool,
+                                         scratch_pool));
+    svn_pool_destroy(scratch_pool);
 
     /* Now compare the prop-keys of the skels.  Note that just because
        the keys are different -doesn't- mean the proplists have
@@ -2518,65 +2533,6 @@ fs_same_p(svn_boolean_t *same_p,
   return SVN_NO_ERROR;
 }
 
-/* Set CHANGES to TRUE if PATH in ROOT is unchanged in REVISION if the
-   same files system.  If the content is identical, parent path copies and
-   deletions still count as changes.  Use POOL for temporary allocations.
-   Not that we will return an error if PATH does not exist in ROOT or
-   REVISION- */
-static svn_error_t *
-is_changed_node(svn_boolean_t *changed,
-                svn_fs_root_t *root,
-                const char *path,
-                svn_revnum_t revision,
-                apr_pool_t *pool)
-{
-  dag_node_t *node, *rev_node;
-  svn_fs_root_t *rev_root;
-  svn_fs_root_t *copy_from_root1, *copy_from_root2;
-  const char *copy_from_path1, *copy_from_path2;
-
-  SVN_ERR(svn_fs_fs__revision_root(&rev_root, root->fs, revision, pool));
-
-  /* Get the NODE for FROM_PATH in FROM_ROOT.*/
-  SVN_ERR(get_dag(&node, root, path, TRUE, pool));
-  SVN_ERR(get_dag(&rev_node, rev_root, path, TRUE, pool));
-
-  /* different ID -> got changed */
-  if (!svn_fs_fs__id_eq(svn_fs_fs__dag_get_id(node),
-                        svn_fs_fs__dag_get_id(rev_node)))
-    {
-      *changed = TRUE;
-       return SVN_NO_ERROR;
-    }
-
-  /* same node. might still be a lazy copy with separate history */
-  SVN_ERR(fs_closest_copy(&copy_from_root1, &copy_from_path1, root,
-                          path, pool));
-  SVN_ERR(fs_closest_copy(&copy_from_root2, &copy_from_path2, rev_root,
-                          path, pool));
-
-  if (copy_from_root1 == NULL && copy_from_root2 == NULL)
-    {
-      /* never copied -> same line of history */
-      *changed = FALSE;
-    }
-  else if (copy_from_root1 != NULL && copy_from_root2 != NULL)
-    {
-      /* both got copied. At the same time & location? */
-      *changed = (copy_from_root1->rev != copy_from_root2->rev)
-                 || strcmp(copy_from_path1, copy_from_path2);
-    }
-  else
-    {
-      /* one is a copy while the other one is not
-       * -> different lines of history */
-      *changed = TRUE;
-    }
-
-  return SVN_NO_ERROR;
-}
-
-
 /* Copy the node at FROM_PATH under FROM_ROOT to TO_PATH under
    TO_ROOT.  If PRESERVE_HISTORY is set, then the copy is recorded in
    the copies table.  Perform temporary allocations in POOL. */
@@ -4475,7 +4431,7 @@ verify_node(dag_node_t *node,
               /* access mergeinfo counter with minimal overhead */
               node_revision_t *noderev;
               SVN_ERR(svn_fs_fs__get_node_revision(&noderev, fs, dirent->id,
-                                                   iterpool));
+                                                   iterpool, iterpool));
               child_mergeinfo = noderev->mergeinfo_count;
             }