You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2013/03/06 12:10:05 UTC

svn commit: r1453290 [10/15] - in /subversion/branches/fsfs-format7: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ subversion/bindings/javahl/native/ subversion/bindings/javahl/src/org/apache/subversion/javahl/ subversion/bindi...

Modified: subversion/branches/fsfs-format7/subversion/libsvn_wc/wc_db_update_move.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_wc/wc_db_update_move.c?rev=1453290&r1=1453289&r2=1453290&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_wc/wc_db_update_move.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_wc/wc_db_update_move.c Wed Mar  6 11:10:01 2013
@@ -114,7 +114,6 @@
  */
 
 struct tc_editor_baton {
-  svn_skel_t **work_items;
   svn_wc__db_t *db;
   svn_wc__db_wcroot_t *wcroot;
   const char *move_root_dst_relpath;
@@ -126,9 +125,7 @@ struct tc_editor_baton {
   svn_wc_operation_t operation;
   svn_wc_conflict_version_t *old_version;
   svn_wc_conflict_version_t *new_version;
-  svn_wc_notify_func2_t notify_func;
-  void *notify_baton;
-  apr_pool_t *result_pool;
+  apr_pool_t *result_pool;  /* For things that live as long as the baton. */
 };
 
 /* 
@@ -161,48 +158,52 @@ update_move_list_add(svn_wc__db_wcroot_t
 
 /* Send all notifications stored in the notification list, and then
  * remove the temporary database table. */
-static svn_error_t *
-update_move_list_notify(svn_wc__db_wcroot_t *wcroot,
-                        svn_revnum_t old_revision,
-                        svn_revnum_t new_revision,
-                        svn_wc_notify_func2_t notify_func,
-                        void *notify_baton,
-                        apr_pool_t *scratch_pool)
+svn_error_t *
+svn_wc__db_update_move_list_notify(svn_wc__db_wcroot_t *wcroot,
+                                   svn_revnum_t old_revision,
+                                   svn_revnum_t new_revision,
+                                   svn_wc_notify_func2_t notify_func,
+                                   void *notify_baton,
+                                   apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
-  svn_boolean_t have_row;
-  apr_pool_t *iterpool;
 
-  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                    STMT_SELECT_UPDATE_MOVE_LIST));
-  SVN_ERR(svn_sqlite__step(&have_row, stmt));
-
-  iterpool = svn_pool_create(scratch_pool);
-  while (have_row)
+  if (notify_func)
     {
-      const char *local_relpath;
-      svn_wc_notify_action_t action;
-      svn_wc_notify_t *notify;
+      apr_pool_t *iterpool;
+      svn_boolean_t have_row;
 
-      svn_pool_clear(iterpool);
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                        STMT_SELECT_UPDATE_MOVE_LIST));
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
-      local_relpath = svn_sqlite__column_text(stmt, 0, NULL);
-      action = svn_sqlite__column_int(stmt, 1);
-      notify = svn_wc_create_notify(svn_dirent_join(wcroot->abspath,
-                                                    local_relpath,
-                                                    iterpool),
-                                    action, iterpool);
-      notify->kind = svn_sqlite__column_int(stmt, 2);
-      notify->content_state = svn_sqlite__column_int(stmt, 3);
-      notify->prop_state = svn_sqlite__column_int(stmt, 4);
-      notify->old_revision = old_revision;
-      notify->revision = new_revision;
-      notify_func(notify_baton, notify, scratch_pool);
+      iterpool = svn_pool_create(scratch_pool);
+      while (have_row)
+        {
+          const char *local_relpath;
+          svn_wc_notify_action_t action;
+          svn_wc_notify_t *notify;
 
-      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+          svn_pool_clear(iterpool);
+
+          local_relpath = svn_sqlite__column_text(stmt, 0, NULL);
+          action = svn_sqlite__column_int(stmt, 1);
+          notify = svn_wc_create_notify(svn_dirent_join(wcroot->abspath,
+                                                        local_relpath,
+                                                        iterpool),
+                                        action, iterpool);
+          notify->kind = svn_sqlite__column_int(stmt, 2);
+          notify->content_state = svn_sqlite__column_int(stmt, 3);
+          notify->prop_state = svn_sqlite__column_int(stmt, 4);
+          notify->old_revision = old_revision;
+          notify->revision = new_revision;
+          notify_func(notify_baton, notify, scratch_pool);
+
+          SVN_ERR(svn_sqlite__step(&have_row, stmt));
+        }
+      svn_pool_destroy(iterpool);
+      SVN_ERR(svn_sqlite__reset(stmt));
     }
-  svn_pool_destroy(iterpool);
-  SVN_ERR(svn_sqlite__reset(stmt));
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_FINALIZE_UPDATE_MOVE));
@@ -211,9 +212,16 @@ update_move_list_notify(svn_wc__db_wcroo
   return SVN_NO_ERROR;
 }
 
+/* Mark a tree-conflict on LOCAL_RELPATH if such a tree-conflict does
+   not already exist. */
 static svn_error_t *
-mark_tree_conflict(struct tc_editor_baton *b,
-                   const char *local_relpath,
+mark_tree_conflict(const char *local_relpath,
+                   svn_wc__db_wcroot_t *wcroot,
+                   svn_wc__db_t *db,
+                   const svn_wc_conflict_version_t *old_version,
+                   const svn_wc_conflict_version_t *new_version,
+                   const char *move_root_dst_relpath,
+                   svn_wc_operation_t operation,
                    svn_node_kind_t old_kind,
                    svn_node_kind_t new_kind,
                    const char *old_repos_relpath,
@@ -224,34 +232,34 @@ mark_tree_conflict(struct tc_editor_bato
 {
   svn_error_t *err;
   svn_skel_t *conflict;
-  svn_wc_conflict_version_t *old_version, *new_version;
+  svn_wc_conflict_version_t *conflict_old_version, *conflict_new_version;
   const char *move_src_op_root_abspath
     = move_src_op_root_relpath
-    ? svn_dirent_join(b->wcroot->abspath,
+    ? svn_dirent_join(wcroot->abspath,
                       move_src_op_root_relpath, scratch_pool)
     : NULL;
   const char *old_repos_relpath_part
     = old_repos_relpath
-    ? svn_relpath_skip_ancestor(b->old_version->path_in_repos,
+    ? svn_relpath_skip_ancestor(old_version->path_in_repos,
                                 old_repos_relpath)
     : NULL;
   const char *new_repos_relpath
     = old_repos_relpath_part
-    ? svn_relpath_join(b->new_version->path_in_repos, old_repos_relpath_part,
+    ? svn_relpath_join(new_version->path_in_repos, old_repos_relpath_part,
                        scratch_pool)
     : NULL;
 
   if (!new_repos_relpath)
     new_repos_relpath
-      = svn_relpath_join(b->new_version->path_in_repos,
-                         svn_relpath_skip_ancestor(b->move_root_dst_relpath,
+      = svn_relpath_join(new_version->path_in_repos,
+                         svn_relpath_skip_ancestor(move_root_dst_relpath,
                                                    local_relpath),
                          scratch_pool);
 
-  err = svn_wc__db_read_conflict_internal(&conflict, b->wcroot, local_relpath,
+  err = svn_wc__db_read_conflict_internal(&conflict, wcroot, local_relpath,
                                           scratch_pool, scratch_pool);
   if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
-    return err;
+    return svn_error_trace(err);
   else if (err)
     {
       svn_error_clear(err);
@@ -260,16 +268,16 @@ mark_tree_conflict(struct tc_editor_bato
 
   if (conflict)
     {
-      svn_wc_operation_t operation;
+      svn_wc_operation_t conflict_operation;
       svn_boolean_t tree_conflicted;
 
-      SVN_ERR(svn_wc__conflict_read_info(&operation, NULL, NULL, NULL,
+      SVN_ERR(svn_wc__conflict_read_info(&conflict_operation, NULL, NULL, NULL,
                                          &tree_conflicted,
-                                         b->db, b->wcroot->abspath, conflict,
+                                         db, wcroot->abspath, conflict,
                                          scratch_pool, scratch_pool));
 
-      if (operation != svn_wc_operation_update
-          && operation != svn_wc_operation_switch)
+      if (conflict_operation != svn_wc_operation_update
+          && 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,
@@ -284,7 +292,7 @@ mark_tree_conflict(struct tc_editor_bato
           SVN_ERR(svn_wc__conflict_read_tree_conflict(&existing_reason,
                                                       &existing_action,
                                                       &existing_abspath,
-                                                      b->db, b->wcroot->abspath,
+                                                      db, wcroot->abspath,
                                                       conflict,
                                                       scratch_pool,
                                                       scratch_pool));
@@ -292,7 +300,7 @@ mark_tree_conflict(struct tc_editor_bato
               || action != existing_action
               || (reason == svn_wc_conflict_reason_moved_away
                   && strcmp(move_src_op_root_relpath,
-                            svn_dirent_skip_ancestor(b->wcroot->abspath,
+                            svn_dirent_skip_ancestor(wcroot->abspath,
                                                      existing_abspath))))
             return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
                                      _("'%s' already in conflict"),
@@ -306,11 +314,9 @@ mark_tree_conflict(struct tc_editor_bato
   else
     conflict = svn_wc__conflict_skel_create(scratch_pool);
 
-  b->conflict_root_relpath = apr_pstrdup(b->result_pool, local_relpath);
-
   SVN_ERR(svn_wc__conflict_skel_add_tree_conflict(
-                     conflict, b->db,
-                     svn_dirent_join(b->wcroot->abspath, local_relpath,
+                     conflict, db,
+                     svn_dirent_join(wcroot->abspath, local_relpath,
                                      scratch_pool),
                      reason,
                      action,
@@ -320,40 +326,41 @@ mark_tree_conflict(struct tc_editor_bato
 
   if (reason != svn_wc_conflict_reason_unversioned)
     {
-      old_version = svn_wc_conflict_version_create2(b->old_version->repos_url,
-                                                    b->old_version->repos_uuid,
-                                                    old_repos_relpath,
-                                                    b->old_version->peg_rev,
-                                                    old_kind,
-                                                    scratch_pool);
+      conflict_old_version = svn_wc_conflict_version_create2(
+                               old_version->repos_url, old_version->repos_uuid,
+                               old_repos_relpath, old_version->peg_rev,
+                               old_kind, scratch_pool);
     }
   else
-    old_version = NULL;
+    conflict_old_version = NULL;
 
-  new_version = svn_wc_conflict_version_create2(b->new_version->repos_url,
-                                                b->new_version->repos_uuid,
-                                                new_repos_relpath,
-                                                b->new_version->peg_rev,
-                                                new_kind,
-                                                scratch_pool);
+  conflict_new_version = svn_wc_conflict_version_create2(
+                           new_version->repos_url, new_version->repos_uuid,
+                           new_repos_relpath, new_version->peg_rev,
+                           new_kind, scratch_pool);
 
-  if (b->operation == svn_wc_operation_update)
+  if (operation == svn_wc_operation_update)
     {
       SVN_ERR(svn_wc__conflict_skel_set_op_update(
-                conflict, old_version, new_version,
+                conflict, conflict_old_version, conflict_new_version,
                 scratch_pool, scratch_pool));
     }
   else
     {
-      assert(b->operation == svn_wc_operation_switch);
+      assert(operation == svn_wc_operation_switch);
       SVN_ERR(svn_wc__conflict_skel_set_op_switch(
-                  conflict, old_version, new_version,
+                  conflict, conflict_old_version, conflict_new_version,
                   scratch_pool, scratch_pool));
     }
 
-  SVN_ERR(svn_wc__db_mark_conflict_internal(b->wcroot, local_relpath,
+  SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath,
                                             conflict, scratch_pool));
 
+  SVN_ERR(update_move_list_add(wcroot, local_relpath,
+                               svn_wc_notify_tree_conflict,
+                               new_kind,
+                               svn_wc_notify_state_inapplicable,
+                               svn_wc_notify_state_inapplicable));
   return SVN_NO_ERROR;
 }
 
@@ -427,19 +434,17 @@ check_tree_conflict(svn_boolean_t *is_co
                                        b->wcroot, conflict_root_relpath,
                                        scratch_pool, scratch_pool));
 
-  SVN_ERR(mark_tree_conflict(b, conflict_root_relpath, old_kind, new_kind,
+  SVN_ERR(mark_tree_conflict(conflict_root_relpath,
+                             b->wcroot, b->db, b->old_version, b->new_version,
+                             b->move_root_dst_relpath, b->operation,
+                             old_kind, new_kind,
                              old_repos_relpath,
                              (move_dst_relpath
                               ? svn_wc_conflict_reason_moved_away
                               : svn_wc_conflict_reason_deleted),
                              action, move_src_op_root_relpath,
                              scratch_pool));
-  if (b->notify_func)
-    SVN_ERR(update_move_list_add(b->wcroot, local_relpath,
-                                 svn_wc_notify_tree_conflict,
-                                 new_kind,
-                                 svn_wc_notify_state_inapplicable,
-                                 svn_wc_notify_state_inapplicable));
+  b->conflict_root_relpath = apr_pstrdup(b->result_pool, conflict_root_relpath);
 
   return SVN_NO_ERROR;
 }
@@ -488,7 +493,7 @@ tc_editor_add_directory(void *baton,
 
   /* Check for NODES tree-conflict. */
   SVN_ERR(check_tree_conflict(&is_conflicted, b, relpath,
-                              move_dst_kind, svn_node_dir,
+                              old_kind, svn_node_dir,
                               move_dst_repos_relpath,
                               svn_wc_conflict_action_add,
                               scratch_pool));
@@ -503,17 +508,21 @@ tc_editor_add_directory(void *baton,
     {
     case svn_node_file:
     default:
-      SVN_ERR(mark_tree_conflict(b, relpath, old_kind, svn_node_dir,
+      SVN_ERR(mark_tree_conflict(relpath, b->wcroot, b->db, b->old_version,
+                                 b->new_version, b->move_root_dst_relpath,
+                                 b->operation, old_kind, svn_node_dir,
                                  move_dst_repos_relpath,
                                  svn_wc_conflict_reason_unversioned,
                                  svn_wc_conflict_action_add, NULL,
                                  scratch_pool));
+      b->conflict_root_relpath = apr_pstrdup(b->result_pool, relpath);
       action = svn_wc_notify_tree_conflict;
+      is_conflicted = TRUE;
       break;
 
     case svn_node_none:
       SVN_ERR(svn_wc__wq_build_dir_install(&work_item, b->db, abspath,
-                                           scratch_pool, b->result_pool));
+                                           scratch_pool, scratch_pool));
 
       SVN_ERR(svn_wc__db_wq_add(b->db, b->wcroot->abspath, work_item,
                                 scratch_pool));
@@ -522,7 +531,7 @@ tc_editor_add_directory(void *baton,
       break;
     }
 
-  if (b->notify_func)
+  if (!is_conflicted)
     SVN_ERR(update_move_list_add(b->wcroot, relpath,
                                  action,
                                  svn_node_dir,
@@ -564,7 +573,7 @@ tc_editor_add_file(void *baton,
   if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
     {
       svn_error_clear(err);
-      old_kind = svn_kind_none;
+      old_kind = svn_node_none;
       move_dst_repos_relpath = NULL;
     }
   else
@@ -587,17 +596,14 @@ tc_editor_add_file(void *baton,
 
   if (old_kind != svn_node_none)
     {
-      SVN_ERR(mark_tree_conflict(b, relpath, old_kind, svn_node_file,
+      SVN_ERR(mark_tree_conflict(relpath, b->wcroot, b->db, b->old_version,
+                                 b->new_version, b->move_root_dst_relpath,
+                                 b->operation, old_kind, svn_node_file,
                                  move_dst_repos_relpath,
                                  svn_wc_conflict_reason_unversioned,
                                  svn_wc_conflict_action_add, NULL,
                                  scratch_pool));
-      if (b->notify_func)
-        SVN_ERR(update_move_list_add(b->wcroot, relpath,
-                                     svn_wc_notify_tree_conflict,
-                                     svn_node_file,
-                                     svn_wc_notify_state_inapplicable,
-                                     svn_wc_notify_state_inapplicable));
+      b->conflict_root_relpath = apr_pstrdup(b->result_pool, relpath);
       return SVN_NO_ERROR;
     }
 
@@ -609,17 +615,16 @@ tc_editor_add_file(void *baton,
                                         NULL,
                                         FALSE /* FIXME: use_commit_times? */,
                                         TRUE  /* record_file_info */,
-                                        scratch_pool, b->result_pool));
+                                        scratch_pool, scratch_pool));
 
   SVN_ERR(svn_wc__db_wq_add(b->db, b->wcroot->abspath, work_item,
                             scratch_pool));
 
-  if (b->notify_func)
-    SVN_ERR(update_move_list_add(b->wcroot, relpath,
-                                 svn_wc_notify_update_add,
-                                 svn_node_file,
-                                 svn_wc_notify_state_inapplicable,
-                                 svn_wc_notify_state_inapplicable));
+  SVN_ERR(update_move_list_add(b->wcroot, relpath,
+                               svn_wc_notify_update_add,
+                               svn_node_file,
+                               svn_wc_notify_state_inapplicable,
+                               svn_wc_notify_state_inapplicable));
   return SVN_NO_ERROR;
 }
 
@@ -652,6 +657,7 @@ typedef struct working_node_version_t
   const svn_checksum_t *checksum; /* for files only */
 } working_node_version_t;
 
+/* Return *WORK_ITEMS to create a conflict on LOCAL_ABSPATH. */
 static svn_error_t *
 create_conflict_markers(svn_skel_t **work_items,
                         const char *local_abspath,
@@ -661,21 +667,26 @@ create_conflict_markers(svn_skel_t **wor
                         svn_wc_operation_t operation,
                         const working_node_version_t *old_version,
                         const working_node_version_t *new_version,
-                        svn_kind_t local_kind,
+                        svn_node_kind_t kind,
                         apr_pool_t *result_pool,
                         apr_pool_t *scratch_pool)
 {
-  svn_skel_t *work_item;
   svn_wc_conflict_version_t *original_version;
   svn_wc_conflict_version_t *conflicted_version;
+  const char *part;
 
   original_version = svn_wc_conflict_version_dup(
                        old_version->location_and_kind, scratch_pool);
-  original_version->path_in_repos = repos_relpath;
-
+  original_version->node_kind = kind;
   conflicted_version = svn_wc_conflict_version_dup(
                          new_version->location_and_kind, scratch_pool);
-  conflicted_version->node_kind = svn__node_kind_from_kind(local_kind);
+  conflicted_version->node_kind = kind;
+
+  part = svn_relpath_skip_ancestor(original_version->path_in_repos,
+                                   repos_relpath);
+  conflicted_version->path_in_repos
+    = svn_relpath_join(conflicted_version->path_in_repos, part, scratch_pool);
+  original_version->path_in_repos = repos_relpath;
 
   if (operation == svn_wc_operation_update)
     {
@@ -694,12 +705,11 @@ create_conflict_markers(svn_skel_t **wor
 
   /* According to this func's doc string, it is "Currently only used for
    * property conflicts as text conflict markers are just in-wc files." */
-  SVN_ERR(svn_wc__conflict_create_markers(&work_item, db,
+  SVN_ERR(svn_wc__conflict_create_markers(work_items, db,
                                           local_abspath,
                                           conflict_skel,
                                           result_pool,
                                           scratch_pool));
-  *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
 
   return SVN_NO_ERROR;
 }
@@ -788,7 +798,8 @@ tc_editor_alter_directory(void *baton,
   SVN_ERR_ASSERT(move_dst_kind == svn_kind_dir);
 
   SVN_ERR(check_tree_conflict(&is_conflicted, b, dst_relpath,
-                              move_dst_kind, svn_node_dir,
+                              svn__node_kind_from_kind(move_dst_kind),
+                              svn_node_dir,
                               move_dst_repos_relpath,
                               svn_wc_conflict_action_edit,
                               scratch_pool));
@@ -815,27 +826,30 @@ tc_editor_alter_directory(void *baton,
                                    &propchanges, &actual_props,
                                    b->db, dst_abspath,
                                    &old_version, &new_version,
-                                   b->result_pool, scratch_pool));
+                                   scratch_pool, scratch_pool));
 
       if (conflict_skel)
         {
-          SVN_ERR(create_conflict_markers(b->work_items, dst_abspath,
+          svn_skel_t *work_items;
+
+          SVN_ERR(create_conflict_markers(&work_items, dst_abspath,
                                           b->db, move_dst_repos_relpath,
                                           conflict_skel, b->operation,
                                           &old_version, &new_version,
-                                          move_dst_kind,
-                                          b->result_pool, scratch_pool));
+                                          svn_node_dir,
+                                          scratch_pool, scratch_pool));
           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));
         }
 
-      if (b->notify_func)
-        SVN_ERR(update_move_list_add(b->wcroot, dst_relpath,
-                                     svn_wc_notify_update_update,
-                                     svn_node_dir,
-                                     svn_wc_notify_state_inapplicable,
-                                     prop_state));
+    SVN_ERR(update_move_list_add(b->wcroot, dst_relpath,
+                                 svn_wc_notify_update_update,
+                                 svn_node_dir,
+                                 svn_wc_notify_state_inapplicable,
+                                 prop_state));
     }
 
   return SVN_NO_ERROR;
@@ -857,17 +871,13 @@ tc_editor_alter_directory(void *baton,
  * Set *WORK_ITEMS to any required work items, allocated in RESULT_POOL.
  * Use SCRATCH_POOL for temporary allocations. */
 static svn_error_t *
-update_working_file(svn_skel_t **work_items,
-                    const char *local_relpath,
+update_working_file(const char *local_relpath,
                     const char *repos_relpath,
                     svn_wc_operation_t operation,
                     const working_node_version_t *old_version,
                     const working_node_version_t *new_version,
                     svn_wc__db_wcroot_t *wcroot,
                     svn_wc__db_t *db,
-                    svn_wc_notify_func2_t notify_func,
-                    void *notify_baton,
-                    apr_pool_t *result_pool,
                     apr_pool_t *scratch_pool)
 {
   const char *local_abspath = svn_dirent_join(wcroot->abspath,
@@ -880,84 +890,91 @@ update_working_file(svn_skel_t **work_it
   apr_array_header_t *propchanges;
   enum svn_wc_merge_outcome_t merge_outcome;
   svn_wc_notify_state_t prop_state, content_state;
-  svn_skel_t *work_item;
-
-  *work_items = NULL;
+  svn_skel_t *work_item, *work_items = NULL;
 
   SVN_ERR(update_working_props(&prop_state, &conflict_skel, &propchanges,
                                &actual_props, db, local_abspath,
                                old_version, new_version,
-                               result_pool, scratch_pool));
+                               scratch_pool, scratch_pool));
 
-  /*
-   * Run a 3-way merge to update the file, using the pre-update
-   * pristine text as the merge base, the post-update pristine
-   * text as the merge-left version, and the current content of the
-   * moved-here working file as the merge-right version.
-   */
-  SVN_ERR(svn_wc__db_pristine_get_path(&old_pristine_abspath,
-                                       db, wcroot->abspath,
-                                       old_version->checksum,
-                                       scratch_pool, scratch_pool));
-  SVN_ERR(svn_wc__db_pristine_get_path(&new_pristine_abspath,
-                                       db, wcroot->abspath,
-                                       new_version->checksum,
-                                       scratch_pool, scratch_pool));
-  SVN_ERR(svn_wc__internal_merge(&work_item, &conflict_skel,
-                                 &merge_outcome, db,
-                                 old_pristine_abspath,
-                                 new_pristine_abspath,
-                                 local_abspath,
-                                 local_abspath,
-                                 NULL, NULL, NULL, /* diff labels */
-                                 actual_props,
-                                 FALSE, /* dry-run */
-                                 NULL, /* diff3-cmd */
-                                 NULL, /* merge options */
-                                 propchanges,
-                                 NULL, NULL, /* cancel_func + baton */
-                                 result_pool, scratch_pool));
+  if (!svn_checksum_match(new_version->checksum, old_version->checksum))
+    {
+      /*
+       * Run a 3-way merge to update the file, using the pre-update
+       * pristine text as the merge base, the post-update pristine
+       * text as the merge-left version, and the current content of the
+       * moved-here working file as the merge-right version.
+       */
+      SVN_ERR(svn_wc__db_pristine_get_path(&old_pristine_abspath,
+                                           db, wcroot->abspath,
+                                           old_version->checksum,
+                                           scratch_pool, scratch_pool));
+      SVN_ERR(svn_wc__db_pristine_get_path(&new_pristine_abspath,
+                                           db, wcroot->abspath,
+                                           new_version->checksum,
+                                           scratch_pool, scratch_pool));
+      SVN_ERR(svn_wc__internal_merge(&work_item, &conflict_skel,
+                                     &merge_outcome, db,
+                                     old_pristine_abspath,
+                                     new_pristine_abspath,
+                                     local_abspath,
+                                     local_abspath,
+                                     NULL, NULL, NULL, /* diff labels */
+                                     actual_props,
+                                     FALSE, /* dry-run */
+                                     NULL, /* diff3-cmd */
+                                     NULL, /* merge options */
+                                     propchanges,
+                                     NULL, NULL, /* cancel_func + baton */
+                                     scratch_pool, scratch_pool));
 
-  *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
+      work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
+
+      if (merge_outcome == svn_wc_merge_conflict)
+        {
+          content_state = svn_wc_notify_state_conflicted;
+        }
+      else
+        {
+          svn_boolean_t is_locally_modified;
+          
+          SVN_ERR(svn_wc__internal_file_modified_p(&is_locally_modified,
+                                                   db, local_abspath,
+                                                   FALSE /* exact_comparison */,
+                                                   scratch_pool));
+          if (is_locally_modified)
+            content_state = svn_wc_notify_state_merged;
+          else
+            content_state = svn_wc_notify_state_changed;
+        }
+    }
+  else
+    content_state = svn_wc_notify_state_unchanged;
 
   /* If there are any conflicts to be stored, convert them into work items
    * too. */
   if (conflict_skel)
     {
-      SVN_ERR(create_conflict_markers(work_items, local_abspath, db,
+      SVN_ERR(create_conflict_markers(&work_item, local_abspath, db,
                                       repos_relpath, conflict_skel,
                                       operation, old_version, new_version,
-                                      svn_kind_file,
-                                      result_pool, scratch_pool));
+                                      svn_node_file,
+                                      scratch_pool, scratch_pool));
+
       SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath,
                                                 conflict_skel,
                                                 scratch_pool));
-    }
 
-  if (merge_outcome == svn_wc_merge_conflict)
-    {
-      content_state = svn_wc_notify_state_conflicted;
+      work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
     }
-  else
-    {
-      svn_boolean_t is_locally_modified;
 
-      SVN_ERR(svn_wc__internal_file_modified_p(&is_locally_modified,
-                                               db, local_abspath,
-                                               FALSE /* exact_comparison */,
-                                               scratch_pool));
-      if (is_locally_modified)
-        content_state = svn_wc_notify_state_merged;
-      else
-        content_state = svn_wc_notify_state_changed;
-    }
+  SVN_ERR(svn_wc__db_wq_add(db, wcroot->abspath, work_items, scratch_pool));
 
-  if (notify_func)
-    SVN_ERR(update_move_list_add(wcroot, local_relpath,
-                                 svn_wc_notify_update_update,
-                                 svn_node_file,
-                                 content_state,
-                                 prop_state));
+  SVN_ERR(update_move_list_add(wcroot, local_relpath,
+                               svn_wc_notify_update_update,
+                               svn_node_file,
+                               content_state,
+                               prop_state));
 
   return SVN_NO_ERROR;
 }
@@ -993,7 +1010,8 @@ tc_editor_alter_file(void *baton,
   SVN_ERR_ASSERT(move_dst_kind == svn_kind_file);
 
   SVN_ERR(check_tree_conflict(&is_conflicted, b, dst_relpath,
-                              move_dst_kind, svn_node_file,
+                              svn__node_kind_from_kind(move_dst_kind),
+                              svn_node_file,
                               move_dst_repos_relpath,
                               svn_wc_conflict_action_edit,
                               scratch_pool));
@@ -1010,16 +1028,10 @@ tc_editor_alter_file(void *baton,
   /* Update file and prop contents if the update has changed them. */
   if (!svn_checksum_match(new_checksum, old_version.checksum) || new_props)
     {
-      svn_skel_t *work_items;
-
-      SVN_ERR(update_working_file(&work_items, dst_relpath,
-                                  move_dst_repos_relpath,
+      SVN_ERR(update_working_file(dst_relpath, move_dst_repos_relpath,
                                   b->operation, &old_version, &new_version,
                                   b->wcroot, b->db,
-                                  b->notify_func, b->notify_baton,
-                                  b->result_pool, scratch_pool));
-      *b->work_items = svn_wc__wq_merge(*b->work_items, work_items,
-                                        b->result_pool);
+                                  scratch_pool));
     }
 
   return SVN_NO_ERROR;
@@ -1063,7 +1075,8 @@ tc_editor_delete(void *baton,
      conflicts. This catches conflicts on the node itself; deleted
      children are caught as local modifications below.*/
   SVN_ERR(check_tree_conflict(&is_conflicted, b, relpath,
-                              move_dst_kind, svn_node_unknown,
+                              svn__node_kind_from_kind(move_dst_kind),
+                              svn_node_unknown,
                               move_dst_repos_relpath,
                               svn_wc_conflict_action_delete,
                               scratch_pool));
@@ -1104,16 +1117,15 @@ tc_editor_delete(void *baton,
               must_delete_working_nodes = TRUE;
             }
           is_conflicted = TRUE;
-          SVN_ERR(mark_tree_conflict(b, relpath, move_dst_kind, svn_node_none,
+          SVN_ERR(mark_tree_conflict(relpath, b->wcroot, b->db, b->old_version,
+                                     b->new_version, b->move_root_dst_relpath,
+                                     b->operation,
+                                     svn__node_kind_from_kind(move_dst_kind),
+                                     svn_node_none,
                                      move_dst_repos_relpath, reason,
                                      svn_wc_conflict_action_delete, NULL,
                                      scratch_pool));
-          if (b->notify_func)
-            SVN_ERR(update_move_list_add(b->wcroot, relpath,
-                                         svn_wc_notify_tree_conflict,
-                                         svn_node_dir, /* ### kinds? */
-                                         svn_wc_notify_state_inapplicable,
-                                         svn_wc_notify_state_inapplicable));
+          b->conflict_root_relpath = apr_pstrdup(b->result_pool, relpath);
         }
     }
 
@@ -1176,7 +1188,7 @@ tc_editor_delete(void *baton,
       SVN_ERR(svn_wc__db_wq_add(b->db, b->wcroot->abspath, work_item,
                                 iterpool));
 
-      if (b->notify_func && !is_conflicted)
+      if (!is_conflicted)
         SVN_ERR(update_move_list_add(b->wcroot, relpath,
                                      svn_wc_notify_update_delete,
                                      svn__node_kind_from_kind(del_kind),
@@ -1234,30 +1246,6 @@ static svn_error_t *
 tc_editor_complete(void *baton,
                    apr_pool_t *scratch_pool)
 {
-  struct tc_editor_baton *b = baton;
-
-  /* Send all queued up notifications. */
-  SVN_ERR(update_move_list_notify(b->wcroot,
-                                  b->old_version->peg_rev,
-                                  b->new_version->peg_rev,
-                                  b->notify_func, b->notify_baton,
-                                  scratch_pool));
-  if (b->notify_func)
-    {
-      svn_wc_notify_t *notify;
-
-      notify = svn_wc_create_notify(svn_dirent_join(b->wcroot->abspath,
-                                                    b->move_root_dst_relpath,
-                                                    scratch_pool),
-                                    svn_wc_notify_update_completed,
-                                    scratch_pool);
-      notify->kind = svn_node_none;
-      notify->content_state = svn_wc_notify_state_inapplicable;
-      notify->prop_state = svn_wc_notify_state_inapplicable;
-      notify->revision = b->new_version->peg_rev;
-      b->notify_func(b->notify_baton, notify, scratch_pool);
-    }
-
   return SVN_NO_ERROR;
 }
 
@@ -1763,15 +1751,28 @@ suitable_for_move(svn_wc__db_wcroot_t *w
       relpath = svn_relpath_skip_ancestor(local_relpath, relpath);
       relpath = svn_relpath_join(repos_relpath, relpath, iterpool);
 
-      if (revision != node_revision
-          || strcmp(relpath, svn_sqlite__column_text(stmt, 1, NULL)))
+      if (revision != node_revision)
+        return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
+                                 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));
+
+      if (strcmp(relpath, svn_sqlite__column_text(stmt, 1, NULL)))
         return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
                                  svn_sqlite__reset(stmt),
-                      _("The tree '%s' is not single-revision and unswitched"),
-                        svn_dirent_local_style(svn_dirent_join(wcroot->abspath,
-                                                               local_relpath,
-                                                               scratch_pool),
-                                               scratch_pool));
+                                 _("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));
+
       SVN_ERR(svn_sqlite__step(&have_row, stmt));
     }
   SVN_ERR(svn_sqlite__reset(stmt));
@@ -1784,8 +1785,7 @@ suitable_for_move(svn_wc__db_wcroot_t *w
 /* The body of svn_wc__db_update_moved_away_conflict_victim(), which see.
  */
 static svn_error_t *
-update_moved_away_conflict_victim(svn_skel_t **work_items,
-                                  svn_wc__db_t *db,
+update_moved_away_conflict_victim(svn_wc__db_t *db,
                                   svn_wc__db_wcroot_t *wcroot,
                                   const char *victim_relpath,
                                   svn_wc_operation_t operation,
@@ -1794,11 +1794,8 @@ update_moved_away_conflict_victim(svn_sk
                                   const char *move_src_op_root_relpath,
                                   svn_wc_conflict_version_t *old_version,
                                   svn_wc_conflict_version_t *new_version,
-                                  svn_wc_notify_func2_t notify_func,
-                                  void *notify_baton,
                                   svn_cancel_func_t cancel_func,
                                   void *cancel_baton,
-                                  apr_pool_t *result_pool,
                                   apr_pool_t *scratch_pool)
 {
   svn_editor_t *tc_editor;
@@ -1807,6 +1804,7 @@ update_moved_away_conflict_victim(svn_sk
   svn_boolean_t have_row;
   const char *dummy1, *dummy2, *dummy3;
   int src_op_depth;
+  const char *move_root_dst_abspath;
 
   /* ### assumes wc write lock already held */
 
@@ -1823,15 +1821,18 @@ update_moved_away_conflict_victim(svn_sk
                                svn_dirent_join(wcroot->abspath, victim_relpath,
                                                scratch_pool),
                                scratch_pool));
+
+  move_root_dst_abspath
+    = svn_dirent_join(wcroot->abspath, tc_editor_baton->move_root_dst_relpath,
+                      scratch_pool);
+  SVN_ERR(svn_wc__write_check(db, move_root_dst_abspath, scratch_pool));
+
   tc_editor_baton->operation = operation;
   tc_editor_baton->old_version= old_version;
   tc_editor_baton->new_version= new_version;
   tc_editor_baton->db = db;
   tc_editor_baton->wcroot = wcroot;
-  tc_editor_baton->work_items = work_items;
-  tc_editor_baton->notify_func = notify_func;
-  tc_editor_baton->notify_baton = notify_baton;
-  tc_editor_baton->result_pool = result_pool;
+  tc_editor_baton->result_pool = scratch_pool;
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_SELECT_HIGHEST_WORKING_NODE));
@@ -1880,14 +1881,12 @@ update_moved_away_conflict_victim(svn_sk
 
 
 svn_error_t *
-svn_wc__db_update_moved_away_conflict_victim(svn_skel_t **work_items,
-                                             svn_wc__db_t *db,
+svn_wc__db_update_moved_away_conflict_victim(svn_wc__db_t *db,
                                              const char *victim_abspath,
                                              svn_wc_notify_func2_t notify_func,
                                              void *notify_baton,
                                              svn_cancel_func_t cancel_func,
                                              void *cancel_baton,
-                                             apr_pool_t *result_pool,
                                              apr_pool_t *scratch_pool)
 {
   svn_wc__db_wcroot_t *wcroot;
@@ -1905,6 +1904,8 @@ svn_wc__db_update_moved_away_conflict_vi
                       db, victim_abspath,
                       scratch_pool, scratch_pool));
 
+  SVN_ERR(svn_wc__write_check(db, move_src_op_root_abspath, scratch_pool));
+
   SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
                                                 db, victim_abspath,
                                                 scratch_pool, scratch_pool));
@@ -1915,15 +1916,158 @@ svn_wc__db_update_moved_away_conflict_vi
 
   SVN_WC__DB_WITH_TXN(
     update_moved_away_conflict_victim(
-      work_items, db, wcroot, local_relpath,
+      db, wcroot, local_relpath,
       operation, local_change, incoming_change,
       move_src_op_root_relpath,
       old_version, new_version,
-      notify_func, notify_baton,
       cancel_func, cancel_baton,
-      result_pool, scratch_pool),
+      scratch_pool),
     wcroot);
 
+  /* Send all queued up notifications. */
+  SVN_ERR(svn_wc__db_update_move_list_notify(wcroot,
+                                             old_version->peg_rev,
+                                             new_version->peg_rev,
+                                             notify_func, notify_baton,
+                                             scratch_pool));
+  if (notify_func)
+    {
+      svn_wc_notify_t *notify;
+
+      notify = svn_wc_create_notify(svn_dirent_join(wcroot->abspath,
+                                                    local_relpath,
+                                                    scratch_pool),
+                                    svn_wc_notify_update_completed,
+                                    scratch_pool);
+      notify->kind = svn_node_none;
+      notify->content_state = svn_wc_notify_state_inapplicable;
+      notify->prop_state = svn_wc_notify_state_inapplicable;
+      notify->revision = new_version->peg_rev;
+      notify_func(notify_baton, notify, scratch_pool);
+    }
+
+
+  return SVN_NO_ERROR;
+}
+
+/* Set *CAN_BUMP to TRUE if DEPTH is sufficient to cover the entire
+   BASE tree at LOCAL_RELPATH, to FALSE otherwise. */
+static svn_error_t *
+depth_sufficient_to_bump(svn_boolean_t *can_bump,
+                         const char *local_relpath,
+                         svn_wc__db_wcroot_t *wcroot,
+                         svn_depth_t depth,
+                         apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+          
+  switch (depth)
+    {
+    case svn_depth_infinity:
+      *can_bump = TRUE;
+      return SVN_NO_ERROR;
+
+    case svn_depth_empty:
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                        STMT_SELECT_OP_DEPTH_CHILDREN));
+      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
+                                local_relpath, 0));
+      break;
+
+    case svn_depth_files:
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                        STMT_SELECT_HAS_NON_FILE_CHILDREN));
+      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
+                                local_relpath));
+      break;
+
+    case svn_depth_immediates:
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                        STMT_SELECT_HAS_GRANDCHILDREN));
+      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
+                                local_relpath));
+      break;
+    default:
+      SVN_ERR_MALFUNCTION();
+    }
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  *can_bump = !have_row;
+  return SVN_NO_ERROR;
+}
+
+/* Mark a move-edit conflict on MOVE_SRC_ROOT_RELPATH. */
+static svn_error_t *
+bump_mark_tree_conflict(svn_wc__db_wcroot_t *wcroot,
+                        const char *move_src_root_relpath,
+                        const char *move_src_op_root_relpath,
+                        const char *move_dst_op_root_relpath,
+                        svn_wc__db_t *db,
+                        apr_pool_t *scratch_pool)
+{
+  apr_int64_t repos_id;
+  const char *repos_root_url;
+  const char *repos_uuid;
+  const char *old_repos_relpath;
+  const char *new_repos_relpath;
+  svn_revnum_t old_rev;
+  svn_revnum_t new_rev;
+  const char *old_repos_url;
+  const char *new_repos_url;
+  svn_kind_t old_kind;
+  svn_kind_t new_kind;
+  svn_wc_conflict_version_t *old_version;
+  svn_wc_conflict_version_t *new_version;
+
+  /* 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,
+                                            &new_repos_relpath, &repos_id,
+                                            NULL, NULL, NULL, NULL, NULL,
+                                            NULL, NULL, NULL, NULL, NULL,
+                                            wcroot, move_src_op_root_relpath,
+                                            scratch_pool, scratch_pool));
+  SVN_ERR(svn_wc__db_fetch_repos_info(&repos_root_url, &repos_uuid,
+                                      wcroot->sdb, repos_id, scratch_pool));
+  new_repos_url = svn_uri_canonicalize(apr_pstrcat(scratch_pool,
+                                                   repos_root_url, "/",
+                                                   new_repos_relpath,
+                                                   (const char *)NULL),
+                                       scratch_pool);
+
+  /* Read old (pre-update) information from the move destination node. */
+  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,
+                                    wcroot, move_dst_op_root_relpath,
+                                    relpath_depth(move_dst_op_root_relpath),
+                                    scratch_pool, scratch_pool));
+  old_repos_url = svn_uri_canonicalize(apr_pstrcat(scratch_pool,
+                                                   repos_root_url, "/",
+                                                   old_repos_relpath,
+                                                   (const char *)NULL),
+                                       scratch_pool);
+
+  old_version = svn_wc_conflict_version_create2(
+                  old_repos_url, repos_uuid, old_repos_relpath, old_rev,
+                  svn__node_kind_from_kind(old_kind), scratch_pool);
+  new_version = svn_wc_conflict_version_create2(
+                  new_repos_url, repos_uuid, new_repos_relpath, new_rev,
+                  svn__node_kind_from_kind(new_kind), scratch_pool);
+
+  SVN_ERR(mark_tree_conflict(move_src_root_relpath,
+                             wcroot, db, old_version, new_version,
+                             move_dst_op_root_relpath,
+                             svn_wc_operation_update,
+                             svn__node_kind_from_kind(old_kind),
+                             svn__node_kind_from_kind(new_kind),
+                             old_repos_relpath,
+                             svn_wc_conflict_reason_moved_away,
+                             svn_wc_conflict_action_edit,
+                             move_src_op_root_relpath,
+                             scratch_pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -1936,6 +2080,8 @@ bump_moved_away(svn_wc__db_wcroot_t *wcr
                 const char *local_relpath,
                 int op_depth,
                 apr_hash_t *src_done,
+                svn_depth_t depth,
+                svn_wc__db_t *db,
                 apr_pool_t *result_pool,
                 apr_pool_t *scratch_pool)
 {
@@ -1957,12 +2103,51 @@ bump_moved_away(svn_wc__db_wcroot_t *wcr
       int src_op_depth = svn_sqlite__column_int(stmt, 2);
       svn_error_t *err;
       svn_skel_t *conflict;
+      svn_depth_t src_depth = depth;
 
       svn_pool_clear(iterpool);
 
       src_relpath = svn_sqlite__column_text(stmt, 0, iterpool);
       dst_relpath = svn_sqlite__column_text(stmt, 1, iterpool);
 
+      if (depth != svn_depth_infinity)
+        {
+          svn_boolean_t skip_this_src = FALSE;
+          svn_kind_t src_kind;
+
+          if (strcmp(src_relpath, local_relpath))
+            {
+              switch (depth)
+                {
+                case svn_depth_empty:
+                  skip_this_src = TRUE;
+                  break;
+                case svn_depth_files:
+                  src_kind = svn_sqlite__column_token(stmt, 3, kind_map);
+                  if (src_kind != svn_kind_file)
+                    {
+                      skip_this_src = TRUE;
+                      break;
+                    }
+                  /* Fallthrough */
+                case svn_depth_immediates:
+                  if (strcmp(svn_relpath_dirname(src_relpath, scratch_pool),
+                             local_relpath))
+                    skip_this_src = TRUE;
+                  src_depth = svn_depth_empty;
+                  break;
+                default:
+                  SVN_ERR_MALFUNCTION();
+                }
+            }
+
+          if (skip_this_src)
+            {
+              SVN_ERR(svn_sqlite__step(&have_row, stmt));
+              continue;
+            }
+        }
+
       err = svn_sqlite__get_statement(&stmt2, wcroot->sdb,
                                       STMT_HAS_LAYER_BETWEEN);
       if (!err)
@@ -1974,29 +2159,55 @@ bump_moved_away(svn_wc__db_wcroot_t *wcr
         err = svn_sqlite__reset(stmt2);
       if (!err && !have_row)
         {
+          svn_boolean_t can_bump;
           const char *src_root_relpath = src_relpath;
 
-          while (relpath_depth(src_root_relpath) > src_op_depth)
-            src_root_relpath = svn_relpath_dirname(src_root_relpath, iterpool);
+          if (op_depth == 0)
+            err = depth_sufficient_to_bump(&can_bump, src_relpath, wcroot,
+                                           src_depth, scratch_pool);
+          else
+            /* Having chosen to bump an entire BASE tree move we
+               always have sufficient depth to bump subtree moves. */
+            can_bump = TRUE;
 
-          if (!apr_hash_get(src_done, src_relpath, APR_HASH_KEY_STRING))
+          if (!err)
             {
-              apr_hash_set(src_done, apr_pstrdup(result_pool, src_relpath),
-                           APR_HASH_KEY_STRING, "");
-              err = svn_wc__db_read_conflict_internal(&conflict, wcroot,
-                                                      src_root_relpath,
-                                                      iterpool, iterpool);
-              /* ### TODO: check this is the right sort of tree-conflict? */
-              if (!err && !conflict)
+              if (!can_bump)
+                {
+                  err = bump_mark_tree_conflict(wcroot, src_relpath,
+                                                src_root_relpath, dst_relpath,
+                                                db, scratch_pool);
+                  if (err)
+                    return svn_error_compose_create(err,
+                                                    svn_sqlite__reset(stmt));
+                  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+                  continue;
+                }
+
+              while (relpath_depth(src_root_relpath) > src_op_depth)
+                src_root_relpath = svn_relpath_dirname(src_root_relpath,
+                                                       iterpool);
+
+              if (!apr_hash_get(src_done, src_relpath, APR_HASH_KEY_STRING))
                 {
-                  /* ### TODO: verify moved_here? */
-                  err = replace_moved_layer(src_relpath, dst_relpath, op_depth,
-                                            wcroot, iterpool);
-
-                  if (!err)
-                    err = bump_moved_away(wcroot, dst_relpath,
-                                          relpath_depth(dst_relpath), src_done,
-                                          result_pool, iterpool);
+                  apr_hash_set(src_done, apr_pstrdup(result_pool, src_relpath),
+                               APR_HASH_KEY_STRING, "");
+                  err = svn_wc__db_read_conflict_internal(&conflict, wcroot,
+                                                          src_root_relpath,
+                                                          iterpool, iterpool);
+                  /* ### TODO: check this is the right sort of tree-conflict? */
+                  if (!err && !conflict)
+                    {
+                      /* ### TODO: verify moved_here? */
+                      err = replace_moved_layer(src_relpath, dst_relpath,
+                                                op_depth, wcroot, iterpool);
+
+                      if (!err)
+                        err = bump_moved_away(wcroot, dst_relpath,
+                                              relpath_depth(dst_relpath),
+                                              src_done, depth, db,
+                                              result_pool, iterpool);
+                    }
                 }
             }
         }
@@ -2017,16 +2228,37 @@ svn_error_t *
 svn_wc__db_bump_moved_away(svn_wc__db_wcroot_t *wcroot,
                            const char *local_relpath,
                            svn_depth_t depth,
+                           svn_wc__db_t *db,
                            apr_pool_t *scratch_pool)
 {
+  const char *dummy1, *move_dst_op_root_relpath;
+  const char *move_src_root_relpath, *move_src_op_root_relpath;
   apr_hash_t *src_done;
 
-  /* ### TODO: raise tree-conflicts? */
-  if (depth != svn_depth_infinity)
-    return SVN_NO_ERROR;
+  SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb,
+                                      STMT_CREATE_UPDATE_MOVE_LIST));
+
+  SVN_ERR(svn_wc__db_op_depth_moved_to(&dummy1, &move_dst_op_root_relpath,
+                                       &move_src_root_relpath,
+                                       &move_src_op_root_relpath, 0,
+                                       wcroot, local_relpath,
+                                       scratch_pool, scratch_pool));
+
+  if (move_src_root_relpath)
+    {
+      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));
+          return SVN_NO_ERROR;
+        }
+
+    }
 
   src_done = apr_hash_make(scratch_pool);
-  SVN_ERR(bump_moved_away(wcroot, local_relpath, 0, src_done,
+  SVN_ERR(bump_moved_away(wcroot, local_relpath, 0, src_done, depth, db,
                           scratch_pool, scratch_pool));
 
   return SVN_NO_ERROR;
@@ -2047,6 +2279,9 @@ resolve_delete_raise_moved_away(svn_wc__
   int op_depth = relpath_depth(local_relpath);
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
   
+  SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb,
+                                      STMT_CREATE_UPDATE_MOVE_LIST));
+
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_SELECT_OP_DEPTH_MOVED_PAIR));
   SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
@@ -2054,30 +2289,22 @@ resolve_delete_raise_moved_away(svn_wc__
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
   while(have_row)
     {
-      struct tc_editor_baton b;
-
       const char *moved_relpath = svn_sqlite__column_text(stmt, 0, NULL);
+      const char *move_root_dst_relpath = svn_sqlite__column_text(stmt, 1,
+                                                                  NULL);
       const char *moved_dst_repos_relpath = svn_sqlite__column_text(stmt, 2,
                                                                     NULL);
-
       svn_pool_clear(iterpool);
 
-      b.wcroot = wcroot;
-      b.db = db;
-      b.operation = operation;
-      b.old_version = old_version;
-      b.new_version = new_version;
-      b.move_root_dst_relpath = svn_sqlite__column_text(stmt, 1, NULL);
-      b.result_pool = scratch_pool;
-      
-      SVN_ERR(mark_tree_conflict(&b, moved_relpath,
+      SVN_ERR(mark_tree_conflict(moved_relpath,
+                                 wcroot, db, old_version, new_version,
+                                 move_root_dst_relpath, operation,
                                  svn_node_dir /* ### ? */,
                                  svn_node_dir /* ### ? */,
                                  moved_dst_repos_relpath,
                                  svn_wc_conflict_reason_moved_away,
-                                 action, local_relpath, iterpool));
-
-      /* ### Do notification? */
+                                 action, local_relpath,
+                                 iterpool));
 
       SVN_ERR(svn_sqlite__step(&have_row, stmt));
     }
@@ -2091,6 +2318,8 @@ resolve_delete_raise_moved_away(svn_wc__
 svn_error_t *
 svn_wc__db_resolve_delete_raise_moved_away(svn_wc__db_t *db,
                                            const char *local_abspath,
+                                           svn_wc_notify_func2_t notify_func,
+                                           void *notify_baton,
                                            apr_pool_t *scratch_pool)
 {
   svn_wc__db_wcroot_t *wcroot;
@@ -2116,6 +2345,40 @@ svn_wc__db_resolve_delete_raise_moved_aw
                                     scratch_pool),
     wcroot);
 
+  SVN_ERR(svn_wc__db_update_move_list_notify(wcroot,
+                                             old_version->peg_rev,
+                                             (new_version 
+                                              ? new_version->peg_rev
+                                              : SVN_INVALID_REVNUM),
+                                             notify_func, notify_baton,
+                                             scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+break_move(svn_wc__db_wcroot_t *wcroot,
+           const char *src_relpath,
+           int src_op_depth,
+           const char *dst_relpath,
+           int dst_op_depth,
+           apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_CLEAR_MOVED_TO_RELPATH));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, src_relpath,
+                            src_op_depth));
+  SVN_ERR(svn_sqlite__step_done(stmt));
+
+  /* This statement clears moved_here. */
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_UPDATE_OP_DEPTH_RECURSIVE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isdd", wcroot->wc_id,
+                            dst_relpath, dst_op_depth, dst_op_depth));
+  SVN_ERR(svn_sqlite__step_done(stmt));
+
   return SVN_NO_ERROR;
 }
 
@@ -2126,8 +2389,6 @@ svn_wc__db_resolve_break_moved_away_inte
 {
   const char *dummy1, *move_dst_op_root_relpath;
   const char *dummy2, *move_src_op_root_relpath;
-  svn_sqlite__stmt_t *stmt;
-  int dst_op_depth;
 
   SVN_ERR(svn_wc__db_op_depth_moved_to(&dummy1, &move_dst_op_root_relpath,
                                        &dummy2,
@@ -2135,21 +2396,53 @@ svn_wc__db_resolve_break_moved_away_inte
                                        relpath_depth(local_relpath) - 1,
                                        wcroot, local_relpath,
                                        scratch_pool, scratch_pool));
-  dst_op_depth = relpath_depth(move_dst_op_root_relpath);
+  SVN_ERR(break_move(wcroot, local_relpath,
+                     relpath_depth(move_src_op_root_relpath),
+                     move_dst_op_root_relpath,
+                     relpath_depth(move_dst_op_root_relpath),
+                     scratch_pool));
 
-  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                    STMT_CLEAR_MOVED_TO_RELPATH));
-  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
-                            relpath_depth(move_src_op_root_relpath)));
-  SVN_ERR(svn_sqlite__step_done(stmt));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+break_moved_away_children_internal(svn_wc__db_wcroot_t *wcroot,
+                                   const char *local_relpath,
+                                   apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+  apr_pool_t *iterpool;
+
+  SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb,
+                                      STMT_CREATE_UPDATE_MOVE_LIST));
 
-  /* This statement clears moved_here. */
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                    STMT_UPDATE_OP_DEPTH_RECURSIVE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "isdd", wcroot->wc_id,
-                            move_dst_op_root_relpath,
-                            dst_op_depth, dst_op_depth));
-  SVN_ERR(svn_sqlite__step_done(stmt));
+                                    STMT_SELECT_MOVED_PAIR2));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+  iterpool = svn_pool_create(scratch_pool);
+  while (have_row)
+    {
+      const char *src_relpath = svn_sqlite__column_text(stmt, 0, iterpool);
+      const char *dst_relpath = svn_sqlite__column_text(stmt, 1, iterpool);
+      int src_op_depth = svn_sqlite__column_int(stmt, 2);
+      
+      svn_pool_clear(iterpool);
+
+      SVN_ERR(break_move(wcroot, src_relpath, src_op_depth, dst_relpath,
+                         relpath_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));
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+    }
+  svn_pool_destroy(iterpool);
+
+  SVN_ERR(svn_sqlite__reset(stmt));
 
   return SVN_NO_ERROR;
 }
@@ -2157,6 +2450,8 @@ svn_wc__db_resolve_break_moved_away_inte
 svn_error_t *
 svn_wc__db_resolve_break_moved_away(svn_wc__db_t *db,
                                     const char *local_abspath,
+                                    svn_wc_notify_func2_t notify_func,
+                                    void *notify_baton,
                                     apr_pool_t *scratch_pool)
 {
   svn_wc__db_wcroot_t *wcroot;
@@ -2172,5 +2467,116 @@ svn_wc__db_resolve_break_moved_away(svn_
                                                  scratch_pool),
     wcroot);
 
+  if (notify_func)
+    {
+      svn_wc_notify_t *notify;
+
+      notify = svn_wc_create_notify(svn_dirent_join(wcroot->abspath,
+                                                    local_relpath,
+                                                    scratch_pool),
+                                    svn_wc_notify_move_broken,
+                                    scratch_pool);
+      notify->kind = svn_node_unknown;
+      notify->content_state = svn_wc_notify_state_inapplicable;
+      notify->prop_state = svn_wc_notify_state_inapplicable;
+      notify->revision = SVN_INVALID_REVNUM;
+      notify_func(notify_baton, notify, scratch_pool);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__db_resolve_break_moved_away_children(svn_wc__db_t *db,
+                                             const char *local_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;
+
+  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
+                                                db, local_abspath,
+                                                scratch_pool, scratch_pool));
+  VERIFY_USABLE_WCROOT(wcroot);
+
+  SVN_WC__DB_WITH_TXN(
+    break_moved_away_children_internal(wcroot, local_relpath, scratch_pool),
+    wcroot);
+
+  SVN_ERR(svn_wc__db_update_move_list_notify(wcroot,
+                                             SVN_INVALID_REVNUM,
+                                             SVN_INVALID_REVNUM,
+                                             notify_func, notify_baton,
+                                             scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+required_lock_for_resolve(const char **required_relpath,
+                          svn_wc__db_wcroot_t *wcroot,
+                          const char *local_relpath,
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+
+  *required_relpath = local_relpath;
+
+  /* This simply looks for all moves out of the LOCAL_RELPATH tree. We
+     could attempt to limit it to only those moves that are going to
+     be resolved but that would require second guessing the resolver.
+     This simple algorithm is sufficient although it may give a
+     strictly larger/deeper lock than necessary. */
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_SELECT_MOVED_OUTSIDE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath, 0));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+  
+  while (have_row)
+    {
+      const char *move_dst_relpath = svn_sqlite__column_text(stmt, 1,
+                                                             NULL);
+      
+      *required_relpath
+        = svn_relpath_get_longest_ancestor(*required_relpath,
+                                           move_dst_relpath,
+                                           scratch_pool);
+
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+    }
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  *required_relpath = apr_pstrdup(result_pool, *required_relpath);
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__required_lock_for_resolve(const char **required_abspath,
+                                  svn_wc__db_t *db,
+                                  const char *local_abspath,
+                                  apr_pool_t *result_pool,
+                                  apr_pool_t *scratch_pool)
+{
+  svn_wc__db_wcroot_t *wcroot;
+  const char *local_relpath;
+  const char *required_relpath;
+
+  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
+                                                db, local_abspath,
+                                                scratch_pool, scratch_pool));
+  VERIFY_USABLE_WCROOT(wcroot);
+
+  SVN_WC__DB_WITH_TXN(
+    required_lock_for_resolve(&required_relpath, wcroot, local_relpath,
+                              scratch_pool, scratch_pool),
+    wcroot);
+
+  *required_abspath = svn_dirent_join(wcroot->abspath, required_relpath,
+                                      result_pool);
+
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/fsfs-format7/subversion/libsvn_wc/workqueue.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_wc/workqueue.c?rev=1453290&r1=1453289&r2=1453290&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_wc/workqueue.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_wc/workqueue.c Wed Mar  6 11:10:01 2013
@@ -63,10 +63,12 @@
 /* For work queue debugging. Generates output about its operation.  */
 /* #define SVN_DEBUG_WORK_QUEUE */
 
+typedef struct work_item_baton_t work_item_baton_t;
 
 struct work_item_dispatch {
   const char *name;
-  svn_error_t *(*func)(svn_wc__db_t *db,
+  svn_error_t *(*func)(work_item_baton_t *wqb,
+                       svn_wc__db_t *db,
                        const svn_skel_t *work_item,
                        const char *wri_abspath,
                        svn_cancel_func_t cancel_func,
@@ -74,30 +76,12 @@ struct work_item_dispatch {
                        apr_pool_t *scratch_pool);
 };
 
-
+/* Forward definition */
 static svn_error_t *
-get_and_record_fileinfo(svn_wc__db_t *db,
+get_and_record_fileinfo(work_item_baton_t *wqb,
                         const char *local_abspath,
                         svn_boolean_t ignore_enoent,
-                        apr_pool_t *scratch_pool)
-{
-  const svn_io_dirent2_t *dirent;
-
-  SVN_ERR(svn_io_stat_dirent(&dirent, local_abspath, ignore_enoent,
-                             scratch_pool, scratch_pool));
-
-  if (dirent->kind == svn_node_none)
-    {
-      /* Skip file not found if ignore_enoent */
-      return SVN_NO_ERROR;
-    }
-
-  return svn_error_trace(svn_wc__db_global_record_fileinfo(
-                           db, local_abspath,
-                           dirent->filesize, dirent->mtime,
-                           scratch_pool));
-}
-
+                        apr_pool_t *scratch_pool);
 
 /* ------------------------------------------------------------------------ */
 /* OP_REMOVE_BASE  */
@@ -111,7 +95,8 @@ get_and_record_fileinfo(svn_wc__db_t *db
  * See svn_wc__wq_build_remove_base() which generates this work item.
  * Implements (struct work_item_dispatch).func. */
 static svn_error_t *
-run_base_remove(svn_wc__db_t *db,
+run_base_remove(work_item_baton_t *wqb,
+                svn_wc__db_t *db,
                 const svn_skel_t *work_item,
                 const char *wri_abspath,
                 svn_cancel_func_t cancel_func,
@@ -349,7 +334,8 @@ process_commit_file_install(svn_wc__db_t
 
 
 static svn_error_t *
-run_file_commit(svn_wc__db_t *db,
+run_file_commit(work_item_baton_t *wqb,
+                svn_wc__db_t *db,
                 const svn_skel_t *work_item,
                 const char *wri_abspath,
                 svn_cancel_func_t cancel_func,
@@ -397,7 +383,8 @@ svn_wc__wq_build_file_commit(svn_skel_t 
 /* OP_POSTUPGRADE  */
 
 static svn_error_t *
-run_postupgrade(svn_wc__db_t *db,
+run_postupgrade(work_item_baton_t *wqb,
+                svn_wc__db_t *db,
                 const svn_skel_t *work_item,
                 const char *wri_abspath,
                 svn_cancel_func_t cancel_func,
@@ -465,7 +452,8 @@ svn_wc__wq_build_postupgrade(svn_skel_t 
  * See svn_wc__wq_build_file_install() which generates this work item.
  * Implements (struct work_item_dispatch).func. */
 static svn_error_t *
-run_file_install(svn_wc__db_t *db,
+run_file_install(work_item_baton_t *wqb,
+                 svn_wc__db_t *db,
                  const svn_skel_t *work_item,
                  const char *wri_abspath,
                  svn_cancel_func_t cancel_func,
@@ -665,7 +653,7 @@ run_file_install(svn_wc__db_t *db,
   /* ### this should happen before we rename the file into place.  */
   if (record_fileinfo)
     {
-      SVN_ERR(get_and_record_fileinfo(db, local_abspath,
+      SVN_ERR(get_and_record_fileinfo(wqb, local_abspath,
                                       FALSE /* ignore_enoent */,
                                       scratch_pool));
     }
@@ -717,12 +705,13 @@ svn_wc__wq_build_file_install(svn_skel_t
  * See svn_wc__wq_build_file_remove() which generates this work item.
  * Implements (struct work_item_dispatch).func. */
 static svn_error_t *
-run_file_remove(svn_wc__db_t *db,
-                 const svn_skel_t *work_item,
-                 const char *wri_abspath,
-                 svn_cancel_func_t cancel_func,
-                 void *cancel_baton,
-                 apr_pool_t *scratch_pool)
+run_file_remove(work_item_baton_t *wqb,
+                svn_wc__db_t *db,
+                const svn_skel_t *work_item,
+                const char *wri_abspath,
+                svn_cancel_func_t cancel_func,
+                void *cancel_baton,
+                apr_pool_t *scratch_pool)
 {
   const svn_skel_t *arg1 = work_item->children->next;
   const char *local_relpath;
@@ -766,7 +755,8 @@ svn_wc__wq_build_file_remove(svn_skel_t 
  * See svn_wc__wq_build_file_remove() which generates this work item.
  * Implements (struct work_item_dispatch).func. */
 static svn_error_t *
-run_dir_remove(svn_wc__db_t *db,
+run_dir_remove(work_item_baton_t *wqb,
+               svn_wc__db_t *db,
                const svn_skel_t *work_item,
                const char *wri_abspath,
                svn_cancel_func_t cancel_func,
@@ -847,12 +837,13 @@ svn_wc__wq_build_dir_remove(svn_skel_t *
  * See svn_wc__wq_build_file_move() which generates this work item.
  * Implements (struct work_item_dispatch).func. */
 static svn_error_t *
-run_file_move(svn_wc__db_t *db,
-                 const svn_skel_t *work_item,
-                 const char *wri_abspath,
-                 svn_cancel_func_t cancel_func,
-                 void *cancel_baton,
-                 apr_pool_t *scratch_pool)
+run_file_move(work_item_baton_t *wqb,
+              svn_wc__db_t *db,
+              const svn_skel_t *work_item,
+              const char *wri_abspath,
+              svn_cancel_func_t cancel_func,
+              void *cancel_baton,
+              apr_pool_t *scratch_pool)
 {
   const svn_skel_t *arg1 = work_item->children->next;
   const char *src_abspath, *dst_abspath;
@@ -929,7 +920,8 @@ svn_wc__wq_build_file_move(svn_skel_t **
  * See run_file_copy_translated() which generates this work item.
  * Implements (struct work_item_dispatch).func. */
 static svn_error_t *
-run_file_copy_translated(svn_wc__db_t *db,
+run_file_copy_translated(work_item_baton_t *wqb,
+                         svn_wc__db_t *db,
                          const svn_skel_t *work_item,
                          const char *wri_abspath,
                          svn_cancel_func_t cancel_func,
@@ -1023,12 +1015,13 @@ svn_wc__wq_build_file_copy_translated(sv
 /* OP_DIRECTORY_INSTALL  */
 
 static svn_error_t *
-run_dir_install(svn_wc__db_t *db,
-                    const svn_skel_t *work_item,
-                    const char *wri_abspath,
-                    svn_cancel_func_t cancel_func,
-                    void *cancel_baton,
-                    apr_pool_t *scratch_pool)
+run_dir_install(work_item_baton_t *wqb,
+                svn_wc__db_t *db,
+                const svn_skel_t *work_item,
+                const char *wri_abspath,
+                svn_cancel_func_t cancel_func,
+                void *cancel_baton,
+                apr_pool_t *scratch_pool)
 {
   const svn_skel_t *arg1 = work_item->children->next;
   const char *local_relpath;
@@ -1072,7 +1065,8 @@ svn_wc__wq_build_dir_install(svn_skel_t 
  * See svn_wc__wq_build_sync_file_flags() which generates this work item.
  * Implements (struct work_item_dispatch).func. */
 static svn_error_t *
-run_sync_file_flags(svn_wc__db_t *db,
+run_sync_file_flags(work_item_baton_t *wqb,
+                    svn_wc__db_t *db,
                     const svn_skel_t *work_item,
                     const char *wri_abspath,
                     svn_cancel_func_t cancel_func,
@@ -1117,7 +1111,8 @@ svn_wc__wq_build_sync_file_flags(svn_ske
 /* OP_PREJ_INSTALL  */
 
 static svn_error_t *
-run_prej_install(svn_wc__db_t *db,
+run_prej_install(work_item_baton_t *wqb,
+                 svn_wc__db_t *db,
                  const svn_skel_t *work_item,
                  const char *wri_abspath,
                  svn_cancel_func_t cancel_func,
@@ -1196,7 +1191,8 @@ svn_wc__wq_build_prej_install(svn_skel_t
 
 
 static svn_error_t *
-run_record_fileinfo(svn_wc__db_t *db,
+run_record_fileinfo(work_item_baton_t *wqb,
+                    svn_wc__db_t *db,
                     const svn_skel_t *work_item,
                     const char *wri_abspath,
                     svn_cancel_func_t cancel_func,
@@ -1241,7 +1237,7 @@ run_record_fileinfo(svn_wc__db_t *db,
     }
 
 
-  return svn_error_trace(get_and_record_fileinfo(db, local_abspath,
+  return svn_error_trace(get_and_record_fileinfo(wqb, local_abspath,
                                                  TRUE /* ignore_enoent */,
                                                  scratch_pool));
 }
@@ -1252,12 +1248,13 @@ run_record_fileinfo(svn_wc__db_t *db,
 
 
 static svn_error_t *
-run_set_text_conflict_markers(svn_wc__db_t *db,
-                    const svn_skel_t *work_item,
-                    const char *wri_abspath,
-                    svn_cancel_func_t cancel_func,
-                    void *cancel_baton,
-                    apr_pool_t *scratch_pool)
+run_set_text_conflict_markers(work_item_baton_t *wqb,
+                              svn_wc__db_t *db,
+                              const svn_skel_t *work_item,
+                              const char *wri_abspath,
+                              svn_cancel_func_t cancel_func,
+                              void *cancel_baton,
+                              apr_pool_t *scratch_pool)
 {
   const svn_skel_t *arg = work_item->children->next;
   const char *local_relpath;
@@ -1346,7 +1343,8 @@ run_set_text_conflict_markers(svn_wc__db
 /* OP_TMP_SET_PROPERTY_CONFLICT_MARKER  */
 
 static svn_error_t *
-run_set_property_conflict_marker(svn_wc__db_t *db,
+run_set_property_conflict_marker(work_item_baton_t *wqb,
+                                 svn_wc__db_t *db,
                                  const svn_skel_t *work_item,
                                  const char *wri_abspath,
                                  svn_cancel_func_t cancel_func,
@@ -1432,9 +1430,19 @@ static const struct work_item_dispatch d
   { NULL }
 };
 
+struct work_item_baton_t
+{
+  apr_pool_t *result_pool; /* Pool to allocate result in */
+
+  svn_boolean_t used; /* needs reset */
+
+  apr_hash_t *record_map; /* const char * -> svn_io_dirent2_t map */
+};
+
 
 static svn_error_t *
-dispatch_work_item(svn_wc__db_t *db,
+dispatch_work_item(work_item_baton_t *wqb,
+                   svn_wc__db_t *db,
                    const char *wri_abspath,
                    const svn_skel_t *work_item,
                    svn_cancel_func_t cancel_func,
@@ -1452,7 +1460,7 @@ dispatch_work_item(svn_wc__db_t *db,
 #ifdef SVN_DEBUG_WORK_QUEUE
           SVN_DBG(("dispatch: operation='%s'\n", scan->name));
 #endif
-          SVN_ERR((*scan->func)(db, work_item, wri_abspath,
+          SVN_ERR((*scan->func)(wqb, db, work_item, wri_abspath,
                                 cancel_func, cancel_baton,
                                 scratch_pool));
 
@@ -1497,6 +1505,8 @@ svn_wc__wq_run(svn_wc__db_t *db,
 {
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
   apr_uint64_t last_id = 0;
+  work_item_baton_t wib = { 0 };
+  wib.result_pool = svn_pool_create(scratch_pool);
 
 #ifdef SVN_DEBUG_WORK_QUEUE
   SVN_DBG(("wq_run: wri='%s'\n", wri_abspath));
@@ -1517,11 +1527,29 @@ svn_wc__wq_run(svn_wc__db_t *db,
 
       svn_pool_clear(iterpool);
 
-      /* Make sure to do this *early* in the loop iteration. There may
-         be a LAST_ID that needs to be marked as completed, *before* we
-         start worrying about anything else.  */
-      SVN_ERR(svn_wc__db_wq_fetch_next(&id, &work_item, db, wri_abspath,
-                                       last_id, iterpool, iterpool));
+      if (! wib.used)
+        {
+          /* Make sure to do this *early* in the loop iteration. There may
+             be a LAST_ID that needs to be marked as completed, *before* we
+             start worrying about anything else.  */
+          SVN_ERR(svn_wc__db_wq_fetch_next(&id, &work_item, db, wri_abspath,
+                                           last_id, iterpool, iterpool));
+        }
+      else
+        {
+          /* Make sure to do this *early* in the loop iteration. There may
+             be a LAST_ID that needs to be marked as completed, *before* we
+             start worrying about anything else.  */
+          SVN_ERR(svn_wc__db_wq_record_and_fetch_next(&id, &work_item,
+                                                      db, wri_abspath,
+                                                      last_id, wib.record_map,
+                                                      iterpool,
+                                                      wib.result_pool));
+
+          svn_pool_clear(wib.result_pool);
+          wib.record_map = NULL;
+          wib.used = FALSE;
+        }
 
       /* Stop work queue processing, if requested. A future 'svn cleanup'
          should be able to continue the processing. Note that we may
@@ -1534,7 +1562,7 @@ svn_wc__wq_run(svn_wc__db_t *db,
       if (work_item == NULL)
         break;
 
-      err = dispatch_work_item(db, wri_abspath, work_item,
+      err = dispatch_work_item(&wib, db, wri_abspath, work_item,
                                cancel_func, cancel_baton, iterpool);
       if (err)
         {
@@ -1604,3 +1632,29 @@ svn_wc__wq_merge(svn_skel_t *work_item1,
   svn_skel__append(work_item1, work_item2->children);
   return work_item1;
 }
+
+
+static svn_error_t *
+get_and_record_fileinfo(work_item_baton_t *wqb,
+                        const char *local_abspath,
+                        svn_boolean_t ignore_enoent,
+                        apr_pool_t *scratch_pool)
+{
+  const svn_io_dirent2_t *dirent;
+
+  SVN_ERR(svn_io_stat_dirent2(&dirent, local_abspath, FALSE, ignore_enoent,
+                              wqb->result_pool, scratch_pool));
+
+  if (dirent->kind != svn_node_file)
+    return SVN_NO_ERROR;
+
+  wqb->used = TRUE;
+
+  if (! wqb->record_map)
+    wqb->record_map = apr_hash_make(wqb->result_pool);
+
+  svn_hash_sets(wqb->record_map, apr_pstrdup(wqb->result_pool, local_abspath),
+                dirent);
+
+  return SVN_NO_ERROR;
+}

Modified: subversion/branches/fsfs-format7/subversion/mod_dav_svn/version.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/mod_dav_svn/version.c?rev=1453290&r1=1453289&r2=1453290&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/mod_dav_svn/version.c (original)
+++ subversion/branches/fsfs-format7/subversion/mod_dav_svn/version.c Wed Mar  6 11:10:01 2013
@@ -150,6 +150,7 @@ get_vsn_options(apr_pool_t *p, apr_text_
   apr_text_append(p, phdr, SVN_DAV_NS_DAV_SVN_PARTIAL_REPLAY);
   apr_text_append(p, phdr, SVN_DAV_NS_DAV_SVN_INHERITED_PROPS);
   apr_text_append(p, phdr, SVN_DAV_NS_DAV_SVN_INLINE_PROPS);
+  apr_text_append(p, phdr, SVN_DAV_NS_DAV_SVN_GET_FILE_REVS_REVERSE);
   /* Mergeinfo is a special case: here we merely say that the server
    * knows how to handle mergeinfo -- whether the repository does too
    * is a separate matter.
@@ -242,6 +243,24 @@ get_option(const dav_resource *resource,
         }
     }
 
+  if (resource->info->repos->repos)
+    {
+        svn_error_t *serr;
+        svn_boolean_t has;
+
+        serr = svn_repos_has_capability(resource->info->repos->repos, &has,
+                                        SVN_REPOS_CAPABILITY_MERGEINFO,
+                                        r->pool);
+        if (serr)
+        return dav_svn__convert_err
+                    (serr, HTTP_INTERNAL_SERVER_ERROR,
+                    "Error fetching repository capabilities",
+                    resource->pool);
+
+        apr_table_set(r->headers_out, SVN_DAV_REPOSITORY_MERGEINFO,
+                    has ? "yes" : "no");
+    }
+
   /* Welcome to the 2nd generation of the svn HTTP protocol, now
      DeltaV-free!  If we're configured to advise this support, do so.  */
   if (resource->info->repos->v2_protocol)