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/11/27 09:19:51 UTC

svn commit: r1545958 [8/15] - in /subversion/branches/log-addressing: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/server-side/ contrib/server-side/svncutter/ notes/ subversion/bindings/javahl/native/ subv...

Modified: subversion/branches/log-addressing/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_wc/wc_db.c?rev=1545958&r1=1545957&r2=1545958&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/log-addressing/subversion/libsvn_wc/wc_db.c Wed Nov 27 08:19:45 2013
@@ -627,6 +627,10 @@ svn_wc__db_extend_parent_delete(svn_wc__
    When removing a node if the parent has a higher working node then
    the parent node and this node are both deleted or replaced and any
    delete over this node must be removed.
+
+   This function (like most wcroot functions) assumes that its caller
+   only uses this function within an sqlite transaction if atomic
+   behavior is needed.
  */
 svn_error_t *
 svn_wc__db_retract_parent_delete(svn_wc__db_wcroot_t *wcroot,
@@ -635,14 +639,60 @@ svn_wc__db_retract_parent_delete(svn_wc_
                                  apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+  int working_depth;
+  svn_wc__db_status_t presence;
+  const char *moved_to;
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                    STMT_DELETE_LOWEST_WORKING_NODE));
+                                    STMT_SELECT_LOWEST_WORKING_NODE));
   SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
                             op_depth));
-  SVN_ERR(svn_sqlite__step_done(stmt));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
-  return SVN_NO_ERROR;
+  if (!have_row)
+    return svn_error_trace(svn_sqlite__reset(stmt));
+
+  working_depth = svn_sqlite__column_int(stmt, 0);
+  presence = svn_sqlite__column_token(stmt, 1, presence_map);
+  moved_to = svn_sqlite__column_text(stmt, 3, scratch_pool);
+
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  if (moved_to)
+    {
+      /* Turn the move into a copy to keep the NODES table valid */
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                        STMT_CLEAR_MOVED_HERE_RECURSIVE));
+      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
+                                moved_to, relpath_depth(moved_to)));
+      SVN_ERR(svn_sqlite__step_done(stmt));
+
+      /* This leaves just the moved_to information on the origin,
+         which we will remove in the next step */
+    }
+
+  if (presence == svn_wc__db_status_base_deleted)
+    {
+      /* Nothing left to shadow; remove the base-deleted node */
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_DELETE_NODE));
+    }
+  else if (moved_to)
+    {
+      /* Clear moved to information, as this node is no longer base-deleted */
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                        STMT_CLEAR_MOVED_TO_RELPATH));
+      }
+  else
+    {
+      /* Nothing to update */
+      return SVN_NO_ERROR;
+    }
+
+  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
+                            working_depth));
+
+  return svn_error_trace(svn_sqlite__update(NULL, stmt));
 }
 
 
@@ -1390,6 +1440,15 @@ does_node_exist(svn_boolean_t *exists,
   return svn_error_trace(svn_sqlite__reset(stmt));
 }
 
+svn_error_t *
+svn_wc__db_install_schema_statistics(svn_sqlite__db_t *sdb,
+                                     apr_pool_t *scratch_pool)
+{
+  SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_INSTALL_SCHEMA_STATISTICS));
+
+  return SVN_NO_ERROR;
+}
+
 /* Helper for create_db(). Initializes our wc.db schema.
  */
 static svn_error_t *
@@ -1417,6 +1476,8 @@ init_db(/* output values */
   SVN_ERR(create_repos_id(repos_id, repos_root_url, repos_uuid,
                           db, scratch_pool));
 
+  SVN_ERR(svn_wc__db_install_schema_statistics(db, scratch_pool));
+
   /* Insert the wcroot. */
   /* ### Right now, this just assumes wc metadata is being stored locally. */
   SVN_ERR(svn_sqlite__get_statement(&stmt, db, STMT_INSERT_WCROOT));
@@ -1434,7 +1495,7 @@ init_db(/* output values */
                                 *wc_id,              /* 1 */
                                 "",                  /* 2 */
                                 0,                   /* op_depth is 0 for base */
-                                NULL,                /* 4 */
+                                SVN_VA_NULL,         /* 4 */
                                 *repos_id,
                                 root_node_repos_relpath,
                                 root_node_revision,
@@ -2051,28 +2112,29 @@ svn_wc__db_base_add_not_present_node(svn
 }
 
 /* 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. */
+ * which moved a node to MOVED_TO_RELPATH. This transforms this side of the
+ * move into a simple copy.
+ */
 static svn_error_t *
-clear_moved_here(const char *src_relpath,
-                 svn_wc__db_wcroot_t *wcroot,
+clear_moved_here(svn_wc__db_wcroot_t *wcroot,
+                 const char *moved_to_relpath,
                  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));
+  int affected_rows;
 
   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));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, moved_to_relpath,
+                            relpath_depth(moved_to_relpath)));
+
+  SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
+
+  if (affected_rows == 0)
+     return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
+                              _("The node '%s' was not found."),
+                              path_for_error_message(wcroot, moved_to_relpath,
+                                                     scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -2263,12 +2325,12 @@ db_base_remove(svn_wc__db_wcroot_t *wcro
       iterpool = svn_pool_create(scratch_pool);
       while (have_row)
         {
-          const char *child_relpath;
+          const char *moved_to_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);
+          moved_to_relpath = svn_sqlite__column_text(stmt, 1, iterpool);
+          err = clear_moved_here(wcroot, moved_to_relpath, iterpool);
           if (err)
             return svn_error_compose_create(err, svn_sqlite__reset(stmt));
           SVN_ERR(svn_sqlite__step(&have_row, stmt));
@@ -2553,43 +2615,45 @@ svn_wc__db_base_get_info(svn_wc__db_stat
                               local_abspath, scratch_pool, scratch_pool));
   VERIFY_USABLE_WCROOT(wcroot);
 
-  SVN_ERR(svn_wc__db_base_get_info_internal(status, kind, revision,
+  SVN_WC__DB_WITH_TXN4(
+          svn_wc__db_base_get_info_internal(status, kind, revision,
                                             repos_relpath, &repos_id,
                                             changed_rev, changed_date,
                                             changed_author, depth,
                                             checksum, target, lock,
                                             had_props, props, update_root,
                                             wcroot, local_relpath,
-                                            result_pool, scratch_pool));
+                                            result_pool, scratch_pool),
+          svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid,
+                                      wcroot->sdb, repos_id, result_pool),
+          SVN_NO_ERROR,
+          SVN_NO_ERROR,
+          wcroot);
   SVN_ERR_ASSERT(repos_id != INVALID_REPOS_ID);
-  SVN_ERR(svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid,
-                                      wcroot->sdb, repos_id, result_pool));
 
   return SVN_NO_ERROR;
 }
 
-svn_error_t *
-svn_wc__db_base_get_children_info(apr_hash_t **nodes,
-                                  svn_wc__db_t *db,
-                                  const char *dir_abspath,
-                                  apr_pool_t *result_pool,
-                                  apr_pool_t *scratch_pool)
+/* The implementation of svn_wc__db_base_get_children_info */
+static svn_error_t *
+base_get_children_info(apr_hash_t **nodes,
+                       svn_wc__db_wcroot_t *wcroot,
+                       const char *local_relpath,
+                       svn_boolean_t obtain_locks,
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool)
 {
-  svn_wc__db_wcroot_t *wcroot;
-  const char *local_relpath;
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
-
-  SVN_ERR_ASSERT(svn_dirent_is_absolute(dir_abspath));
-
-  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
-                              dir_abspath, scratch_pool, scratch_pool));
-  VERIFY_USABLE_WCROOT(wcroot);
+  apr_int64_t last_repos_id = INVALID_REPOS_ID;
+  const char *last_repos_root_url = NULL;
 
   *nodes = apr_hash_make(result_pool);
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                    STMT_SELECT_BASE_CHILDREN_INFO));
+                                    obtain_locks
+                                      ? STMT_SELECT_BASE_CHILDREN_INFO_LOCK
+                                      : STMT_SELECT_BASE_CHILDREN_INFO));
   SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
 
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
@@ -2597,7 +2661,6 @@ svn_wc__db_base_get_children_info(apr_ha
   while (have_row)
     {
       struct svn_wc__db_base_info_t *info;
-      svn_error_t *err;
       apr_int64_t repos_id;
       const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
       const char *name = svn_relpath_basename(child_relpath, result_pool);
@@ -2615,16 +2678,26 @@ svn_wc__db_base_get_children_info(apr_ha
 
       info->update_root = svn_sqlite__column_boolean(stmt, 7);
 
-      info->lock = lock_from_columns(stmt, 8, 9, 10, 11, result_pool);
+      if (obtain_locks)
+        info->lock = lock_from_columns(stmt, 8, 9, 10, 11, result_pool);
+
+      if (repos_id != last_repos_id)
+        {
+          svn_error_t *err;
 
-      err = svn_wc__db_fetch_repos_info(&info->repos_root_url, NULL,
-                                        wcroot->sdb, repos_id, result_pool);
+          err = svn_wc__db_fetch_repos_info(&last_repos_root_url, NULL,
+                                            wcroot->sdb, repos_id,
+                                            result_pool);
 
-      if (err)
-        return svn_error_trace(
-                 svn_error_compose_create(err,
-                                          svn_sqlite__reset(stmt)));
+          if (err)
+            return svn_error_trace(
+                     svn_error_compose_create(err,
+                                              svn_sqlite__reset(stmt)));
+
+          last_repos_id = repos_id;
+        }
 
+      info->repos_root_url = last_repos_root_url;
 
       svn_hash_sets(*nodes, name, info);
 
@@ -2636,6 +2709,30 @@ svn_wc__db_base_get_children_info(apr_ha
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_wc__db_base_get_children_info(apr_hash_t **nodes,
+                                  svn_wc__db_t *db,
+                                  const char *dir_abspath,
+                                  apr_pool_t *result_pool,
+                                  apr_pool_t *scratch_pool)
+{
+  svn_wc__db_wcroot_t *wcroot;
+  const char *local_relpath;
+
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(dir_abspath));
+
+  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
+                              dir_abspath, scratch_pool, scratch_pool));
+  VERIFY_USABLE_WCROOT(wcroot);
+
+  return svn_error_trace(base_get_children_info(nodes,
+                                                wcroot,
+                                                local_relpath,
+                                                TRUE /* obtain_locks */,
+                                                result_pool,
+                                                scratch_pool));
+}
+
 
 svn_error_t *
 svn_wc__db_base_get_props(apr_hash_t **props,
@@ -4812,7 +4909,7 @@ handle_move_back(svn_boolean_t *moved_ba
              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));
+                                        STMT_DELETE_WORKING_OP_DEPTH));
 
       SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
                                              local_relpath,
@@ -5684,6 +5781,25 @@ set_actual_props(apr_int64_t wc_id,
   return svn_error_trace(svn_sqlite__step_done(stmt));
 }
 
+svn_error_t *
+svn_wc__db_op_set_props_internal(svn_wc__db_wcroot_t *wcroot,
+                                 const char *local_relpath,
+                                 apr_hash_t *props,
+                                 svn_boolean_t clear_recorded_info,
+                                 apr_pool_t *scratch_pool)
+{
+  SVN_ERR(set_actual_props(wcroot->wc_id, local_relpath,
+                           props, wcroot->sdb, scratch_pool));
+
+  if (clear_recorded_info)
+    {
+      SVN_ERR(db_record_fileinfo(wcroot, local_relpath,
+                                 SVN_INVALID_FILESIZE, 0,
+                                 scratch_pool));
+    }
+
+  return SVN_NO_ERROR;
+}
 
 /* The body of svn_wc__db_op_set_props().
 
@@ -5719,15 +5835,8 @@ set_props_txn(svn_wc__db_wcroot_t *wcroo
         props = NULL;
     }
 
-  SVN_ERR(set_actual_props(wcroot->wc_id, local_relpath,
-                           props, wcroot->sdb, scratch_pool));
-
-  if (clear_recorded_info)
-    {
-      SVN_ERR(db_record_fileinfo(wcroot, local_relpath,
-                                 SVN_INVALID_FILESIZE, 0,
-                                 scratch_pool));
-    }
+  SVN_ERR(svn_wc__db_op_set_props_internal(wcroot, local_relpath, props,
+                                           clear_recorded_info, scratch_pool));
 
   /* And finally.  */
   SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
@@ -6291,36 +6400,36 @@ svn_wc__db_op_mark_resolved(svn_wc__db_t
   return SVN_NO_ERROR;
 }
 
-/* Clear moved-to information at the delete-half of the move which
- * moved LOCAL_RELPATH here. This transforms the move into a simple delete. */
+/* Clear moved-to information at the delete-half of the move which moved
+ * MOVED_TO_RELPATH here. This transforms the delete part of the move into a
+ * normal delete.
+ *
+ * Note that the moved-to location is always an op-root, while this is not the
+ * case for a moved-from location.
+ */
 static svn_error_t *
-clear_moved_to(const char *local_relpath,
-               svn_wc__db_wcroot_t *wcroot,
+clear_moved_to(svn_wc__db_wcroot_t *wcroot,
+               const char *moved_to_relpath,
                apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
-  svn_boolean_t have_row;
   const char *moved_from_relpath;
+  int moved_from_op_depth;
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_SELECT_MOVED_FROM_RELPATH));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
-  SVN_ERR(svn_sqlite__step(&have_row, stmt));
-  if (!have_row)
-    {
-      SVN_ERR(svn_sqlite__reset(stmt));
-      return SVN_NO_ERROR;
-    }
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, moved_to_relpath));
+  SVN_ERR(svn_sqlite__step_row(stmt));
 
   moved_from_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool);
+  moved_from_op_depth = svn_sqlite__column_int(stmt, 1);
   SVN_ERR(svn_sqlite__reset(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,
-                            moved_from_relpath,
-                            relpath_depth(moved_from_relpath)));
-  SVN_ERR(svn_sqlite__step_done(stmt));
+                            moved_from_relpath, moved_from_op_depth));
+  SVN_ERR(svn_sqlite__update(NULL, stmt));
 
   return SVN_NO_ERROR;
 }
@@ -6476,7 +6585,7 @@ op_revert_txn(void *baton,
 
       /* If this node was moved-here, clear moved-to at the move source. */
       if (moved_here)
-        SVN_ERR(clear_moved_to(local_relpath, wcroot, scratch_pool));
+        SVN_ERR(clear_moved_to(wcroot, local_relpath, scratch_pool));
     }
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
@@ -6619,7 +6728,7 @@ op_revert_recursive_txn(void *baton,
       svn_pool_clear(iterpool);
 
       moved_here_child_relpath = svn_sqlite__column_text(stmt, 0, iterpool);
-      err = clear_moved_to(moved_here_child_relpath, wcroot, iterpool);
+      err = clear_moved_to(wcroot, moved_here_child_relpath, iterpool);
       if (err)
         return svn_error_trace(svn_error_compose_create(
                                         err,
@@ -6633,7 +6742,7 @@ op_revert_recursive_txn(void *baton,
   /* Clear potential moved-to pointing at the target node itself. */
   if (op_depth > 0 && op_depth == relpath_depth(local_relpath)
       && moved_here)
-    SVN_ERR(clear_moved_to(local_relpath, wcroot, scratch_pool));
+    SVN_ERR(clear_moved_to(wcroot, local_relpath, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -7149,7 +7258,7 @@ remove_node_txn(svn_boolean_t *left_chan
   if (local_relpath[0] != '\0')
     {
       SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                        STMT_DELETE_NODE));
+                                        STMT_DELETE_NODE_ALL_LAYERS));
       SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
       SVN_ERR(svn_sqlite__step_done(stmt));
     }
@@ -8610,19 +8719,22 @@ svn_wc__db_read_info(svn_wc__db_status_t
                               local_abspath, scratch_pool, scratch_pool));
   VERIFY_USABLE_WCROOT(wcroot);
 
-  SVN_ERR(read_info(status, kind, revision, repos_relpath, &repos_id,
+  SVN_WC__DB_WITH_TXN4(
+          read_info(status, kind, revision, repos_relpath, &repos_id,
                     changed_rev, changed_date, changed_author,
                     depth, checksum, target, original_repos_relpath,
                     &original_repos_id, original_revision, lock,
                     recorded_size, recorded_time, changelist, conflicted,
                     op_root, have_props, props_mod,
                     have_base, have_more_work, have_work,
-                    wcroot, local_relpath, result_pool, scratch_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, local_relpath, result_pool, scratch_pool),
+          svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid,
+                                      wcroot->sdb, repos_id, result_pool),
+          svn_wc__db_fetch_repos_info(original_root_url, original_uuid,
                                       wcroot->sdb, original_repos_id,
-                                      result_pool));
+                                      result_pool),
+        SVN_NO_ERROR,
+        wcroot);
 
   return SVN_NO_ERROR;
 }
@@ -8642,6 +8754,7 @@ struct read_children_info_item_t
   int nr_layers;
 };
 
+/* Implementation of svn_wc__db_read_children_info */
 static svn_error_t *
 read_children_info(svn_wc__db_wcroot_t *wcroot,
                    const char *dir_relpath,
@@ -8655,6 +8768,7 @@ read_children_info(svn_wc__db_wcroot_t *
   const char *repos_root_url = NULL;
   const char *repos_uuid = NULL;
   apr_int64_t last_repos_id = INVALID_REPOS_ID;
+  const char *last_repos_root_url = NULL;
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_SELECT_NODE_CHILDREN_INFO));
@@ -8719,8 +8833,6 @@ read_children_info(svn_wc__db_wcroot_t *
             }
           else
             {
-              const char *last_repos_root_url = NULL;
-
               apr_int64_t repos_id = svn_sqlite__column_int64(stmt, 1);
               if (!repos_root_url ||
                   (last_repos_id != INVALID_REPOS_ID &&
@@ -8770,8 +8882,14 @@ read_children_info(svn_wc__db_wcroot_t *
               child->depth = svn_sqlite__column_token_null(stmt, 11, depth_map,
                                                            svn_depth_unknown);
               if (new_child)
-                SVN_ERR(is_wclocked(&child->locked, wcroot, child_relpath,
-                                    scratch_pool));
+                {
+                  err = is_wclocked(&child->locked, wcroot, child_relpath,
+                                    scratch_pool);
+
+                  if (err)
+                    SVN_ERR(svn_error_compose_create(err,
+                                                     svn_sqlite__reset(stmt)));
+                }
             }
 
           child->recorded_time = svn_sqlite__column_int64(stmt, 13);
@@ -8797,7 +8915,11 @@ read_children_info(svn_wc__db_wcroot_t *
           else
             child->op_root = (op_depth == relpath_depth(child_relpath));
 
-          svn_hash_sets(nodes, apr_pstrdup(result_pool, name), child);
+          if (op_depth && child->op_root)
+            child_item->info.moved_here = svn_sqlite__column_boolean(stmt, 20);
+
+          if (new_child)
+            svn_hash_sets(nodes, apr_pstrdup(result_pool, name), child);
         }
 
       if (op_depth == 0)
@@ -8819,18 +8941,40 @@ read_children_info(svn_wc__db_wcroot_t *
           child_item->nr_layers++;
           child_item->info.have_more_work = (child_item->nr_layers > 1);
 
-          /* Moved-to can only exist at op_depth > 0. */
-          /* ### Should we really do this for every layer where op_depth > 0
-                 in undefined order? */
+
+          /* A local_relpath can be moved multiple times at different op
+             depths and it really depends on the caller what is interesting.
+             We provide a simple linked list with the moved_from information */
+
           moved_to_relpath = svn_sqlite__column_text(stmt, 21, NULL);
           if (moved_to_relpath)
-            child_item->info.moved_to_abspath =
-              svn_dirent_join(wcroot->abspath, moved_to_relpath, result_pool);
+            {
+              struct svn_wc__db_moved_to_info_t *moved_to;
+              struct svn_wc__db_moved_to_info_t **next;
+              const char *shadow_op_relpath;
+
+              moved_to = apr_pcalloc(result_pool, sizeof(*moved_to));
+              moved_to->moved_to_abspath = svn_dirent_join(wcroot->abspath,
+                                                           moved_to_relpath,
+                                                           result_pool);
+
+              shadow_op_relpath = svn_relpath_limit(child_relpath, op_depth,
+                                                    scratch_pool);
+
+              moved_to->shadow_op_root_abspath =
+                        svn_dirent_join(wcroot->abspath, shadow_op_relpath,
+                                        result_pool);
+
+              next = &child_item->info.moved_to;
+
+              while (*next &&
+                     0 < strcmp((*next)->shadow_op_root_abspath,
+                                moved_to->shadow_op_root_abspath))
+                next = &((*next)->next);
 
-          /* Moved-here can only exist at op_depth > 0. */
-          /* ### Should we really do this for every layer where op_depth > 0
-                 in undefined order? */
-          child_item->info.moved_here = svn_sqlite__column_boolean(stmt, 20);
+              moved_to->next = *next;
+              *next = moved_to;
+            }
         }
 
       SVN_ERR(svn_sqlite__step(&have_row, stmt));
@@ -8918,77 +9062,246 @@ svn_wc__db_read_children_info(apr_hash_t
   return SVN_NO_ERROR;
 }
 
-svn_error_t *
-svn_wc__db_read_pristine_info(svn_wc__db_status_t *status,
-                              svn_node_kind_t *kind,
-                              svn_revnum_t *changed_rev,
-                              apr_time_t *changed_date,
-                              const char **changed_author,
-                              svn_depth_t *depth,  /* dirs only */
-                              const svn_checksum_t **checksum, /* files only */
-                              const char **target, /* symlinks only */
-                              svn_boolean_t *had_props,
-                              apr_hash_t **props,
-                              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_sqlite__stmt_t *stmt;
-  svn_boolean_t have_row;
-  svn_error_t *err = NULL;
-  int op_depth;
-  svn_wc__db_status_t raw_status;
-  svn_node_kind_t node_kind;
+/* Implementation of svn_wc__db_read_single_info.
 
-  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+   ### This function is very similar to a lot of code inside
+   read_children_info, but that performs some tricks to re-use data between
+   different siblings.
+
+   ### We read the same few NODES records a few times via different helper
+   functions, so this could be optimized bit, but everything is within
+   a sqlite transaction and all queries are backed by an index, so generally
+   everything (including the used indexes) should be in the sqlite page cache
+   after the first query.
+*/
+static svn_error_t *
+read_single_info(const struct svn_wc__db_info_t **info,
+                 svn_wc__db_wcroot_t *wcroot,
+                 const char *local_relpath,
+                 apr_pool_t *result_pool,
+                 apr_pool_t *scratch_pool)
+{
+  struct svn_wc__db_info_t *mtb;
+  apr_int64_t repos_id;
+  const svn_checksum_t *checksum;
+  const char *original_repos_relpath;
+  svn_boolean_t have_work;
 
-  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
-                                                local_abspath,
-                                                scratch_pool, scratch_pool));
-  VERIFY_USABLE_WCROOT(wcroot);
+  mtb = apr_pcalloc(result_pool, sizeof(*mtb));
 
-  /* Obtain the most likely to exist record first, to make sure we don't
-     have to obtain the SQLite read-lock multiple times */
-  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                    STMT_SELECT_NODE_INFO));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
-  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+  SVN_ERR(read_info(&mtb->status, &mtb->kind, &mtb->revnum,
+                    &mtb->repos_relpath, &repos_id, &mtb->changed_rev,
+                    &mtb->changed_date, &mtb->changed_author, &mtb->depth,
+                    &checksum, NULL, &original_repos_relpath, NULL, NULL,
+                    &mtb->lock, &mtb->recorded_size, &mtb->recorded_time,
+                    &mtb->changelist, &mtb->conflicted, &mtb->op_root,
+                    &mtb->had_props, &mtb->props_mod, &mtb->have_base,
+                    &mtb->have_more_work, &have_work,
+                    wcroot, local_relpath,
+                    result_pool, scratch_pool));
 
-  if (!have_row)
+  /* Query the same rows in the database again for move information */
+  if (have_work && (mtb->have_base || mtb->have_more_work))
     {
-      return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND,
-                               svn_sqlite__reset(stmt),
-                               _("The node '%s' was not found."),
-                               path_for_error_message(wcroot,
-                                                      local_relpath,
-                                                      scratch_pool));
-    }
+      svn_sqlite__stmt_t *stmt;
+      svn_boolean_t have_row;
 
-  op_depth = svn_sqlite__column_int(stmt, 0);
-  raw_status = svn_sqlite__column_token(stmt, 3, presence_map);
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                        STMT_SELECT_MOVED_TO_NODE));
+      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
 
-  if (op_depth > 0 && raw_status == svn_wc__db_status_base_deleted)
-    {
-      SVN_ERR(svn_sqlite__step_row(stmt));
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
-      op_depth = svn_sqlite__column_int(stmt, 0);
-      raw_status = svn_sqlite__column_token(stmt, 3, presence_map);
-    }
+      while (have_row)
+        {
+          struct svn_wc__db_moved_to_info_t *move;
+          int op_depth = svn_sqlite__column_int(stmt, 0);
+          const char *moved_to_relpath = svn_sqlite__column_text(stmt, 1, NULL);
+          const char *cur_relpath;
 
-  node_kind = svn_sqlite__column_token(stmt, 4, kind_map);
+          move = apr_pcalloc(result_pool, sizeof(*move));
+          move->moved_to_abspath = svn_dirent_join(wcroot->abspath,
+                                                   moved_to_relpath,
+                                                   result_pool);
 
-  if (status)
-    {
-      if (op_depth > 0)
-        {
-          err = svn_error_compose_create(err,
-                                         convert_to_working_status(
-                                                    status,
-                                                    raw_status));
-        }
+          cur_relpath = svn_relpath_limit(local_relpath, op_depth,
+                                          scratch_pool);
+
+          move->shadow_op_root_abspath = svn_dirent_join(wcroot->abspath,
+                                                         cur_relpath,
+                                                         result_pool);
+
+          move->next = mtb->moved_to;
+          mtb->moved_to = move;
+
+          SVN_ERR(svn_sqlite__step(&have_row, stmt));
+        }
+
+      SVN_ERR(svn_sqlite__reset(stmt));
+    }
+
+  /* Maybe we have to get some shadowed lock from BASE to make our test suite
+     happy... (It might be completely unrelated, but...)
+     This queries the same BASE row again, joined to the lock table */
+  if (mtb->have_base && (have_work || mtb->kind == svn_node_file))
+    {
+      svn_boolean_t update_root;
+      svn_wc__db_lock_t **lock_arg = NULL;
+
+      if (have_work)
+        lock_arg = &mtb->lock;
+
+      SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, NULL, NULL, NULL,
+                                                NULL, NULL, NULL, NULL, NULL,
+                                                NULL, lock_arg, NULL, NULL,
+                                                &update_root,
+                                                wcroot, local_relpath,
+                                                result_pool, scratch_pool));
+
+      mtb->file_external = (update_root && mtb->kind == svn_node_file);
+    }
+
+  if (mtb->status == svn_wc__db_status_added)
+    {
+      svn_wc__db_status_t status;
+
+      SVN_ERR(scan_addition(&status, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                            NULL, NULL,
+                            wcroot, local_relpath,
+                            result_pool, scratch_pool));
+
+      mtb->moved_here = (status == svn_wc__db_status_moved_here);
+      mtb->incomplete = (status == svn_wc__db_status_incomplete);
+    }
+
+#ifdef HAVE_SYMLINK
+  if (mtb->kind == svn_node_file
+      && (mtb->had_props || mtb->props_mod))
+    {
+      apr_hash_t *properties;
+
+      if (mtb->props_mod)
+        SVN_ERR(svn_wc__db_read_props_internal(&properties,
+                                               wcroot, local_relpath,
+                                               scratch_pool, scratch_pool));
+      else
+        SVN_ERR(db_read_pristine_props(&properties, wcroot, local_relpath,
+                                       TRUE /* deleted_ok */,
+                                       scratch_pool, scratch_pool));
+
+      mtb->special = (NULL != svn_hash_gets(properties, SVN_PROP_SPECIAL));
+    }
+#endif
+
+  mtb->has_checksum = (checksum != NULL);
+  mtb->copied = (original_repos_relpath != NULL);
+
+  SVN_ERR(svn_wc__db_fetch_repos_info(&mtb->repos_root_url, &mtb->repos_uuid,
+                                      wcroot->sdb, repos_id, result_pool));
+
+  if (mtb->kind == svn_node_dir)
+    SVN_ERR(is_wclocked(&mtb->locked, wcroot, local_relpath, scratch_pool));
+
+  *info = mtb;
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__db_read_single_info(const struct svn_wc__db_info_t **info,
+                            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_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_WC__DB_WITH_TXN(read_single_info(info, wcroot, local_relpath,
+                                       result_pool, scratch_pool),
+                      wcroot);
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__db_read_pristine_info(svn_wc__db_status_t *status,
+                              svn_node_kind_t *kind,
+                              svn_revnum_t *changed_rev,
+                              apr_time_t *changed_date,
+                              const char **changed_author,
+                              svn_depth_t *depth,  /* dirs only */
+                              const svn_checksum_t **checksum, /* files only */
+                              const char **target, /* symlinks only */
+                              svn_boolean_t *had_props,
+                              apr_hash_t **props,
+                              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_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+  svn_error_t *err = NULL;
+  int op_depth;
+  svn_wc__db_status_t raw_status;
+  svn_node_kind_t node_kind;
+
+  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);
+
+  /* Obtain the most likely to exist record first, to make sure we don't
+     have to obtain the SQLite read-lock multiple times */
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_SELECT_NODE_INFO));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+  if (!have_row)
+    {
+      return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND,
+                               svn_sqlite__reset(stmt),
+                               _("The node '%s' was not found."),
+                               path_for_error_message(wcroot,
+                                                      local_relpath,
+                                                      scratch_pool));
+    }
+
+  op_depth = svn_sqlite__column_int(stmt, 0);
+  raw_status = svn_sqlite__column_token(stmt, 3, presence_map);
+
+  if (op_depth > 0 && raw_status == svn_wc__db_status_base_deleted)
+    {
+      SVN_ERR(svn_sqlite__step_row(stmt));
+
+      op_depth = svn_sqlite__column_int(stmt, 0);
+      raw_status = svn_sqlite__column_token(stmt, 3, presence_map);
+    }
+
+  node_kind = svn_sqlite__column_token(stmt, 4, kind_map);
+
+  if (status)
+    {
+      if (op_depth > 0)
+        {
+          err = svn_error_compose_create(err,
+                                         convert_to_working_status(
+                                                    status,
+                                                    raw_status));
+        }
       else
         *status = raw_status;
     }
@@ -9499,12 +9812,12 @@ svn_wc__db_read_props_streamily(svn_wc__
 
 /* Helper for svn_wc__db_read_props().
  */
-static svn_error_t *
-db_read_props(apr_hash_t **props,
-              svn_wc__db_wcroot_t *wcroot,
-              const char *local_relpath,
-              apr_pool_t *result_pool,
-              apr_pool_t *scratch_pool)
+svn_error_t *
+svn_wc__db_read_props_internal(apr_hash_t **props,
+                               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;
@@ -9561,8 +9874,10 @@ svn_wc__db_read_props(apr_hash_t **props
                               local_abspath, scratch_pool, scratch_pool));
   VERIFY_USABLE_WCROOT(wcroot);
 
-  SVN_WC__DB_WITH_TXN(db_read_props(props, wcroot, local_relpath,
-                                    result_pool, scratch_pool),
+  SVN_WC__DB_WITH_TXN(svn_wc__db_read_props_internal(props, wcroot,
+                                                     local_relpath,
+                                                     result_pool,
+                                                     scratch_pool),
                       wcroot);
 
   return SVN_NO_ERROR;
@@ -10387,71 +10702,22 @@ svn_wc__db_read_children(const apr_array
 }
 
 
-/* */
+/* Implementation of svn_wc__db_global_relocate */
 static svn_error_t *
 relocate_txn(svn_wc__db_wcroot_t *wcroot,
              const char *local_relpath,
              const char *repos_root_url,
-             const char *repos_uuid,
-             svn_boolean_t have_base_node,
-             apr_int64_t old_repos_id,
              apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
   apr_int64_t new_repos_id;
-
-  /* This function affects all the children of the given local_relpath,
-     but the way that it does this is through the repos inheritance mechanism.
-     So, we only need to rewrite the repos_id of the given local_relpath,
-     as well as any children with a non-null repos_id, as well as various
-     repos_id fields in the locks and working_node tables.
-   */
-
-  /* Get the repos_id for the new repository. */
-  SVN_ERR(create_repos_id(&new_repos_id, repos_root_url, repos_uuid,
-                          wcroot->sdb, scratch_pool));
-
-  /* Set the (base and working) repos_ids and clear the dav_caches */
-  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                    STMT_RECURSIVE_UPDATE_NODE_REPO));
-  SVN_ERR(svn_sqlite__bindf(stmt, "isii", wcroot->wc_id, local_relpath,
-                            old_repos_id, new_repos_id));
-  SVN_ERR(svn_sqlite__step_done(stmt));
-
-  if (have_base_node)
-    {
-      /* Update any locks for the root or its children. */
-      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                        STMT_UPDATE_LOCK_REPOS_ID));
-      SVN_ERR(svn_sqlite__bindf(stmt, "ii", old_repos_id, new_repos_id));
-      SVN_ERR(svn_sqlite__step_done(stmt));
-    }
-
-  return SVN_NO_ERROR;
-}
-
-
-svn_error_t *
-svn_wc__db_global_relocate(svn_wc__db_t *db,
-                           const char *local_dir_abspath,
-                           const char *repos_root_url,
-                           apr_pool_t *scratch_pool)
-{
-  svn_wc__db_wcroot_t *wcroot;
-  const char *local_relpath;
   const char *local_dir_relpath;
   svn_wc__db_status_t status;
   const char *repos_uuid;
   svn_boolean_t have_base_node;
   apr_int64_t old_repos_id;
 
-  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_dir_abspath));
-  /* ### assert that we were passed a directory?  */
-
-  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_dir_relpath,
-                           db, local_dir_abspath, scratch_pool, scratch_pool));
-  VERIFY_USABLE_WCROOT(wcroot);
-  local_relpath = local_dir_relpath;
+  local_dir_relpath = local_relpath;
 
   SVN_ERR(read_info(&status,
                     NULL, NULL, NULL, &old_repos_id,
@@ -10524,13 +10790,60 @@ svn_wc__db_global_relocate(svn_wc__db_t 
 
   SVN_ERR(svn_wc__db_fetch_repos_info(NULL, &repos_uuid, wcroot->sdb,
                                       old_repos_id, scratch_pool));
-  SVN_ERR_ASSERT(repos_uuid);
+  SVN_ERR_ASSERT(repos_uuid);  /* This function affects all the children of the given local_relpath,
+     but the way that it does this is through the repos inheritance mechanism.
+     So, we only need to rewrite the repos_id of the given local_relpath,
+     as well as any children with a non-null repos_id, as well as various
+     repos_id fields in the locks and working_node tables.
+   */
+
+  /* Get the repos_id for the new repository. */
+  SVN_ERR(create_repos_id(&new_repos_id, repos_root_url, repos_uuid,
+                          wcroot->sdb, scratch_pool));
+
+  /* Set the (base and working) repos_ids and clear the dav_caches */
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_RECURSIVE_UPDATE_NODE_REPO));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isii", wcroot->wc_id, local_relpath,
+                            old_repos_id, new_repos_id));
+  SVN_ERR(svn_sqlite__step_done(stmt));
+
+  if (have_base_node)
+    {
+      /* Update any locks for the root or its children. */
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                        STMT_UPDATE_LOCK_REPOS_ID));
+      SVN_ERR(svn_sqlite__bindf(stmt, "ii", old_repos_id, new_repos_id));
+      SVN_ERR(svn_sqlite__step_done(stmt));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__db_global_relocate(svn_wc__db_t *db,
+                           const char *local_dir_abspath,
+                           const char *repos_root_url,
+                           apr_pool_t *scratch_pool)
+{
+  svn_wc__db_wcroot_t *wcroot;
+  const char *local_relpath;
+
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_dir_abspath));
+  /* ### assert that we were passed a directory?  */
+
+  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
+                           db, local_dir_abspath, scratch_pool, scratch_pool));
+  VERIFY_USABLE_WCROOT(wcroot);
 
   SVN_WC__DB_WITH_TXN(
-    relocate_txn(wcroot, local_relpath, repos_root_url, repos_uuid,
-                 have_base_node, old_repos_id, scratch_pool),
+    relocate_txn(wcroot, local_relpath, repos_root_url, scratch_pool),
     wcroot);
 
+  SVN_ERR(flush_entries(wcroot, local_dir_abspath, svn_depth_infinity,
+                        scratch_pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -10847,7 +11160,7 @@ commit_node(svn_wc__db_wcroot_t *wcroot,
          if we need to remove shadowed layers below our descendants. */
 
       SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                        STMT_DELETE_ALL_LAYERS));
+                                        STMT_DELETE_NODE_ALL_LAYERS));
       SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
       SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
 
@@ -11154,6 +11467,9 @@ db_op_set_rev_repos_relpath_iprops(svn_w
  * non-NULL update the entry to the new url specified by NEW_REPOS_RELPATH,
  * NEW_REPOS_ID.  If NEW_REV is valid, make this the node's working revision.
  *
+ * NODE_STATUS, NODE_KIND, NODE_REVISION and NODE_REPOS_RELPATH represent the
+ * values as stored currently in WCROOT for LOCAL_RELPATH.
+ *
  * If WCROOT_IPROPS is not NULL it is a hash mapping const char * absolute
  * working copy paths to depth-first ordered arrays of
  * svn_prop_inherited_item_t * structures.  If the absolute path equivalent
@@ -11166,6 +11482,10 @@ db_op_set_rev_repos_relpath_iprops(svn_w
 static svn_error_t *
 bump_node_revision(svn_wc__db_wcroot_t *wcroot,
                    const char *local_relpath,
+                   svn_wc__db_status_t node_status,
+                   svn_node_kind_t node_kind,
+                   svn_revnum_t node_revision,
+                   const char *node_repos_relpath,
                    apr_int64_t new_repos_id,
                    const char *new_repos_relpath,
                    svn_revnum_t new_rev,
@@ -11178,56 +11498,14 @@ bump_node_revision(svn_wc__db_wcroot_t *
                    apr_pool_t *scratch_pool)
 {
   apr_pool_t *iterpool;
-  const apr_array_header_t *children;
-  int i;
-  svn_wc__db_status_t status;
-  svn_node_kind_t db_kind;
-  svn_revnum_t revision;
-  const char *repos_relpath;
-  apr_int64_t repos_id;
+  apr_hash_t *children;
+  apr_hash_index_t *hi;
   svn_boolean_t set_repos_relpath = FALSE;
-  svn_boolean_t update_root;
   svn_depth_t depth_below_here = depth;
   apr_array_header_t *iprops = NULL;
 
-  /* Skip an excluded path and its descendants. */
-  if (svn_hash_gets(exclude_relpaths, local_relpath))
-    return SVN_NO_ERROR;
-
-  SVN_ERR(svn_wc__db_base_get_info_internal(&status, &db_kind, &revision,
-                                            &repos_relpath, &repos_id,
-                                            NULL, NULL, NULL, NULL, NULL,
-                                            NULL, NULL, NULL, NULL, &update_root,
-                                            wcroot, local_relpath,
-                                            scratch_pool, scratch_pool));
-
-  /* Skip file externals */
-  if (update_root
-      && db_kind == svn_node_file
-      && !is_root)
-    return SVN_NO_ERROR;
-
-  if (skip_when_dir && db_kind == svn_node_dir)
-    return SVN_NO_ERROR;
-
-  /* If the node is still marked 'not-present', then the server did not
-     re-add it.  So it's really gone in this revision, thus we remove the node.
-
-     If the node is still marked 'server-excluded' and yet is not the same
-     revision as new_rev, then the server did not re-add it, nor
-     re-server-exclude it, so we can remove the node. */
-  if (!is_root
-      && (status == svn_wc__db_status_not_present
-          || (status == svn_wc__db_status_server_excluded &&
-              revision != new_rev)))
-    {
-      return svn_error_trace(db_base_remove(wcroot, local_relpath,
-                                            db, FALSE, FALSE, FALSE,
-                                            SVN_INVALID_REVNUM,
-                                            NULL, NULL, scratch_pool));
-    }
-
-  if (new_repos_relpath != NULL && strcmp(repos_relpath, new_repos_relpath))
+  if (new_repos_relpath != NULL
+      && strcmp(node_repos_relpath, new_repos_relpath))
     set_repos_relpath = TRUE;
 
   if (wcroot_iprops)
@@ -11237,7 +11515,7 @@ bump_node_revision(svn_wc__db_wcroot_t *
 
   if (iprops
       || set_repos_relpath
-      || (SVN_IS_VALID_REVNUM(new_rev) && new_rev != revision))
+      || (SVN_IS_VALID_REVNUM(new_rev) && new_rev != node_revision))
     {
       SVN_ERR(db_op_set_rev_repos_relpath_iprops(wcroot, local_relpath,
                                                  iprops, new_rev,
@@ -11249,10 +11527,10 @@ bump_node_revision(svn_wc__db_wcroot_t *
 
   /* Early out */
   if (depth <= svn_depth_empty
-      || db_kind != svn_node_dir
-      || status == svn_wc__db_status_server_excluded
-      || status == svn_wc__db_status_excluded
-      || status == svn_wc__db_status_not_present)
+      || node_kind != svn_node_dir
+      || node_status == svn_wc__db_status_server_excluded
+      || node_status == svn_wc__db_status_excluded
+      || node_status == svn_wc__db_status_not_present)
     return SVN_NO_ERROR;
 
   /* And now recurse over the children */
@@ -11264,25 +11542,62 @@ bump_node_revision(svn_wc__db_wcroot_t *
 
   iterpool = svn_pool_create(scratch_pool);
 
-  SVN_ERR(gather_repo_children(&children, wcroot, local_relpath, 0,
-                               scratch_pool, iterpool));
-  for (i = 0; i < children->nelts; i++)
+  SVN_ERR(base_get_children_info(&children, wcroot, local_relpath, 0,
+                                 scratch_pool, iterpool));
+  for (hi = apr_hash_first(scratch_pool, children); hi; hi = apr_hash_next(hi))
     {
-      const char *child_basename = APR_ARRAY_IDX(children, i, const char *);
+      const char *child_basename = svn__apr_hash_index_key(hi);
+      const struct svn_wc__db_base_info_t *child_info;
       const char *child_local_relpath;
       const char *child_repos_relpath = NULL;
 
       svn_pool_clear(iterpool);
 
+      child_info = svn__apr_hash_index_val(hi);
+
+      if (child_info->update_root && child_info->kind == svn_node_file)
+        continue; /* Skip file externals */
+
+      if (depth < svn_depth_immediates && child_info->kind == svn_node_dir)
+          continue; /* Skip directories */
+
+      child_local_relpath = svn_relpath_join(local_relpath, child_basename,
+                                             iterpool);
+
+      /* Don't touch nodes that can't be touched via the exclude list */
+      if (svn_hash_gets(exclude_relpaths, child_local_relpath))
+          continue;
+
+      /* If the node is still marked 'not-present', then the server did not
+          re-add it.  So it's really gone in this revision, thus we remove the
+          node.
+
+          If the node is still marked 'server-excluded' and yet is not the same
+          revision as new_rev, then the server did not re-add it, nor
+          re-server-exclude it, so we can remove the node. */
+      if (child_info->status == svn_wc__db_status_not_present
+          || (child_info->status == svn_wc__db_status_server_excluded &&
+              child_info->revnum != new_rev))
+        {
+          SVN_ERR(db_base_remove(wcroot,
+                                 child_local_relpath,
+                                 db, FALSE, FALSE, FALSE,
+                                 SVN_INVALID_REVNUM,
+                                 NULL, NULL, scratch_pool));
+          continue;
+        }
+
       /* Derive the new URL for the current (child) entry */
       if (new_repos_relpath)
         child_repos_relpath = svn_relpath_join(new_repos_relpath,
                                                child_basename, iterpool);
 
-      child_local_relpath = svn_relpath_join(local_relpath, child_basename,
-                                             iterpool);
-
-      SVN_ERR(bump_node_revision(wcroot, child_local_relpath, new_repos_id,
+      SVN_ERR(bump_node_revision(wcroot, child_local_relpath,
+                                 child_info->status,
+                                 child_info->kind,
+                                 child_info->revnum,
+                                 child_info->repos_relpath,
+                                 new_repos_id,
                                  child_repos_relpath, new_rev,
                                  depth_below_here,
                                  exclude_relpaths, wcroot_iprops,
@@ -11318,8 +11633,11 @@ bump_revisions_post_update(svn_wc__db_wc
   svn_node_kind_t kind;
   svn_error_t *err;
   apr_int64_t new_repos_id = INVALID_REPOS_ID;
+  svn_revnum_t revision;
+  const char *repos_relpath;
 
-  err = svn_wc__db_base_get_info_internal(&status, &kind, NULL, NULL, NULL,
+  err = svn_wc__db_base_get_info_internal(&status, &kind, &revision,
+                                          &repos_relpath, NULL,
                                           NULL, NULL, NULL, NULL, NULL, NULL,
                                           NULL, NULL, NULL, NULL,
                                           wcroot, local_relpath,
@@ -11349,7 +11667,9 @@ bump_revisions_post_update(svn_wc__db_wc
                             new_repos_uuid,
                             wcroot->sdb, scratch_pool));
 
-  SVN_ERR(bump_node_revision(wcroot, local_relpath, new_repos_id,
+  SVN_ERR(bump_node_revision(wcroot, local_relpath,
+                             status, kind,  revision, repos_relpath,
+                             new_repos_id,
                              new_repos_relpath, new_revision,
                              depth, exclude_relpaths,
                              wcroot_iprops,
@@ -11653,23 +11973,26 @@ get_moved_from_info(const char **moved_f
   return SVN_NO_ERROR;
 }
 
-/* The body of scan_addition().
- */
+/* Like svn_wc__db_scan_addition(), but with WCROOT+LOCAL_RELPATH instead of
+   DB+LOCAL_ABSPATH.
+
+   The output value of *ORIGINAL_REPOS_ID will be INVALID_REPOS_ID if there
+   is no 'copy-from' repository.  */
 static svn_error_t *
-scan_addition_txn(svn_wc__db_status_t *status,
-                  const char **op_root_relpath_p,
-                  const char **repos_relpath,
-                  apr_int64_t *repos_id,
-                  const char **original_repos_relpath,
-                  apr_int64_t *original_repos_id,
-                  svn_revnum_t *original_revision,
-                  const char **moved_from_relpath,
-                  const char **moved_from_op_root_relpath,
-                  int *moved_from_op_depth,
-                  svn_wc__db_wcroot_t *wcroot,
-                  const char *local_relpath,
-                  apr_pool_t *result_pool,
-                  apr_pool_t *scratch_pool)
+scan_addition(svn_wc__db_status_t *status,
+              const char **op_root_relpath_p,
+              const char **repos_relpath,
+              apr_int64_t *repos_id,
+              const char **original_repos_relpath,
+              apr_int64_t *original_repos_id,
+              svn_revnum_t *original_revision,
+              const char **moved_from_relpath,
+              const char **moved_from_op_root_relpath,
+              int *moved_from_op_depth,
+              svn_wc__db_wcroot_t *wcroot,
+              const char *local_relpath,
+              apr_pool_t *result_pool,
+              apr_pool_t *scratch_pool)
 {
   const char *op_root_relpath;
   const char *build_relpath = "";
@@ -11698,8 +12021,7 @@ scan_addition_txn(svn_wc__db_status_t *s
     svn_boolean_t have_row;
     svn_wc__db_status_t presence;
     int op_depth;
-    const char *repos_prefix_path = "";
-    int i;
+    const char *repos_prefix_path;
 
     /* ### is it faster to fetch fewer columns? */
     SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
@@ -11748,17 +12070,9 @@ scan_addition_txn(svn_wc__db_status_t *s
 
 
     /* Calculate the op root local path components */
-    op_root_relpath = local_relpath;
-
-    for (i = relpath_depth(local_relpath); i > op_depth; --i)
-      {
-        /* Calculate the path of the operation root */
-        repos_prefix_path =
-          svn_relpath_join(svn_relpath_basename(op_root_relpath, NULL),
-                           repos_prefix_path,
-                           scratch_pool);
-        op_root_relpath = svn_relpath_dirname(op_root_relpath, scratch_pool);
-      }
+    op_root_relpath = svn_relpath_limit(local_relpath, op_depth, scratch_pool);
+    repos_prefix_path = svn_relpath_skip_ancestor(op_root_relpath,
+                                                  local_relpath);
 
     if (op_root_relpath_p)
       *op_root_relpath_p = apr_pstrdup(result_pool, op_root_relpath);
@@ -11852,6 +12166,7 @@ scan_addition_txn(svn_wc__db_status_t *s
 
     while (TRUE)
       {
+        const char *tmp;
 
         SVN_ERR(svn_sqlite__reset(stmt));
 
@@ -11872,16 +12187,13 @@ scan_addition_txn(svn_wc__db_status_t *s
         op_depth = svn_sqlite__column_int(stmt, 0);
 
         /* Skip to op_depth */
-        for (i = relpath_depth(op_root_relpath); i > op_depth; i--)
-          {
-            /* Calculate the path of the operation root */
-            repos_prefix_path =
-              svn_relpath_join(svn_relpath_basename(op_root_relpath, NULL),
-                               repos_prefix_path,
-                               scratch_pool);
-            op_root_relpath =
-              svn_relpath_dirname(op_root_relpath, scratch_pool);
-          }
+        tmp = op_root_relpath;
+
+        op_root_relpath = svn_relpath_limit(op_root_relpath, op_depth,
+                                              scratch_pool);
+        repos_prefix_path = svn_relpath_join(
+                              svn_relpath_skip_ancestor(op_root_relpath, tmp),
+                              repos_prefix_path, scratch_pool);
       }
 
       SVN_ERR(svn_sqlite__reset(stmt));
@@ -11942,39 +12254,6 @@ scan_addition_txn(svn_wc__db_status_t *s
   return SVN_NO_ERROR;
 }
 
-
-/* Like svn_wc__db_scan_addition(), but with WCROOT+LOCAL_RELPATH instead of
-   DB+LOCAL_ABSPATH.
-
-   The output value of *ORIGINAL_REPOS_ID will be INVALID_REPOS_ID if there
-   is no 'copy-from' repository.  */
-static svn_error_t *
-scan_addition(svn_wc__db_status_t *status,
-              const char **op_root_relpath,
-              const char **repos_relpath,
-              apr_int64_t *repos_id,
-              const char **original_repos_relpath,
-              apr_int64_t *original_repos_id,
-              svn_revnum_t *original_revision,
-              const char **moved_from_relpath,
-              const char **moved_from_op_root_relpath,
-              int *moved_from_op_depth,
-              svn_wc__db_wcroot_t *wcroot,
-              const char *local_relpath,
-              apr_pool_t *result_pool,
-              apr_pool_t *scratch_pool)
-{
-  SVN_WC__DB_WITH_TXN(
-    scan_addition_txn(status, op_root_relpath, repos_relpath, repos_id,
-                      original_repos_relpath, original_repos_id,
-                      original_revision, moved_from_relpath,
-                      moved_from_op_root_relpath, moved_from_op_depth,
-                      wcroot, local_relpath, result_pool, scratch_pool),
-    wcroot);
-  return SVN_NO_ERROR;
-}
-
-
 svn_error_t *
 svn_wc__db_scan_addition(svn_wc__db_status_t *status,
                          const char **op_root_abspath,
@@ -12006,7 +12285,8 @@ svn_wc__db_scan_addition(svn_wc__db_stat
                               local_abspath, scratch_pool, scratch_pool));
   VERIFY_USABLE_WCROOT(wcroot);
 
-  SVN_ERR(scan_addition(status,
+  SVN_WC__DB_WITH_TXN(
+          scan_addition(status,
                         op_root_abspath
                                 ? &op_root_relpath
                                 : NULL,
@@ -12014,7 +12294,8 @@ svn_wc__db_scan_addition(svn_wc__db_stat
                         original_repos_relpath, original_repos_id_p,
                         original_revision,
                         NULL, NULL, NULL,
-                        wcroot, local_relpath, result_pool, scratch_pool));
+                        wcroot, local_relpath, result_pool, scratch_pool),
+          wcroot);
 
   if (op_root_abspath)
     *op_root_abspath = svn_dirent_join(wcroot->abspath, op_root_relpath,
@@ -12055,7 +12336,8 @@ svn_wc__db_scan_moved(const char **moved
                               local_abspath, scratch_pool, scratch_pool));
   VERIFY_USABLE_WCROOT(wcroot);
 
-  SVN_ERR(scan_addition(&status,
+  SVN_WC__DB_WITH_TXN(
+          scan_addition(&status,
                         op_root_abspath
                                 ? &op_root_relpath
                                 : NULL,
@@ -12071,7 +12353,8 @@ svn_wc__db_scan_moved(const char **moved
                         moved_from_delete_abspath
                             ? &moved_from_op_depth
                             : NULL,
-                        wcroot, local_relpath, scratch_pool, scratch_pool));
+                        wcroot, local_relpath, scratch_pool, scratch_pool),
+          wcroot);
 
   if (status != svn_wc__db_status_moved_here || !moved_from_relpath)
     return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
@@ -12095,12 +12378,8 @@ svn_wc__db_scan_moved(const char **moved
   /* The deleted node is either where we moved from, or one of its ancestors */
   if (moved_from_delete_abspath)
     {
-      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);
+      const char *tmp = svn_relpath_limit(moved_from_op_root_relpath,
+                                          moved_from_op_depth, scratch_pool);
 
       *moved_from_delete_abspath = svn_dirent_join(wcroot->abspath, tmp,
                                                    scratch_pool);
@@ -12112,23 +12391,20 @@ svn_wc__db_scan_moved(const char **moved
 /* ###
  */
 static svn_error_t *
-follow_moved_to(apr_array_header_t **moved_tos,
-                int op_depth,
-                const char *repos_path,
-                svn_revnum_t revision,
-                svn_wc__db_wcroot_t *wcroot,
+follow_moved_to(svn_wc__db_wcroot_t *wcroot,
                 const char *local_relpath,
+                int op_depth,
+                apr_array_header_t **moved_tos,
                 apr_pool_t *result_pool,
                 apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
   int working_op_depth;
-  const char *ancestor_relpath, *node_moved_to = NULL;
+  const char *ancestor_relpath;
+  const char *node_moved_to = NULL;
   int i;
 
-  SVN_ERR_ASSERT((!op_depth && !repos_path) || (op_depth && repos_path));
-
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_SELECT_OP_DEPTH_MOVED_TO));
   SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
@@ -12138,50 +12414,26 @@ follow_moved_to(apr_array_header_t **mov
     {
       working_op_depth = svn_sqlite__column_int(stmt, 0);
       node_moved_to = svn_sqlite__column_text(stmt, 1, result_pool);
-      if (!repos_path)
-        {
-          SVN_ERR(svn_sqlite__step(&have_row, stmt));
-          if (!have_row || svn_sqlite__column_revnum(stmt, 0))
-            return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND,
-                                     svn_sqlite__reset(stmt),
-                                     _("The base node '%s' was not found."),
-                                     path_for_error_message(wcroot,
-                                                            local_relpath,
-                                                            scratch_pool));
-          repos_path = svn_sqlite__column_text(stmt, 2, scratch_pool);
-          revision = svn_sqlite__column_revnum(stmt, 3);
-        }
-    }
-  SVN_ERR(svn_sqlite__reset(stmt));
 
-  if (node_moved_to)
-    {
-      svn_boolean_t have_row2;
+      if (node_moved_to)
+        {
+          struct svn_wc__db_moved_to_t *moved_to;
 
-      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                        STMT_SELECT_MOVED_HERE));
-      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, node_moved_to,
-                                relpath_depth(node_moved_to)));
-      SVN_ERR(svn_sqlite__step(&have_row2, stmt));
-      if (!have_row2 || !svn_sqlite__column_int(stmt, 0)
-          || revision != svn_sqlite__column_revnum(stmt, 3)
-          || strcmp(repos_path, svn_sqlite__column_text(stmt, 2, NULL)))
-        node_moved_to = NULL;
-      SVN_ERR(svn_sqlite__reset(stmt));
+          moved_to = apr_palloc(result_pool, sizeof(*moved_to));
+          moved_to->op_depth = working_op_depth;
+          moved_to->local_relpath = node_moved_to;
+          APR_ARRAY_PUSH(*moved_tos, struct svn_wc__db_moved_to_t *) = moved_to;
+        }
     }
 
-  if (node_moved_to)
-    {
-      struct svn_wc__db_moved_to_t *moved_to;
-
-      moved_to = apr_palloc(result_pool, sizeof(*moved_to));
-      moved_to->op_depth = working_op_depth;
-      moved_to->local_relpath = node_moved_to;
-      APR_ARRAY_PUSH(*moved_tos, struct svn_wc__db_moved_to_t *) = moved_to;
-    }
+  SVN_ERR(svn_sqlite__reset(stmt));
 
-  /* A working row with moved_to, or no working row, and we are done. */
-  if (node_moved_to || !have_row)
+  if (!have_row)
+    return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
+                             _("The node '%s' was not found."),
+                             path_for_error_message(wcroot, local_relpath,
+                                                    scratch_pool));
+  else if (node_moved_to)
     return SVN_NO_ERROR;
 
   /* Need to handle being moved via an ancestor. */
@@ -12196,55 +12448,29 @@ follow_moved_to(apr_array_header_t **mov
                                         STMT_SELECT_MOVED_TO));
       SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, ancestor_relpath,
                                 working_op_depth));
-      SVN_ERR(svn_sqlite__step(&have_row, stmt));
-      SVN_ERR_ASSERT(have_row);
+      SVN_ERR(svn_sqlite__step_row(stmt));
+
       ancestor_moved_to = svn_sqlite__column_text(stmt, 0, scratch_pool);
       SVN_ERR(svn_sqlite__reset(stmt));
       if (ancestor_moved_to)
         {
-          node_moved_to
-            = svn_relpath_join(ancestor_moved_to,
-                               svn_relpath_skip_ancestor(ancestor_relpath,
-                                                         local_relpath),
-                               result_pool);
-
-          SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                            STMT_SELECT_MOVED_HERE));
-          SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, node_moved_to,
-                                    relpath_depth(ancestor_moved_to)));
-          SVN_ERR(svn_sqlite__step(&have_row, stmt));
-          if (!have_row)
-            ancestor_moved_to = NULL;
-          else if (!svn_sqlite__column_int(stmt, 0))
-            {
-              svn_wc__db_status_t presence
-                = svn_sqlite__column_token(stmt, 1, presence_map);
-              if (presence != svn_wc__db_status_not_present)
-                ancestor_moved_to = NULL;
-              else
-                {
-                  SVN_ERR(svn_sqlite__step(&have_row, stmt));
-                  if (!have_row && !svn_sqlite__column_int(stmt, 0))
-                    ancestor_moved_to = NULL;
-                }
-            }
-          SVN_ERR(svn_sqlite__reset(stmt));
-          if (!ancestor_moved_to)
-            break;
-          /* verify repos_path points back? */
-        }
-      if (ancestor_moved_to)
-        {
           struct svn_wc__db_moved_to_t *moved_to;
 
+          node_moved_to
+              = svn_relpath_join(ancestor_moved_to,
+                                 svn_relpath_skip_ancestor(ancestor_relpath,
+                                                           local_relpath),
+                                 result_pool);
+
           moved_to = apr_palloc(result_pool, sizeof(*moved_to));
           moved_to->op_depth = working_op_depth;
           moved_to->local_relpath = node_moved_to;
           APR_ARRAY_PUSH(*moved_tos, struct svn_wc__db_moved_to_t *) = moved_to;
 
-          SVN_ERR(follow_moved_to(moved_tos, relpath_depth(ancestor_moved_to),
-                                  repos_path, revision, wcroot, node_moved_to,
-                                  result_pool, scratch_pool));
+          SVN_ERR(follow_moved_to(wcroot, node_moved_to,
+                                  relpath_depth(ancestor_moved_to),
+                                  moved_tos, result_pool, scratch_pool));
+
           break;
         }
     }
@@ -12272,9 +12498,9 @@ svn_wc__db_follow_moved_to(apr_array_hea
                               sizeof(struct svn_wc__db_moved_to_t *));
 
   /* ### Wrap in a transaction */
-  SVN_ERR(follow_moved_to(moved_tos, 0, NULL, SVN_INVALID_REVNUM,
-                          wcroot, local_relpath,
-                          result_pool, scratch_pool));
+  SVN_WC__DB_WITH_TXN(follow_moved_to(wcroot, local_relpath, 0, moved_tos,
+                                      result_pool, scratch_pool),
+                      wcroot);
 
   /* ### Convert moved_to to abspath */
 
@@ -12332,9 +12558,9 @@ svn_wc__db_op_depth_moved_to(const char 
         = svn_relpath_join(*move_dst_op_root_relpath,
                            svn_relpath_skip_ancestor(relpath, local_relpath),
                            result_pool);
-      while (delete_op_depth < relpath_depth(relpath))
-        relpath = svn_relpath_dirname(relpath, scratch_pool);
-      *move_src_op_root_relpath = apr_pstrdup(result_pool, relpath);
+
+      *move_src_op_root_relpath = svn_relpath_limit(relpath, delete_op_depth,
+                                                    result_pool);
     }
 
   return SVN_NO_ERROR;

Modified: subversion/branches/log-addressing/subversion/libsvn_wc/wc_db.h
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_wc/wc_db.h?rev=1545958&r1=1545957&r2=1545958&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_wc/wc_db.h (original)
+++ subversion/branches/log-addressing/subversion/libsvn_wc/wc_db.h Wed Nov 27 08:19:45 2013
@@ -1909,6 +1909,16 @@ svn_wc__db_read_info(svn_wc__db_status_t
                      apr_pool_t *result_pool,
                      apr_pool_t *scratch_pool);
 
+/* Structure used as linked list in svn_wc__db_info_t to describe all nodes
+   in this location that were moved to another location */
+struct svn_wc__db_moved_to_info_t
+{
+  const char *moved_to_abspath;
+  const char *shadow_op_root_abspath;
+
+  struct svn_wc__db_moved_to_info_t *next;
+};
+
 /* Structure returned by svn_wc__db_read_children_info.  Only has the
    fields needed by status. */
 struct svn_wc__db_info_t {
@@ -1945,7 +1955,10 @@ struct svn_wc__db_info_t {
   svn_wc__db_lock_t *lock;  /* Repository file lock */
   svn_boolean_t incomplete; /* TRUE if a working node is incomplete */
 
-  const char *moved_to_abspath; /* Only on op-roots. See svn_wc_status3_t. */
+  struct svn_wc__db_moved_to_info_t *moved_to; /* A linked list of locations
+                                                 where nodes at this path
+                                                 are moved to. Highest layers
+                                                 first */
   svn_boolean_t moved_here;     /* Only on op-roots. */
 
   svn_boolean_t file_external;
@@ -1967,6 +1980,14 @@ svn_wc__db_read_children_info(apr_hash_t
                               apr_pool_t *result_pool,
                               apr_pool_t *scratch_pool);
 
+/* Like svn_wc__db_read_children_info, but only gets an info node for the root
+   element. */
+svn_error_t *
+svn_wc__db_read_single_info(const struct svn_wc__db_info_t **info,
+                            svn_wc__db_t *db,
+                            const char *local_abspath,
+                            apr_pool_t *result_pool,
+                            apr_pool_t *scratch_pool);
 
 /* Structure returned by svn_wc__db_read_walker_info.  Only has the
    fields needed by svn_wc__internal_walk_children(). */
@@ -2685,7 +2706,8 @@ svn_wc__db_scan_addition(svn_wc__db_stat
                          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 LOCAL_ABSPATH is not moved here return an
+ * 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.
@@ -2831,6 +2853,16 @@ svn_wc__db_scan_deletion(const char **ba
    @{
 */
 
+/* Installs or updates Sqlite schema statistics for the current (aka latest)
+   working copy schema.
+
+   This function should be called once on initializing the database and after
+   an schema update completes */
+svn_error_t *
+svn_wc__db_install_schema_statistics(svn_sqlite__db_t *sdb,
+                                     apr_pool_t *scratch_pool);
+
+
 /* Create a new wc.db file for LOCAL_DIR_ABSPATH, which is going to be a
    working copy for the repository REPOS_ROOT_URL with uuid REPOS_UUID.
    Return the raw sqlite handle, repository id and working copy id

Modified: subversion/branches/log-addressing/subversion/libsvn_wc/wc_db_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/log-addressing/subversion/libsvn_wc/wc_db_private.h?rev=1545958&r1=1545957&r2=1545958&view=diff
==============================================================================
--- subversion/branches/log-addressing/subversion/libsvn_wc/wc_db_private.h (original)
+++ subversion/branches/log-addressing/subversion/libsvn_wc/wc_db_private.h Wed Nov 27 08:19:45 2013
@@ -361,6 +361,18 @@ svn_wc__db_with_txn(svn_wc__db_wcroot_t 
   SVN_SQLITE__WITH_LOCK(expr, (wcroot)->sdb)
 
 
+/* Evaluate the expressions EXPR1..EXPR4 within a transaction, returning the
+ * first error if an error occurs.
+ *
+ * Begin a transaction in WCROOT's DB; evaluate the expressions, which would
+ * typically be  function calls that do some work in DB; finally commit
+ * the transaction if EXPR evaluated to SVN_NO_ERROR, otherwise roll back
+ * the transaction.
+ */
+#define SVN_WC__DB_WITH_TXN4(expr1, expr2, expr3, expr4, wcroot) \
+  SVN_SQLITE__WITH_LOCK4(expr1, expr2, expr3, expr4, (wcroot)->sdb)
+
+
 /* Return CHILDREN mapping const char * names to svn_node_kind_t * for the
    children of LOCAL_RELPATH at OP_DEPTH. */
 svn_error_t *
@@ -466,6 +478,23 @@ svn_wc__db_op_depth_moved_to(const char 
                              apr_pool_t *result_pool,
                              apr_pool_t *scratch_pool);
 
+/* Like svn_wc__db_op_set_props, but updates ACTUAL_NODE directly without
+   comparing with the pristine properties, etc.
+*/
+svn_error_t *
+svn_wc__db_op_set_props_internal(svn_wc__db_wcroot_t *wcroot,
+                                 const char *local_relpath,
+                                 apr_hash_t *props,
+                                 svn_boolean_t clear_recorded_info,
+                                 apr_pool_t *scratch_pool);
+
+svn_error_t *
+svn_wc__db_read_props_internal(apr_hash_t **props,
+                               svn_wc__db_wcroot_t *wcroot,
+                               const char *local_relpath,
+                               apr_pool_t *result_pool,
+                               apr_pool_t *scratch_pool);
+
 /* Do a post-drive revision bump for the moved-away destination for
    any move sources under LOCAL_RELPATH.  This is called from within
    the revision bump transaction after the tree at LOCAL_RELPATH has