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 [9/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/bindin...

Modified: subversion/branches/fsfs-format7/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_wc/wc_db.c?rev=1453290&r1=1453289&r2=1453290&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_wc/wc_db.c Wed Mar  6 11:10:01 2013
@@ -421,16 +421,12 @@ lock_from_columns(svn_sqlite__stmt_t *st
 }
 
 
-/* Look up REPOS_ID in SDB and set *REPOS_ROOT_URL and/or *REPOS_UUID to
-   its root URL and UUID respectively.  If REPOS_ID is INVALID_REPOS_ID,
-   use NULL for both URL and UUID.  Either or both output parameters may be
-   NULL if not wanted.  */
-static svn_error_t *
-fetch_repos_info(const char **repos_root_url,
-                 const char **repos_uuid,
-                 svn_sqlite__db_t *sdb,
-                 apr_int64_t repos_id,
-                 apr_pool_t *result_pool)
+svn_error_t *
+svn_wc__db_fetch_repos_info(const char **repos_root_url,
+                            const char **repos_uuid,
+                            svn_sqlite__db_t *sdb,
+                            apr_int64_t repos_id,
+                            apr_pool_t *result_pool)
 {
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
@@ -464,7 +460,6 @@ fetch_repos_info(const char **repos_root
   return svn_error_trace(svn_sqlite__reset(stmt));
 }
 
-
 /* Set *REPOS_ID, *REVISION and *REPOS_RELPATH from the given columns of the
    SQLITE statement STMT, or to NULL/SVN_INVALID_REVNUM if the respective
    column value is null.  Any of the output parameters may be NULL if not
@@ -975,7 +970,7 @@ insert_working_node(void *baton,
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_INSERT_NODE));
   SVN_ERR(svn_sqlite__bindf(stmt, "isdsnnntstrisn"
                 "nnnn" /* properties translated_size last_mod_time dav_cache */
-                "snsd", /* symlink_target, file_external, moved_to, moved_here */
+                "sns", /* symlink_target, file_external, moved_to */
                 wcroot->wc_id, local_relpath,
                 piwb->op_depth,
                 parent_relpath,
@@ -989,8 +984,12 @@ insert_working_node(void *baton,
                 /* Note: incomplete nodes may have a NULL target.  */
                 (piwb->kind == svn_kind_symlink)
                             ? piwb->target : NULL,
-                moved_to_relpath,
-                piwb->moved_here));
+                moved_to_relpath));
+
+  if (piwb->moved_here)
+    {
+      SVN_ERR(svn_sqlite__bind_int(stmt, 8, TRUE));
+    }
 
   if (piwb->kind == svn_kind_file)
     {
@@ -2055,6 +2054,33 @@ svn_wc__db_base_add_not_present_node(svn
     kind, svn_wc__db_status_not_present, conflict, work_items, scratch_pool);
 }
 
+/* Recursively clear moved-here information at the copy-half of the move
+ * which moved the node at SRC_RELPATH away. This transforms the move into
+ * a simple copy. */
+static svn_error_t *
+clear_moved_here(const char *src_relpath,
+                 svn_wc__db_wcroot_t *wcroot,
+                 apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+  const char *dst_relpath;
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_MOVED_TO));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
+                            src_relpath, relpath_depth(src_relpath)));
+  SVN_ERR(svn_sqlite__step_row(stmt));
+  dst_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool);
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_CLEAR_MOVED_HERE_RECURSIVE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
+                            dst_relpath, relpath_depth(dst_relpath)));
+  SVN_ERR(svn_sqlite__step_done(stmt));
+
+  return SVN_NO_ERROR;
+}
+
 /* The body of svn_wc__db_base_remove().
  */
 static svn_error_t *
@@ -2199,6 +2225,44 @@ db_base_remove(svn_wc__db_wcroot_t *wcro
            ACTUAL_NODE records */
 
   /* Step 3: Delete WORKING nodes */
+  if (conflict)
+    {
+      apr_pool_t *iterpool;
+
+      /* 
+       * When deleting a conflicted node, moves of any moved-outside children
+       * of the node must be broken. Else, the destination will still be marked
+       * moved-here after the move source disappears from the working copy.
+       *
+       * ### FIXME: It would be nicer to have the conflict resolver
+       * break the move instead. It might also be a good idea to
+       * flag a tree conflict on each moved-away child. But doing so
+       * might introduce actual-only nodes without direct parents,
+       * and we're not yet sure if other existing code is prepared
+       * to handle such nodes. To be revisited post-1.8.
+       */
+      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,
+                                             relpath_depth(local_relpath)));
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+      iterpool = svn_pool_create(scratch_pool);
+      while (have_row)
+        {
+          const char *child_relpath;
+          svn_error_t *err;
+          
+          svn_pool_clear(iterpool);
+          child_relpath = svn_sqlite__column_text(stmt, 0, iterpool);
+          err = clear_moved_here(child_relpath, wcroot, iterpool);
+          if (err)
+            return svn_error_compose_create(err, svn_sqlite__reset(stmt));
+          SVN_ERR(svn_sqlite__step(&have_row, stmt));
+        }
+      svn_pool_destroy(iterpool);
+      SVN_ERR(svn_sqlite__reset(stmt));
+    }
   if (keep_working)
     {
       SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
@@ -2484,8 +2548,8 @@ svn_wc__db_base_get_info(svn_wc__db_stat
                                             wcroot, local_relpath,
                                             result_pool, scratch_pool));
   SVN_ERR_ASSERT(repos_id != INVALID_REPOS_ID);
-  SVN_ERR(fetch_repos_info(repos_root_url, repos_uuid,
-                           wcroot->sdb, repos_id, result_pool));
+  SVN_ERR(svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid,
+                                      wcroot->sdb, repos_id, result_pool));
 
   return SVN_NO_ERROR;
 }
@@ -2539,8 +2603,8 @@ svn_wc__db_base_get_children_info(apr_ha
 
       info->lock = lock_from_columns(stmt, 8, 9, 10, 11, result_pool);
 
-      err = fetch_repos_info(&info->repos_root_url, NULL, wcroot->sdb,
-                             repos_id, result_pool);
+      err = svn_wc__db_fetch_repos_info(&info->repos_root_url, NULL,
+                                        wcroot->sdb, repos_id, result_pool);
 
       if (err)
         return svn_error_trace(
@@ -3380,8 +3444,9 @@ svn_wc__db_external_read(svn_wc__db_stat
 
           err = svn_error_compose_create(
                         err,
-                        fetch_repos_info(repos_root_url, repos_uuid,
-                                         wcroot->sdb, repos_id, result_pool));
+                        svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid,
+                                                    wcroot->sdb, repos_id,
+                                                    result_pool));
         }
 
       if (recorded_repos_relpath)
@@ -3990,15 +4055,21 @@ get_info_for_copy(apr_int64_t *copyfrom_
   const char *repos_relpath;
   svn_revnum_t revision;
   svn_wc__db_status_t node_status;
+  apr_int64_t repos_id;
+  svn_boolean_t is_op_root;
 
-  SVN_ERR(read_info(&node_status, kind, &revision, &repos_relpath, copyfrom_id,
-                    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                    NULL, NULL, NULL, NULL, NULL, op_root, NULL, NULL,
+  SVN_ERR(read_info(&node_status, kind, &revision, &repos_relpath, &repos_id,
+                    NULL, NULL, NULL, NULL, NULL, NULL, copyfrom_relpath,
+                    copyfrom_id, copyfrom_rev, NULL, NULL, NULL, NULL,
+                    NULL, &is_op_root, NULL, NULL,
                     NULL /* have_base */,
                     NULL /* have_more_work */,
                     NULL /* have_work */,
                     wcroot, local_relpath, result_pool, scratch_pool));
 
+  if (op_root)
+    *op_root = is_op_root;
+
   if (node_status == svn_wc__db_status_excluded)
     {
       /* The parent cannot be excluded, so look at the parent and then
@@ -4017,23 +4088,11 @@ get_info_for_copy(apr_int64_t *copyfrom_
     }
   else if (node_status == svn_wc__db_status_added)
     {
-      const char *op_root_relpath;
-
-      SVN_ERR(scan_addition(&node_status, &op_root_relpath,
-                            NULL, NULL, /* repos_* */
-                            copyfrom_relpath, copyfrom_id, copyfrom_rev,
+      SVN_ERR(scan_addition(&node_status, NULL, NULL, NULL, NULL, NULL, NULL,
                             NULL, NULL, NULL, wcroot, local_relpath,
                             scratch_pool, scratch_pool));
-      if (*copyfrom_relpath)
-        {
-          *copyfrom_relpath
-            = svn_relpath_join(*copyfrom_relpath,
-                               svn_relpath_skip_ancestor(op_root_relpath,
-                                                         local_relpath),
-                               result_pool);
-        }
     }
-  else if (node_status == svn_wc__db_status_deleted)
+  else if (node_status == svn_wc__db_status_deleted && is_op_root)
     {
       const char *base_del_relpath, *work_del_relpath;
 
@@ -4074,10 +4133,16 @@ get_info_for_copy(apr_int64_t *copyfrom_
       else
         SVN_ERR_MALFUNCTION();
     }
+  else if (node_status == svn_wc__db_status_deleted)
+    {
+      /* Keep original_* from read_info() to allow seeing the difference
+         between base-deleted and not present */
+    }
   else
     {
       *copyfrom_relpath = repos_relpath;
       *copyfrom_rev = revision;
+      *copyfrom_id = repos_id;
     }
 
   if (status)
@@ -4290,7 +4355,24 @@ db_op_copy(svn_wc__db_wcroot_t *src_wcro
               return SVN_NO_ERROR;
             }
         }
-      /* else: fall through */
+      else
+        {
+          /* This node is either a not-present node (which should be copied), or
+             a base-delete of some lower layer (which shouldn't).
+             Subversion <= 1.7 always added a not-present node here, which is
+             safe (as it postpones the hard work until commit time and then we
+             ask the repository), but it breaks some move scenarios.
+             */
+
+           if (! copyfrom_relpath)
+             {
+               SVN_ERR(add_work_items(dst_wcroot->sdb, work_items,
+                                     scratch_pool));
+               return SVN_NO_ERROR;
+             }
+
+           /* Fall through. Install not present node */
+        }
     case svn_wc__db_status_not_present:
     case svn_wc__db_status_excluded:
       /* These presence values should not create a new op depth */
@@ -4553,6 +4635,224 @@ svn_wc__db_op_copy(svn_wc__db_t *db,
   return SVN_NO_ERROR;
 }
 
+/* The txn body of svn_wc__db_op_handle_move_back */
+static svn_error_t *
+handle_move_back(svn_boolean_t *moved_back,
+                 svn_wc__db_wcroot_t *wcroot,
+                 const char *local_relpath,
+                 const char *moved_from_relpath,
+                 const svn_skel_t *work_items,
+                 apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+  svn_wc__db_status_t status;
+  svn_boolean_t op_root;
+  svn_boolean_t have_more_work;
+  int from_op_depth = 0;
+  svn_boolean_t have_row;
+  svn_boolean_t different = FALSE;
+
+  SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
+
+  SVN_ERR(svn_wc__db_read_info_internal(&status, NULL, NULL, NULL, NULL, NULL,
+                                        NULL, NULL, NULL, NULL, NULL, NULL,
+                                        NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                                        &op_root, NULL, NULL, NULL,
+                                        &have_more_work, NULL,
+                                        wcroot, local_relpath,
+                                        scratch_pool, scratch_pool));
+
+  if (status != svn_wc__db_status_added || !op_root)
+    return SVN_NO_ERROR;
+
+  /* We have two cases here: BASE-move-back and WORKING-move-back */
+  if (have_more_work)
+    SVN_ERR(op_depth_of(&from_op_depth, wcroot,
+                        svn_relpath_dirname(local_relpath, scratch_pool)));
+  else
+    from_op_depth = 0;
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_SELECT_MOVED_BACK));
+
+  SVN_ERR(svn_sqlite__bindf(stmt, "isdd", wcroot->wc_id,
+                                          local_relpath,
+                                          from_op_depth,
+                                          relpath_depth(local_relpath)));
+
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+  SVN_ERR_ASSERT(have_row); /* We checked that the node is an op-root */
+
+  {
+    svn_boolean_t moved_here = svn_sqlite__column_boolean(stmt, 9);
+    const char *moved_to = svn_sqlite__column_text(stmt, 10, NULL);
+
+    if (!moved_here
+        || !moved_to
+        || strcmp(moved_to, moved_from_relpath))
+      {
+        different = TRUE;
+        have_row = FALSE;
+      }
+  }
+
+  while (have_row)
+    {
+      svn_wc__db_status_t upper_status;
+      svn_wc__db_status_t lower_status;
+
+      upper_status = svn_sqlite__column_token(stmt, 1, presence_map);
+
+      if (svn_sqlite__column_is_null(stmt, 5))
+        {
+          /* No lower layer replaced. */
+          if (upper_status != svn_wc__db_status_not_present)
+            {
+              different = TRUE;
+              break;
+            }
+          continue;
+        }
+
+      lower_status = svn_sqlite__column_token(stmt, 5, presence_map);
+
+      if (upper_status != lower_status)
+        {
+          different = TRUE;
+          break;
+        }
+
+      if (upper_status == svn_wc__db_status_not_present
+          || upper_status == svn_wc__db_status_excluded)
+        {
+          SVN_ERR(svn_sqlite__step(&have_row, stmt));
+          continue; /* Nothing to check */
+        }
+      else if (upper_status != svn_wc__db_status_normal)
+        {
+          /* Not a normal move. Mixed revision move? */
+          different = TRUE;
+          break;
+        }
+
+      {
+        const char *upper_repos_relpath;
+        const char *lower_repos_relpath;
+
+        upper_repos_relpath = svn_sqlite__column_text(stmt, 3, NULL);
+        lower_repos_relpath = svn_sqlite__column_text(stmt, 7, NULL);
+
+        if (! upper_repos_relpath
+            || strcmp(upper_repos_relpath, lower_repos_relpath))
+          {
+            different = TRUE;
+            break;
+          }
+      }
+
+      {
+        svn_revnum_t upper_rev;
+        svn_revnum_t lower_rev;
+
+        upper_rev = svn_sqlite__column_revnum(stmt, 4);
+        lower_rev = svn_sqlite__column_revnum(stmt, 8);
+
+        if (upper_rev != lower_rev)
+          {
+            different = TRUE;
+            break;
+          }
+      }
+
+      {
+        apr_int64_t upper_repos_id;
+        apr_int64_t lower_repos_id;
+
+        upper_repos_id = svn_sqlite__column_int64(stmt, 2);
+        lower_repos_id = svn_sqlite__column_int64(stmt, 6);
+
+        if (upper_repos_id != lower_repos_id)
+          {
+            different = TRUE;
+            break;
+          }
+      }
+
+      /* Check moved_here? */
+
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+    }
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  if (! different)
+    {
+      /* Ok, we can now safely remove this complete move, because we
+         determined that it 100% matches the layer below it. */
+
+      /* ### We could copy the recorded timestamps from the higher to the
+             lower layer in an attempt to improve status performance, but
+             generally these values should be the same anyway as it was
+             a no-op move. */
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                        STMT_DELETE_MOVED_BACK));
+
+      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
+                                             local_relpath,
+                                             relpath_depth(local_relpath)));
+
+      SVN_ERR(svn_sqlite__step_done(stmt));
+
+      if (moved_back)
+        *moved_back = TRUE;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__db_op_handle_move_back(svn_boolean_t *moved_back,
+                               svn_wc__db_t *db,
+                               const char *local_abspath,
+                               const char *moved_from_abspath,
+                               const svn_skel_t *work_items,
+                               apr_pool_t *scratch_pool)
+{
+  svn_wc__db_wcroot_t *wcroot;
+  const char *local_relpath;
+  const char *moved_from_relpath;
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
+                                                local_abspath,
+                                                scratch_pool, scratch_pool));
+  VERIFY_USABLE_WCROOT(wcroot);
+
+  if (moved_back)
+    *moved_back = FALSE;
+
+  moved_from_relpath = svn_dirent_skip_ancestor(wcroot->abspath,
+                                                moved_from_abspath);
+
+  if (! local_relpath[0]
+      || !moved_from_relpath)
+    {
+       /* WC-Roots can't be moved */
+      SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
+      return SVN_NO_ERROR;
+    }
+
+  SVN_WC__DB_WITH_TXN(handle_move_back(moved_back, wcroot, local_relpath,
+                                       moved_from_relpath, work_items,
+                                       scratch_pool),
+                      wcroot);
+
+  SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_infinity,
+                        scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
 
 /* The recursive implementation of svn_wc__db_op_copy_shadowed_layer.
  *
@@ -4619,9 +4919,9 @@ db_op_copy_shadowed_layer(svn_wc__db_wcr
           const char *repos_root_url;
           const char *repos_uuid;
 
-          SVN_ERR(fetch_repos_info(&repos_root_url, &repos_uuid,
-                                   src_wcroot->sdb, node_repos_id,
-                                   scratch_pool));
+          SVN_ERR(svn_wc__db_fetch_repos_info(&repos_root_url, &repos_uuid,
+                                              src_wcroot->sdb, node_repos_id,
+                                              scratch_pool));
 
           SVN_ERR(create_repos_id(&node_repos_id, repos_root_url, repos_uuid,
                                   dst_wcroot->sdb, scratch_pool));
@@ -4684,15 +4984,18 @@ db_op_copy_shadowed_layer(svn_wc__db_wcr
       SVN_ERR(svn_sqlite__get_statement(&stmt, src_wcroot->sdb,
                              STMT_INSERT_WORKING_NODE_COPY_FROM_DEPTH));
 
-      SVN_ERR(svn_sqlite__bindf(stmt, "issdstdd",
+      SVN_ERR(svn_sqlite__bindf(stmt, "issdstd",
                         src_wcroot->wc_id, src_relpath,
                         dst_relpath,
                         dst_op_depth,
                         svn_relpath_dirname(dst_relpath, iterpool),
                         presence_map, dst_presence,
-                        (dst_op_depth == move_op_depth), /* moved_here */
                         src_op_depth));
 
+      /* moved_here */
+      if (dst_op_depth == move_op_depth)
+        SVN_ERR(svn_sqlite__bind_int(stmt, 8, TRUE));
+
       SVN_ERR(svn_sqlite__step_done(stmt));
 
       {
@@ -5273,28 +5576,21 @@ svn_wc__db_op_add_symlink(svn_wc__db_t *
   return SVN_NO_ERROR;
 }
 
-/* Baton for passing args to db_record_fileinfo(). */
-struct record_baton_t {
-  svn_filesize_t recorded_size;
-  apr_time_t recorded_time;
-};
-
-
 /* Record RECORDED_SIZE and RECORDED_TIME into top layer in NODES */
 static svn_error_t *
-db_record_fileinfo(void *baton,
-                   svn_wc__db_wcroot_t *wcroot,
+db_record_fileinfo(svn_wc__db_wcroot_t *wcroot,
                    const char *local_relpath,
+                   apr_int64_t recorded_size,
+                   apr_int64_t recorded_time,
                    apr_pool_t *scratch_pool)
 {
-  struct record_baton_t *rb = baton;
   svn_sqlite__stmt_t *stmt;
   int affected_rows;
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_UPDATE_NODE_FILEINFO));
   SVN_ERR(svn_sqlite__bindf(stmt, "isii", wcroot->wc_id, local_relpath,
-                            rb->recorded_size, rb->recorded_time));
+                            recorded_size, recorded_time));
   SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
 
   SVN_ERR_ASSERT(affected_rows == 1);
@@ -5312,7 +5608,6 @@ svn_wc__db_global_record_fileinfo(svn_wc
 {
   svn_wc__db_wcroot_t *wcroot;
   const char *local_relpath;
-  struct record_baton_t rb;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
@@ -5320,10 +5615,8 @@ svn_wc__db_global_record_fileinfo(svn_wc
                               local_abspath, scratch_pool, scratch_pool));
   VERIFY_USABLE_WCROOT(wcroot);
 
-  rb.recorded_size = recorded_size;
-  rb.recorded_time = recorded_time;
-
-  SVN_ERR(db_record_fileinfo(&rb, wcroot, local_relpath, scratch_pool));
+  SVN_ERR(db_record_fileinfo(wcroot, local_relpath,
+                             recorded_size, recorded_time, scratch_pool));
 
   /* We *totally* monkeyed the entries. Toss 'em.  */
   SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_empty, scratch_pool));
@@ -5408,10 +5701,9 @@ set_props_txn(svn_wc__db_wcroot_t *wcroo
 
   if (clear_recorded_info)
     {
-      struct record_baton_t rb;
-      rb.recorded_size = SVN_INVALID_FILESIZE;
-      rb.recorded_time = 0;
-      SVN_ERR(db_record_fileinfo(&rb, wcroot, local_relpath, scratch_pool));
+      SVN_ERR(db_record_fileinfo(wcroot, local_relpath,
+                                 SVN_INVALID_FILESIZE, 0,
+                                 scratch_pool));
     }
 
   /* And finally.  */
@@ -6115,6 +6407,7 @@ op_revert_txn(void *baton,
                 SVN_ERR(svn_wc__db_resolve_delete_raise_moved_away(
                           db, svn_dirent_join(wcroot->abspath, local_relpath,
                                               scratch_pool),
+                          NULL, NULL /* ### How do we notify this? */,
                           scratch_pool));
             }
         }
@@ -7087,6 +7380,7 @@ delete_update_movedto(svn_wc__db_wcroot_
                       apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
+  int affected;
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_UPDATE_MOVED_TO_RELPATH));
@@ -7096,14 +7390,14 @@ delete_update_movedto(svn_wc__db_wcroot_
                             child_moved_from_relpath,
                             op_depth,
                             new_moved_to_relpath));
-  SVN_ERR(svn_sqlite__step_done(stmt));
+  SVN_ERR(svn_sqlite__update(&affected, stmt));
+  assert(affected == 1);
 
   return SVN_NO_ERROR;
 }
 
 
 struct op_delete_baton_t {
-  int delete_depth;  /* op-depth for root of delete */
   const char *moved_to_relpath; /* NULL if delete is not part of a move */
   svn_skel_t *conflict;
   svn_skel_t *work_items;
@@ -7157,6 +7451,7 @@ delete_node(void *baton,
   svn_boolean_t refetch_depth = FALSE;
   svn_kind_t kind;
   apr_array_header_t *moved_nodes = NULL;
+  int delete_depth = relpath_depth(local_relpath);
 
   SVN_ERR(read_info(&status,
                     &kind, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -7211,124 +7506,137 @@ delete_node(void *baton,
 
   if (b->moved_to_relpath)
     {
-      const char *moved_from_op_root_relpath;
-      struct moved_node_t *moved_node
-        = apr_palloc(scratch_pool, sizeof(struct moved_node_t));
+      const char *moved_from_relpath = NULL;
+      struct moved_node_t *moved_node;
+      int move_op_depth;
+
+      moved_nodes = apr_array_make(scratch_pool, 1,
+                                   sizeof(struct moved_node_t *));
 
       /* The node is being moved-away.
        * Figure out if the node was moved-here before, or whether this
        * is the first time the node is moved. */
       if (status == svn_wc__db_status_added)
         SVN_ERR(scan_addition(&status, NULL, NULL, NULL, NULL, NULL, NULL,
-                              &moved_node->local_relpath,
-                              &moved_from_op_root_relpath,
-                              &moved_node->op_depth,
+                              &moved_from_relpath,
+                              NULL,
+                              &move_op_depth,
                               wcroot, local_relpath,
                               scratch_pool, scratch_pool));
 
-      if (status != svn_wc__db_status_moved_here ||
-          strcmp(moved_from_op_root_relpath, moved_node->local_relpath) != 0)
+      if (op_root && moved_from_relpath)
+        {
+          /* Existing move-root is moved to another location */
+          moved_node = apr_palloc(scratch_pool, sizeof(struct moved_node_t));
+          moved_node->local_relpath = moved_from_relpath;
+          moved_node->op_depth = move_op_depth;
+          moved_node->moved_to_relpath = b->moved_to_relpath;
+
+          APR_ARRAY_PUSH(moved_nodes, const struct moved_node_t *) = moved_node;
+        }
+      else if (!op_root && (status == svn_wc__db_status_normal
+                            || status == svn_wc__db_status_copied
+                            || status == svn_wc__db_status_moved_here))
         {
           /* The node is becoming a move-root for the first time,
            * possibly because of a nested move operation. */
+          moved_node = apr_palloc(scratch_pool, sizeof(struct moved_node_t));
           moved_node->local_relpath = local_relpath;
-          moved_node->op_depth = b->delete_depth;
-        }
-      moved_node->moved_to_relpath = b->moved_to_relpath;
-
-      /* ### Use array of struct rather than pointers? */
-      moved_nodes = apr_array_make(scratch_pool, 1,
-                                   sizeof(struct moved_node_t *));
-      APR_ARRAY_PUSH(moved_nodes, const struct moved_node_t *) = moved_node;
-
-      /* If a subtree is being moved-away, we need to update moved-to
-       * information for all children that were moved into, within or
-       * from this subtree. */
-      if (kind == svn_kind_dir)
-        {
-          SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                            STMT_SELECT_MOVED_PAIR));
-          SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
-          SVN_ERR(svn_sqlite__step(&have_row, stmt));
-
-          while (have_row)
-            {
-              /* Source of move */
-              const char *move_relpath
-                = svn_sqlite__column_text(stmt, 0, NULL);
-              const char *move_subtree_relpath
-                = svn_relpath_skip_ancestor(local_relpath, move_relpath);
-              /* Destination of move */
-              const char *child_moved_to
-                = svn_sqlite__column_text(stmt, 1, NULL);
-              const char *child_moved_to_subtree_relpath
-                = svn_relpath_skip_ancestor(local_relpath, child_moved_to);
-              int child_op_depth = svn_sqlite__column_int(stmt, 2);
-
-              moved_node = apr_palloc(scratch_pool,
-                                      sizeof(struct moved_node_t));
-              if (move_subtree_relpath)
-                moved_node->local_relpath
-                  = svn_relpath_join(b->moved_to_relpath,
-                                     move_subtree_relpath, scratch_pool);
-              else
-                moved_node->local_relpath
-                  = apr_pstrdup(scratch_pool, move_relpath);
-
-              if (child_moved_to_subtree_relpath)
-                moved_node->moved_to_relpath
-                  = svn_relpath_join(b->moved_to_relpath,
-                                     child_moved_to_subtree_relpath,
-                                     scratch_pool);
-              else
-                moved_node->moved_to_relpath
-                  = apr_pstrdup(scratch_pool, child_moved_to);
-
-              if (child_op_depth > b->delete_depth
-                  && svn_relpath_skip_ancestor(local_relpath,
-                                               moved_node->local_relpath))
-                moved_node->op_depth = b->delete_depth;
-              else
-                moved_node->op_depth = relpath_depth(moved_node->local_relpath);
-
-              APR_ARRAY_PUSH(moved_nodes, const struct moved_node_t *)
-                = moved_node;
+          moved_node->op_depth = delete_depth;
+          moved_node->moved_to_relpath = b->moved_to_relpath;
 
-              SVN_ERR(svn_sqlite__step(&have_row, stmt));
-            }
-          SVN_ERR(svn_sqlite__reset(stmt));
+          APR_ARRAY_PUSH(moved_nodes, const struct moved_node_t *) = moved_node;
         }
+      /* Else: We can't track history of local additions and/or of things we are
+               about to delete. */
+
+      /* And update all moved_to values still pointing to this location */
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                        STMT_UPDATE_MOVED_TO_DESCENDANTS));
+      SVN_ERR(svn_sqlite__bindf(stmt, "iss", wcroot->wc_id,
+                                             local_relpath,
+                                             b->moved_to_relpath));
+      SVN_ERR(svn_sqlite__update(NULL, stmt));
+    }
+  else
+    {
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                        STMT_CLEAR_MOVED_TO_DESCENDANTS));
+      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
+                                            local_relpath));
+      SVN_ERR(svn_sqlite__update(NULL, stmt));
     }
 
   /* Find children that were moved out of the subtree rooted at this node.
    * We'll need to update their op-depth columns because their deletion
    * is now implied by the deletion of their parent (i.e. this node). */
-  if (kind == svn_kind_dir && !b->moved_to_relpath)
     {
       apr_pool_t *iterpool;
 
       SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                        STMT_SELECT_MOVED_PAIR2));
+                                        STMT_SELECT_MOVED_FOR_DELETE));
       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)
         {
-          struct moved_node_t *moved_node
-            = apr_palloc(scratch_pool, sizeof(struct moved_node_t));
+          struct moved_node_t *mn;
+          const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
+          const char *mv_to_relpath = svn_sqlite__column_text(stmt, 1, NULL);
+          int child_op_depth = svn_sqlite__column_int(stmt, 2);
+          svn_boolean_t fixup = FALSE;
 
-          moved_node->local_relpath
-            = svn_sqlite__column_text(stmt, 0, scratch_pool);
-          moved_node->moved_to_relpath
-            = svn_sqlite__column_text(stmt, 1, scratch_pool);
-          moved_node->op_depth = b->delete_depth;
-
-          if (!moved_nodes)
-            moved_nodes = apr_array_make(scratch_pool, 1,
-                                         sizeof(struct moved_node_t *));
-          APR_ARRAY_PUSH(moved_nodes, const struct moved_node_t *) = moved_node;
+          if (!b->moved_to_relpath
+              && ! svn_relpath_skip_ancestor(local_relpath, mv_to_relpath))
+            {
+              /* Update the op-depth of an moved node below this tree */
+              fixup = TRUE;
+              child_op_depth = delete_depth;
+            }
+          else if (b->moved_to_relpath
+                   && delete_depth == child_op_depth)
+            {
+              /* Update the op-depth of a tree shadowed by this tree */
+              fixup = TRUE;
+              child_op_depth = delete_depth;
+            }
+          else if (b->moved_to_relpath
+                   && child_op_depth >= delete_depth
+                   && !svn_relpath_skip_ancestor(local_relpath, mv_to_relpath))
+            {
+              /* Update the move destination of something that is now moved
+                 away further */
+
+              child_relpath = svn_relpath_skip_ancestor(local_relpath, child_relpath);
+
+              if (child_relpath)
+                {
+                  child_relpath = svn_relpath_join(b->moved_to_relpath, child_relpath, scratch_pool);
+
+                  if (child_op_depth > delete_depth
+                      && svn_relpath_skip_ancestor(local_relpath, child_relpath))
+                    child_op_depth = delete_depth;
+                  else
+                    child_op_depth = relpath_depth(child_relpath);
+
+                  fixup = TRUE;
+                }
+            }
+
+          if (fixup)
+            {
+              mn = apr_pcalloc(scratch_pool, sizeof(struct moved_node_t));
+
+              mn->local_relpath = apr_pstrdup(scratch_pool, child_relpath);
+              mn->moved_to_relpath = apr_pstrdup(scratch_pool, mv_to_relpath);
+              mn->op_depth = child_op_depth;
+
+              if (!moved_nodes)
+                moved_nodes = apr_array_make(scratch_pool, 1,
+                                             sizeof(struct moved_node_t *));
+              APR_ARRAY_PUSH(moved_nodes, struct moved_node_t *) = mn;
+            }
 
           SVN_ERR(svn_sqlite__step(&have_row, stmt));
         }
@@ -7355,35 +7663,6 @@ delete_node(void *baton,
         }
 
       select_depth = relpath_depth(local_relpath);
-
-      /* When deleting a moved-here op-root, clear moved-to data at the
-       * pre-move location, transforming the move into a normal delete.
-       * This way, deleting the copied half of a move has the same effect
-       * as reverting it. */
-      if (status == svn_wc__db_status_added ||
-          status == svn_wc__db_status_moved_here)
-        {
-          const char *moved_from_relpath;
-          const char *moved_from_op_root_relpath;
-
-          SVN_ERR(scan_addition(&status, NULL, NULL, NULL, NULL, NULL, NULL,
-                                &moved_from_relpath,
-                                &moved_from_op_root_relpath, NULL,
-                                wcroot, local_relpath,
-                                scratch_pool, scratch_pool));
-          if (status == svn_wc__db_status_moved_here &&
-              moved_from_relpath && moved_from_op_root_relpath &&
-              strcmp(moved_from_relpath, moved_from_op_root_relpath) == 0)
-            {
-              SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                                STMT_CLEAR_MOVED_TO_RELPATH));
-              SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
-                                        moved_from_op_root_relpath,
-                                        relpath_depth(
-                                          moved_from_op_root_relpath)));
-              SVN_ERR(svn_sqlite__step_done(stmt));
-            }
-        }
     }
   else
     {
@@ -7407,7 +7686,7 @@ delete_node(void *baton,
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_DELETE_NODES_ABOVE_DEPTH_RECURSIVE));
   SVN_ERR(svn_sqlite__bindf(stmt, "isd",
-                            wcroot->wc_id, local_relpath, b->delete_depth));
+                            wcroot->wc_id, local_relpath, delete_depth));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
   if (refetch_depth)
@@ -7442,7 +7721,7 @@ delete_node(void *baton,
                                  STMT_INSERT_DELETE_FROM_NODE_RECURSIVE));
       SVN_ERR(svn_sqlite__bindf(stmt, "isdd",
                                 wcroot->wc_id, local_relpath,
-                                select_depth, b->delete_depth));
+                                select_depth, delete_depth));
       SVN_ERR(svn_sqlite__step_done(stmt));
     }
 
@@ -7509,24 +7788,25 @@ op_delete_many_txn(void *baton,
                    apr_pool_t *scratch_pool)
 {
   struct op_delete_many_baton_t *odmb = baton;
+  struct op_delete_baton_t odb;
   int i;
   apr_pool_t *iterpool;
 
+  odb.moved_to_relpath = NULL;
+  odb.conflict = NULL;
+  odb.work_items = NULL;
+  odb.delete_dir_externals = odmb->delete_dir_externals;
+  odb.notify = TRUE;
+
   SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb, STMT_CREATE_DELETE_LIST));
   iterpool = svn_pool_create(scratch_pool);
   for (i = 0; i < odmb->rel_targets->nelts; i++)
     {
       const char *target_relpath = APR_ARRAY_IDX(odmb->rel_targets, i,
                                                  const char *);
-      struct op_delete_baton_t odb;
+
 
       svn_pool_clear(iterpool);
-      odb.delete_depth = relpath_depth(target_relpath);
-      odb.moved_to_relpath = NULL;
-      odb.conflict = NULL;
-      odb.work_items = NULL;
-      odb.delete_dir_externals = odmb->delete_dir_externals;
-      odb.notify = TRUE;
       SVN_ERR(delete_node(&odb, wcroot, target_relpath, iterpool));
     }
   svn_pool_destroy(iterpool);
@@ -7636,7 +7916,6 @@ svn_wc__db_op_delete(svn_wc__db_t *db,
   else
     moved_to_relpath = NULL;
 
-  odb.delete_depth = relpath_depth(local_relpath);
   odb.moved_to_relpath = moved_to_relpath;
   odb.conflict = conflict;
   odb.work_items = work_items;
@@ -8162,10 +8441,11 @@ svn_wc__db_read_info(svn_wc__db_status_t
                     op_root, have_props, props_mod,
                     have_base, have_more_work, have_work,
                     wcroot, local_relpath, result_pool, scratch_pool));
-  SVN_ERR(fetch_repos_info(repos_root_url, repos_uuid,
-                           wcroot->sdb, repos_id, result_pool));
-  SVN_ERR(fetch_repos_info(original_root_url, original_uuid,
-                           wcroot->sdb, original_repos_id, result_pool));
+  SVN_ERR(svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid,
+                                      wcroot->sdb, repos_id, result_pool));
+  SVN_ERR(svn_wc__db_fetch_repos_info(original_root_url, original_uuid,
+                                      wcroot->sdb, original_repos_id,
+                                      result_pool));
 
   return SVN_NO_ERROR;
 }
@@ -8270,8 +8550,10 @@ read_children_info(svn_wc__db_wcroot_t *
                    repos_id != last_repos_id))
                 {
                   last_repos_root_url = repos_root_url;
-                  err = fetch_repos_info(&repos_root_url, &repos_uuid,
-                                         wcroot->sdb, repos_id, result_pool);
+                  err = svn_wc__db_fetch_repos_info(&repos_root_url,
+                                                    &repos_uuid,
+                                                    wcroot->sdb, repos_id,
+                                                    result_pool);
                   if (err)
                     SVN_ERR(svn_error_compose_create(err,
                                                  svn_sqlite__reset(stmt)));
@@ -8870,8 +9152,8 @@ read_url_txn(const char **url,
         }
     }
 
-  SVN_ERR(fetch_repos_info(&repos_root_url, NULL, wcroot->sdb, repos_id,
-                           scratch_pool));
+  SVN_ERR(svn_wc__db_fetch_repos_info(&repos_root_url, NULL, wcroot->sdb,
+                                      repos_id, scratch_pool));
 
   SVN_ERR_ASSERT(repos_root_url != NULL && repos_relpath != NULL);
   *url = svn_path_url_add_component2(repos_root_url, repos_relpath,
@@ -9970,8 +10252,8 @@ svn_wc__db_global_relocate(svn_wc__db_t 
                                                   scratch_pool, scratch_pool));
     }
 
-  SVN_ERR(fetch_repos_info(NULL, &repos_uuid,
-                           wcroot->sdb, old_repos_id, scratch_pool));
+  SVN_ERR(svn_wc__db_fetch_repos_info(NULL, &repos_uuid, wcroot->sdb,
+                                      old_repos_id, scratch_pool));
   SVN_ERR_ASSERT(repos_uuid);
 
   SVN_WC__DB_WITH_TXN(
@@ -10759,6 +11041,8 @@ bump_revisions_post_update(svn_wc__db_wc
                            svn_revnum_t new_revision,
                            apr_hash_t *exclude_relpaths,
                            apr_hash_t *wcroot_iprops,
+                           svn_wc_notify_func2_t notify_func,
+                           void *notify_baton,
                            apr_pool_t *scratch_pool)
 {
   svn_wc__db_status_t status;
@@ -10803,9 +11087,13 @@ bump_revisions_post_update(svn_wc__db_wc
                              TRUE /* is_root */, FALSE, db,
                              scratch_pool));
 
-  SVN_ERR(svn_wc__db_bump_moved_away(wcroot, local_relpath, depth,
+  SVN_ERR(svn_wc__db_bump_moved_away(wcroot, local_relpath, depth, db,
                                      scratch_pool));
 
+  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;
 }
 
@@ -10819,6 +11107,8 @@ svn_wc__db_op_bump_revisions_post_update
                                          svn_revnum_t new_revision,
                                          apr_hash_t *exclude_relpaths,
                                          apr_hash_t *wcroot_iprops,
+                                         svn_wc_notify_func2_t notify_func,
+                                         void *notify_baton,
                                          apr_pool_t *scratch_pool)
 {
   const char *local_relpath;
@@ -10839,7 +11129,8 @@ svn_wc__db_op_bump_revisions_post_update
     bump_revisions_post_update(wcroot, local_relpath, db,
                                depth, new_repos_relpath, new_repos_root_url,
                                new_repos_uuid, new_revision,
-                               exclude_relpaths, wcroot_iprops, scratch_pool),
+                               exclude_relpaths, wcroot_iprops,
+                               notify_func, notify_baton, scratch_pool),
     wcroot);
 
   return SVN_NO_ERROR;
@@ -10988,8 +11279,8 @@ svn_wc__db_scan_base_repos(const char **
                                             NULL, NULL, NULL, NULL, NULL,
                                             wcroot, local_relpath,
                                             result_pool, scratch_pool));
-  SVN_ERR(fetch_repos_info(repos_root_url, repos_uuid, wcroot->sdb,
-                           repos_id, result_pool));
+  SVN_ERR(svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid, wcroot->sdb,
+                                      repos_id, result_pool));
 
   return SVN_NO_ERROR;
 }
@@ -10998,8 +11289,6 @@ svn_wc__db_scan_base_repos(const char **
 /* A helper for scan_addition().
  * Compute moved-from information for the node at LOCAL_RELPATH which
  * has been determined as having been moved-here.
- * If STATUS is not NULL, return an appropriate status in *STATUS (usually
- * "moved-here").
  * If MOVED_FROM_RELPATH is not NULL, set *MOVED_FROM_RELPATH to the
  * path of the move-source node in *MOVED_FROM_RELPATH.
  * If DELETE_OP_ROOT_RELPATH is not NULL, set *DELETE_OP_ROOT_RELPATH
@@ -11009,8 +11298,7 @@ svn_wc__db_scan_base_repos(const char **
  * COPY_OPT_ROOT_RELPATH is the relpath of the op-root of the copied-half
  * of the move. */
 static svn_error_t *
-get_moved_from_info(svn_wc__db_status_t *status,
-                    const char **moved_from_relpath,
+get_moved_from_info(const char **moved_from_relpath,
                     const char **moved_from_op_root_relpath,
                     const char *moved_to_op_root_relpath,
                     int *op_depth,
@@ -11034,8 +11322,6 @@ get_moved_from_info(svn_wc__db_status_t 
       /* The move was only recorded at the copy-half, possibly because
        * the move operation was interrupted mid-way between the copy
        * and the delete. Treat this node as a normal copy. */
-      if (status)
-        *status = svn_wc__db_status_copied;
       if (moved_from_relpath)
         *moved_from_relpath = NULL;
       if (moved_from_op_root_relpath)
@@ -11045,10 +11331,6 @@ get_moved_from_info(svn_wc__db_status_t 
       return SVN_NO_ERROR;
     }
 
-  /* It's a properly recorded move. */
-  if (status)
-    *status = svn_wc__db_status_moved_here;
-
   if (op_depth)
     *op_depth = svn_sqlite__column_int(stmt, 1);
 
@@ -11261,23 +11543,31 @@ scan_addition_txn(svn_wc__db_status_t *s
           /* If column 10 (original_repos_id) is NULL,
              this is a plain add, not a copy or a move */
           {
+            svn_boolean_t moved_here;
             if (original_repos_id)
               *original_repos_id = svn_sqlite__column_int64(stmt, 10);
 
-            if (status ||
-                moved_from_relpath || moved_from_op_root_relpath)
+            moved_here = svn_sqlite__column_boolean(stmt, 13 /* moved_here */);
+            if (status)
+              *status = moved_here ? svn_wc__db_status_moved_here
+                                   : svn_wc__db_status_copied;
+
+            if (moved_here
+                && (moved_from_relpath || moved_from_op_root_relpath))
               {
-                if (svn_sqlite__column_boolean(stmt, 13 /* moved_here */))
-                  SVN_ERR(get_moved_from_info(status,
-                                              moved_from_relpath,
-                                              moved_from_op_root_relpath,
-                                              op_root_relpath,
-                                              moved_from_op_depth,
-                                              wcroot, local_relpath,
-                                              result_pool,
-                                              scratch_pool));
-                else if (status)
-                  *status = svn_wc__db_status_copied;
+                svn_error_t *err;
+
+                err = get_moved_from_info(moved_from_relpath,
+                                          moved_from_op_root_relpath,
+                                          op_root_relpath,
+                                          moved_from_op_depth,
+                                          wcroot, local_relpath,
+                                          result_pool,
+                                          scratch_pool);
+
+                if (err)
+                  return svn_error_compose_create(
+                                err, svn_sqlite__reset(stmt));
               }
           }
       }
@@ -11287,6 +11577,10 @@ scan_addition_txn(svn_wc__db_status_t *s
        because base_get_info() doesn't accommodate the scenario that
        we're looking at here; we found the true op_root, which may be inside
        further changed trees. */
+    if (repos_relpath || repos_id)
+      {
+        const char *base_relpath;
+
     while (TRUE)
       {
 
@@ -11321,19 +11615,14 @@ scan_addition_txn(svn_wc__db_status_t *s
           }
       }
 
-    SVN_ERR(svn_sqlite__reset(stmt));
-
-    build_relpath = repos_prefix_path;
-  }
+      SVN_ERR(svn_sqlite__reset(stmt));
 
-  /* If we're here, then we have an added/copied/moved (start) node, and
-     CURRENT_ABSPATH now points to a BASE node. Figure out the repository
-     information for the current node, and use that to compute the start
-     node's repository information.  */
-  if (repos_relpath || repos_id)
-    {
-      const char *base_relpath;
+      build_relpath = repos_prefix_path;
 
+      /* If we're here, then we have an added/copied/moved (start) node, and
+         CURRENT_ABSPATH now points to a BASE node. Figure out the repository
+         information for the current node, and use that to compute the start
+         node's repository information.  */
       SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, NULL,
                                                 &base_relpath, repos_id,
                                                 NULL, NULL, NULL, NULL, NULL,
@@ -11341,11 +11630,13 @@ scan_addition_txn(svn_wc__db_status_t *s
                                                 wcroot, op_root_relpath,
                                                 scratch_pool, scratch_pool));
 
-      if (repos_relpath)
-        *repos_relpath = svn_relpath_join(base_relpath, build_relpath,
-                                               result_pool);
-    }
-
+        if (repos_relpath)
+          *repos_relpath = svn_relpath_join(base_relpath, build_relpath,
+                                            result_pool);
+      }
+    else
+      SVN_ERR(svn_sqlite__reset(stmt));
+  }
   /* Postconditions */
 #ifdef SVN_DEBUG
   if (status)
@@ -11425,8 +11716,6 @@ svn_wc__db_scan_addition(svn_wc__db_stat
                          const char **original_root_url,
                          const char **original_uuid,
                          svn_revnum_t *original_revision,
-                         const char **moved_from_abspath,
-                         const char **moved_from_op_root_abspath,
                          svn_wc__db_t *db,
                          const char *local_abspath,
                          apr_pool_t *result_pool,
@@ -11434,15 +11723,13 @@ svn_wc__db_scan_addition(svn_wc__db_stat
 {
   svn_wc__db_wcroot_t *wcroot;
   const char *local_relpath;
-  const char *op_root_relpath;
+  const char *op_root_relpath = NULL;
   apr_int64_t repos_id = INVALID_REPOS_ID;
   apr_int64_t original_repos_id = INVALID_REPOS_ID;
   apr_int64_t *repos_id_p
     = (repos_root_url || repos_uuid) ? &repos_id : NULL;
   apr_int64_t *original_repos_id_p
     = (original_root_url || original_uuid) ? &original_repos_id : NULL;
-  const char *moved_from_relpath;
-  const char *moved_from_op_root_relpath;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
@@ -11450,10 +11737,14 @@ svn_wc__db_scan_addition(svn_wc__db_stat
                               local_abspath, scratch_pool, scratch_pool));
   VERIFY_USABLE_WCROOT(wcroot);
 
-  SVN_ERR(scan_addition(status, &op_root_relpath, repos_relpath, repos_id_p,
+  SVN_ERR(scan_addition(status,
+                        op_root_abspath
+                                ? &op_root_relpath
+                                : NULL,
+                        repos_relpath, repos_id_p,
                         original_repos_relpath, original_repos_id_p,
-                        original_revision, &moved_from_relpath,
-                        &moved_from_op_root_relpath, NULL,
+                        original_revision,
+                        NULL, NULL, NULL,
                         wcroot, local_relpath, result_pool, scratch_pool));
 
   if (op_root_abspath)
@@ -11462,31 +11753,88 @@ svn_wc__db_scan_addition(svn_wc__db_stat
   /* REPOS_ID must be valid if requested; ORIGINAL_REPOS_ID need not be. */
   SVN_ERR_ASSERT(repos_id_p == NULL || repos_id != INVALID_REPOS_ID);
 
-  SVN_ERR(fetch_repos_info(repos_root_url, repos_uuid, wcroot->sdb,
-                           repos_id, result_pool));
-  SVN_ERR(fetch_repos_info(original_root_url, original_uuid,
-                           wcroot->sdb, original_repos_id,
-                           result_pool));
+  SVN_ERR(svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid, wcroot->sdb,
+                                      repos_id, result_pool));
+  SVN_ERR(svn_wc__db_fetch_repos_info(original_root_url, original_uuid,
+                                      wcroot->sdb, original_repos_id,
+                                      result_pool));
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__db_scan_moved(const char **moved_from_abspath,
+                      const char **op_root_abspath,
+                      const char **op_root_moved_from_abspath,
+                      const char **moved_from_delete_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;
+  svn_wc__db_status_t status;
+  const char *op_root_relpath = NULL;
+  const char *moved_from_relpath = NULL;
+  const char *moved_from_op_root_relpath = NULL;
+  int moved_from_op_depth = -1;
+
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
+                              local_abspath, scratch_pool, scratch_pool));
+  VERIFY_USABLE_WCROOT(wcroot);
+
+  SVN_ERR(scan_addition(&status,
+                        op_root_abspath
+                                ? &op_root_relpath
+                                : NULL,
+                        NULL, NULL,
+                        NULL, NULL, NULL,
+                        moved_from_abspath
+                            ? &moved_from_relpath
+                            : NULL,
+                        (op_root_moved_from_abspath
+                         || moved_from_delete_abspath)
+                            ? &moved_from_op_root_relpath
+                            : NULL,
+                        moved_from_delete_abspath
+                            ? &moved_from_op_depth
+                            : NULL,
+                        wcroot, local_relpath, scratch_pool, scratch_pool));
+
+  if (status != svn_wc__db_status_moved_here)
+    return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
+                             _("Path '%s' was not moved here"),
+                             path_for_error_message(wcroot, local_relpath,
+                                                    scratch_pool));
+
+  if (op_root_abspath)
+    *op_root_abspath = svn_dirent_join(wcroot->abspath, op_root_relpath,
+                                       result_pool);
 
   if (moved_from_abspath)
-    {
-      if (moved_from_relpath)
-        *moved_from_abspath = svn_dirent_join(wcroot->abspath,
-                                              moved_from_relpath,
-                                              result_pool);
-      else
-        *moved_from_abspath = NULL;
-    }
+    *moved_from_abspath = svn_dirent_join(wcroot->abspath, moved_from_relpath,
+                                          result_pool);
+
+  if (op_root_moved_from_abspath)
+    *op_root_moved_from_abspath = svn_dirent_join(wcroot->abspath,
+                                                  moved_from_op_root_relpath,
+                                                  result_pool);
 
-  if (moved_from_op_root_abspath)
+  /* The deleted node is either where we moved from, or one of its ancestors */
+  if (moved_from_delete_abspath)
     {
-      if (moved_from_op_root_relpath)
-        *moved_from_op_root_abspath =
-          svn_dirent_join(wcroot->abspath,
-                          moved_from_op_root_relpath,
-                          result_pool);
-      else
-        *moved_from_op_root_abspath = NULL;
+      const char *tmp = moved_from_op_root_relpath;
+
+      SVN_ERR_ASSERT(moved_from_op_depth >= 0);
+
+      while (relpath_depth(tmp) > moved_from_op_depth)
+        tmp = svn_relpath_dirname(tmp, scratch_pool);
+
+      *moved_from_delete_abspath = svn_dirent_join(wcroot->abspath, tmp,
+                                                   scratch_pool);
     }
 
   return SVN_NO_ERROR;
@@ -12226,6 +12574,70 @@ svn_wc__db_wq_fetch_next(apr_uint64_t *i
   return SVN_NO_ERROR;
 }
 
+/* Records timestamp and date for one or more files in wcroot */
+static svn_error_t *
+wq_record(svn_wc__db_wcroot_t *wcroot,
+          apr_hash_t *record_map,
+          apr_pool_t *scratch_pool)
+{
+  apr_hash_index_t *hi;
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+  for (hi = apr_hash_first(scratch_pool, record_map); hi;
+       hi = apr_hash_next(hi))
+    {
+      const char *local_abspath = svn__apr_hash_index_key(hi);
+      const svn_io_dirent2_t *dirent = svn__apr_hash_index_val(hi);
+      const char *local_relpath = svn_dirent_skip_ancestor(wcroot->abspath,
+                                                           local_abspath);
+
+      svn_pool_clear(iterpool);
+
+      if (! local_relpath)
+        continue;
+
+      SVN_ERR(db_record_fileinfo(wcroot, local_relpath,
+                                 dirent->filesize, dirent->mtime,
+                                 iterpool));
+    }
+
+  svn_pool_destroy(iterpool);
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__db_wq_record_and_fetch_next(apr_uint64_t *id,
+                                    svn_skel_t **work_item,
+                                    svn_wc__db_t *db,
+                                    const char *wri_abspath,
+                                    apr_uint64_t completed_id,
+                                    apr_hash_t *record_map,
+                                    apr_pool_t *result_pool,
+                                    apr_pool_t *scratch_pool)
+{
+  svn_wc__db_wcroot_t *wcroot;
+  const char *local_relpath;
+
+  SVN_ERR_ASSERT(id != NULL);
+  SVN_ERR_ASSERT(work_item != NULL);
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
+
+  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
+                              wri_abspath, scratch_pool, scratch_pool));
+  VERIFY_USABLE_WCROOT(wcroot);
+
+  SVN_WC__DB_WITH_TXN(
+    svn_error_compose_create(
+            wq_fetch_next(id, work_item,
+                          wcroot, local_relpath, completed_id,
+                          result_pool, scratch_pool),
+            wq_record(wcroot, record_map, scratch_pool)),
+    wcroot);
+
+  return SVN_NO_ERROR;
+}
+
+
 
 /* ### temporary API. remove before release.  */
 svn_error_t *
@@ -12675,6 +13087,7 @@ svn_wc__db_read_kind(svn_kind_t *kind,
                      svn_wc__db_t *db,
                      const char *local_abspath,
                      svn_boolean_t allow_missing,
+                     svn_boolean_t show_deleted,
                      svn_boolean_t show_hidden,
                      apr_pool_t *scratch_pool)
 {
@@ -12713,22 +13126,39 @@ svn_wc__db_read_kind(svn_kind_t *kind,
         }
     }
 
-  if (!show_hidden)
+  if (!(show_deleted && show_hidden))
     {
       int op_depth = svn_sqlite__column_int(stmt_info, 0);
+      svn_boolean_t report_none = FALSE;
       svn_wc__db_status_t status = svn_sqlite__column_token(stmt_info, 3,
                                                             presence_map);
 
       if (op_depth > 0)
         SVN_ERR(convert_to_working_status(&status, status));
 
-      if (status == svn_wc__db_status_not_present
-          || status == svn_wc__db_status_excluded
-          || status == svn_wc__db_status_server_excluded)
+      switch (status)
+        {
+          case svn_wc__db_status_not_present:
+            if (! (show_hidden && show_deleted))
+              report_none = TRUE;
+            break;
+          case svn_wc__db_status_excluded:
+          case svn_wc__db_status_server_excluded:
+            if (! show_hidden)
+              report_none = TRUE;
+            break;
+          case svn_wc__db_status_deleted:
+            if (! show_deleted)
+              report_none = TRUE;
+            break;
+          default:
+            break;
+        }
+
+      if (report_none)
         {
           *kind = svn_kind_none;
-          SVN_ERR(svn_sqlite__reset(stmt_info));
-          return SVN_NO_ERROR;
+          return svn_error_trace(svn_sqlite__reset(stmt_info));
         }
     }
 
@@ -13933,8 +14363,8 @@ has_switched_subtrees(svn_boolean_t *is_
          does not match the given trailing URL then the whole working
          copy is switched. */
 
-      SVN_ERR(fetch_repos_info(&repos_root_url, NULL, wcroot->sdb, repos_id,
-                           scratch_pool));
+      SVN_ERR(svn_wc__db_fetch_repos_info(&repos_root_url, NULL, wcroot->sdb,
+                                          repos_id, scratch_pool));
       url = svn_path_url_add_component2(repos_root_url, repos_relpath,
                                         scratch_pool);
 
@@ -13947,36 +14377,9 @@ has_switched_subtrees(svn_boolean_t *is_
         }
     }
 
-  /* Select the right query based on whether the node is the wcroot, repos root
-     or neither. */
-  if (*local_relpath == '\0')
-    {
-      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                        (*repos_relpath == '\0')
-                            ? STMT_HAS_SWITCHED_WCROOT_REPOS_ROOT
-                            : STMT_HAS_SWITCHED_WCROOT));
-    }
-  else
-    {
-      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                        (*repos_relpath == '\0')
-                            ? STMT_HAS_SWITCHED_REPOS_ROOT
-                            : STMT_HAS_SWITCHED));
-    }
-
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
-
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_HAS_SWITCHED));
+  SVN_ERR(svn_sqlite__bindf(stmt, "iss", wcroot->wc_id, local_relpath, repos_relpath));
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
-  /* ### Please keep this code for a little while or until the code has enough
-         test coverage. These columns are only available in the 4 queries
-         after their selection is uncommented. */
-/*if (have_row)
-    SVN_DBG(("Expected %s for %s, but got %s. Origin=%s with %s\n",
-             svn_sqlite__column_text(stmt, 0, scratch_pool),
-             svn_sqlite__column_text(stmt, 1, scratch_pool),
-             svn_sqlite__column_text(stmt, 2, scratch_pool),
-             svn_sqlite__column_text(stmt, 3, scratch_pool),
-             svn_sqlite__column_text(stmt, 4, scratch_pool)));*/
   if (have_row)
     *is_switched = TRUE;
   SVN_ERR(svn_sqlite__reset(stmt));
@@ -14349,9 +14752,10 @@ svn_wc__db_base_get_lock_tokens_recursiv
 
       if (child_repos_id != last_repos_id)
         {
-          svn_error_t *err = fetch_repos_info(&last_repos_root_url, NULL,
-                                              wcroot->sdb, child_repos_id,
-                                              scratch_pool);
+          svn_error_t *err = svn_wc__db_fetch_repos_info(&last_repos_root_url,
+                                                         NULL, wcroot->sdb,
+                                                         child_repos_id,
+                                                         scratch_pool);
 
           if (err)
             {

Modified: subversion/branches/fsfs-format7/subversion/libsvn_wc/wc_db.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_wc/wc_db.h?rev=1453290&r1=1453289&r2=1453290&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_wc/wc_db.h (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_wc/wc_db.h Wed Mar  6 11:10:01 2013
@@ -1303,6 +1303,22 @@ svn_wc__db_op_copy(svn_wc__db_t *db,
                    const svn_skel_t *work_items,
                    apr_pool_t *scratch_pool);
 
+/* Checks if LOCAL_ABSPATH represents a move back to its original location,
+ * and if it is reverts the move while keeping local changes after it has been
+ * moved from MOVED_FROM_ABSPATH.
+ *
+ * If MOVED_BACK is not NULL, set *MOVED_BACK to TRUE when a move was reverted,
+ * otherwise to FALSE.
+ */
+svn_error_t *
+svn_wc__db_op_handle_move_back(svn_boolean_t *moved_back,
+                               svn_wc__db_t *db,
+                               const char *local_abspath,
+                               const char *moved_from_abspath,
+                               const svn_skel_t *work_items,
+                               apr_pool_t *scratch_pool);
+
+
 /* Copy the leaves of the op_depth layer directly shadowed by the operation
  * of SRC_ABSPATH (so SRC_ABSPATH must be an op_root) to dst_abspaths
  * parents layer.
@@ -2254,8 +2270,18 @@ svn_wc__db_read_conflict(svn_skel_t **co
    If the node is missing and ALLOW_MISSING is FALSE, then it will return
    SVN_ERR_WC_PATH_NOT_FOUND.
 
-   If SHOW_HIDDEN is FALSE and the status of LOCAL_ABSPATH is NOT_PRESENT or
-   EXCLUDED, set KIND to svn_kind_none.
+   The SHOW_HIDDEN and SHOW_DELETED flags report certain states as kind none.
+
+   When nodes have certain statee they are only reported when:
+      svn_wc__db_status_not_present         when show_hidden && show_deleted
+
+      svn_wc__db_status_excluded            when show_hidden
+      svn_wc__db_status_server_excluded     when show_hidden
+
+      svn_wc__db_status_deleted             when show_deleted
+
+   In other cases these nodes are reported with *KIND as svn_kind_none.
+   (See also svn_wc_read_kind2()'s documentation)
 
    Uses SCRATCH_POOL for temporary allocations.  */
 svn_error_t *
@@ -2263,6 +2289,7 @@ svn_wc__db_read_kind(svn_kind_t *kind,
                      svn_wc__db_t *db,
                      const char *local_abspath,
                      svn_boolean_t allow_missing,
+                     svn_boolean_t show_deleted,
                      svn_boolean_t show_hidden,
                      apr_pool_t *scratch_pool);
 
@@ -2499,6 +2526,8 @@ svn_wc__db_op_bump_revisions_post_update
                                          svn_revnum_t new_revision,
                                          apr_hash_t *exclude_relpaths,
                                          apr_hash_t *wcroot_iprops,
+                                         svn_wc_notify_func2_t notify_func,
+                                         void *notify_baton,
                                          apr_pool_t *scratch_pool);
 
 
@@ -2612,12 +2641,6 @@ svn_wc__db_scan_base_repos(const char **
        BASE node. And again, the REPOS_* values are implied by this node's
        position in the subtree under the ancestor unshadowed BASE node.
        ORIGINAL_* will indicate the source of the move.
-       Additionally, information about the local move source is provided.
-       If MOVED_FROM_ABSPATH is not NULL, set *MOVED_FROM_ABSPATH to the
-       absolute path of the move source node in the working copy.
-       If MOVED_FROM_OP_ROOT_ABSPATH is not NULL, set
-       *MOVED_FROM_OP_ROOT_ABSPATH to the absolute path of the op-root of the
-       delete-half of the move.
 
    All OUT parameters may be NULL to indicate a lack of interest in
    that piece of information.
@@ -2648,13 +2671,46 @@ svn_wc__db_scan_addition(svn_wc__db_stat
                          const char **original_root_url,
                          const char **original_uuid,
                          svn_revnum_t *original_revision,
-                         const char **moved_from_abspath,
-                         const char **moved_from_oproot_abspath,
                          svn_wc__db_t *db,
                          const char *local_abspath,
                          apr_pool_t *result_pool,
                          apr_pool_t *scratch_pool);
 
+/* Scan the working copy for move information of the node LOCAL_ABSPATH.
+ * If LOCAL_ABSPATH return a SVN_ERR_WC_PATH_UNEXPECTED_STATUS error.
+ *
+ * If not NULL *MOVED_FROM_ABSPATH will be set to the previous location
+ * of LOCAL_ABSPATH, before it or an ancestror was moved.
+ *
+ * If not NULL *OP_ROOT_ABSPATH will be set to the new location of the
+ * path that was actually moved
+ *
+ * If not NULL *OP_ROOT_MOVED_FROM_ABSPATH will be set to the old location
+ * of the path that was actually moved.
+ *
+ * If not NULL *MOVED_FROM_DELETE_ABSPATH will be set to the ancestor of the
+ * moved from location that deletes the original location
+ *
+ * Given a working copy
+ * A/B/C
+ * svn mv A/B D
+ * svn rm A
+ *
+ * You can call this function on D and D/C. When called on D/C all output
+ *              MOVED_FROM_ABSPATH will be A/B/C
+ *              OP_ROOT_ABSPATH will be D
+ *              OP_ROOT_MOVED_FROM_ABSPATH will be A/B
+ *              MOVED_FROM_DELETE_ABSPATH will be A
+ */
+svn_error_t *
+svn_wc__db_scan_moved(const char **moved_from_abspath,
+                      const char **op_root_abspath,
+                      const char **op_root_moved_from_abspath,
+                      const char **moved_from_delete_abspath,
+                      svn_wc__db_t *db,
+                      const char *local_abspath,
+                      apr_pool_t *result_pool,
+                      apr_pool_t *scratch_pool);
 
 /* Scan upwards for additional information about a deleted node.
 
@@ -2897,6 +2953,19 @@ svn_wc__db_wq_fetch_next(apr_uint64_t *i
                          apr_pool_t *result_pool,
                          apr_pool_t *scratch_pool);
 
+/* Special variant of svn_wc__db_wq_fetch_next(), which in the same transaction
+   also records timestamps and sizes for one or more nodes */
+svn_error_t *
+svn_wc__db_wq_record_and_fetch_next(apr_uint64_t *id,
+                                    svn_skel_t **work_item,
+                                    svn_wc__db_t *db,
+                                    const char *wri_abspath,
+                                    apr_uint64_t completed_id,
+                                    apr_hash_t *record_map,
+                                    apr_pool_t *result_pool,
+                                    apr_pool_t *scratch_pool);
+
+
 /* @} */
 
 
@@ -3257,18 +3326,14 @@ svn_wc__db_follow_moved_to(apr_array_hea
                            apr_pool_t *scratch_pool);
 
 /* Update a moved-away tree conflict victim at VICTIM_ABSPATH with changes
- * brought in by the update operation which flagged the tree conflict.
- * Set *WORK_ITEMS to a list of work items, allocated in RESULT_POOL, that
- * need to run as part of marking the conflict resolved. */
+ * brought in by the update operation which flagged the tree conflict. */
 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);
 
 /* LOCAL_ABSPATH is moved to MOVE_DST_ABSPATH.  MOVE_SRC_ROOT_ABSPATH
@@ -3300,6 +3365,8 @@ svn_wc__db_vacuum(svn_wc__db_t *db,
 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);
 
 /* Like svn_wc__db_resolve_delete_raise_moved_away this should be
@@ -3307,7 +3374,31 @@ svn_wc__db_resolve_delete_raise_moved_aw
 svn_error_t *
 svn_wc__db_resolve_break_moved_away(svn_wc__db_t *db,
                                     const char *local_abspath,
+                                    svn_wc_notify_func2_t notify_func,
+                                    void *notify_baton,
                                     apr_pool_t *scratch_pool);
+
+/* Break moves for all moved-away children of LOCAL_ABSPATH, within
+ * a single transaction.
+ *
+ * ### Like svn_wc__db_resolve_delete_raise_moved_away this should be
+ * combined. */
+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);
+
+/* Set *REQUIRED_ABSPATH to the path that should be locked to ensure
+ * that the lock covers all paths affected by resolving the conflicts
+ * in the tree LOCAL_ABSPATH. */
+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);
 /* @} */
 
 

Modified: subversion/branches/fsfs-format7/subversion/libsvn_wc/wc_db_pristine.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_wc/wc_db_pristine.c?rev=1453290&r1=1453289&r2=1453290&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_wc/wc_db_pristine.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_wc/wc_db_pristine.c Wed Mar  6 11:10:01 2013
@@ -122,7 +122,10 @@ svn_wc__db_pristine_get_path(const char 
                                     scratch_pool));
   if (! present)
     return svn_error_createf(SVN_ERR_WC_DB_ERROR, NULL,
-                             _("Pristine text not found"));
+                             _("The pristine text with checksum '%s' was "
+                               "not found"),
+                             svn_checksum_to_cstring_display(sha1_checksum,
+                                                             scratch_pool));
 
   SVN_ERR(get_pristine_fname(pristine_abspath, wcroot->abspath,
                              sha1_checksum,
@@ -881,46 +884,42 @@ svn_wc__db_pristine_check(svn_boolean_t 
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
 
-  SVN_ERR_ASSERT(present != NULL);
   SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
   SVN_ERR_ASSERT(sha1_checksum != NULL);
-  /* ### Transitional: accept MD-5 and look up the SHA-1.  Return an error
-   * if the pristine text is not in the store. */
+
   if (sha1_checksum->kind != svn_checksum_sha1)
-    SVN_ERR(svn_wc__db_pristine_get_sha1(&sha1_checksum, db, wri_abspath,
-                                         sha1_checksum,
-                                         scratch_pool, scratch_pool));
-  SVN_ERR_ASSERT(sha1_checksum->kind == svn_checksum_sha1);
+    {
+      *present = FALSE;
+      return SVN_NO_ERROR;
+    }
 
   SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
                               wri_abspath, scratch_pool, scratch_pool));
   VERIFY_USABLE_WCROOT(wcroot);
 
+  /* A filestat is much cheaper than a sqlite transaction especially on NFS,
+     so first check if there is a pristine file and then if we are allowed
+     to use it. */
+  {
+    const char *pristine_abspath;
+    svn_node_kind_t kind_on_disk;
+
+    SVN_ERR(get_pristine_fname(&pristine_abspath, wcroot->abspath,
+                               sha1_checksum, scratch_pool, scratch_pool));
+    SVN_ERR(svn_io_check_path(pristine_abspath, &kind_on_disk, scratch_pool));
+    if (kind_on_disk != svn_node_file)
+      {
+        *present = FALSE;
+        return SVN_NO_ERROR;
+      }
+  }
+
   /* Check that there is an entry in the PRISTINE table. */
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_PRISTINE));
   SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool));
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
   SVN_ERR(svn_sqlite__reset(stmt));
 
-#ifdef SVN_DEBUG
-  /* Check that the pristine text file exists iff the DB says it does. */
-  if (have_row)
-    {
-      const char *pristine_abspath;
-      svn_node_kind_t kind_on_disk;
-      SVN_ERR(get_pristine_fname(&pristine_abspath, wcroot->abspath,
-                                 sha1_checksum, scratch_pool, scratch_pool));
-      SVN_ERR(svn_io_check_path(pristine_abspath, &kind_on_disk, scratch_pool));
-
-      if (kind_on_disk != svn_node_file)
-        return svn_error_createf(SVN_ERR_WC_DB_ERROR, svn_sqlite__reset(stmt),
-                                 _("The pristine text with checksum '%s' was "
-                                   "found in the DB but not on disk"),
-                                 svn_checksum_to_cstring_display(sha1_checksum,
-                                                                 scratch_pool));
-    }
-#endif
-
   *present = have_row;
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/fsfs-format7/subversion/libsvn_wc/wc_db_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_wc/wc_db_private.h?rev=1453290&r1=1453289&r2=1453290&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_wc/wc_db_private.h (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_wc/wc_db_private.h Wed Mar  6 11:10:01 2013
@@ -299,6 +299,17 @@ svn_wc__db_depth_get_info(svn_wc__db_sta
                           apr_pool_t *result_pool,
                           apr_pool_t *scratch_pool);
 
+/* Look up REPOS_ID in SDB and set *REPOS_ROOT_URL and/or *REPOS_UUID to
+   its root URL and UUID respectively.  If REPOS_ID is INVALID_REPOS_ID,
+   use NULL for both URL and UUID.  Either or both output parameters may be
+   NULL if not wanted.  */
+svn_error_t *
+svn_wc__db_fetch_repos_info(const char **repos_root_url,
+                            const char **repos_uuid,
+                            svn_sqlite__db_t *sdb,
+                            apr_int64_t repos_id,
+                            apr_pool_t *result_pool);
+
 /* Like svn_wc__db_read_conflict(), but with WCROOT+LOCAL_RELPATH instead of
    DB+LOCAL_ABSPATH, and outputting relpaths instead of abspaths. */
 svn_error_t *
@@ -428,6 +439,7 @@ 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);
 
 svn_error_t *
@@ -435,4 +447,12 @@ svn_wc__db_resolve_break_moved_away_inte
                                              const char *local_relpath,
                                              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);
+
 #endif /* WC_DB_PRIVATE_H */