You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2015/01/21 17:22:22 UTC

svn commit: r1653578 [15/18] - in /subversion/branches/pin-externals: ./ notes/ subversion/bindings/swig/ subversion/bindings/swig/include/ subversion/bindings/swig/perl/native/ subversion/bindings/swig/perl/native/t/ subversion/bindings/swig/python/te...

Modified: subversion/branches/pin-externals/subversion/libsvn_repos/dump.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_repos/dump.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_repos/dump.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_repos/dump.c Wed Jan 21 16:22:19 2015
@@ -38,6 +38,7 @@
 #include "svn_props.h"
 #include "svn_sorts.h"
 
+#include "private/svn_repos_private.h"
 #include "private/svn_mergeinfo_private.h"
 #include "private/svn_fs_private.h"
 #include "private/svn_sorts_private.h"
@@ -356,6 +357,7 @@ store_delta(apr_file_t **tempfile, svn_f
    with message WARNING_FMT formatted with the remaining variable arguments.
    Send it by calling NOTIFY_FUNC (if not null) with NOTIFY_BATON.
  */
+__attribute__((format(printf, 5, 6)))
 static void
 notify_warning(apr_pool_t *scratch_pool,
                svn_repos_notify_func_t notify_func,
@@ -382,6 +384,187 @@ notify_warning(apr_pool_t *scratch_pool,
 
 /*----------------------------------------------------------------------*/
 
+/* Write to STREAM the header in HEADERS named KEY, if present.
+ */
+static svn_error_t *
+write_header(svn_stream_t *stream,
+             apr_hash_t *headers,
+             const char *key,
+             apr_pool_t *scratch_pool)
+{
+  const char *val = svn_hash_gets(headers, key);
+
+  if (val)
+    {
+      SVN_ERR(svn_stream_printf(stream, scratch_pool,
+                                "%s: %s\n", key, val));
+    }
+  return SVN_NO_ERROR;
+}
+
+/* Write headers, in arbitrary order.
+ * ### TODO: use a stable order
+ * ### Modifies HEADERS.
+ */
+static svn_error_t *
+write_revision_headers(svn_stream_t *stream,
+                       apr_hash_t *headers,
+                       apr_pool_t *scratch_pool)
+{
+  const char **h;
+  apr_hash_index_t *hi;
+
+  static const char *revision_headers_order[] =
+  {
+    SVN_REPOS_DUMPFILE_REVISION_NUMBER,  /* must be first */
+    NULL
+  };
+
+  /* Write some headers in a given order */
+  for (h = revision_headers_order; *h; h++)
+    {
+      SVN_ERR(write_header(stream, headers, *h, scratch_pool));
+      svn_hash_sets(headers, *h, NULL);
+    }
+
+  /* Write any and all remaining headers except Content-length.
+   * ### TODO: use a stable order
+   */
+  for (hi = apr_hash_first(scratch_pool, headers); hi; hi = apr_hash_next(hi))
+    {
+      const char *key = apr_hash_this_key(hi);
+
+      if (strcmp(key, SVN_REPOS_DUMPFILE_CONTENT_LENGTH) != 0)
+        SVN_ERR(write_header(stream, headers, key, scratch_pool));
+    }
+
+  /* Content-length must be last */
+  SVN_ERR(write_header(stream, headers, SVN_REPOS_DUMPFILE_CONTENT_LENGTH,
+                       scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+apr_array_header_t *
+svn_repos__dumpfile_headers_create(apr_pool_t *pool)
+{
+  apr_array_header_t *headers
+    = apr_array_make(pool, 5, sizeof(svn_repos__dumpfile_header_entry_t));
+
+  return headers;
+}
+
+void
+svn_repos__dumpfile_header_push(apr_array_header_t *headers,
+                                const char *key,
+                                const char *val)
+{
+  svn_repos__dumpfile_header_entry_t *h
+    = &APR_ARRAY_PUSH(headers, svn_repos__dumpfile_header_entry_t);
+
+  h->key = apr_pstrdup(headers->pool, key);
+  h->val = apr_pstrdup(headers->pool, val);
+}
+
+void
+svn_repos__dumpfile_header_pushf(apr_array_header_t *headers,
+                                 const char *key,
+                                 const char *val_fmt,
+                                 ...)
+{
+  va_list ap;
+  svn_repos__dumpfile_header_entry_t *h
+    = &APR_ARRAY_PUSH(headers, svn_repos__dumpfile_header_entry_t);
+
+  h->key = apr_pstrdup(headers->pool, key);
+  va_start(ap, val_fmt);
+  h->val = apr_pvsprintf(headers->pool, val_fmt, ap);
+  va_end(ap);
+}
+
+svn_error_t *
+svn_repos__dump_headers(svn_stream_t *stream,
+                        apr_array_header_t *headers,
+                        svn_boolean_t terminate,
+                        apr_pool_t *scratch_pool)
+{
+  int i;
+
+  for (i = 0; i < headers->nelts; i++)
+    {
+      svn_repos__dumpfile_header_entry_t *h
+        = &APR_ARRAY_IDX(headers, i, svn_repos__dumpfile_header_entry_t);
+
+      SVN_ERR(svn_stream_printf(stream, scratch_pool,
+                                "%s: %s\n", h->key, h->val));
+    }
+
+  /* End of headers */
+  if (terminate)
+    SVN_ERR(svn_stream_puts(stream, "\n"));
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_repos__dump_revision_record(svn_stream_t *dump_stream,
+                                svn_revnum_t revision,
+                                apr_hash_t *extra_headers,
+                                apr_hash_t *revprops,
+                                svn_boolean_t props_section_always,
+                                apr_pool_t *scratch_pool)
+{
+  svn_stringbuf_t *propstring = NULL;
+  apr_hash_t *headers;
+
+  if (extra_headers)
+    headers = apr_hash_copy(scratch_pool, extra_headers);
+  else
+    headers = apr_hash_make(scratch_pool);
+
+  /* ### someday write a revision-content-checksum */
+
+  svn_hash_sets(headers, SVN_REPOS_DUMPFILE_REVISION_NUMBER,
+                apr_psprintf(scratch_pool, "%ld", revision));
+
+  if (apr_hash_count(revprops) || props_section_always)
+    {
+      svn_stream_t *propstream;
+
+      propstring = svn_stringbuf_create_empty(scratch_pool);
+      propstream = svn_stream_from_stringbuf(propstring, scratch_pool);
+      SVN_ERR(svn_hash_write2(revprops, propstream, "PROPS-END", scratch_pool));
+      SVN_ERR(svn_stream_close(propstream));
+
+      svn_hash_sets(headers, SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH,
+                    apr_psprintf(scratch_pool,
+                                 "%" APR_SIZE_T_FMT, propstring->len));
+    }
+
+  /* Write out a regular Content-length header for the benefit of
+     non-Subversion RFC-822 parsers. */
+  svn_hash_sets(headers, SVN_REPOS_DUMPFILE_CONTENT_LENGTH,
+                apr_psprintf(scratch_pool,
+                             "%" APR_SIZE_T_FMT, propstring->len));
+  SVN_ERR(write_revision_headers(dump_stream, headers, scratch_pool));
+
+  /* End of headers */
+  SVN_ERR(svn_stream_puts(dump_stream, "\n"));
+
+  /* Property data. */
+  if (propstring)
+    {
+      SVN_ERR(svn_stream_write(dump_stream, propstring->data, &propstring->len));
+    }
+
+  /* put an end to revision */
+  SVN_ERR(svn_stream_puts(dump_stream, "\n"));
+
+  return SVN_NO_ERROR;
+}
+
+/*----------------------------------------------------------------------*/
+
 /** An editor which dumps node-data in 'dumpfile format' to a file. **/
 
 /* Look, mom!  No file batons! */
@@ -426,10 +609,6 @@ struct edit_baton
      revisions older than OLDEST_DUMPED_REV. */
   svn_boolean_t *found_old_mergeinfo;
 
-  /* reusable buffer for writing file contents */
-  char buffer[SVN__STREAM_CHUNK_SIZE];
-  apr_size_t bufsize;
-
   /* Structure allows us to verify the paths currently being dumped.
      If NULL, validity checks are being skipped. */
   path_tracker_t *path_tracker;
@@ -438,10 +617,6 @@ struct edit_baton
 struct dir_baton
 {
   struct edit_baton *edit_baton;
-  struct dir_baton *parent_dir_baton;
-
-  /* is this directory a new addition to this revision? */
-  svn_boolean_t added;
 
   /* has this directory been written to the output stream? */
   svn_boolean_t written_out;
@@ -481,21 +656,19 @@ struct dir_baton
    path, SVN_INVALID_REVNUM for the rev), just compare this directory
    PATH against itself in the previous revision.
 
-   PARENT_DIR_BATON is the directory baton of this directory's parent,
-   or NULL if this is the top-level directory of the edit.  ADDED
-   indicated if this directory is newly added in this revision.
+   PB is the directory baton of this directory's parent,
+   or NULL if this is the top-level directory of the edit.
+
    Perform all allocations in POOL.  */
 static struct dir_baton *
 make_dir_baton(const char *path,
                const char *cmp_path,
                svn_revnum_t cmp_rev,
                void *edit_baton,
-               void *parent_dir_baton,
-               svn_boolean_t added,
+               struct dir_baton *pb,
                apr_pool_t *pool)
 {
   struct edit_baton *eb = edit_baton;
-  struct dir_baton *pb = parent_dir_baton;
   struct dir_baton *new_db = apr_pcalloc(pool, sizeof(*new_db));
   const char *full_path;
 
@@ -513,11 +686,9 @@ make_dir_baton(const char *path,
     cmp_path = svn_relpath_canonicalize(cmp_path, pool);
 
   new_db->edit_baton = eb;
-  new_db->parent_dir_baton = pb;
   new_db->path = full_path;
   new_db->cmp_path = cmp_path;
   new_db->cmp_rev = cmp_rev;
-  new_db->added = added;
   new_db->written_out = FALSE;
   new_db->deleted_entries = apr_hash_make(pool);
   new_db->check_name_collision = FALSE;
@@ -693,7 +864,6 @@ extract_mergeinfo_paths(void *baton, con
 struct filter_mergeinfo_paths_baton
 {
   apr_hash_t *paths;
-  svn_membuf_t buffer;
 };
 
 /* Compare two sets of denormalized paths from mergeinfo entries,
@@ -800,7 +970,6 @@ check_mergeinfo_normalization(const char
       normalized_paths = extract_baton.result;
 
       filter_baton.paths = added_paths;
-      filter_baton.buffer = extract_baton.buffer;
       SVN_ERR(svn_iter_apr_hash(NULL, oldinfo,
                                 filter_mergeinfo_paths,
                                 &filter_baton, pool));
@@ -826,7 +995,7 @@ check_mergeinfo_normalization(const char
 
    Write out a node record for PATH of type KIND under EB->FS_ROOT.
    ACTION describes what is happening to the node (see enum svn_node_action).
-   Write record to writable EB->STREAM, using EB->BUFFER to write in chunks.
+   Write record to writable EB->STREAM.
 
    If the node was itself copied, IS_COPY is TRUE and the
    path/revision of the copy source are in CMP_PATH/CMP_REV.  If
@@ -851,6 +1020,7 @@ dump_node(struct edit_baton *eb,
   svn_revnum_t compare_rev = eb->current_rev - 1;
   svn_fs_root_t *compare_root = NULL;
   apr_file_t *delta_file = NULL;
+  apr_array_header_t *headers = svn_repos__dumpfile_headers_create(pool);
 
   /* Maybe validate the path. */
   if (eb->verify || eb->notify_func)
@@ -879,15 +1049,14 @@ dump_node(struct edit_baton *eb,
     }
 
   /* Write out metadata headers for this file node. */
-  SVN_ERR(svn_stream_printf(eb->stream, pool,
-                            SVN_REPOS_DUMPFILE_NODE_PATH ": %s\n",
-                            path));
+  svn_repos__dumpfile_header_push(
+    headers, SVN_REPOS_DUMPFILE_NODE_PATH, path);
   if (kind == svn_node_file)
-    SVN_ERR(svn_stream_puts(eb->stream,
-                            SVN_REPOS_DUMPFILE_NODE_KIND ": file\n"));
+    svn_repos__dumpfile_header_push(
+      headers, SVN_REPOS_DUMPFILE_NODE_KIND, "file");
   else if (kind == svn_node_dir)
-    SVN_ERR(svn_stream_puts(eb->stream,
-                            SVN_REPOS_DUMPFILE_NODE_KIND ": dir\n"));
+    svn_repos__dumpfile_header_push(
+      headers, SVN_REPOS_DUMPFILE_NODE_KIND, "dir");
 
   /* Remove leading slashes from copyfrom paths. */
   if (cmp_path)
@@ -907,8 +1076,8 @@ dump_node(struct edit_baton *eb,
                   apr_psprintf(pool, _("Change invalid path '%s' in r%ld"),
                                path, eb->current_rev));
 
-      SVN_ERR(svn_stream_puts(eb->stream,
-                              SVN_REPOS_DUMPFILE_NODE_ACTION ": change\n"));
+      svn_repos__dumpfile_header_push(
+        headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "change");
 
       /* either the text or props changed, or possibly both. */
       SVN_ERR(svn_fs_revision_root(&compare_root,
@@ -938,9 +1107,8 @@ dump_node(struct edit_baton *eb,
             tracker_path_replace(eb->path_tracker, path);
 
           /* a simple delete+add, implied by a single 'replace' action. */
-          SVN_ERR(svn_stream_puts(eb->stream,
-                                  SVN_REPOS_DUMPFILE_NODE_ACTION
-                                  ": replace\n"));
+          svn_repos__dumpfile_header_push(
+            headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "replace");
 
           /* definitely need to dump all content for a replace. */
           if (kind == svn_node_file)
@@ -967,9 +1135,12 @@ dump_node(struct edit_baton *eb,
 
           /* the path & kind headers have already been printed;  just
              add a delete action, and end the current record.*/
-          SVN_ERR(svn_stream_puts(eb->stream,
-                                  SVN_REPOS_DUMPFILE_NODE_ACTION
-                                  ": delete\n\n"));
+          svn_repos__dumpfile_header_push(
+            headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "delete");
+
+          SVN_ERR(svn_repos__dump_headers(eb->stream, headers, TRUE, pool));
+          /* ### Unusually, here we end this node record with only a single
+                 blank line after the header block -- no extra blank line. */
 
           /* recurse:  print an additional add-with-history record. */
           SVN_ERR(dump_node(eb, path, kind, svn_node_action_add,
@@ -977,8 +1148,7 @@ dump_node(struct edit_baton *eb,
 
           /* we can leave this routine quietly now, don't need to dump
              any content;  that was already done in the second record. */
-          must_dump_text = FALSE;
-          must_dump_props = FALSE;
+          return SVN_NO_ERROR;
         }
     }
   else if (action == svn_node_action_delete)
@@ -991,8 +1161,8 @@ dump_node(struct edit_baton *eb,
           tracker_path_delete(eb->path_tracker, path);
         }
 
-      SVN_ERR(svn_stream_puts(eb->stream,
-                              SVN_REPOS_DUMPFILE_NODE_ACTION ": delete\n"));
+      svn_repos__dumpfile_header_push(
+        headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "delete");
 
       /* we can leave this routine quietly now, don't need to dump
          any content. */
@@ -1007,8 +1177,8 @@ dump_node(struct edit_baton *eb,
                                _("Adding already existing path '%s' in r%ld"),
                                path, eb->current_rev));
 
-      SVN_ERR(svn_stream_puts(eb->stream,
-                              SVN_REPOS_DUMPFILE_NODE_ACTION ": add\n"));
+      svn_repos__dumpfile_header_push(
+        headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "add");
 
       if (! is_copy)
         {
@@ -1049,12 +1219,10 @@ dump_node(struct edit_baton *eb,
                 *eb->found_old_reference = TRUE;
             }
 
-          SVN_ERR(svn_stream_printf(eb->stream, pool,
-                                    SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV
-                                    ": %ld\n"
-                                    SVN_REPOS_DUMPFILE_NODE_COPYFROM_PATH
-                                    ": %s\n",
-                                    cmp_rev, cmp_path));
+          svn_repos__dumpfile_header_pushf(
+            headers, SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV, "%ld", cmp_rev);
+          svn_repos__dumpfile_header_push(
+            headers, SVN_REPOS_DUMPFILE_NODE_COPYFROM_PATH, cmp_path);
 
           SVN_ERR(svn_fs_revision_root(&compare_root,
                                        svn_fs_root_fs(eb->fs_root),
@@ -1078,18 +1246,16 @@ dump_node(struct edit_baton *eb,
                                            FALSE, pool));
               hex_digest = svn_checksum_to_cstring(checksum, pool);
               if (hex_digest)
-                SVN_ERR(svn_stream_printf(eb->stream, pool,
-                                      SVN_REPOS_DUMPFILE_TEXT_COPY_SOURCE_MD5
-                                      ": %s\n", hex_digest));
+                svn_repos__dumpfile_header_push(
+                  headers, SVN_REPOS_DUMPFILE_TEXT_COPY_SOURCE_MD5, hex_digest);
 
               SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_sha1,
                                            compare_root, compare_path,
                                            FALSE, pool));
               hex_digest = svn_checksum_to_cstring(checksum, pool);
               if (hex_digest)
-                SVN_ERR(svn_stream_printf(eb->stream, pool,
-                                      SVN_REPOS_DUMPFILE_TEXT_COPY_SOURCE_SHA1
-                                      ": %s\n", hex_digest));
+                svn_repos__dumpfile_header_push(
+                  headers, SVN_REPOS_DUMPFILE_TEXT_COPY_SOURCE_SHA1, hex_digest);
             }
         }
     }
@@ -1101,8 +1267,9 @@ dump_node(struct edit_baton *eb,
          then our dumpstream format demands that at a *minimum*, we
          see a lone "PROPS-END" as a divider between text and props
          content within the content-block. */
-      len = 2;
-      return svn_stream_write(eb->stream, "\n\n", &len); /* ### needed? */
+      SVN_ERR(svn_repos__dump_headers(eb->stream, headers, TRUE, pool));
+      len = 1;
+      return svn_stream_write(eb->stream, "\n", &len); /* ### needed? */
     }
 
   /*** Start prepping content to dump... ***/
@@ -1171,8 +1338,8 @@ dump_node(struct edit_baton *eb,
           if (!oldhash)         /* May have been set for normalization check */
             SVN_ERR(svn_fs_node_proplist(&oldhash, compare_root, compare_path,
                                          pool));
-          SVN_ERR(svn_stream_puts(eb->stream,
-                                  SVN_REPOS_DUMPFILE_PROP_DELTA ": true\n"));
+          svn_repos__dumpfile_header_push(
+            headers, SVN_REPOS_DUMPFILE_PROP_DELTA, "true");
         }
       else
         oldhash = apr_hash_make(pool);
@@ -1183,9 +1350,9 @@ dump_node(struct edit_baton *eb,
       SVN_ERR(svn_stream_close(propstream));
       proplen = propstring->len;
       content_length += proplen;
-      SVN_ERR(svn_stream_printf(eb->stream, pool,
-                                SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH
-                                ": %" APR_SIZE_T_FMT "\n", proplen));
+      svn_repos__dumpfile_header_pushf(
+        headers, SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH,
+        "%" APR_SIZE_T_FMT, proplen);
     }
 
   /* If we are supposed to dump text, write out a text length header
@@ -1203,8 +1370,8 @@ dump_node(struct edit_baton *eb,
              saying our text contents are a delta. */
           SVN_ERR(store_delta(&delta_file, &textlen, compare_root,
                               compare_path, eb->fs_root, path, pool));
-          SVN_ERR(svn_stream_puts(eb->stream,
-                                  SVN_REPOS_DUMPFILE_TEXT_DELTA ": true\n"));
+          svn_repos__dumpfile_header_push(
+            headers, SVN_REPOS_DUMPFILE_TEXT_DELTA, "true");
 
           if (compare_root)
             {
@@ -1213,18 +1380,16 @@ dump_node(struct edit_baton *eb,
                                            FALSE, pool));
               hex_digest = svn_checksum_to_cstring(checksum, pool);
               if (hex_digest)
-                SVN_ERR(svn_stream_printf(eb->stream, pool,
-                                          SVN_REPOS_DUMPFILE_TEXT_DELTA_BASE_MD5
-                                          ": %s\n", hex_digest));
+                svn_repos__dumpfile_header_push(
+                  headers, SVN_REPOS_DUMPFILE_TEXT_DELTA_BASE_MD5, hex_digest);
 
               SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_sha1,
                                            compare_root, compare_path,
                                            FALSE, pool));
               hex_digest = svn_checksum_to_cstring(checksum, pool);
               if (hex_digest)
-                SVN_ERR(svn_stream_printf(eb->stream, pool,
-                                      SVN_REPOS_DUMPFILE_TEXT_DELTA_BASE_SHA1
-                                      ": %s\n", hex_digest));
+                svn_repos__dumpfile_header_push(
+                  headers, SVN_REPOS_DUMPFILE_TEXT_DELTA_BASE_SHA1, hex_digest);
             }
         }
       else
@@ -1234,34 +1399,33 @@ dump_node(struct edit_baton *eb,
         }
 
       content_length += textlen;
-      SVN_ERR(svn_stream_printf(eb->stream, pool,
-                                SVN_REPOS_DUMPFILE_TEXT_CONTENT_LENGTH
-                                ": %" SVN_FILESIZE_T_FMT "\n", textlen));
+      svn_repos__dumpfile_header_pushf(
+        headers, SVN_REPOS_DUMPFILE_TEXT_CONTENT_LENGTH,
+        "%" SVN_FILESIZE_T_FMT, textlen);
 
       SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_md5,
                                    eb->fs_root, path, FALSE, pool));
       hex_digest = svn_checksum_to_cstring(checksum, pool);
       if (hex_digest)
-        SVN_ERR(svn_stream_printf(eb->stream, pool,
-                                  SVN_REPOS_DUMPFILE_TEXT_CONTENT_MD5
-                                  ": %s\n", hex_digest));
+        svn_repos__dumpfile_header_push(
+          headers, SVN_REPOS_DUMPFILE_TEXT_CONTENT_MD5, hex_digest);
 
       SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_sha1,
                                    eb->fs_root, path, FALSE, pool));
       hex_digest = svn_checksum_to_cstring(checksum, pool);
       if (hex_digest)
-        SVN_ERR(svn_stream_printf(eb->stream, pool,
-                                  SVN_REPOS_DUMPFILE_TEXT_CONTENT_SHA1
-                                  ": %s\n", hex_digest));
+        svn_repos__dumpfile_header_push(
+          headers, SVN_REPOS_DUMPFILE_TEXT_CONTENT_SHA1, hex_digest);
     }
 
   /* 'Content-length:' is the last header before we dump the content,
      and is the sum of the text and prop contents lengths.  We write
      this only for the benefit of non-Subversion RFC-822 parsers. */
-  SVN_ERR(svn_stream_printf(eb->stream, pool,
-                            SVN_REPOS_DUMPFILE_CONTENT_LENGTH
-                            ": %" SVN_FILESIZE_T_FMT "\n\n",
-                            content_length));
+  svn_repos__dumpfile_header_pushf(
+    headers, SVN_REPOS_DUMPFILE_CONTENT_LENGTH,
+    "%" SVN_FILESIZE_T_FMT, content_length);
+
+  SVN_ERR(svn_repos__dump_headers(eb->stream, headers, TRUE, pool));
 
   /* Dump property content if we're supposed to do so. */
   if (must_dump_props)
@@ -1300,7 +1464,7 @@ open_root(void *edit_baton,
           void **root_baton)
 {
   *root_baton = make_dir_baton(NULL, NULL, SVN_INVALID_REVNUM,
-                               edit_baton, NULL, FALSE, pool);
+                               edit_baton, NULL, pool);
   return SVN_NO_ERROR;
 }
 
@@ -1331,13 +1495,13 @@ add_directory(const char *path,
 {
   struct dir_baton *pb = parent_baton;
   struct edit_baton *eb = pb->edit_baton;
-  void *val;
+  void *was_deleted;
   svn_boolean_t is_copy = FALSE;
   struct dir_baton *new_db
-    = make_dir_baton(path, copyfrom_path, copyfrom_rev, eb, pb, TRUE, pool);
+    = make_dir_baton(path, copyfrom_path, copyfrom_rev, eb, pb, pool);
 
   /* This might be a replacement -- is the path already deleted? */
-  val = svn_hash_gets(pb->deleted_entries, path);
+  was_deleted = svn_hash_gets(pb->deleted_entries, path);
 
   /* Detect an add-with-history. */
   is_copy = ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev);
@@ -1345,19 +1509,19 @@ add_directory(const char *path,
   /* Dump the node. */
   SVN_ERR(dump_node(eb, path,
                     svn_node_dir,
-                    val ? svn_node_action_replace : svn_node_action_add,
+                    was_deleted ? svn_node_action_replace : svn_node_action_add,
                     is_copy,
                     is_copy ? copyfrom_path : NULL,
                     is_copy ? copyfrom_rev : SVN_INVALID_REVNUM,
                     pool));
 
-  if (val)
+  if (was_deleted)
     /* Delete the path, it's now been dumped. */
     svn_hash_sets(pb->deleted_entries, path, NULL);
 
   /* Check for normalized name clashes, but only if this is actually a
      new name in the parent, not a replacement. */
-  if (!val && eb->verify && eb->check_normalization && eb->notify_func)
+  if (!was_deleted && eb->verify && eb->check_normalization && eb->notify_func)
     {
       pb->check_name_collision = TRUE;
     }
@@ -1391,7 +1555,7 @@ open_directory(const char *path,
       cmp_rev = pb->cmp_rev;
     }
 
-  new_db = make_dir_baton(path, cmp_path, cmp_rev, eb, pb, FALSE, pool);
+  new_db = make_dir_baton(path, cmp_path, cmp_rev, eb, pb, pool);
   *child_baton = new_db;
   return SVN_NO_ERROR;
 }
@@ -1443,11 +1607,11 @@ add_file(const char *path,
 {
   struct dir_baton *pb = parent_baton;
   struct edit_baton *eb = pb->edit_baton;
-  void *val;
+  void *was_deleted;
   svn_boolean_t is_copy = FALSE;
 
   /* This might be a replacement -- is the path already deleted? */
-  val = svn_hash_gets(pb->deleted_entries, path);
+  was_deleted = svn_hash_gets(pb->deleted_entries, path);
 
   /* Detect add-with-history. */
   is_copy = ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev);
@@ -1455,19 +1619,19 @@ add_file(const char *path,
   /* Dump the node. */
   SVN_ERR(dump_node(eb, path,
                     svn_node_file,
-                    val ? svn_node_action_replace : svn_node_action_add,
+                    was_deleted ? svn_node_action_replace : svn_node_action_add,
                     is_copy,
                     is_copy ? copyfrom_path : NULL,
                     is_copy ? copyfrom_rev : SVN_INVALID_REVNUM,
                     pool));
 
-  if (val)
+  if (was_deleted)
     /* delete the path, it's now been dumped. */
     svn_hash_sets(pb->deleted_entries, path, NULL);
 
   /* Check for normalized name clashes, but only if this is actually a
      new name in the parent, not a replacement. */
-  if (!val && eb->verify && eb->check_normalization && eb->notify_func)
+  if (!was_deleted && eb->verify && eb->check_normalization && eb->notify_func)
     {
       pb->check_name_collision = TRUE;
     }
@@ -1518,11 +1682,16 @@ change_dir_prop(void *parent_baton,
 
   /* This function is what distinguishes between a directory that is
      opened to merely get somewhere, vs. one that is opened because it
-     *actually* changed by itself.  */
+     *actually* changed by itself.
+
+     Instead of recording the prop changes here, we just use this method
+     to trigger writing the node; dump_node() finds all the changes. */
   if (! db->written_out)
     {
       SVN_ERR(dump_node(eb, db->path,
                         svn_node_dir, svn_node_action_change,
+                        /* ### We pass is_copy=FALSE; this might be wrong
+                           but the parameter isn't used when action=change. */
                         FALSE, db->cmp_path, db->cmp_rev, pool));
       db->written_out = TRUE;
     }
@@ -1651,7 +1820,6 @@ get_dump_editor(const svn_delta_editor_t
   eb->notify_func = notify_func;
   eb->notify_baton = notify_baton;
   eb->oldest_dumped_rev = oldest_dumped_rev;
-  eb->bufsize = sizeof(eb->buffer);
   eb->path = apr_pstrdup(pool, root_path);
   SVN_ERR(svn_fs_revision_root(&(eb->fs_root), fs, to_rev, pool));
   eb->fs = fs;
@@ -1712,15 +1880,10 @@ write_revision_record(svn_stream_t *stre
                       svn_revnum_t rev,
                       apr_pool_t *pool)
 {
-  apr_size_t len;
   apr_hash_t *props;
-  svn_stringbuf_t *encoded_prophash;
   apr_time_t timetemp;
   svn_string_t *datevalue;
-  svn_stream_t *propstream;
 
-  /* Read the revision props even if we're aren't going to dump
-     them for verification purposes */
   SVN_ERR(svn_fs_revision_proplist(&props, fs, rev, pool));
 
   /* Run revision date properties through the time conversion to
@@ -1735,33 +1898,10 @@ write_revision_record(svn_stream_t *stre
       svn_hash_sets(props, SVN_PROP_REVISION_DATE, datevalue);
     }
 
-  encoded_prophash = svn_stringbuf_create_ensure(0, pool);
-  propstream = svn_stream_from_stringbuf(encoded_prophash, pool);
-  SVN_ERR(svn_hash_write2(props, propstream, "PROPS-END", pool));
-  SVN_ERR(svn_stream_close(propstream));
-
-  /* ### someday write a revision-content-checksum */
-
-  SVN_ERR(svn_stream_printf(stream, pool,
-                            SVN_REPOS_DUMPFILE_REVISION_NUMBER
-                            ": %ld\n", rev));
-  SVN_ERR(svn_stream_printf(stream, pool,
-                            SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH
-                            ": %" APR_SIZE_T_FMT "\n",
-                            encoded_prophash->len));
-
-  /* Write out a regular Content-length header for the benefit of
-     non-Subversion RFC-822 parsers. */
-  SVN_ERR(svn_stream_printf(stream, pool,
-                            SVN_REPOS_DUMPFILE_CONTENT_LENGTH
-                            ": %" APR_SIZE_T_FMT "\n\n",
-                            encoded_prophash->len));
-
-  len = encoded_prophash->len;
-  SVN_ERR(svn_stream_write(stream, encoded_prophash->data, &len));
-
-  len = 1;
-  return svn_stream_write(stream, "\n", &len);
+  SVN_ERR(svn_repos__dump_revision_record(stream, rev, NULL, props,
+                                          TRUE /*props_section_always*/,
+                                          pool));
+  return SVN_NO_ERROR;
 }
 
 

Modified: subversion/branches/pin-externals/subversion/libsvn_repos/load-fs-vtable.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_repos/load-fs-vtable.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_repos/load-fs-vtable.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_repos/load-fs-vtable.c Wed Jan 21 16:22:19 2015
@@ -31,11 +31,9 @@
 #include "svn_string.h"
 #include "svn_props.h"
 #include "repos.h"
-#include "svn_private_config.h"
 #include "svn_mergeinfo.h"
 #include "svn_checksum.h"
 #include "svn_subst.h"
-#include "svn_ctype.h"
 #include "svn_dirent_uri.h"
 
 #include <apr_lib.h>
@@ -43,6 +41,7 @@
 #include "private/svn_fspath.h"
 #include "private/svn_dep_compat.h"
 #include "private/svn_mergeinfo_private.h"
+#include "private/svn_repos_private.h"
 
 /*----------------------------------------------------------------------*/
 
@@ -84,9 +83,9 @@ struct parse_baton
      SVN_INVALID_REVNUM. */
   svn_revnum_t last_rev_mapped;
 
-  /* The oldest old revision loaded from the dump stream.  If no revisions
+  /* The oldest revision loaded from the dump stream.  If no revisions
      have been loaded yet, this is set to SVN_INVALID_REVNUM. */
-  svn_revnum_t oldest_old_rev;
+  svn_revnum_t oldest_dumpstream_rev;
 };
 
 struct revision_baton
@@ -194,8 +193,6 @@ change_node_prop(svn_fs_root_t *txn_root
 
 /* Prepend the mergeinfo source paths in MERGEINFO_ORIG with PARENT_DIR, and
    return it in *MERGEINFO_VAL. */
-/* ### FIXME:  Consider somehow sharing code with
-   ### svnrdump/load_editor.c:prefix_mergeinfo_paths() */
 static svn_error_t *
 prefix_mergeinfo_paths(svn_string_t **mergeinfo_val,
                        const svn_string_t *mergeinfo_orig,
@@ -227,13 +224,20 @@ prefix_mergeinfo_paths(svn_string_t **me
 
 /* Examine the mergeinfo in INITIAL_VAL, renumber revisions in rangelists
    as appropriate, and return the (possibly new) mergeinfo in *FINAL_VAL
-   (allocated from POOL). */
-/* ### FIXME:  Consider somehow sharing code with
-   ### svnrdump/load_editor.c:renumber_mergeinfo_revs() */
+   (allocated from POOL).
+
+   Adjust any mergeinfo revisions not older than OLDEST_DUMPSTREAM_REV by
+   using REV_MAP which maps (svn_revnum_t) old rev to (svn_revnum_t) new rev.
+
+   Adjust any mergeinfo revisions older than OLDEST_DUMPSTREAM_REV by
+   (-OLDER_REVS_OFFSET), dropping any that become <= 0.
+ */
 static svn_error_t *
 renumber_mergeinfo_revs(svn_string_t **final_val,
                         const svn_string_t *initial_val,
-                        struct revision_baton *rb,
+                        apr_hash_t *rev_map,
+                        svn_revnum_t oldest_dumpstream_rev,
+                        apr_int32_t older_revs_offset,
                         apr_pool_t *pool)
 {
   apr_pool_t *subpool = svn_pool_create(pool);
@@ -248,19 +252,22 @@ renumber_mergeinfo_revs(svn_string_t **f
      Remove mergeinfo older than the oldest revision in the dump stream
      and adjust its revisions by the difference between the head rev of
      the target repository and the current dump stream rev. */
-  if (rb->pb->oldest_old_rev > 1)
+  if (oldest_dumpstream_rev > 1)
     {
+      /* predates_stream_mergeinfo := mergeinfo that refers to revs before
+         oldest_dumpstream_rev */
       SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges(
         &predates_stream_mergeinfo, mergeinfo,
-        rb->pb->oldest_old_rev - 1, 0,
+        oldest_dumpstream_rev - 1, 0,
         TRUE, subpool, subpool));
+      /* mergeinfo := mergeinfo that refers to revs >= oldest_dumpstream_rev */
       SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges(
         &mergeinfo, mergeinfo,
-        rb->pb->oldest_old_rev - 1, 0,
+        oldest_dumpstream_rev - 1, 0,
         FALSE, subpool, subpool));
       SVN_ERR(svn_mergeinfo__adjust_mergeinfo_rangelists(
         &predates_stream_mergeinfo, predates_stream_mergeinfo,
-        -rb->rev_offset, subpool, subpool));
+        -older_revs_offset, subpool, subpool));
     }
   else
     {
@@ -271,7 +278,6 @@ renumber_mergeinfo_revs(svn_string_t **f
     {
       const char *merge_source = apr_hash_this_key(hi);
       svn_rangelist_t *rangelist = apr_hash_this_val(hi);
-      struct parse_baton *pb = rb->pb;
       int i;
 
       /* Possibly renumber revisions in merge source's rangelist. */
@@ -280,27 +286,27 @@ renumber_mergeinfo_revs(svn_string_t **f
           svn_revnum_t rev_from_map;
           svn_merge_range_t *range = APR_ARRAY_IDX(rangelist, i,
                                                    svn_merge_range_t *);
-          rev_from_map = get_revision_mapping(pb->rev_map, range->start);
+          rev_from_map = get_revision_mapping(rev_map, range->start);
           if (SVN_IS_VALID_REVNUM(rev_from_map))
             {
               range->start = rev_from_map;
             }
-          else if (range->start == pb->oldest_old_rev - 1)
+          else if (range->start == oldest_dumpstream_rev - 1)
             {
               /* Since the start revision of svn_merge_range_t are not
                  inclusive there is one possible valid start revision that
-                 won't be found in the PB->REV_MAP mapping of load stream
+                 won't be found in the REV_MAP mapping of load stream
                  revsions to loaded revisions: The revision immediately
                  preceding the oldest revision from the load stream.
                  This is a valid revision for mergeinfo, but not a valid
-                 copy from revision (which PB->REV_MAP also maps for) so it
+                 copy from revision (which REV_MAP also maps for) so it
                  will never be in the mapping.
 
                  If that is what we have here, then find the mapping for the
                  oldest rev from the load stream and subtract 1 to get the
                  renumbered, non-inclusive, start revision. */
-              rev_from_map = get_revision_mapping(pb->rev_map,
-                                                  pb->oldest_old_rev);
+              rev_from_map = get_revision_mapping(rev_map,
+                                                  oldest_dumpstream_rev);
               if (SVN_IS_VALID_REVNUM(rev_from_map))
                 range->start = rev_from_map - 1;
             }
@@ -317,7 +323,7 @@ renumber_mergeinfo_revs(svn_string_t **f
               continue;
             }
 
-          rev_from_map = get_revision_mapping(pb->rev_map, range->end);
+          rev_from_map = get_revision_mapping(rev_map, range->end);
           if (SVN_IS_VALID_REVNUM(rev_from_map))
             range->end = rev_from_map;
         }
@@ -325,19 +331,12 @@ renumber_mergeinfo_revs(svn_string_t **f
     }
 
   if (predates_stream_mergeinfo)
+    {
       SVN_ERR(svn_mergeinfo_merge2(final_mergeinfo, predates_stream_mergeinfo,
                                    subpool, subpool));
+    }
 
-  SVN_ERR(svn_mergeinfo_sort(final_mergeinfo, subpool));
-
-  /* Mergeinfo revision sources for r0 and r1 are invalid; you can't merge r0
-     or r1.  However, svndumpfilter can be abused to produce r1 merge source
-     revs.  So if we encounter any, then strip them out, no need to put them
-     into the load target. */
-  SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges(&final_mergeinfo,
-                                                    final_mergeinfo,
-                                                    1, 0, FALSE,
-                                                    subpool, subpool));
+  SVN_ERR(svn_mergeinfo__canonicalize_ranges(final_mergeinfo, subpool));
 
   SVN_ERR(svn_mergeinfo_to_string(final_val, final_mergeinfo, pool));
   svn_pool_destroy(subpool);
@@ -350,6 +349,12 @@ renumber_mergeinfo_revs(svn_string_t **f
 /** vtable for doing commits to a fs **/
 
 
+/* Make a node baton, parsing the relevant HEADERS.
+ *
+ * If RB->pb->parent_dir:
+ *   prefix it to NB->path
+ *   prefix it to NB->copyfrom_path (if present)
+ */
 static svn_error_t *
 make_node_baton(struct node_baton **node_baton_p,
                 apr_hash_t *headers,
@@ -436,6 +441,10 @@ make_node_baton(struct node_baton **node
   return SVN_NO_ERROR;
 }
 
+/* Make a revision baton, parsing the relevant HEADERS.
+ *
+ * Set RB->skipped iff the revision number is outside the range given in PB.
+ */
 static struct revision_baton *
 make_revision_baton(apr_hash_t *headers,
                     struct parse_baton *pb,
@@ -514,8 +523,8 @@ new_revision_record(void **revision_bato
         }
 
       /* Stash the oldest "old" revision committed from the load stream. */
-      if (!SVN_IS_VALID_REVNUM(pb->oldest_old_rev))
-        pb->oldest_old_rev = rb->rev;
+      if (!SVN_IS_VALID_REVNUM(pb->oldest_dumpstream_rev))
+        pb->oldest_dumpstream_rev = rb->rev;
     }
 
   /* If we're skipping this revision, try to notify someone. */
@@ -542,7 +551,11 @@ new_revision_record(void **revision_bato
 
 
 
-/* Factorized helper func for new_node_record() */
+/* Perform a copy or a plain add.
+ *
+ * For a copy, also adjust the copy-from rev, check any copy-source checksum,
+ * and send a notification.
+ */
 static svn_error_t *
 maybe_add_with_history(struct node_baton *nb,
                        struct revision_baton *rb,
@@ -753,24 +766,23 @@ set_revision_property(void *baton,
 }
 
 
-/* Adjust mergeinfo:
- *   - normalize line endings (if all CRLF, change to LF; but error if mixed);
- *   - adjust revision numbers (see renumber_mergeinfo_revs());
- *   - adjust paths (see prefix_mergeinfo_paths()).
- */
-static svn_error_t *
-adjust_mergeinfo_property(struct revision_baton *rb,
-                          svn_string_t **new_value_p,
-                          const svn_string_t *old_value,
-                          apr_pool_t *result_pool)
+svn_error_t *
+svn_repos__adjust_mergeinfo_property(svn_string_t **new_value_p,
+                                     const svn_string_t *old_value,
+                                     const char *parent_dir,
+                                     apr_hash_t *rev_map,
+                                     svn_revnum_t oldest_dumpstream_rev,
+                                     apr_int32_t older_revs_offset,
+                                     svn_repos_notify_func_t notify_func,
+                                     void *notify_baton,
+                                     apr_pool_t *result_pool,
+                                     apr_pool_t *scratch_pool)
 {
-  struct parse_baton *pb = rb->pb;
   svn_string_t prop_val = *old_value;
 
   /* Tolerate mergeinfo with "\r\n" line endings because some
      dumpstream sources might contain as much.  If so normalize
-     the line endings to '\n' and make a notification to
-     PARSE_BATON->FEEDBACK_STREAM that we have made this
+     the line endings to '\n' and notify that we have made this
      correction. */
   if (strstr(prop_val.data, "\r"))
     {
@@ -786,28 +798,29 @@ adjust_mergeinfo_property(struct revisio
       prop_val.data = prop_eol_normalized;
       prop_val.len = strlen(prop_eol_normalized);
 
-      if (pb->notify_func)
+      if (notify_func)
         {
-          /* ### TODO: Use proper scratch pool instead of pb->notify_pool */
           svn_repos_notify_t *notify
                   = svn_repos_notify_create(
                                 svn_repos_notify_load_normalized_mergeinfo,
-                                pb->notify_pool);
+                                scratch_pool);
 
-          pb->notify_func(pb->notify_baton, notify, pb->notify_pool);
-          svn_pool_clear(pb->notify_pool);
+          notify_func(notify_baton, notify, scratch_pool);
         }
     }
 
   /* Renumber mergeinfo as appropriate. */
-  SVN_ERR(renumber_mergeinfo_revs(new_value_p, &prop_val, rb,
+  SVN_ERR(renumber_mergeinfo_revs(new_value_p, &prop_val,
+                                  rev_map, oldest_dumpstream_rev,
+                                  older_revs_offset,
                                   result_pool));
-  if (pb->parent_dir)
+
+  if (parent_dir)
     {
-      /* Prefix the merge source paths with PB->parent_dir. */
+      /* Prefix the merge source paths with PARENT_DIR. */
       /* ASSUMPTION: All source paths are included in the dump stream. */
       SVN_ERR(prefix_mergeinfo_paths(new_value_p, *new_value_p,
-                                     pb->parent_dir, result_pool));
+                                     parent_dir, result_pool));
     }
 
   return SVN_NO_ERROR;
@@ -837,7 +850,14 @@ set_node_property(void *baton,
       svn_string_t *new_value;
       svn_error_t *err;
 
-      err = adjust_mergeinfo_property(rb, &new_value, value, nb->pool);
+      err = svn_repos__adjust_mergeinfo_property(&new_value, value,
+                                                 pb->parent_dir,
+                                                 pb->rev_map,
+                                                 pb->oldest_dumpstream_rev,
+                                                 rb->rev_offset,
+                                                 pb->notify_func, pb->notify_baton,
+                                                 nb->pool, pb->notify_pool);
+      svn_pool_clear(pb->notify_pool);
       if (err)
         {
           if (pb->validate_props)
@@ -1130,7 +1150,7 @@ close_revision(void *baton)
 
 
 svn_error_t *
-svn_repos_get_fs_build_parser4(const svn_repos_parse_fns3_t **callbacks,
+svn_repos_get_fs_build_parser5(const svn_repos_parse_fns3_t **callbacks,
                                void **parse_baton,
                                svn_repos_t *repos,
                                svn_revnum_t start_rev,
@@ -1139,6 +1159,9 @@ svn_repos_get_fs_build_parser4(const svn
                                svn_boolean_t validate_props,
                                enum svn_repos_load_uuid uuid_action,
                                const char *parent_dir,
+                               svn_boolean_t use_pre_commit_hook,
+                               svn_boolean_t use_post_commit_hook,
+                               svn_boolean_t ignore_dates,
                                svn_repos_notify_func_t notify_func,
                                void *notify_baton,
                                apr_pool_t *pool)
@@ -1180,10 +1203,13 @@ svn_repos_get_fs_build_parser4(const svn
   pb->pool = pool;
   pb->notify_pool = svn_pool_create(pool);
   pb->rev_map = apr_hash_make(pool);
-  pb->oldest_old_rev = SVN_INVALID_REVNUM;
+  pb->oldest_dumpstream_rev = SVN_INVALID_REVNUM;
   pb->last_rev_mapped = SVN_INVALID_REVNUM;
   pb->start_rev = start_rev;
   pb->end_rev = end_rev;
+  pb->use_pre_commit_hook = use_pre_commit_hook;
+  pb->use_post_commit_hook = use_post_commit_hook;
+  pb->ignore_dates = ignore_dates;
 
   *callbacks = parser;
   *parse_baton = pb;
@@ -1210,28 +1236,23 @@ svn_repos_load_fs5(svn_repos_t *repos,
 {
   const svn_repos_parse_fns3_t *parser;
   void *parse_baton;
-  struct parse_baton *pb;
 
   /* This is really simple. */
 
-  SVN_ERR(svn_repos_get_fs_build_parser4(&parser, &parse_baton,
+  SVN_ERR(svn_repos_get_fs_build_parser5(&parser, &parse_baton,
                                          repos,
                                          start_rev, end_rev,
                                          TRUE, /* look for copyfrom revs */
                                          validate_props,
                                          uuid_action,
                                          parent_dir,
+                                         use_pre_commit_hook,
+                                         use_post_commit_hook,
+                                         ignore_dates,
                                          notify_func,
                                          notify_baton,
                                          pool));
 
-  /* Heh.  We know this is a parse_baton.  This file made it.  So
-     cast away, and set our hook booleans.  */
-  pb = parse_baton;
-  pb->use_pre_commit_hook = use_pre_commit_hook;
-  pb->use_post_commit_hook = use_post_commit_hook;
-  pb->ignore_dates = ignore_dates;
-
   return svn_repos_parse_dumpstream3(dumpstream, parser, parse_baton, FALSE,
                                      cancel_func, cancel_baton, pool);
 }

Modified: subversion/branches/pin-externals/subversion/libsvn_subr/cache-membuffer.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_subr/cache-membuffer.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_subr/cache-membuffer.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_subr/cache-membuffer.c Wed Jan 21 16:22:19 2015
@@ -31,6 +31,7 @@
 #include "cache.h"
 #include "svn_string.h"
 #include "svn_sorts.h"  /* get the MIN macro */
+#include "private/svn_atomic.h"
 #include "private/svn_dep_compat.h"
 #include "private/svn_mutex.h"
 #include "private/svn_pseudo_md5.h"
@@ -364,7 +365,7 @@ typedef struct entry_t
   /* Number of (read) hits for this entry. Will be reset upon write.
    * Only valid for used entries.
    */
-  apr_uint32_t hit_count;
+  svn_atomic_t hit_count;
 
   /* Reference to the next used entry in the order defined by offset.
    * NO_INDEX indicates the end of the list; this entry must be referenced
@@ -557,19 +558,14 @@ struct svn_membuffer_t
    */
   cache_level_t l2;
 
+
   /* Number of used dictionary entries, i.e. number of cached items.
-   * In conjunction with hit_count, this is used calculate the average
-   * hit count as part of the randomized LFU algorithm.
+   * Purely statistical information that may be used for profiling only.
+   * Updates are not synchronized and values may be nonsensicle on some
+   * platforms.
    */
   apr_uint32_t used_entries;
 
-  /* Sum of (read) hit counts of all used dictionary entries.
-   * In conjunction used_entries used_entries, this is used calculate
-   * the average hit count as part of the randomized LFU algorithm.
-   */
-  apr_uint64_t hit_count;
-
-
   /* Total number of calls to membuffer_cache_get.
    * Purely statistical information that may be used for profiling only.
    * Updates are not synchronized and values may be nonsensicle on some
@@ -608,12 +604,6 @@ struct svn_membuffer_t
    */
   svn_boolean_t allow_blocking_writes;
 #endif
-
-  /* All counters that have consistency requirements on thems (currently,
-   * that's only the hit counters) must use this mutex to serialize their
-   * updates.
-   */
-  svn_mutex__t *counter_mutex;
 };
 
 /* Align integer VALUE to the next ITEM_ALIGNMENT boundary.
@@ -715,7 +705,7 @@ unlock_cache(svn_membuffer_t *cache, svn
 #if APR_HAS_THREADS
 #  if USE_SIMPLE_MUTEX
 
-  return svn_mutex__unlock(cache->lock, SVN_NO_ERROR);
+  return svn_mutex__unlock(cache->lock, err);
 
 #  else
 
@@ -1027,7 +1017,6 @@ drop_entry(svn_membuffer_t *cache, entry
   /* update global cache usage counters
    */
   cache->used_entries--;
-  cache->hit_count -= entry->hit_count;
   cache->data_used -= entry->size;
 
   /* extend the insertion window, if the entry happens to border it
@@ -1163,7 +1152,6 @@ let_entry_age(svn_membuffer_t *cache, en
 
   if (hits_removed)
     {
-      cache->hit_count -= hits_removed;
       entry->hit_count -= hits_removed;
     }
   else
@@ -1795,7 +1783,6 @@ svn_cache__membuffer_cache_create(svn_me
       c[seg].max_entry_size = max_entry_size;
 
       c[seg].used_entries = 0;
-      c[seg].hit_count = 0;
       c[seg].total_reads = 0;
       c[seg].total_writes = 0;
       c[seg].total_hits = 0;
@@ -1836,11 +1823,6 @@ svn_cache__membuffer_cache_create(svn_me
        */
       c[seg].allow_blocking_writes = allow_blocking_writes;
 #endif
-
-      /* Since a simple mutex already guarantees fully serialized access,
-         we need this mutex only when we use multple-reader-1-writer locks. */
-      SVN_ERR(svn_mutex__init(&c[seg].counter_mutex,
-                              thread_safe && !USE_SIMPLE_MUTEX, pool));
     }
 
   /* done here
@@ -2067,21 +2049,17 @@ membuffer_cache_set(svn_membuffer_t *cac
 
 /* Count a hit in ENTRY within CACHE.
  */
-static svn_error_t *
+static void
 increment_hit_counters(svn_membuffer_t *cache, entry_t *entry)
 {
   /* To minimize the memory footprint of the cache index, we limit local
-   * hit counters to 32 bits.  These may overflow and we must make sure that
-   * the global sums are still the sum of all local counters. */
-  if (++entry->hit_count == 0)
-    cache->hit_count -= APR_UINT32_MAX;
-  else
-    cache->hit_count++;
+   * hit counters to 32 bits.  These may overflow but we don't really
+   * care because at worst, ENTRY will be dropped from cache once every
+   * few billion hits. */
+  svn_atomic_inc(&entry->hit_count);
 
   /* That one is for stats only. */
   cache->total_hits++;
-
-  return SVN_NO_ERROR;
 }
 
 /* Look for the cache entry in group GROUP_INDEX of CACHE, identified
@@ -2140,8 +2118,7 @@ membuffer_cache_get_internal(svn_membuff
 
   /* update hit statistics
    */
-  SVN_MUTEX__WITH_LOCK(cache->counter_mutex,
-                       increment_hit_counters(cache, entry));
+  increment_hit_counters(cache, entry);
   *item_size = entry->size;
 
   return SVN_NO_ERROR;
@@ -2205,9 +2182,7 @@ membuffer_cache_has_key_internal(svn_mem
          again.  While items in L1 are well protected for a while, L2
          items may get evicted soon.  Thus, mark all them as "hit" to give
          them a higher chance of survival. */
-      SVN_MUTEX__WITH_LOCK(cache->counter_mutex,
-                           increment_hit_counters(cache, entry));
-
+      increment_hit_counters(cache, entry);
       *found = TRUE;
     }
   else
@@ -2276,9 +2251,7 @@ membuffer_cache_get_partial_internal(svn
   else
     {
       *found = TRUE;
-
-      SVN_MUTEX__WITH_LOCK(cache->counter_mutex,
-                           increment_hit_counters(cache, entry));
+      increment_hit_counters(cache, entry);
 
 #ifdef SVN_DEBUG_CACHE_MEMBUFFER
 
@@ -2368,8 +2341,7 @@ membuffer_cache_set_partial_internal(svn
       char *orig_data = data;
       apr_size_t size = entry->size;
 
-      SVN_MUTEX__WITH_LOCK(cache->counter_mutex,
-                           increment_hit_counters(cache, entry));
+      increment_hit_counters(cache, entry);
       cache->total_writes++;
 
 #ifdef SVN_DEBUG_CACHE_MEMBUFFER
@@ -2398,6 +2370,8 @@ membuffer_cache_set_partial_internal(svn
            * We better drop that.
            */
           drop_entry(cache, entry);
+
+          return err;
         }
       else
         {

Modified: subversion/branches/pin-externals/subversion/libsvn_subr/cache.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_subr/cache.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_subr/cache.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_subr/cache.c Wed Jan 21 16:22:19 2015
@@ -259,15 +259,15 @@ svn_cache__format_info(const svn_cache__
 
       int i;
       int count = sizeof(info->histogram) / sizeof(info->histogram[0]);
-      for (i = 0; i < count; ++i)
+      for (i = count - 1; i >= 0; --i)
         if (info->histogram[i] > 0 || text->len > 0)
           text = svn_stringbuf_createf(result_pool,
                                        i == count - 1
-                                         ? "%12" APR_UINT64_T_FMT
-                                           " buckets with >%d entries\n%s"
-                                         : "%12" APR_UINT64_T_FMT
-                                           " buckets with %d entries\n%s",
-                                        info->histogram[i], i, text->data);
+                                         ? "%s%12" APR_UINT64_T_FMT
+                                           " buckets with >%d entries\n"
+                                         : "%s%12" APR_UINT64_T_FMT
+                                           " buckets with %d entries\n",
+                                       text->data, info->histogram[i], i);
 
       histogram = text->data;
     }

Modified: subversion/branches/pin-externals/subversion/libsvn_subr/cache_config.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_subr/cache_config.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_subr/cache_config.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_subr/cache_config.c Wed Jan 21 16:22:19 2015
@@ -27,6 +27,7 @@
 #include "private/svn_cache.h"
 
 #include "svn_pools.h"
+#include "svn_sorts.h"
 
 /* The cache settings as a process-wide singleton.
  */
@@ -80,7 +81,13 @@ initialize_cache(void *baton, apr_pool_t
   svn_membuffer_t **cache_p = baton;
   svn_membuffer_t *cache = NULL;
 
-  apr_uint64_t cache_size = cache_settings.cache_size;
+  /* Limit the cache size to about half the available address space
+   * (typ. 1G under 32 bits).
+   */
+  apr_uint64_t cache_size = MIN(cache_settings.cache_size,
+                                (apr_uint64_t)SVN_MAX_OBJECT_SIZE / 2);
+
+  /* Create caches at all? */
   if (cache_size)
     {
       svn_error_t *err;

Modified: subversion/branches/pin-externals/subversion/libsvn_subr/config.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_subr/config.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_subr/config.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_subr/config.c Wed Jan 21 16:22:19 2015
@@ -514,14 +514,15 @@ make_string_from_option(const char **val
           expand_option_value(cfg, section, opt->value, &opt->x_value, tmp_pool);
           opt->expanded = TRUE;
 
-          if (!x_pool)
+          if (x_pool != cfg->x_pool)
             {
               /* Grab the fully expanded value from tmp_pool before its
                  disappearing act. */
               if (opt->x_value)
                 opt->x_value = apr_pstrmemdup(cfg->x_pool, opt->x_value,
                                               strlen(opt->x_value));
-              svn_pool_destroy(tmp_pool);
+              if (!x_pool)
+                svn_pool_destroy(tmp_pool);
             }
         }
       else

Modified: subversion/branches/pin-externals/subversion/libsvn_subr/error.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_subr/error.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_subr/error.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_subr/error.c Wed Jan 21 16:22:19 2015
@@ -288,6 +288,8 @@ svn_error_compose(svn_error_t *chain, sv
       *chain = *new_err;
       if (chain->message)
         chain->message = apr_pstrdup(pool, new_err->message);
+      if (chain->file)
+        chain->file = apr_pstrdup(pool, new_err->file);
       chain->pool = pool;
 #if defined(SVN_DEBUG)
       if (! new_err->child)
@@ -364,6 +366,8 @@ svn_error_dup(const svn_error_t *err)
       tmp_err->pool = pool;
       if (tmp_err->message)
         tmp_err->message = apr_pstrdup(pool, tmp_err->message);
+      if (tmp_err->file)
+        tmp_err->file = apr_pstrdup(pool, tmp_err->file);
     }
 
 #if defined(SVN_DEBUG)
@@ -425,10 +429,8 @@ svn_error_purge_tracing(svn_error_t *err
       if (! err)
         return svn_error_create(
                  SVN_ERR_ASSERTION_ONLY_TRACING_LINKS,
-                 svn_error_compose_create(
-                   svn_error__malfunction(TRUE, __FILE__, __LINE__,
-                                          NULL /* ### say something? */),
-                   err),
+                 svn_error__malfunction(TRUE, __FILE__, __LINE__,
+                                        NULL /* ### say something? */),
                  NULL);
 
       /* Copy the current error except for its child error pointer

Modified: subversion/branches/pin-externals/subversion/libsvn_subr/io.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_subr/io.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_subr/io.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_subr/io.c Wed Jan 21 16:22:19 2015
@@ -1170,10 +1170,10 @@ svn_io_make_dir_recursively(const char *
 }
 
 svn_error_t *
-svn_io_file_create_binary(const char *file,
-                          const char *contents,
-                          apr_size_t length,
-                          apr_pool_t *pool)
+svn_io_file_create_bytes(const char *file,
+                         const void *contents,
+                         apr_size_t length,
+                         apr_pool_t *pool)
 {
   apr_file_t *f;
   apr_size_t written;
@@ -1209,18 +1209,17 @@ svn_io_file_create(const char *file,
                    const char *contents,
                    apr_pool_t *pool)
 {
-  return svn_error_trace(svn_io_file_create_binary(file, contents,
-                                                   contents
-                                                        ? strlen(contents)
-                                                        : 0,
-                                                   pool));
+  return svn_error_trace(svn_io_file_create_bytes(file, contents,
+                                                  contents ? strlen(contents)
+                                                           : 0,
+                                                  pool));
 }
 
 svn_error_t *
 svn_io_file_create_empty(const char *file,
                          apr_pool_t *pool)
 {
-  return svn_error_trace(svn_io_file_create_binary(file, "", 0, pool));
+  return svn_error_trace(svn_io_file_create_bytes(file, NULL, 0, pool));
 }
 
 svn_error_t *

Modified: subversion/branches/pin-externals/subversion/libsvn_subr/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_subr/mergeinfo.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_subr/mergeinfo.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_subr/mergeinfo.c Wed Jan 21 16:22:19 2015
@@ -99,9 +99,6 @@ parse_pathname(const char **input,
   if (!last_colon)
     return svn_error_create(SVN_ERR_MERGEINFO_PARSE_ERROR, NULL,
                             _("Pathname not terminated by ':'"));
-  if (last_colon == *input)
-    return svn_error_create(SVN_ERR_MERGEINFO_PARSE_ERROR, NULL,
-                            _("No pathname preceding ':'"));
 
   /* Tolerate relative repository paths, but convert them to absolute.
      ### Efficiency?  1 string duplication here, 2 in canonicalize. */
@@ -612,7 +609,12 @@ svn_rangelist__parse(svn_rangelist_t **r
 }
 
 /* Return TRUE, if all ranges in RANGELIST are in ascending order and do
- * not overlap.  If this returns FALSE, you probaly want to qsort() the
+ * not overlap and are not adjacent.
+ *
+ * ### Can yield false negatives: ranges of differing inheritance are
+ * allowed to be adjacent.
+ *
+ * If this returns FALSE, you probaly want to qsort() the
  * ranges and then call svn_rangelist__combine_adjacent_ranges().
  */
 static svn_boolean_t
@@ -629,6 +631,20 @@ is_rangelist_normalized(svn_rangelist_t
 }
 
 svn_error_t *
+svn_rangelist__canonicalize(svn_rangelist_t *rangelist,
+                            apr_pool_t *scratch_pool)
+{
+  if (! is_rangelist_normalized(rangelist))
+    {
+      svn_sort__array(rangelist, svn_sort_compare_ranges);
+
+      SVN_ERR(svn_rangelist__combine_adjacent_ranges(rangelist, scratch_pool));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_rangelist__combine_adjacent_ranges(svn_rangelist_t *rangelist,
                                        apr_pool_t *scratch_pool)
 {
@@ -715,14 +731,9 @@ parse_revision_line(const char **input,
 
   /* Sort the rangelist, combine adjacent ranges into single ranges, and
      make sure there are no overlapping ranges.  Luckily, most data in
-     svn:mergeinfo will already be in normalized form and we can skip this.
+     svn:mergeinfo will already be in normalized form and this will be quick.
    */
-  if (! is_rangelist_normalized(rangelist))
-    {
-      svn_sort__array(rangelist, svn_sort_compare_ranges);
-
-      SVN_ERR(svn_rangelist__combine_adjacent_ranges(rangelist, scratch_pool));
-    }
+  SVN_ERR(svn_rangelist__canonicalize(rangelist, scratch_pool));
 
   /* Handle any funky mergeinfo with relative merge source paths that
      might exist due to issue #3547.  It's possible that this issue allowed
@@ -1999,6 +2010,22 @@ svn_mergeinfo_sort(svn_mergeinfo_t input
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_mergeinfo__canonicalize_ranges(svn_mergeinfo_t mergeinfo,
+                                   apr_pool_t *scratch_pool)
+{
+  apr_hash_index_t *hi;
+
+  for (hi = apr_hash_first(scratch_pool, mergeinfo); hi; hi = apr_hash_next(hi))
+    {
+      apr_array_header_t *rl = apr_hash_this_val(hi);
+
+      SVN_ERR(svn_rangelist__canonicalize(rl, scratch_pool));
+    }
+
+  return SVN_NO_ERROR;
+}
+
 svn_mergeinfo_catalog_t
 svn_mergeinfo_catalog_dup(svn_mergeinfo_catalog_t mergeinfo_catalog,
                           apr_pool_t *pool)

Modified: subversion/branches/pin-externals/subversion/libsvn_subr/prefix_string.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_subr/prefix_string.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_subr/prefix_string.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_subr/prefix_string.c Wed Jan 21 16:22:19 2015
@@ -267,7 +267,7 @@ svn_prefix_string__expand(const svn_pref
   apr_size_t len = s->prefix->length + s_len;
   char *buffer = apr_palloc(pool, len + 1);
 
-  svn_string_t *result = apr_pcalloc(pool, sizeof(result));
+  svn_string_t *result = apr_pcalloc(pool, sizeof(*result));
   result->data = buffer;
   result->len = len;
   buffer[len] = '\0';

Modified: subversion/branches/pin-externals/subversion/libsvn_subr/sqlite.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_subr/sqlite.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_subr/sqlite.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_subr/sqlite.c Wed Jan 21 16:22:19 2015
@@ -189,6 +189,21 @@ struct svn_sqlite__value_t
                              sqlite3_errmsg((db)->db3));          \
 } while (0)
 
+#define SQLITE_ERR_CLOSE(x, db, pool) do                          \
+{                                                                 \
+  int sqlite_err__temp = (x);                                     \
+  if (sqlite_err__temp != SQLITE_OK)                              \
+    {                                                             \
+      const char *sqlite_err__msg                                 \
+        = apr_pstrdup(pool, sqlite3_errmsg((db)->db3));           \
+      return svn_error_compose_create(                            \
+           svn_error_createf(SQLITE_ERROR_CODE(sqlite_err__temp), \
+                             NULL, "sqlite[S%d]: %s",             \
+                             sqlite_err__temp, sqlite_err__msg),  \
+           svn_sqlite__close(db));                                \
+    }                                                             \
+} while (0)
+
 #define SQLITE_ERR_MSG(x, msg) do                                \
 {                                                                \
   int sqlite_err__temp = (x);                                    \
@@ -198,6 +213,13 @@ struct svn_sqlite__value_t
                              sqlite_err__temp, msg);             \
 } while (0)
 
+#define SVN_ERR_CLOSE(x, db) do                                       \
+{                                                                     \
+  svn_error_t *svn__err = (x);                                        \
+  if (svn__err)                                                       \
+    return svn_error_compose_create(svn__err, svn_sqlite__close(db)); \
+} while (0)
+
 
 /* Time (in milliseconds) to wait for sqlite locks before giving up. */
 #define BUSY_TIMEOUT 10000
@@ -809,7 +831,7 @@ init_sqlite(void *baton, apr_pool_t *poo
 }
 
 static svn_error_t *
-internal_open(sqlite3 **db3, const char *path, svn_sqlite__mode_t mode,
+internal_open(svn_sqlite__db_t *db, const char *path, svn_sqlite__mode_t mode,
               apr_int32_t timeout, apr_pool_t *scratch_pool)
 {
   {
@@ -856,13 +878,13 @@ internal_open(sqlite3 **db3, const char
 
     /* Open the database. Note that a handle is returned, even when an error
        occurs (except for out-of-memory); thus, we can safely use it to
-       extract an error message and construct an svn_error_t. */
+       extract an error message and construct an svn_error_t.  SQLite always
+       requires sqlite3_close() after sqlite3_open_v2() while Subversion 
+       typically does not require close() after an open() that returns an
+       error.  So we must ensure we close the handle if this function, or
+       the caller svn_sqlite__open, returns an error to the application. */
     {
       const char *vFs = NULL;
-      int err_code;
-      /* We'd like to use SQLITE_ERR here, but we can't since it would
-         just return an error and leave the database open.  So, we need to
-         do this manually. */
 
 #if defined(WIN32) && SQLITE_VERSION_AT_LEAST(3, 8, 1)
       if (strlen(path) > 248)
@@ -886,18 +908,8 @@ internal_open(sqlite3 **db3, const char
 #endif
 
       /* ### SQLITE_CANTOPEN */
-      err_code = sqlite3_open_v2(path, db3, flags, vFs);
-      if (err_code != SQLITE_OK)
-        {
-          /* Save the error message before closing the SQLite handle. */
-          char *msg = apr_pstrdup(scratch_pool, sqlite3_errmsg(*db3));
-
-          /* We don't catch the error here, since we care more about the open
-             error than the close error at this point. */
-          sqlite3_close(*db3);
-
-          SQLITE_ERR_MSG(err_code, msg);
-        }
+      SQLITE_ERR_CLOSE(sqlite3_open_v2(path, &db->db3, flags, vFs),
+                       db, scratch_pool);
     }
   }
 
@@ -905,7 +917,8 @@ internal_open(sqlite3 **db3, const char
     timeout = BUSY_TIMEOUT;
 
   /* Retry until timeout when database is busy. */
-  SQLITE_ERR_MSG(sqlite3_busy_timeout(*db3, timeout), sqlite3_errmsg(*db3));
+  SQLITE_ERR_CLOSE(sqlite3_busy_timeout(db->db3, timeout),
+                   db, scratch_pool);
 
   return SVN_NO_ERROR;
 }
@@ -925,35 +938,29 @@ close_apr(void *data)
   if (db->db3 == NULL)
     return APR_SUCCESS;
 
-  /* Finalize any existing prepared statements. */
-  for (i = 0; i < db->nbr_statements; i++)
+  /* Finalize any prepared statements. */
+  if (db->prepared_stmts)
     {
-      if (db->prepared_stmts[i])
+      for (i = 0; i < db->nbr_statements + STMT_INTERNAL_LAST; i++)
         {
-          if (db->prepared_stmts[i]->needs_reset)
+          if (db->prepared_stmts[i])
             {
+              if (i < db->nbr_statements
+                  && db->prepared_stmts[i]->needs_reset)
+                {
 #ifdef SVN_DEBUG
-              const char *stmt_text = db->statement_strings[i];
-              SVN_UNUSED(stmt_text);
+                  const char *stmt_text = db->statement_strings[i];
+                  SVN_UNUSED(stmt_text);
 
-              SVN_ERR_MALFUNCTION_NO_RETURN();
+                  SVN_ERR_MALFUNCTION_NO_RETURN();
 #else
-              err = svn_error_compose_create(
-                            err,
+                  err = svn_error_compose_create(err,
                             svn_sqlite__reset(db->prepared_stmts[i]));
 #endif
-            }
-          err = svn_error_compose_create(
-                        svn_sqlite__finalize(db->prepared_stmts[i]), err);
-        }
-    }
-  /* And finalize any used internal statements */
-  for (; i < db->nbr_statements + STMT_INTERNAL_LAST; i++)
-    {
-      if (db->prepared_stmts[i])
-        {
-          err = svn_error_compose_create(
+                }
+              err = svn_error_compose_create(
                         svn_sqlite__finalize(db->prepared_stmts[i]), err);
+            }
         }
     }
 
@@ -1081,7 +1088,7 @@ svn_sqlite__open(svn_sqlite__db_t **db,
 
   *db = apr_pcalloc(result_pool, sizeof(**db));
 
-  SVN_ERR(internal_open(&(*db)->db3, path, mode, timeout, scratch_pool));
+  SVN_ERR(internal_open(*db, path, mode, timeout, scratch_pool));
 
 #if SQLITE_VERSION_NUMBER >= 3008000 && SQLITE_VERSION_NUMBER < 3009000
   /* disable SQLITE_ENABLE_STAT3/4 from 3.8.1 - 3.8.3 (but not 3.8.3.1+)
@@ -1102,10 +1109,10 @@ svn_sqlite__open(svn_sqlite__db_t **db,
   svn_membuf__create(&(*db)->sqlext_buf3, 800, result_pool);
 
   /* Register collation and LIKE and GLOB operator replacements. */
-  SQLITE_ERR(sqlite3_create_collation((*db)->db3,
-                                      "svn-ucs-nfd", SQLITE_UTF8,
-                                      *db, collate_ucs_nfd),
-             *db);
+  SQLITE_ERR_CLOSE(sqlite3_create_collation((*db)->db3,
+                                            "svn-ucs-nfd", SQLITE_UTF8,
+                                            *db, collate_ucs_nfd),
+                   db, scratch_pool);
   /* ### Is it really necessary to override these functions?
          I would assume the default implementation to be collation agnostic?
          And otherwise our implementation should be...
@@ -1113,18 +1120,18 @@ svn_sqlite__open(svn_sqlite__db_t **db,
          The default implementation is in some cases index backed, while our
          implementation can't be. With an index based on the collation it could
          be. */
-  SQLITE_ERR(sqlite3_create_function((*db)->db3, "glob", 2,
-                                     SQLITE_UTF8 | SQLITE_DETERMINISTIC,
-                                     *db, glob_ucs_nfd, NULL, NULL),
-             *db);
-  SQLITE_ERR(sqlite3_create_function((*db)->db3, "like", 2,
-                                     SQLITE_UTF8 | SQLITE_DETERMINISTIC,
-                                     *db, like_ucs_nfd, NULL, NULL),
-             *db);
-  SQLITE_ERR(sqlite3_create_function((*db)->db3, "like", 3,
-                                     SQLITE_UTF8 | SQLITE_DETERMINISTIC,
-                                     *db, like_ucs_nfd, NULL, NULL),
-             *db);
+  SQLITE_ERR_CLOSE(sqlite3_create_function((*db)->db3, "glob", 2,
+                                           SQLITE_UTF8 | SQLITE_DETERMINISTIC,
+                                           *db, glob_ucs_nfd, NULL, NULL),
+                   db, scratch_pool);
+  SQLITE_ERR_CLOSE(sqlite3_create_function((*db)->db3, "like", 2,
+                                           SQLITE_UTF8 | SQLITE_DETERMINISTIC,
+                                           *db, like_ucs_nfd, NULL, NULL),
+                   db, scratch_pool);
+  SQLITE_ERR_CLOSE(sqlite3_create_function((*db)->db3, "like", 3,
+                                           SQLITE_UTF8 | SQLITE_DETERMINISTIC,
+                                           *db, like_ucs_nfd, NULL, NULL),
+                   db, scratch_pool);
 #endif /* SVN_UNICODE_NORMALIZATION_FIXES */
 
 #ifdef SQLITE3_DEBUG
@@ -1134,7 +1141,7 @@ svn_sqlite__open(svn_sqlite__db_t **db,
   sqlite3_profile((*db)->db3, sqlite_profiler, (*db)->db3);
 #endif
 
-  SVN_ERR(exec_sql(*db,
+  SVN_ERR_CLOSE(exec_sql(*db,
               /* The default behavior of the LIKE operator is to ignore case
                  for ASCII characters. Hence, by default 'a' LIKE 'A' is true.
                  The case_sensitive_like pragma installs a new application-
@@ -1164,13 +1171,15 @@ svn_sqlite__open(svn_sqlite__db_t **db,
                  affects application(read: Subversion) performance/behavior. */
               "PRAGMA foreign_keys=OFF;"      /* SQLITE_DEFAULT_FOREIGN_KEYS*/
               "PRAGMA locking_mode = NORMAL;" /* SQLITE_DEFAULT_LOCKING_MODE */
-              ));
+                            ),
+                *db);
 
 #if defined(SVN_DEBUG)
   /* When running in debug mode, enable the checking of foreign key
      constraints.  This has possible performance implications, so we don't
      bother to do it for production...for now. */
-  SVN_ERR(exec_sql(*db, "PRAGMA foreign_keys=ON;"));
+  SVN_ERR_CLOSE(exec_sql(*db, "PRAGMA foreign_keys=ON;"),
+                *db);
 #endif
 
 #ifdef SVN_SQLITE_REVERSE_UNORDERED_SELECTS
@@ -1178,7 +1187,8 @@ svn_sqlite__open(svn_sqlite__db_t **db,
      clause to emit their results in the reverse order of what they normally
      would.  This can help detecting invalid assumptions about the result
      order.*/
-  SVN_ERR(exec_sql(*db, "PRAGMA reverse_unordered_selects=ON;"));
+  SVN_ERR_CLOSE(exec_sql(*db, "PRAGMA reverse_unordered_selects=ON;"),
+                *db);
 #endif
 
   /* Store temporary tables in RAM instead of in temporary files, but don't

Modified: subversion/branches/pin-externals/subversion/libsvn_subr/string.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_subr/string.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_subr/string.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_subr/string.c Wed Jan 21 16:22:19 2015
@@ -655,23 +655,18 @@ svn_stringbuf_insert(svn_stringbuf_t *st
   if (count == 0)
     return;
 
+  /* special case: BYTES overlaps with this string -> copy the source */
   if (bytes + count > str->data && bytes < str->data + str->blocksize)
-    {
-      /* special case: BYTES overlaps with this string -> copy the source */
-      const char *temp = apr_pstrndup(str->pool, bytes, count);
-      svn_stringbuf_insert(str, pos, temp, count);
-    }
-  else
-    {
-      if (pos > str->len)
-        pos = str->len;
+    bytes = apr_pmemdup(str->pool, bytes, count);
+
+  if (pos > str->len)
+    pos = str->len;
 
-      svn_stringbuf_ensure(str, str->len + count);
-      memmove(str->data + pos + count, str->data + pos, str->len - pos + 1);
-      memcpy(str->data + pos, bytes, count);
+  svn_stringbuf_ensure(str, str->len + count);
+  memmove(str->data + pos + count, str->data + pos, str->len - pos + 1);
+  memcpy(str->data + pos, bytes, count);
 
-      str->len += count;
-    }
+  str->len += count;
 }
 
 void
@@ -703,32 +698,27 @@ svn_stringbuf_replace(svn_stringbuf_t *s
       return;
     }
 
+  /* special case: BYTES overlaps with this string -> copy the source */
   if (bytes + new_count > str->data && bytes < str->data + str->blocksize)
+    bytes = apr_pmemdup(str->pool, bytes, new_count);
+
+  if (pos > str->len)
+    pos = str->len;
+  if (pos + old_count > str->len)
+    old_count = str->len - pos;
+
+  if (old_count < new_count)
     {
-      /* special case: BYTES overlaps with this string -> copy the source */
-      const char *temp = apr_pstrndup(str->pool, bytes, new_count);
-      svn_stringbuf_replace(str, pos, old_count, temp, new_count);
+      apr_size_t delta = new_count - old_count;
+      svn_stringbuf_ensure(str, str->len + delta);
     }
-  else
-    {
-      if (pos > str->len)
-        pos = str->len;
-      if (pos + old_count > str->len)
-        old_count = str->len - pos;
 
-      if (old_count < new_count)
-        {
-          apr_size_t delta = new_count - old_count;
-          svn_stringbuf_ensure(str, str->len + delta);
-        }
+  if (old_count != new_count)
+    memmove(str->data + pos + new_count, str->data + pos + old_count,
+            str->len - pos - old_count + 1);
 
-      if (old_count != new_count)
-        memmove(str->data + pos + new_count, str->data + pos + old_count,
-                str->len - pos - old_count + 1);
-
-      memcpy(str->data + pos, bytes, new_count);
-      str->len += new_count - old_count;
-    }
+  memcpy(str->data + pos, bytes, new_count);
+  str->len += new_count - old_count;
 }
 
 
@@ -879,7 +869,7 @@ char *
 svn_cstring_tokenize(const char *sep, char **str)
 {
     char *token;
-    const char * next;
+    char *next;
     char csep;
 
     /* check parameters */
@@ -909,8 +899,8 @@ svn_cstring_tokenize(const char *sep, ch
       }
     else
       {
-        *(char *)next = '\0';
-        *str = (char *)next + 1;
+        *next = '\0';
+        *str = next + 1;
       }
 
     return token;

Modified: subversion/branches/pin-externals/subversion/libsvn_subr/sysinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_subr/sysinfo.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_subr/sysinfo.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_subr/sysinfo.c Wed Jan 21 16:22:19 2015
@@ -55,6 +55,10 @@
 
 #ifdef SVN_HAVE_MACOS_PLIST
 #include <CoreFoundation/CoreFoundation.h>
+#include <AvailabilityMacros.h>
+# ifndef MAC_OS_X_VERSION_10_6
+#  define MAC_OS_X_VERSION_10_6  1060
+# endif
 #endif
 
 #ifdef SVN_HAVE_MACHO_ITERATE
@@ -927,7 +931,6 @@ system_version_plist(svn_boolean_t *serv
   svn_error_t *err;
   CFPropertyListRef plist = NULL;
   CFMutableDataRef resource = CFDataCreateMutable(kCFAllocatorDefault, 0);
-  CFStringRef errstr = NULL;
 
   /* failed getting the CFMutableDataRef, shouldn't happen */
   if (!resource)
@@ -940,6 +943,7 @@ system_version_plist(svn_boolean_t *serv
       if (!APR_STATUS_IS_ENOENT(err->apr_err))
         {
           svn_error_clear(err);
+          CFRelease(resource);
           return NULL;
         }
       else
@@ -950,6 +954,7 @@ system_version_plist(svn_boolean_t *serv
           if (err)
             {
               svn_error_clear(err);
+              CFRelease(resource);
               return NULL;
             }
 
@@ -972,16 +977,23 @@ system_version_plist(svn_boolean_t *serv
       return NULL;
     }
 
-  /* ### CFPropertyListCreateFromXMLData is obsolete, but its
-         replacement CFPropertyListCreateWithData is only available
-         from Mac OS 10.6 onward. */
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
+  /* This function is only available from Mac OS 10.6 onward. */
+  plist = CFPropertyListCreateWithData(kCFAllocatorDefault, resource,
+                                       kCFPropertyListImmutable,
+                                       NULL, NULL);
+#else  /* Mac OS 10.5 or earlier */
+  /* This function obsolete and deprecated since Mac OS 10.10. */
   plist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resource,
                                           kCFPropertyListImmutable,
-                                          &errstr);
+                                          NULL);
+#endif /* MAC_OS_X_VERSION_10_6 */
+
   if (resource)
     CFRelease(resource);
-  if (errstr)
-    CFRelease(errstr);
+
+  if (!plist)
+    return NULL;
 
   if (CFDictionaryGetTypeID() != CFGetTypeID(plist))
     {

Modified: subversion/branches/pin-externals/subversion/libsvn_wc/conflicts.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_wc/conflicts.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_wc/conflicts.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_wc/conflicts.c Wed Jan 21 16:22:19 2015
@@ -2694,6 +2694,7 @@ resolve_tree_conflict_on_node(svn_boolea
   svn_skel_t *conflicts;
   svn_wc_operation_t operation;
   svn_boolean_t tree_conflicted;
+  const char *src_op_root_abspath;
 
   *did_resolve = FALSE;
 
@@ -2708,7 +2709,8 @@ resolve_tree_conflict_on_node(svn_boolea
   if (!tree_conflicted)
     return SVN_NO_ERROR;
 
-  SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, &action, NULL,
+  SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, &action,
+                                              &src_op_root_abspath,
                                               db, local_abspath,
                                               conflicts,
                                               scratch_pool, scratch_pool));
@@ -2725,7 +2727,8 @@ resolve_tree_conflict_on_node(svn_boolea
               /* Break moves for any children moved out of this directory,
                * and leave this directory deleted. */
               SVN_ERR(svn_wc__db_resolve_break_moved_away_children(
-                        db, local_abspath, notify_func, notify_baton,
+                        db, local_abspath, src_op_root_abspath,
+                        notify_func, notify_baton,
                         scratch_pool));
               *did_resolve = TRUE;
             }
@@ -2807,6 +2810,7 @@ resolve_tree_conflict_on_node(svn_boolea
                  ### involving the move until
                  ### svn_wc__db_op_mark_resolved. */
               SVN_ERR(svn_wc__db_resolve_break_moved_away(db, local_abspath,
+                                                          src_op_root_abspath,
                                                           notify_func,
                                                           notify_baton,
                                                           scratch_pool));

Modified: subversion/branches/pin-externals/subversion/libsvn_wc/wc-queries.sql
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_wc/wc-queries.sql?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/branches/pin-externals/subversion/libsvn_wc/wc-queries.sql Wed Jan 21 16:22:19 2015
@@ -235,11 +235,11 @@ WHERE wc_id = ?1 AND IS_STRICT_DESCENDAN
 DELETE FROM nodes
 WHERE wc_id = ?1 AND IS_STRICT_DESCENDANT_OF(local_relpath, ?2)
   AND presence = MAP_BASE_DELETED
-  AND op_depth > 0
+  AND op_depth > ?3
   AND op_depth = (SELECT MIN(op_depth) FROM nodes n
                     WHERE n.wc_id = ?1
                       AND n.local_relpath = nodes.local_relpath
-                      AND op_depth > 0)
+                      AND op_depth > ?3)
 
 -- STMT_DELETE_WORKING_RECURSIVE
 DELETE FROM nodes

Modified: subversion/branches/pin-externals/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_wc/wc_db.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_wc/wc_db.c Wed Jan 21 16:22:19 2015
@@ -1561,6 +1561,7 @@ svn_wc__db_init(svn_wc__db_t *db,
   svn_wc__db_wcroot_t *wcroot;
   svn_boolean_t sqlite_exclusive = FALSE;
   apr_int32_t sqlite_timeout = 0; /* default timeout */
+  apr_hash_index_t *hi;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
   SVN_ERR_ASSERT(repos_relpath != NULL);
@@ -1593,6 +1594,16 @@ svn_wc__db_init(svn_wc__db_t *db,
   /* The WCROOT is complete. Stash it into DB.  */
   svn_hash_sets(db->dir_data, wcroot->abspath, wcroot);
 
+  /* Any previously cached children now have a new WCROOT. */
+  for (hi = apr_hash_first(scratch_pool, db->dir_data);
+       hi;
+       hi = apr_hash_next(hi))
+    {
+      const char *abspath = apr_hash_this_key(hi);
+      if (svn_dirent_is_ancestor(wcroot->abspath, abspath))
+        svn_hash_sets(db->dir_data, abspath, wcroot);
+    }
+
   return SVN_NO_ERROR;
 }
 
@@ -2340,7 +2351,7 @@ db_base_remove(svn_wc__db_wcroot_t *wcro
     {
       SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                         STMT_DELETE_WORKING_BASE_DELETE));
-      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath, 0));
       SVN_ERR(svn_sqlite__step_done(stmt));
     }
   else
@@ -7594,7 +7605,11 @@ delete_update_movedto(svn_wc__db_wcroot_
                             op_depth,
                             new_moved_to_relpath));
   SVN_ERR(svn_sqlite__update(&affected, stmt));
-  assert(affected == 1);
+#ifdef SVN_DEBUG
+  /* Not fatal in release mode. The move recording is broken,
+     but the rest of the working copy can handle this. */
+  SVN_ERR_ASSERT(affected == 1);
+#endif
 
   return SVN_NO_ERROR;
 }
@@ -7984,7 +7999,12 @@ delete_node(void *baton,
                                                         child_relpath))
                         child_op_depth = delete_op_depth;
                       else
-                        child_op_depth = relpath_depth(child_relpath);
+                        {
+                          /* Calculate depth of the shadowing at the new location */
+                          child_op_depth = child_op_depth
+                                                - relpath_depth(local_relpath)
+                                                + relpath_depth(b->moved_to_relpath);
+                        }
 
                       fixup = TRUE;
                     }
@@ -13038,6 +13058,15 @@ svn_wc__db_upgrade_get_repos_id(apr_int6
   return svn_error_trace(svn_sqlite__reset(stmt));
 }
 
+svn_error_t *
+svn_wc__db_wq_add_internal(svn_wc__db_wcroot_t *wcroot,
+                           const svn_skel_t *work_item,
+                           apr_pool_t *scratch_pool)
+{
+  /* Add the work item(s) to the WORK_QUEUE.  */
+  return svn_error_trace(add_work_items(wcroot->sdb, work_item,
+                                        scratch_pool));
+}
 
 svn_error_t *
 svn_wc__db_wq_add(svn_wc__db_t *db,

Modified: subversion/branches/pin-externals/subversion/libsvn_wc/wc_db.h
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_wc/wc_db.h?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_wc/wc_db.h (original)
+++ subversion/branches/pin-externals/subversion/libsvn_wc/wc_db.h Wed Jan 21 16:22:19 2015
@@ -3479,6 +3479,7 @@ svn_wc__db_resolve_delete_raise_moved_aw
 svn_error_t *
 svn_wc__db_resolve_break_moved_away(svn_wc__db_t *db,
                                     const char *local_abspath,
+                                    const char *src_op_root_abspath,
                                     svn_wc_notify_func2_t notify_func,
                                     void *notify_baton,
                                     apr_pool_t *scratch_pool);
@@ -3491,6 +3492,7 @@ svn_wc__db_resolve_break_moved_away(svn_
 svn_error_t *
 svn_wc__db_resolve_break_moved_away_children(svn_wc__db_t *db,
                                              const char *local_abspath,
+                                             const char *src_op_root_abspath,
                                              svn_wc_notify_func2_t notify_func,
                                              void *notify_baton,
                                              apr_pool_t *scratch_pool);