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 [16/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_wc/wc_db_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_wc/wc_db_private.h?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_wc/wc_db_private.h (original)
+++ subversion/branches/pin-externals/subversion/libsvn_wc/wc_db_private.h Wed Jan 21 16:22:19 2015
@@ -216,6 +216,13 @@ svn_wc__db_util_open_db(svn_sqlite__db_t
                         apr_pool_t *result_pool,
                         apr_pool_t *scratch_pool);
 
+/* Like svn_wc__db_wq_add() but taking WCROOT */
+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);
+
+
 /* Like svn_wc__db_read_info(), but taking WCROOT+LOCAL_RELPATH instead of
    DB+LOCAL_ABSPATH, and outputting repos ids instead of URL+UUID. */
 svn_error_t *

Modified: subversion/branches/pin-externals/subversion/libsvn_wc/wc_db_update_move.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_wc/wc_db_update_move.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/libsvn_wc/wc_db_update_move.c (original)
+++ subversion/branches/pin-externals/subversion/libsvn_wc/wc_db_update_move.c Wed Jan 21 16:22:19 2015
@@ -101,6 +101,20 @@
 #include "token-map.h"
 
 /* Helper functions */
+/* Return the absolute path, in local path style, of LOCAL_RELPATH
+   in WCROOT.  */
+static const char *
+path_for_error_message(const svn_wc__db_wcroot_t *wcroot,
+                       const char *local_relpath,
+                       apr_pool_t *result_pool)
+{
+  const char *local_abspath
+    = svn_dirent_join(wcroot->abspath, local_relpath, result_pool);
+
+  return svn_dirent_local_style(local_abspath, result_pool);
+}
+
+/* Ensure that there is a working copy lock for LOCAL_RELPATH in WCROOT */
 static svn_error_t *
 verify_write_lock(svn_wc__db_wcroot_t *wcroot,
                   const char *local_relpath,
@@ -114,11 +128,8 @@ verify_write_lock(svn_wc__db_wcroot_t *w
     {
       return svn_error_createf(SVN_ERR_WC_NOT_LOCKED, NULL,
                                _("No write-lock in '%s'"),
-                               svn_dirent_local_style(
-                                            svn_dirent_join(wcroot->abspath,
-                                                            local_relpath,
-                                                            scratch_pool),
-                                            scratch_pool));
+                               path_for_error_message(wcroot, local_relpath,
+                                                      scratch_pool));
     }
 
   return SVN_NO_ERROR;
@@ -308,7 +319,7 @@ mark_tree_conflict(const char *local_rel
           && conflict_operation != svn_wc_operation_switch)
         return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
                                  _("'%s' already in conflict"),
-                                 svn_dirent_local_style(local_relpath,
+                                 path_for_error_message(wcroot, local_relpath,
                                                         scratch_pool));
 
       if (tree_conflicted)
@@ -332,7 +343,8 @@ mark_tree_conflict(const char *local_rel
                                                      existing_abspath))))
             return svn_error_createf(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
                                      _("'%s' already in conflict"),
-                                     svn_dirent_local_style(local_relpath,
+                                     path_for_error_message(wcroot,
+                                                            local_relpath,
                                                             scratch_pool));
 
           /* Already a suitable tree-conflict. */
@@ -396,28 +408,33 @@ mark_tree_conflict(const char *local_rel
 /* Checks if a specific local path is shadowed as seen from the move root */
 static svn_error_t *
 check_node_shadowed(svn_boolean_t *shadowed,
-                    update_move_baton_t *b,
+                    svn_wc__db_wcroot_t *wcroot,
                     const char *local_relpath,
+                    const char *move_root_dst_relpath,
                     apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
-  int op_depth = -1;
-  *shadowed = FALSE;
 
   /* ### This should really be optimized by using something smart
          in the baton */
 
-  SVN_ERR(svn_sqlite__get_statement(&stmt, b->wcroot->sdb,
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_SELECT_WORKING_NODE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", b->wcroot->wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
+
   if (have_row)
-    op_depth = svn_sqlite__column_int(stmt, 0);
-  SVN_ERR(svn_sqlite__reset(stmt));
+    {
+      int op_depth = -1;
 
-  *shadowed = (op_depth > relpath_depth(b->move_root_dst_relpath));
+      *shadowed = (op_depth > relpath_depth(move_root_dst_relpath));
+    }
+  else
+    *shadowed = FALSE;
+  SVN_ERR(svn_sqlite__reset(stmt));
 
   return SVN_NO_ERROR;
 }
@@ -576,8 +593,7 @@ tc_editor_add_directory(update_move_bato
       SVN_ERR(svn_wc__wq_build_dir_install(&work_item, b->db, abspath,
                                            scratch_pool, scratch_pool));
 
-      SVN_ERR(svn_wc__db_wq_add(b->db, b->wcroot->abspath, work_item,
-                                scratch_pool));
+      SVN_ERR(svn_wc__db_wq_add_internal(b->wcroot, work_item, scratch_pool));
       /* Fall through */
     case svn_node_dir:
       break;
@@ -663,8 +679,7 @@ tc_editor_add_file(update_move_baton_t *
                                         TRUE  /* record_file_info */,
                                         scratch_pool, scratch_pool));
 
-  SVN_ERR(svn_wc__db_wq_add(b->db, b->wcroot->abspath, work_item,
-                            scratch_pool));
+  SVN_ERR(svn_wc__db_wq_add_internal(b->wcroot, work_item, scratch_pool));
 
   SVN_ERR(update_move_list_add(b->wcroot, relpath,
                                svn_wc_notify_update_add,
@@ -867,8 +882,8 @@ tc_editor_alter_directory(update_move_ba
           SVN_ERR(svn_wc__db_mark_conflict_internal(b->wcroot, dst_relpath,
                                                     conflict_skel,
                                                     scratch_pool));
-          SVN_ERR(svn_wc__db_wq_add(b->db, b->wcroot->abspath, work_items,
-                                    scratch_pool));
+          SVN_ERR(svn_wc__db_wq_add_internal(b->wcroot, work_items,
+                                             scratch_pool));
         }
 
     SVN_ERR(update_move_list_add(b->wcroot, dst_relpath,
@@ -1003,8 +1018,7 @@ update_working_file(update_move_baton_t
       work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
     }
 
-  SVN_ERR(svn_wc__db_wq_add(b->db, b->wcroot->abspath, work_items,
-                            scratch_pool));
+  SVN_ERR(svn_wc__db_wq_add_internal(b->wcroot, work_items, scratch_pool));
 
   SVN_ERR(update_move_list_add(b->wcroot, local_relpath,
                                svn_wc_notify_update_update,
@@ -1182,8 +1196,7 @@ tc_editor_delete(update_move_baton_t *b,
                                                b->wcroot->abspath, del_abspath,
                                                iterpool, iterpool);
           if (!err)
-            err = svn_wc__db_wq_add(b->db, b->wcroot->abspath, work_item,
-                                    iterpool);
+            err = svn_wc__db_wq_add_internal(b->wcroot, work_item, iterpool);
           if (err)
             return svn_error_compose_create(err, svn_sqlite__reset(stmt));
 
@@ -1205,8 +1218,7 @@ tc_editor_delete(update_move_baton_t *b,
         SVN_ERR(svn_wc__wq_build_file_remove(&work_item, b->db,
                                              b->wcroot->abspath, local_abspath,
                                              iterpool, iterpool));
-      SVN_ERR(svn_wc__db_wq_add(b->db, b->wcroot->abspath, work_item,
-                                iterpool));
+      SVN_ERR(svn_wc__db_wq_add_internal(b->wcroot, work_item, iterpool));
 
       if (!is_conflicted)
         SVN_ERR(update_move_list_add(b->wcroot, relpath,
@@ -1221,23 +1233,23 @@ tc_editor_delete(update_move_baton_t *b,
 
 /* Delete handling for both WORKING and shadowed nodes */
 static svn_error_t *
-delete_move_leaf(update_move_baton_t *b,
-                 const char *relpath,
+delete_move_leaf(svn_wc__db_wcroot_t *wcroot,
+                 const char *local_relpath,
+                 int op_depth,
                  apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
-  int op_depth = relpath_depth(b->move_root_dst_relpath);
-  const char *parent_relpath = svn_relpath_dirname(relpath, scratch_pool);
   svn_boolean_t have_row;
   int op_depth_below;
 
-  /* Deleting the ROWS is valid so long as we update the parent before
+  /* Deleting the ROWS is valid as long as we update the parent before
      committing the transaction.  The removed rows could have been
      replacing a lower layer in which case we need to add base-deleted
      rows. */
-  SVN_ERR(svn_sqlite__get_statement(&stmt, b->wcroot->sdb,
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_SELECT_HIGHEST_WORKING_NODE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "isd", b->wcroot->wc_id, parent_relpath,
+  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
+                            svn_relpath_dirname(local_relpath, scratch_pool),
                             op_depth));
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
   if (have_row)
@@ -1246,30 +1258,38 @@ delete_move_leaf(update_move_baton_t *b,
   if (have_row)
     {
       /* Remove non-shadowing nodes. */
-      SVN_ERR(svn_sqlite__get_statement(&stmt, b->wcroot->sdb,
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                         STMT_DELETE_NO_LOWER_LAYER));
-      SVN_ERR(svn_sqlite__bindf(stmt, "isdd", b->wcroot->wc_id, relpath,
+      SVN_ERR(svn_sqlite__bindf(stmt, "isdd", wcroot->wc_id, local_relpath,
                                 op_depth, op_depth_below));
       SVN_ERR(svn_sqlite__step_done(stmt));
 
       /* Convert remaining shadowing nodes to presence='base-deleted'. */
-      SVN_ERR(svn_sqlite__get_statement(&stmt, b->wcroot->sdb,
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                         STMT_REPLACE_WITH_BASE_DELETED));
-      SVN_ERR(svn_sqlite__bindf(stmt, "isd", b->wcroot->wc_id, relpath,
+      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
                                 op_depth));
       SVN_ERR(svn_sqlite__step_done(stmt));
     }
   else
     {
-      SVN_ERR(svn_sqlite__get_statement(&stmt, b->wcroot->sdb,
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                         STMT_DELETE_WORKING_OP_DEPTH));
-      SVN_ERR(svn_sqlite__bindf(stmt, "isd", b->wcroot->wc_id, relpath,
+      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
                                 op_depth));
       SVN_ERR(svn_sqlite__step_done(stmt));
     }
 
-  /* Retract any base-delete. */
-  SVN_ERR(svn_wc__db_retract_parent_delete(b->wcroot, relpath, op_depth,
+  /* Retract any base-delete for descendants. */
+  {
+    SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                        STMT_DELETE_WORKING_BASE_DELETE));
+    SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
+                              op_depth));
+    SVN_ERR(svn_sqlite__step_done(stmt));
+  }
+  /* And for the node itself */
+  SVN_ERR(svn_wc__db_retract_parent_delete(wcroot, local_relpath, op_depth,
                                            scratch_pool));
 
   return SVN_NO_ERROR;
@@ -1492,6 +1512,9 @@ update_moved_away_node(update_move_baton
   apr_array_header_t *src_children, *dst_children;
   int dst_op_depth = relpath_depth(move_root_dst_relpath);
 
+  SVN_ERR(verify_write_lock(wcroot, src_relpath, scratch_pool));
+  SVN_ERR(verify_write_lock(wcroot, dst_relpath, scratch_pool));
+
   SVN_ERR(get_info(&src_props, &src_checksum, &src_children, &src_kind,
                    src_relpath, src_op_depth,
                    wcroot, scratch_pool, scratch_pool));
@@ -1508,7 +1531,9 @@ update_moved_away_node(update_move_baton
 
       /* And perform some work that in some ways belongs in
          replace_moved_layer() after creating all conflicts */
-      SVN_ERR(delete_move_leaf(b, dst_relpath, scratch_pool));
+      SVN_ERR(delete_move_leaf(b->wcroot, dst_relpath,
+                               relpath_depth(b->move_root_dst_relpath),
+                               scratch_pool));
     }
 
   if (src_kind != svn_node_none && src_kind != dst_kind)
@@ -1609,8 +1634,8 @@ update_moved_away_node(update_move_baton
                                                iterpool);
 
           if (!child_shadowed)
-            SVN_ERR(check_node_shadowed(&child_shadowed, b, dst_child_relpath,
-                                        iterpool));
+            SVN_ERR(check_node_shadowed(&child_shadowed, wcroot, dst_child_relpath,
+                                        b->move_root_dst_relpath, iterpool));
 
           SVN_ERR(update_moved_away_node(b, wcroot, src_child_relpath,
                                          dst_child_relpath, src_op_depth,
@@ -1641,6 +1666,9 @@ replace_moved_layer(const char *src_relp
   svn_boolean_t have_row;
   int dst_op_depth = relpath_depth(dst_relpath);
 
+  SVN_ERR(verify_write_lock(wcroot, src_relpath, scratch_pool));
+  SVN_ERR(verify_write_lock(wcroot, dst_relpath, scratch_pool));
+
   /* Replace entire subtree at one op-depth. */
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_SELECT_LOCAL_RELPATH_OP_DEPTH));
@@ -1719,10 +1747,8 @@ drive_tree_conflict_editor(update_move_b
       operation != svn_wc_operation_switch)
     return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
                             _("Cannot auto-resolve tree-conflict on '%s'"),
-                            svn_dirent_local_style(
-                              svn_dirent_join(wcroot->abspath,
-                                              src_relpath, scratch_pool),
-                              scratch_pool));
+                            path_for_error_message(wcroot, src_relpath,
+                                                   scratch_pool));
 
   /* We walk the move source (i.e. the post-update tree), comparing each node
    * with the equivalent node at the move destination and applying the update
@@ -1780,22 +1806,17 @@ suitable_for_move(svn_wc__db_wcroot_t *w
                                  svn_sqlite__reset(stmt),
                                  _("Cannot apply update because move source "
                                    "%s' is a mixed-revision working copy"),
-                                 svn_dirent_local_style(svn_dirent_join(
-                                                          wcroot->abspath,
-                                                          local_relpath,
-                                                          scratch_pool),
-                                 scratch_pool));
+                                 path_for_error_message(wcroot, local_relpath,
+                                                        scratch_pool));
 
       if (strcmp(relpath, svn_sqlite__column_text(stmt, 1, NULL)))
         return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
                                  svn_sqlite__reset(stmt),
                                  _("Cannot apply update because move source "
                                    "'%s' is a switched subtree"),
-                                 svn_dirent_local_style(svn_dirent_join(
-                                                          wcroot->abspath,
-                                                          local_relpath,
-                                                          scratch_pool),
-                                 scratch_pool));
+                                 path_for_error_message(wcroot,
+                                                        local_relpath,
+                                                        scratch_pool));
 
       SVN_ERR(svn_sqlite__step(&have_row, stmt));
     }
@@ -1840,10 +1861,8 @@ update_moved_away_conflict_victim(svn_wc
   if (umb.move_root_dst_relpath == NULL)
     return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
                              _("The node '%s' has not been moved away"),
-                             svn_dirent_local_style(
-                               svn_dirent_join(wcroot->abspath, victim_relpath,
-                                               scratch_pool),
-                               scratch_pool));
+                             path_for_error_message(wcroot, victim_relpath,
+                                                    scratch_pool));
 
   move_root_dst_abspath
     = svn_dirent_join(wcroot->abspath, umb.move_root_dst_relpath,
@@ -1869,10 +1888,8 @@ update_moved_away_conflict_victim(svn_wc
   if (!have_row)
     return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
                              _("'%s' is not deleted"),
-                             svn_dirent_local_style(
-                               svn_dirent_join(wcroot->abspath, victim_relpath,
-                                               scratch_pool),
-                               scratch_pool));
+                             path_for_error_message(wcroot, victim_relpath,
+                                                    scratch_pool));
 
   if (src_op_depth == 0)
     SVN_ERR(suitable_for_move(wcroot, victim_relpath, scratch_pool));
@@ -2045,8 +2062,8 @@ bump_mark_tree_conflict(svn_wc__db_wcroo
   svn_wc_conflict_version_t *old_version;
   svn_wc_conflict_version_t *new_version;
 
-  SVN_ERR(verify_write_lock(wcroot, move_src_op_root_relpath, scratch_pool));
-  SVN_ERR(verify_write_lock(wcroot, move_dst_op_root_relpath, scratch_pool));
+  /* Verify precondition: We are allowed to set a tree conflict here. */
+  SVN_ERR(verify_write_lock(wcroot, move_src_root_relpath, scratch_pool));
 
   /* Read new (post-update) information from the new move source BASE node. */
   SVN_ERR(svn_wc__db_base_get_info_internal(NULL, &new_kind, &new_rev,
@@ -2058,7 +2075,14 @@ bump_mark_tree_conflict(svn_wc__db_wcroo
   SVN_ERR(svn_wc__db_fetch_repos_info(&repos_root_url, &repos_uuid,
                                       wcroot->sdb, repos_id, scratch_pool));
 
-  /* Read old (pre-update) information from the move destination node. */
+  /* Read old (pre-update) information from the move destination node.
+
+     This potentially touches nodes that aren't locked by us, but that is not
+     a problem because we have a SQLite write lock here, and all sqlite
+     operations that affect move stability use a sqlite lock as well.
+     (And affecting the move itself requires a write lock on the node that
+      we do own the lock for: the move source)
+  */
   SVN_ERR(svn_wc__db_depth_get_info(NULL, &old_kind, &old_rev,
                                     &old_repos_relpath, NULL, NULL, NULL,
                                     NULL, NULL, NULL, NULL, NULL, NULL,
@@ -2066,6 +2090,21 @@ bump_mark_tree_conflict(svn_wc__db_wcroo
                                     relpath_depth(move_dst_op_root_relpath),
                                     scratch_pool, scratch_pool));
 
+  if (strcmp(move_src_root_relpath, move_src_op_root_relpath))
+    {
+      /* We have information for the op-root, but need it for the node that
+         we are putting the tree conflict on. Luckily we know that we have
+         a clean BASE */
+
+      const char *rpath = svn_relpath_skip_ancestor(move_src_op_root_relpath,
+                                                    move_src_root_relpath);
+
+      old_repos_relpath = svn_relpath_join(old_repos_relpath, rpath,
+                                           scratch_pool);
+      new_repos_relpath = svn_relpath_join(new_repos_relpath, rpath,
+                                           scratch_pool);
+    }
+
   old_version = svn_wc_conflict_version_create2(
                   repos_root_url, repos_uuid, old_repos_relpath, old_rev,
                   old_kind, scratch_pool);
@@ -2332,10 +2371,26 @@ svn_wc__db_bump_moved_away(svn_wc__db_wc
         {
           if (strcmp(move_src_root_relpath, local_relpath))
             {
-              SVN_ERR(bump_mark_tree_conflict(wcroot, move_src_root_relpath,
-                                              move_src_op_root_relpath,
-                                              move_dst_op_root_relpath,
-                                              db, scratch_pool));
+              /* An ancestor of the path that was updated is moved away.
+
+                 If we have a lock on that ancestor, we can mark a tree
+                 conflict on it, if we don't we ignore this case. A future
+                 update of the ancestor will handle this. */
+              svn_boolean_t locked;
+
+              SVN_ERR(svn_wc__db_wclock_owns_lock_internal(
+                                &locked, wcroot,
+                                move_src_root_relpath,
+                                FALSE, scratch_pool));
+
+              if (locked)
+                {
+                  SVN_ERR(bump_mark_tree_conflict(wcroot,
+                                                  move_src_root_relpath,
+                                                  move_src_op_root_relpath,
+                                                  move_dst_op_root_relpath,
+                                                  db, scratch_pool));
+                }
               return SVN_NO_ERROR;
             }
         }
@@ -2524,16 +2579,29 @@ break_moved_away_children_internal(svn_w
       const char *src_relpath = svn_sqlite__column_text(stmt, 0, NULL);
       const char *dst_relpath = svn_sqlite__column_text(stmt, 1, NULL);
       int src_op_depth = svn_sqlite__column_int(stmt, 2);
+      svn_error_t *err;
 
       svn_pool_clear(iterpool);
 
-      SVN_ERR(break_move(wcroot, src_relpath, src_op_depth, dst_relpath,
-                         iterpool));
-      SVN_ERR(update_move_list_add(wcroot, src_relpath,
-                                   svn_wc_notify_move_broken,
-                                   svn_node_unknown,
-                                   svn_wc_notify_state_inapplicable,
-                                   svn_wc_notify_state_inapplicable));
+      err = break_move(wcroot, src_relpath, src_op_depth, dst_relpath,
+                       iterpool);
+
+      if (! err)
+        {
+          err = update_move_list_add(wcroot, src_relpath,
+                                     svn_wc_notify_move_broken,
+                                     svn_node_unknown,
+                                     svn_wc_notify_state_inapplicable,
+                                     svn_wc_notify_state_inapplicable);
+        }
+
+      if (err)
+        {
+          return svn_error_trace(
+                          svn_error_compose_create(err,
+                                                   svn_sqlite__reset(stmt)));
+        }
+
       SVN_ERR(svn_sqlite__step(&have_row, stmt));
     }
   svn_pool_destroy(iterpool);
@@ -2546,21 +2614,26 @@ break_moved_away_children_internal(svn_w
 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)
 {
   svn_wc__db_wcroot_t *wcroot;
   const char *local_relpath;
+  const char *src_relpath;
 
   SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
                                                 db, local_abspath,
                                                 scratch_pool, scratch_pool));
   VERIFY_USABLE_WCROOT(wcroot);
 
+  src_relpath = svn_dirent_skip_ancestor(wcroot->abspath, src_op_root_abspath);
+  SVN_ERR_ASSERT(src_relpath != NULL);
+
   SVN_WC__DB_WITH_TXN(
     svn_wc__db_resolve_break_moved_away_internal(wcroot, local_relpath,
-                                                 relpath_depth(local_relpath),
+                                                 relpath_depth(src_relpath),
                                                  scratch_pool),
     wcroot);
 
@@ -2586,6 +2659,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)

Modified: subversion/branches/pin-externals/subversion/mod_authz_svn/mod_authz_svn.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/mod_authz_svn/mod_authz_svn.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/mod_authz_svn/mod_authz_svn.c (original)
+++ subversion/branches/pin-externals/subversion/mod_authz_svn/mod_authz_svn.c Wed Jan 21 16:22:19 2015
@@ -244,15 +244,26 @@ static const command_rec authz_svn_cmds[
  * per-module loglevel configuration.  It expands to FILE and LINE
  * in older server versions.  ALLOWED is boolean.
  * REPOS_PATH and DEST_REPOS_PATH are information
- * about the request.  DEST_REPOS_PATH may be NULL. */
+ * about the request.  DEST_REPOS_PATH may be NULL.
+ * Non-zero IS_SUBREQ_BYPASS means that this authorization check was
+ * implicitly requested using 'subrequest bypass' callback from
+ * mod_dav_svn.
+ */
 static void
 log_access_verdict(LOG_ARGS_SIGNATURE,
-                   const request_rec *r, int allowed,
+                   const request_rec *r, int allowed, int is_subreq_bypass,
                    const char *repos_path, const char *dest_repos_path)
 {
-  int level = allowed ? APLOG_INFO : APLOG_WARNING;
+  int level = allowed ? APLOG_INFO : APLOG_ERR;
   const char *verdict = allowed ? "granted" : "denied";
 
+  /* Use less important log level for implicit sub-request authorization
+     checks. */
+  if (is_subreq_bypass)
+    level = APLOG_INFO;
+  else if (r->main && r->method_number == M_GET)
+    level = APLOG_INFO;
+
   if (r->user)
     {
       if (dest_repos_path)
@@ -361,7 +372,7 @@ get_access_conf(request_rec *r, authz_sv
   svn_error_t *svn_err = SVN_NO_ERROR;
   dav_error *dav_err;
 
-  dav_err = dav_svn_get_repos_path(r, conf->base_path, &repos_path);
+  dav_err = dav_svn_get_repos_path2(r, conf->base_path, &repos_path, scratch_pool);
   if (dav_err)
     {
       ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "%s", dav_err->desc);
@@ -749,7 +760,7 @@ subreq_bypass2(request_rec *r,
   if (!conf->anonymous
       || (! (conf->access_file || conf->repo_relative_access_file)))
     {
-      log_access_verdict(APLOG_MARK, r, 0, repos_path, NULL);
+      log_access_verdict(APLOG_MARK, r, 0, TRUE, repos_path, NULL);
       return HTTP_FORBIDDEN;
     }
 
@@ -778,12 +789,12 @@ subreq_bypass2(request_rec *r,
         }
       if (!authz_access_granted)
         {
-          log_access_verdict(APLOG_MARK, r, 0, repos_path, NULL);
+          log_access_verdict(APLOG_MARK, r, 0, TRUE, repos_path, NULL);
           return HTTP_FORBIDDEN;
         }
     }
 
-  log_access_verdict(APLOG_MARK, r, 1, repos_path, NULL);
+  log_access_verdict(APLOG_MARK, r, 1, TRUE, repos_path, NULL);
 
   return OK;
 }
@@ -858,7 +869,7 @@ access_checker(request_rec *r)
         return DECLINED;
 
       if (!authn_required)
-        log_access_verdict(APLOG_MARK, r, 0, repos_path, dest_repos_path);
+        log_access_verdict(APLOG_MARK, r, 0, FALSE, repos_path, dest_repos_path);
 
       return HTTP_FORBIDDEN;
     }
@@ -866,7 +877,7 @@ access_checker(request_rec *r)
   if (status != OK)
     return status;
 
-  log_access_verdict(APLOG_MARK, r, 1, repos_path, dest_repos_path);
+  log_access_verdict(APLOG_MARK, r, 1, FALSE, repos_path, dest_repos_path);
 
   return OK;
 }
@@ -893,7 +904,7 @@ check_user_id(request_rec *r)
   if (status == OK)
     {
       apr_table_setn(r->notes, "authz_svn-anon-ok", (const char*)1);
-      log_access_verdict(APLOG_MARK, r, 1, repos_path, dest_repos_path);
+      log_access_verdict(APLOG_MARK, r, 1, FALSE, repos_path, dest_repos_path);
       return OK;
     }
 
@@ -923,7 +934,7 @@ auth_checker(request_rec *r)
     {
       if (conf->authoritative)
         {
-          log_access_verdict(APLOG_MARK, r, 0, repos_path, dest_repos_path);
+          log_access_verdict(APLOG_MARK, r, 0, FALSE, repos_path, dest_repos_path);
           ap_note_auth_failure(r);
           return HTTP_FORBIDDEN;
         }
@@ -933,7 +944,7 @@ auth_checker(request_rec *r)
   if (status != OK)
     return status;
 
-  log_access_verdict(APLOG_MARK, r, 1, repos_path, dest_repos_path);
+  log_access_verdict(APLOG_MARK, r, 1, FALSE, repos_path, dest_repos_path);
 
   return OK;
 }

Modified: subversion/branches/pin-externals/subversion/mod_dav_svn/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/mod_dav_svn/merge.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/mod_dav_svn/merge.c (original)
+++ subversion/branches/pin-externals/subversion/mod_dav_svn/merge.c Wed Jan 21 16:22:19 2015
@@ -136,12 +136,13 @@ do_resources(const dav_svn_repos *repos,
       const void *key;
       void *val;
       const char *path;
+      apr_ssize_t path_len;
       svn_fs_path_change2_t *change;
       svn_boolean_t send_self;
       svn_boolean_t send_parent;
 
       svn_pool_clear(subpool);
-      apr_hash_this(hi, &key, NULL, &val);
+      apr_hash_this(hi, &key, &path_len, &val);
       path = key;
       change = val;
 
@@ -170,14 +171,14 @@ do_resources(const dav_svn_repos *repos,
         {
           /* If we haven't already sent this path, send it (and then
              remember that we sent it). */
-          if (! svn_hash_gets(sent, path))
+          if (! apr_hash_get(sent, path, path_len))
             {
               svn_node_kind_t kind;
               SVN_ERR(svn_fs_check_path(&kind, root, path, subpool));
               SVN_ERR(send_response(repos, root, path,
                                     kind == svn_node_dir,
                                     output, bb, subpool));
-              svn_hash_sets(sent, path, (void *)1);
+              apr_hash_set(sent, path, path_len, (void *)1);
             }
         }
       if (send_parent)

Modified: subversion/branches/pin-externals/subversion/mod_dav_svn/mod_dav_svn.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/mod_dav_svn/mod_dav_svn.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/mod_dav_svn/mod_dav_svn.c (original)
+++ subversion/branches/pin-externals/subversion/mod_dav_svn/mod_dav_svn.c Wed Jan 21 16:22:19 2015
@@ -662,9 +662,10 @@ dav_svn__get_fs_parent_path(request_rec
 
 
 AP_MODULE_DECLARE(dav_error *)
-dav_svn_get_repos_path(request_rec *r,
-                       const char *root_path,
-                       const char **repos_path)
+dav_svn_get_repos_path2(request_rec *r,
+                        const char *root_path,
+                        const char **repos_path,
+                        apr_pool_t *pool)
 {
 
   const char *fs_path;
@@ -692,19 +693,26 @@ dav_svn_get_repos_path(request_rec *r,
 
   /* Split the svn URI to get the name of the repository below
      the parent path. */
-  derr = dav_svn_split_uri(r, r->uri, root_path,
-                           &ignored_cleaned_uri, &ignored_had_slash,
-                           &repos_name,
-                           &ignored_relative, &ignored_path_in_repos);
+  derr = dav_svn_split_uri2(r, r->uri, root_path,
+                            &ignored_cleaned_uri, &ignored_had_slash,
+                            &repos_name,
+                            &ignored_relative, &ignored_path_in_repos, pool);
   if (derr)
     return derr;
 
   /* Construct the full path from the parent path base directory
      and the repository name. */
-  *repos_path = svn_dirent_join(fs_parent_path, repos_name, r->pool);
+  *repos_path = svn_dirent_join(fs_parent_path, repos_name, pool);
   return NULL;
 }
 
+AP_MODULE_DECLARE(dav_error *)
+dav_svn_get_repos_path(request_rec *r,
+                       const char *root_path,
+                       const char **repos_path)
+{
+  return dav_svn_get_repos_path2(r, root_path, repos_path, r->pool);
+}
 
 const char *
 dav_svn__get_repo_name(request_rec *r)
@@ -1324,8 +1332,8 @@ static const command_rec cmds[] =
   AP_INIT_TAKE1("SVNInMemoryCacheSize", SVNInMemoryCacheSize_cmd, NULL,
                 RSRC_CONF,
                 "specifies the maximum size in kB per process of Subversion's "
-                "in-memory object cache (default value is 16384; 0 deactivates "
-                "the cache)."),
+                "in-memory object cache (default value is 16384; 0 switches "
+                "to dynamically sized caches)."),
   /* per server */
   AP_INIT_TAKE1("SVNCompressionLevel", SVNCompressionLevel_cmd, NULL,
                 RSRC_CONF,

Modified: subversion/branches/pin-externals/subversion/mod_dav_svn/repos.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/mod_dav_svn/repos.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/mod_dav_svn/repos.c (original)
+++ subversion/branches/pin-externals/subversion/mod_dav_svn/repos.c Wed Jan 21 16:22:19 2015
@@ -1209,14 +1209,15 @@ static void log_warning(void *baton, svn
 
 
 AP_MODULE_DECLARE(dav_error *)
-dav_svn_split_uri(request_rec *r,
-                  const char *uri_to_split,
-                  const char *root_path,
-                  const char **cleaned_uri,
-                  int *trailing_slash,
-                  const char **repos_basename,
-                  const char **relative_path,
-                  const char **repos_path)
+dav_svn_split_uri2(request_rec *r,
+                   const char *uri_to_split,
+                   const char *root_path,
+                   const char **cleaned_uri,
+                   int *trailing_slash,
+                   const char **repos_basename,
+                   const char **relative_path,
+                   const char **repos_path,
+                   apr_pool_t *pool)
 {
   apr_size_t len1;
   int had_slash;
@@ -1232,7 +1233,7 @@ dav_svn_split_uri(request_rec *r,
   if ((fs_path == NULL) && (fs_parent_path == NULL))
     {
       /* ### are SVN_ERR_APMOD codes within the right numeric space? */
-      return dav_svn__new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR,
+      return dav_svn__new_error(pool, HTTP_INTERNAL_SERVER_ERROR,
                                 SVN_ERR_APMOD_MISSING_PATH_TO_FS,
                                 "The server is misconfigured: "
                                 "either an SVNPath or SVNParentPath "
@@ -1241,7 +1242,7 @@ dav_svn_split_uri(request_rec *r,
     }
 
   /* make a copy so that we can do some work on it */
-  uri = apr_pstrdup(r->pool, uri_to_split);
+  uri = apr_pstrdup(pool, uri_to_split);
 
   /* remove duplicate slashes, and make sure URI has no trailing '/' */
   ap_no2slash(uri);
@@ -1256,7 +1257,7 @@ dav_svn_split_uri(request_rec *r,
     *trailing_slash = FALSE;
 
   /* return the first item.  */
-  *cleaned_uri = apr_pstrdup(r->pool, uri);
+  *cleaned_uri = apr_pstrdup(pool, uri);
 
   /* The URL space defined by the SVN provider is always a virtual
      space. Construct the path relative to the configured Location
@@ -1297,7 +1298,7 @@ dav_svn_split_uri(request_rec *r,
   if (fs_path != NULL)
     {
       /* the repos_basename is the last component of root_path. */
-      *repos_basename = svn_dirent_basename(root_path, r->pool);
+      *repos_basename = svn_dirent_basename(root_path, pool);
 
       /* 'relative' is already correct for SVNPath; the root_path
          already contains the name of the repository, so relative is
@@ -1315,7 +1316,7 @@ dav_svn_split_uri(request_rec *r,
       if (relative[1] == '\0')
         {
           /* ### are SVN_ERR_APMOD codes within the right numeric space? */
-          return dav_svn__new_error(r->pool, HTTP_FORBIDDEN,
+          return dav_svn__new_error(pool, HTTP_FORBIDDEN,
                                     SVN_ERR_APMOD_MALFORMED_URI,
                                     "The URI does not contain the name "
                                     "of a repository.");
@@ -1332,7 +1333,7 @@ dav_svn_split_uri(request_rec *r,
         }
       else
         {
-          magic_component = apr_pstrndup(r->pool, relative + 1,
+          magic_component = apr_pstrndup(pool, relative + 1,
                                          magic_end - relative - 1);
           relative = magic_end;
         }
@@ -1342,7 +1343,7 @@ dav_svn_split_uri(request_rec *r,
     }
 
   /* We can return 'relative' at this point too. */
-  *relative_path = apr_pstrdup(r->pool, relative);
+  *relative_path = apr_pstrdup(pool, relative);
 
   /* Code to remove the !svn junk from the front of the relative path,
      mainly stolen from parse_uri().  This code assumes that
@@ -1363,7 +1364,7 @@ dav_svn_split_uri(request_rec *r,
         if (ch == '\0')
           {
             /* relative is just "!svn", which is malformed. */
-            return dav_svn__new_error(r->pool, HTTP_NOT_FOUND,
+            return dav_svn__new_error(pool, HTTP_NOT_FOUND,
                                       SVN_ERR_APMOD_MALFORMED_URI,
                                       "Nothing follows the svn special_uri.");
           }
@@ -1390,7 +1391,7 @@ dav_svn_split_uri(request_rec *r,
                           *repos_path = NULL;
                         else
                           return dav_svn__new_error(
-                                     r->pool, HTTP_NOT_FOUND,
+                                     pool, HTTP_NOT_FOUND,
                                      SVN_ERR_APMOD_MALFORMED_URI,
                                      "Missing info after special_uri.");
                       }
@@ -1414,7 +1415,7 @@ dav_svn_split_uri(request_rec *r,
                             /* Did we break from the loop prematurely? */
                             if (j != (defn->numcomponents - 1))
                               return dav_svn__new_error(
-                                         r->pool, HTTP_NOT_FOUND,
+                                         pool, HTTP_NOT_FOUND,
                                          SVN_ERR_APMOD_MALFORMED_URI,
                                          "Not enough components after "
                                          "special_uri.");
@@ -1428,13 +1429,13 @@ dav_svn_split_uri(request_rec *r,
                         else
                           {
                             /* Found a slash after the special components. */
-                            *repos_path = apr_pstrdup(r->pool, start - 1);
+                            *repos_path = apr_pstrdup(pool, start - 1);
                           }
                       }
                     else
                       {
                         return
-                          dav_svn__new_error(r->pool, HTTP_NOT_FOUND,
+                          dav_svn__new_error(pool, HTTP_NOT_FOUND,
                                         SVN_ERR_APMOD_MALFORMED_URI,
                                         "Unknown data after special_uri.");
                       }
@@ -1445,7 +1446,7 @@ dav_svn_split_uri(request_rec *r,
 
             if (defn->name == NULL)
               return
-                dav_svn__new_error(r->pool, HTTP_NOT_FOUND,
+                dav_svn__new_error(pool, HTTP_NOT_FOUND,
                                    SVN_ERR_APMOD_MALFORMED_URI,
                                    "Couldn't match subdir after special_uri.");
           }
@@ -1454,13 +1455,27 @@ dav_svn_split_uri(request_rec *r,
       {
         /* There's no "!svn/" at all, so the relative path is already
            a valid path within the repository.  */
-        *repos_path = apr_pstrdup(r->pool, relative - 1);
+        *repos_path = apr_pstrdup(pool, relative - 1);
       }
   }
 
   return NULL;
 }
 
+AP_MODULE_DECLARE(dav_error *)
+dav_svn_split_uri(request_rec *r,
+                  const char *uri_to_split,
+                  const char *root_path,
+                  const char **cleaned_uri,
+                  int *trailing_slash,
+                  const char **repos_basename,
+                  const char **relative_path,
+                  const char **repos_path)
+{
+  return dav_svn_split_uri2(r, uri_to_split, root_path, cleaned_uri,
+                            trailing_slash, repos_basename, relative_path,
+                            repos_path, r->pool);
+}
 
 /* Context for cleanup handler. */
 struct cleanup_fs_access_baton

Modified: subversion/branches/pin-externals/subversion/svn/conflict-callbacks.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/svn/conflict-callbacks.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/svn/conflict-callbacks.c (original)
+++ subversion/branches/pin-externals/subversion/svn/conflict-callbacks.c Wed Jan 21 16:22:19 2015
@@ -695,6 +695,10 @@ handle_text_conflict(svn_wc_conflict_res
                                 b->path_prefix, desc->local_abspath,
                                 scratch_pool)));
 
+  /* ### TODO This whole feature availability check is grossly outdated.
+     DIFF_ALLOWED needs either to be redefined or to go away.
+   */
+
   /* Diffing can happen between base and merged, to show conflict
      markers to the user (this is the typical 3-way merge
      scenario), or if no base is available, we can show a diff
@@ -714,9 +718,15 @@ handle_text_conflict(svn_wc_conflict_res
       *next_option++ = "p";
       if (diff_allowed)
         {
-          *next_option++ = "df";
+          /* We need one more path for this feature. */
+          if (desc->my_abspath)
+            *next_option++ = "df";
+
           *next_option++ = "e";
-          *next_option++ = "m";
+
+          /* We need one more path for this feature. */
+          if (desc->my_abspath)
+            *next_option++ = "m";
 
           if (knows_something)
             *next_option++ = "r";
@@ -781,7 +791,8 @@ handle_text_conflict(svn_wc_conflict_res
         }
       else if (strcmp(opt->code, "df") == 0)
         {
-          if (! diff_allowed)
+          /* Re-check preconditions. */
+          if (! diff_allowed || desc->my_abspath)
             {
               SVN_ERR(svn_cmdline_fprintf(stderr, iterpool,
                              _("Invalid option; there's no "
@@ -805,6 +816,15 @@ handle_text_conflict(svn_wc_conflict_res
         {
           svn_error_t *err;
 
+          /* Re-check preconditions. */
+          if (! desc->my_abspath)
+            {
+              SVN_ERR(svn_cmdline_fprintf(stderr, iterpool,
+                             _("Invalid option; there's no "
+                                "base path to merge.\n\n")));
+              continue;
+            }
+
           err = svn_cl__merge_file_externally(desc->base_abspath,
                                               desc->their_abspath,
                                               desc->my_abspath,

Modified: subversion/branches/pin-externals/subversion/svnadmin/svnadmin.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/svnadmin/svnadmin.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/svnadmin/svnadmin.c (original)
+++ subversion/branches/pin-externals/subversion/svnadmin/svnadmin.c Wed Jan 21 16:22:19 2015
@@ -1271,7 +1271,7 @@ subcommand_freeze(apr_getopt_t *os, void
     }
 
   b.command = APR_ARRAY_IDX(args, 0, const char *);
-  b.args = apr_palloc(pool, sizeof(char *) * args->nelts + 1);
+  b.args = apr_palloc(pool, sizeof(char *) * (args->nelts + 1));
   for (i = 0; i < args->nelts; ++i)
     b.args[i] = APR_ARRAY_IDX(args, i, const char *);
   b.args[args->nelts] = NULL;

Modified: subversion/branches/pin-externals/subversion/svndumpfilter/svndumpfilter.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/svndumpfilter/svndumpfilter.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/svndumpfilter/svndumpfilter.c (original)
+++ subversion/branches/pin-externals/subversion/svndumpfilter/svndumpfilter.c Wed Jan 21 16:22:19 2015
@@ -43,6 +43,7 @@
 #include "svn_mergeinfo.h"
 #include "svn_version.h"
 
+#include "private/svn_repos_private.h"
 #include "private/svn_mergeinfo_private.h"
 #include "private/svn_cmdline_private.h"
 #include "private/svn_sorts_private.h"
@@ -240,7 +241,6 @@ struct revision_baton_t
 
   /* Does this revision have node or prop changes? */
   svn_boolean_t has_nodes;
-  svn_boolean_t has_props;
 
   /* Did we drop any nodes? */
   svn_boolean_t had_dropped_nodes;
@@ -253,7 +253,7 @@ struct revision_baton_t
   svn_revnum_t rev_actual;
 
   /* Pointers to dumpfile data. */
-  svn_stringbuf_t *header;
+  apr_hash_t *original_headers;
   apr_hash_t *props;
 };
 
@@ -278,7 +278,7 @@ struct node_baton_t
   svn_filesize_t tcl;
 
   /* Pointers to dumpfile data. */
-  svn_stringbuf_t *header;
+  apr_array_header_t *headers;
   svn_stringbuf_t *props;
 
   /* Expect deltas? */
@@ -287,6 +287,8 @@ struct node_baton_t
 
   /* We might need the node path in a parse error message. */
   char *node_path;
+
+  apr_pool_t *node_pool;
 };
 
 
@@ -310,6 +312,24 @@ magic_header_record(int version, void *p
 }
 
 
+/* Return a deep copy of a (char * -> char *) hash. */
+static apr_hash_t *
+headers_dup(apr_hash_t *headers,
+            apr_pool_t *pool)
+{
+  apr_hash_t *new_hash = apr_hash_make(pool);
+  apr_hash_index_t *hi;
+
+  for (hi = apr_hash_first(pool, headers); hi; hi = apr_hash_next(hi))
+    {
+      const char *key = apr_hash_this_key(hi);
+      const char *val = apr_hash_this_val(hi);
+
+      svn_hash_sets(new_hash, apr_pstrdup(pool, key), apr_pstrdup(pool, val));
+    }
+  return new_hash;
+}
+
 /* New revision: set up revision_baton, decide if we skip it. */
 static svn_error_t *
 new_revision_record(void **revision_baton,
@@ -318,21 +338,16 @@ new_revision_record(void **revision_bato
                     apr_pool_t *pool)
 {
   struct revision_baton_t *rb;
-  apr_hash_index_t *hi;
   const char *rev_orig;
-  svn_stream_t *header_stream;
 
   *revision_baton = apr_palloc(pool, sizeof(struct revision_baton_t));
   rb = *revision_baton;
   rb->pb = parse_baton;
   rb->has_nodes = FALSE;
-  rb->has_props = FALSE;
   rb->had_dropped_nodes = FALSE;
   rb->writing_begun = FALSE;
-  rb->header = svn_stringbuf_create_empty(pool);
   rb->props = apr_hash_make(pool);
-
-  header_stream = svn_stream_from_stringbuf(rb->header, pool);
+  rb->original_headers = headers_dup(headers, pool);
 
   rev_orig = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_REVISION_NUMBER);
   rb->rev_orig = SVN_STR_TO_REV(rev_orig);
@@ -342,28 +357,6 @@ new_revision_record(void **revision_bato
   else
     rb->rev_actual = rb->rev_orig;
 
-  SVN_ERR(svn_stream_printf(header_stream, pool,
-                            SVN_REPOS_DUMPFILE_REVISION_NUMBER ": %ld\n",
-                            rb->rev_actual));
-
-  for (hi = apr_hash_first(pool, headers); hi; hi = apr_hash_next(hi))
-    {
-      const char *key = apr_hash_this_key(hi);
-      const char *val = apr_hash_this_val(hi);
-
-      if ((!strcmp(key, SVN_REPOS_DUMPFILE_CONTENT_LENGTH))
-          || (!strcmp(key, SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH))
-          || (!strcmp(key, SVN_REPOS_DUMPFILE_REVISION_NUMBER)))
-        continue;
-
-      /* passthru: put header into header stringbuf. */
-
-      SVN_ERR(svn_stream_printf(header_stream, pool, "%s: %s\n",
-                                key, val));
-    }
-
-  SVN_ERR(svn_stream_close(header_stream));
-
   return SVN_NO_ERROR;
 }
 
@@ -375,12 +368,8 @@ new_revision_record(void **revision_bato
 static svn_error_t *
 output_revision(struct revision_baton_t *rb)
 {
-  int bytes_used;
-  char buf[SVN_KEYLINE_MAXLEN];
-  apr_hash_index_t *hi;
   svn_boolean_t write_out_rev = FALSE;
   apr_pool_t *hash_pool = apr_hash_pool_get(rb->props);
-  svn_stringbuf_t *props = svn_stringbuf_create_empty(hash_pool);
   apr_pool_t *subpool = svn_pool_create(hash_pool);
 
   rb->writing_begun = TRUE;
@@ -398,7 +387,6 @@ output_revision(struct revision_baton_t
       && (! rb->pb->drop_all_empty_revs))
     {
       apr_hash_t *old_props = rb->props;
-      rb->has_props = TRUE;
       rb->props = apr_hash_make(hash_pool);
       svn_hash_sets(rb->props, SVN_PROP_REVISION_DATE,
                     svn_hash_gets(old_props, SVN_PROP_REVISION_DATE));
@@ -407,39 +395,6 @@ output_revision(struct revision_baton_t
                                         "padding."), hash_pool));
     }
 
-  /* Now, "rasterize" the props to a string, and append the property
-     information to the header string.  */
-  if (rb->has_props)
-    {
-      for (hi = apr_hash_first(subpool, rb->props);
-           hi;
-           hi = apr_hash_next(hi))
-        {
-          const char *pname = apr_hash_this_key(hi);
-          const svn_string_t *pval = apr_hash_this_val(hi);
-
-          write_prop_to_stringbuf(props, pname, pval);
-        }
-      svn_stringbuf_appendcstr(props, "PROPS-END\n");
-      svn_stringbuf_appendcstr(rb->header,
-                               SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH);
-      bytes_used = apr_snprintf(buf, sizeof(buf), ": %" APR_SIZE_T_FMT,
-                                props->len);
-      svn_stringbuf_appendbytes(rb->header, buf, bytes_used);
-      svn_stringbuf_appendbyte(rb->header, '\n');
-    }
-
-  svn_stringbuf_appendcstr(rb->header, SVN_REPOS_DUMPFILE_CONTENT_LENGTH);
-  bytes_used = apr_snprintf(buf, sizeof(buf), ": %" APR_SIZE_T_FMT, props->len);
-  svn_stringbuf_appendbytes(rb->header, buf, bytes_used);
-  svn_stringbuf_appendbyte(rb->header, '\n');
-
-  /* put an end to headers */
-  svn_stringbuf_appendbyte(rb->header, '\n');
-
-  /* put an end to revision */
-  svn_stringbuf_appendbyte(props, '\n');
-
   /* write out the revision */
   /* Revision is written out in the following cases:
      1. If the revision has nodes or
@@ -459,10 +414,12 @@ output_revision(struct revision_baton_t
   if (write_out_rev)
     {
       /* This revision is a keeper. */
-      SVN_ERR(svn_stream_write(rb->pb->out_stream,
-                               rb->header->data, &(rb->header->len)));
-      SVN_ERR(svn_stream_write(rb->pb->out_stream,
-                               props->data, &(props->len)));
+      SVN_ERR(svn_repos__dump_revision_record(rb->pb->out_stream,
+                                              rb->rev_actual,
+                                              rb->original_headers,
+                                              rb->props,
+                                              FALSE /*props_section_always*/,
+                                              subpool));
 
       /* Stash the oldest original rev not dropped. */
       if (rb->rev_orig > 0
@@ -544,6 +501,7 @@ new_node_record(void **node_baton,
   *node_baton = apr_palloc(pool, sizeof(struct node_baton_t));
   nb          = *node_baton;
   nb->rb      = rev_baton;
+  nb->node_pool = pool;
   pb          = nb->rb->pb;
 
   node_path = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_NODE_PATH);
@@ -615,7 +573,7 @@ new_node_record(void **node_baton,
       nb->has_text_delta = FALSE;
       nb->writing_begun = FALSE;
       nb->tcl = tcl ? svn__atoui64(tcl) : 0;
-      nb->header = svn_stringbuf_create_empty(pool);
+      nb->headers = svn_repos__dumpfile_headers_create(pool);
       nb->props = svn_stringbuf_create_empty(pool);
       nb->node_path = apr_pstrdup(pool, node_path);
 
@@ -627,23 +585,20 @@ new_node_record(void **node_baton,
 
       /* A node record is required to begin with 'Node-path', skip the
          leading '/' to match the form used by 'svnadmin dump'. */
-      SVN_ERR(svn_stream_printf(nb->rb->pb->out_stream,
-                                pool, "%s: %s\n",
-                                SVN_REPOS_DUMPFILE_NODE_PATH, node_path + 1));
+      svn_repos__dumpfile_header_push(
+        nb->headers, SVN_REPOS_DUMPFILE_NODE_PATH, node_path + 1);
 
       /* Node-kind is next and is optional. */
       kind = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_NODE_KIND);
       if (kind)
-        SVN_ERR(svn_stream_printf(nb->rb->pb->out_stream,
-                                  pool, "%s: %s\n",
-                                  SVN_REPOS_DUMPFILE_NODE_KIND, kind));
+        svn_repos__dumpfile_header_push(
+          nb->headers, SVN_REPOS_DUMPFILE_NODE_KIND, kind);
 
       /* Node-action is next and required. */
       action = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_NODE_ACTION);
       if (action)
-        SVN_ERR(svn_stream_printf(nb->rb->pb->out_stream,
-                                  pool, "%s: %s\n",
-                                  SVN_REPOS_DUMPFILE_NODE_ACTION, action));
+        svn_repos__dumpfile_header_push(
+          nb->headers, SVN_REPOS_DUMPFILE_NODE_ACTION, action);
       else
         return svn_error_createf(SVN_ERR_INCOMPLETE_DATA, 0,
                                  _("Missing Node-action for path '%s'"),
@@ -690,18 +645,14 @@ new_node_record(void **node_baton,
                 return svn_error_createf
                   (SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
                    _("No valid copyfrom revision in filtered stream"));
-              SVN_ERR(svn_stream_printf
-                      (nb->rb->pb->out_stream, pool,
-                       SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV ": %ld\n",
-                       cf_renum_val->rev));
+              svn_repos__dumpfile_header_pushf(
+                nb->headers, SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV,
+                "%ld", cf_renum_val->rev);
               continue;
             }
 
           /* passthru: put header straight to output */
-
-          SVN_ERR(svn_stream_printf(nb->rb->pb->out_stream,
-                                    pool, "%s: %s\n",
-                                    key, val));
+          svn_repos__dumpfile_header_push(nb->headers, key, val);
         }
     }
 
@@ -709,61 +660,62 @@ new_node_record(void **node_baton,
 }
 
 
-/* Output node header and props to dumpstream
-   This will be called by set_fulltext() after setting nb->has_text to TRUE,
-   if the node has any text, or by close_node() otherwise. This must only
-   be called if nb->writing_begun is FALSE. */
-static svn_error_t *
-output_node(struct node_baton_t *nb)
-{
-  int bytes_used;
-  char buf[SVN_KEYLINE_MAXLEN];
+/* Output node headers and props.
+ *
+ * Write HEADERS, content length headers, a blank line, and the properties
+ * content section PROPS_STR (if non-null) to DUMP_STREAM.
+ *
+ * HEADERS is an array of headers as struct {const char *key, *val;}.
+ * Write them all in the given order.
+ *
+ * PROPS_STR is the property content block, including a terminating
+ * 'PROPS_END\n' line. Iff PROPS_STR is non-null, write a
+ * Prop-content-length header and the prop content block.
+ *
+ * Iff HAS_TEXT is true, write a Text-content length, using the value
+ * TEXT_CONTENT_LENGTH.
+ *
+ * Always write a Content-length header, its value being the sum of the
+ * Prop- and Text- content length headers.
+ * ### TODO: Make it optional (only written if props and/or text present).
+ */
+static svn_error_t *
+output_node_record(svn_stream_t *dump_stream,
+                   apr_array_header_t *headers,
+                   svn_stringbuf_t *props_str,
+                   svn_boolean_t has_text,
+                   svn_filesize_t text_content_length,
+                   apr_pool_t *scratch_pool)
+{
+  svn_filesize_t content_length = 0;
+
+  /* add content-length headers */
+  if (props_str)
+    {
+      svn_repos__dumpfile_header_pushf(
+        headers, SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH,
+        "%" APR_SIZE_T_FMT, props_str->len);
+      content_length += props_str->len;
+    }
+  if (has_text)
+    {
+      svn_repos__dumpfile_header_pushf(
+        headers, SVN_REPOS_DUMPFILE_TEXT_CONTENT_LENGTH,
+        "%" SVN_FILESIZE_T_FMT, text_content_length);
+      content_length += text_content_length;
+    }
+  svn_repos__dumpfile_header_pushf(
+    headers, SVN_REPOS_DUMPFILE_CONTENT_LENGTH,
+    "%" SVN_FILESIZE_T_FMT, content_length);
 
-  nb->writing_begun = TRUE;
-
-  /* when there are no props nb->props->len would be zero and won't mess up
-     Content-Length. */
-  if (nb->has_props)
-    svn_stringbuf_appendcstr(nb->props, "PROPS-END\n");
-
-  /* 1. recalculate & check text-md5 if present. Passed through right now. */
-
-  /* 2. recalculate and add content-lengths */
-
-  if (nb->has_props)
-    {
-      svn_stringbuf_appendcstr(nb->header,
-                               SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH);
-      bytes_used = apr_snprintf(buf, sizeof(buf), ": %" APR_SIZE_T_FMT,
-                                nb->props->len);
-      svn_stringbuf_appendbytes(nb->header, buf, bytes_used);
-      svn_stringbuf_appendbyte(nb->header, '\n');
-    }
-  if (nb->has_text)
-    {
-      svn_stringbuf_appendcstr(nb->header,
-                               SVN_REPOS_DUMPFILE_TEXT_CONTENT_LENGTH);
-      bytes_used = apr_snprintf(buf, sizeof(buf), ": %" SVN_FILESIZE_T_FMT,
-                                nb->tcl);
-      svn_stringbuf_appendbytes(nb->header, buf, bytes_used);
-      svn_stringbuf_appendbyte(nb->header, '\n');
-    }
-  svn_stringbuf_appendcstr(nb->header, SVN_REPOS_DUMPFILE_CONTENT_LENGTH);
-  bytes_used = apr_snprintf(buf, sizeof(buf), ": %" SVN_FILESIZE_T_FMT,
-                            (svn_filesize_t) (nb->props->len + nb->tcl));
-  svn_stringbuf_appendbytes(nb->header, buf, bytes_used);
-  svn_stringbuf_appendbyte(nb->header, '\n');
-
-  /* put an end to headers */
-  svn_stringbuf_appendbyte(nb->header, '\n');
-
-  /* 3. output all the stuff */
-
-  SVN_ERR(svn_stream_write(nb->rb->pb->out_stream,
-                           nb->header->data , &(nb->header->len)));
-  SVN_ERR(svn_stream_write(nb->rb->pb->out_stream,
-                           nb->props->data , &(nb->props->len)));
+  /* write the headers */
+  SVN_ERR(svn_repos__dump_headers(dump_stream, headers, TRUE, scratch_pool));
 
+  /* write the props */
+  if (props_str)
+    {
+      SVN_ERR(svn_stream_write(dump_stream, props_str->data, &props_str->len));
+    }
   return SVN_NO_ERROR;
 }
 
@@ -791,10 +743,16 @@ adjust_mergeinfo(svn_string_t **final_va
      start of all history.  E.g. if we dump -r100:400 then dumpfilter the
      result with --skip-missing-merge-sources, any mergeinfo with revision
      100 implies a change of -r99:100, but r99 is part of the history we
-     want filtered.  This is analogous to how r1 is always meaningless as
-     a merge source revision.
+     want filtered.
 
      If the oldest rev is r0 then there is nothing to filter. */
+
+  /* ### This seems to cater only for use cases where the revisions being
+         processed are not following on from revisions that will already
+         exist in the destination repository. If the revisions being
+         processed do follow on, then we might want to keep the mergeinfo
+         that refers to those older revisions. */
+
   if (rb->pb->skip_missing_merge_sources && rb->pb->oldest_original_rev > 0)
     SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges(
       &mergeinfo, mergeinfo,
@@ -852,7 +810,7 @@ adjust_mergeinfo(svn_string_t **final_va
       svn_hash_sets(final_mergeinfo, merge_source, rangelist);
     }
 
-  SVN_ERR(svn_mergeinfo_sort(final_mergeinfo, 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);
 
@@ -868,7 +826,6 @@ set_revision_property(void *revision_bat
   struct revision_baton_t *rb = revision_baton;
   apr_pool_t *hash_pool = apr_hash_pool_get(rb->props);
 
-  rb->has_props = TRUE;
   svn_hash_sets(rb->props,
                 apr_pstrdup(hash_pool, name),
                 svn_string_dup(value, hash_pool));
@@ -887,6 +844,9 @@ set_node_property(void *node_baton,
   if (nb->do_skip)
     return SVN_NO_ERROR;
 
+  /* Try to detect if a delta-mode property occurs unexpectedly. HAS_PROPS
+     can be false here only if the parser didn't call remove_node_props(),
+     so this may indicate a bug rather than bad data. */
   if (! (nb->has_props || nb->has_prop_delta))
     return svn_error_createf(SVN_ERR_STREAM_MALFORMED_DATA, NULL,
                              _("Delta property block detected, but deltas "
@@ -932,14 +892,17 @@ delete_node_property(void *node_baton, c
 }
 
 
+/* The parser calls this method if the node record has a non-delta
+ * property content section, before any calls to set_node_property().
+ * If the node record uses property deltas, this is not called.
+ */
 static svn_error_t *
 remove_node_props(void *node_baton)
 {
   struct node_baton_t *nb = node_baton;
 
   /* In this case, not actually indicating that the node *has* props,
-     rather that we know about all the props that it has, since it now
-     has none. */
+     rather that it has a property content section. */
   nb->has_props = TRUE;
 
   return SVN_NO_ERROR;
@@ -955,7 +918,19 @@ set_fulltext(svn_stream_t **stream, void
     {
       nb->has_text = TRUE;
       if (! nb->writing_begun)
-        SVN_ERR(output_node(nb));
+        {
+          nb->writing_begun = TRUE;
+          if (nb->has_props)
+            {
+              svn_stringbuf_appendcstr(nb->props, "PROPS-END\n");
+            }
+          SVN_ERR(output_node_record(nb->rb->pb->out_stream,
+                                     nb->headers,
+                                     nb->has_props ? nb->props : NULL,
+                                     nb->has_text,
+                                     nb->tcl,
+                                     nb->node_pool));
+        }
       *stream = nb->rb->pb->out_stream;
     }
 
@@ -976,7 +951,19 @@ close_node(void *node_baton)
 
   /* If the node was not flushed already to output its text, do it now. */
   if (! nb->writing_begun)
-    SVN_ERR(output_node(nb));
+    {
+      nb->writing_begun = TRUE;
+      if (nb->has_props)
+        {
+          svn_stringbuf_appendcstr(nb->props, "PROPS-END\n");
+        }
+      SVN_ERR(output_node_record(nb->rb->pb->out_stream,
+                                 nb->headers,
+                                 nb->has_props ? nb->props : NULL,
+                                 nb->has_text,
+                                 nb->tcl,
+                                 nb->node_pool));
+    }
 
   /* put an end to node. */
   SVN_ERR(svn_stream_write(nb->rb->pb->out_stream, "\n\n", &len));

Modified: subversion/branches/pin-externals/subversion/svnfsfs/stats-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/svnfsfs/stats-cmd.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/svnfsfs/stats-cmd.c (original)
+++ subversion/branches/pin-externals/subversion/svnfsfs/stats-cmd.c Wed Jan 21 16:22:19 2015
@@ -31,6 +31,35 @@
 #include "svn_private_config.h"
 #include "svnfsfs.h"
 
+/* Return the string, allocated in RESULT_POOL, describing the value 2**I.
+ */
+static const char *
+print_two_power(int i,
+                apr_pool_t *result_pool)
+{
+  /* These are the SI prefixes for base-1000, the binary ones with base-1024
+     are too clumsy and require appending B for "byte" to be intelligible,
+     e.g. "MiB".
+
+     Therefore, we ignore the official standard and revert to the traditional
+     contextual use were the base-1000 prefixes are understood as base-1024
+     when it came to data sizes.
+   */
+  const char *si_prefixes = " kMGTPEZY";
+
+  int number = (1 << (i % 10));
+  int thousands = i / 10;
+
+  char si_prefix = ((thousands >= 0) && (thousands < strlen(si_prefixes)))
+                 ? si_prefixes[thousands]
+                 : '?';
+
+  if (si_prefix == ' ')
+    return apr_psprintf(result_pool, "%d", number);
+
+  return apr_psprintf(result_pool, "%d%c", number, si_prefix);
+}
+
 /* Print statistics for the given group of representations to console.
  * Use POOL for allocations.
  */
@@ -88,8 +117,8 @@ print_histogram(svn_fs_fs__histogram_t *
 
   /* display histogram lines */
   for (i = last; i >= first; --i)
-    printf(_("  [2^%2d, 2^%2d)   %15s (%2d%%) bytes in %12s (%2d%%) items\n"),
-           i-1, i,
+    printf(_("  %4s .. < %-4s %19s (%2d%%) bytes in %12s (%2d%%) items\n"),
+           print_two_power(i-1, pool), print_two_power(i, pool),
            svn__ui64toa_sep(histogram->lines[i].sum, ',', pool),
            (int)(histogram->lines[i].sum * 100 / histogram->total.sum),
            svn__ui64toa_sep(histogram->lines[i].count, ',', pool),