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 08:53:35 UTC

svn commit: r1545955 [7/15] - in /subversion/branches/fsfs-improvements: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/server-side/ contrib/server-side/svncutter/ notes/ subversion/bindings/javahl/native/ s...

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/win32_crashrpt.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/win32_crashrpt.c?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/win32_crashrpt.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/win32_crashrpt.c Wed Nov 27 07:53:29 2013
@@ -244,7 +244,7 @@ write_process_info(EXCEPTION_RECORD *exc
                 "Rsp=%016I64x Rbp=%016I64x Rsi=%016I64x Rdi=%016I64x\n",
                 context->Rsp, context->Rbp, context->Rsi, context->Rdi);
   fprintf(log_file,
-                "R8= %016I64x R9= %016I64x R10= %016I64x R11=%016I64x\n",
+                "R8= %016I64x R9= %016I64x R10=%016I64x R11=%016I64x\n",
                 context->R8, context->R9, context->R10, context->R11);
   fprintf(log_file,
                 "R12=%016I64x R13=%016I64x R14=%016I64x R15=%016I64x\n",

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/win32_crypto.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/win32_crypto.c?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/win32_crypto.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/win32_crypto.c Wed Nov 27 07:53:29 2013
@@ -42,6 +42,7 @@ typedef int win32_crypto__dummy;
 #include "svn_user.h"
 #include "svn_base64.h"
 
+#include "auth.h"
 #include "private/svn_auth_private.h"
 
 #include <wincrypt.h>
@@ -213,7 +214,7 @@ static const svn_auth_provider_t windows
 
 /* Public API */
 void
-svn_auth_get_windows_simple_provider(svn_auth_provider_object_t **provider,
+svn_auth__get_windows_simple_provider(svn_auth_provider_object_t **provider,
                                      apr_pool_t *pool)
 {
   svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
@@ -331,7 +332,7 @@ static const svn_auth_provider_t windows
 
 /* Public API */
 void
-svn_auth_get_windows_ssl_client_cert_pw_provider
+svn_auth__get_windows_ssl_client_cert_pw_provider
    (svn_auth_provider_object_t **provider,
     apr_pool_t *pool)
 {
@@ -482,7 +483,7 @@ static const svn_auth_provider_t windows
 
 /* Public API */
 void
-svn_auth_get_windows_ssl_server_trust_provider
+svn_auth__get_windows_ssl_server_trust_provider
   (svn_auth_provider_object_t **provider, apr_pool_t *pool)
 {
   svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_wc/conflicts.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_wc/conflicts.c?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_wc/conflicts.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_wc/conflicts.c Wed Nov 27 07:53:29 2013
@@ -2709,12 +2709,17 @@ resolve_prop_conflict_on_node(svn_boolea
  * existed and was resolved, set *DID_RESOLVE to TRUE, else set it to FALSE.
  *
  * It is not an error if there is no tree conflict.
+ *
+ * If the conflict can't be resolved yet because another tree conflict is
+ * blocking a storage location, store the tree conflict in the RESOLVE_LATER
+ * hash.
  */
 static svn_error_t *
 resolve_tree_conflict_on_node(svn_boolean_t *did_resolve,
                               svn_wc__db_t *db,
                               const char *local_abspath,
                               svn_wc_conflict_choice_t conflict_choice,
+                              apr_hash_t *resolve_later,
                               svn_wc_notify_func2_t notify_func,
                               void *notify_baton,
                               svn_cancel_func_t cancel_func,
@@ -2748,6 +2753,7 @@ resolve_tree_conflict_on_node(svn_boolea
   if (operation == svn_wc_operation_update
       || operation == svn_wc_operation_switch)
     {
+      svn_error_t *err;
       if (reason == svn_wc_conflict_reason_deleted ||
           reason == svn_wc_conflict_reason_replaced)
         {
@@ -2766,10 +2772,26 @@ resolve_tree_conflict_on_node(svn_boolea
                * this directory, and leave this directory deleted.
                * The newly conflicted moved-away children will be updated
                * if they are resolved with 'mine_conflict' as well. */
-              SVN_ERR(svn_wc__db_resolve_delete_raise_moved_away(
+              err = svn_wc__db_resolve_delete_raise_moved_away(
                         db, local_abspath, notify_func, notify_baton,
-                        scratch_pool));
-              *did_resolve = TRUE;
+                        scratch_pool);
+
+              if (err)
+                {
+                  const char *dup_abspath;
+                  if (err && err->apr_err != SVN_ERR_WC_OBSTRUCTED_UPDATE)
+                    return svn_error_trace(err);
+
+                  svn_error_clear(err);
+                  dup_abspath = apr_pstrdup(apr_hash_pool_get(resolve_later),
+                                            local_abspath);
+
+                  svn_hash_sets(resolve_later, dup_abspath, dup_abspath);
+
+                  return SVN_NO_ERROR; /* Retry after other conflicts */
+                }
+              else
+                *did_resolve = TRUE;
             }
           else
             return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
@@ -2789,12 +2811,28 @@ resolve_tree_conflict_on_node(svn_boolea
            * move (theirs-conflict). */
           if (conflict_choice == svn_wc_conflict_choose_mine_conflict)
             {
-              SVN_ERR(svn_wc__db_update_moved_away_conflict_victim(
+              err = svn_wc__db_update_moved_away_conflict_victim(
                         db, local_abspath,
                         notify_func, notify_baton,
                         cancel_func, cancel_baton,
-                        scratch_pool));
-              *did_resolve = TRUE;
+                        scratch_pool);
+
+              if (err)
+                {
+                  const char *dup_abspath;
+                  if (err && err->apr_err != SVN_ERR_WC_OBSTRUCTED_UPDATE)
+                    return svn_error_trace(err);
+
+                  svn_error_clear(err);
+                  dup_abspath = apr_pstrdup(apr_hash_pool_get(resolve_later),
+                                            local_abspath);
+
+                  svn_hash_sets(resolve_later, dup_abspath, dup_abspath);
+
+                  return SVN_NO_ERROR; /* Retry after other conflicts */
+                }
+              else
+                *did_resolve = TRUE;
             }
           else if (conflict_choice == svn_wc_conflict_choose_merged)
             {
@@ -2822,20 +2860,27 @@ resolve_tree_conflict_on_node(svn_boolea
         }
     }
 
-  if (! *did_resolve && conflict_choice != svn_wc_conflict_choose_merged)
+  if (! *did_resolve)
     {
-      /* For other tree conflicts, there is no way to pick
-       * theirs-full or mine-full, etc. Throw an error if the
-       * user expects us to be smarter than we really are. */
-      return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
-                               NULL,
-                               _("Tree conflict can only be "
-                                 "resolved to 'working' state; "
-                                 "'%s' not resolved"),
-                               svn_dirent_local_style(local_abspath,
-                                                      scratch_pool));
+      if (conflict_choice != svn_wc_conflict_choose_merged)
+        {
+          /* For other tree conflicts, there is no way to pick
+           * theirs-full or mine-full, etc. Throw an error if the
+           * user expects us to be smarter than we really are. */
+          return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
+                                   NULL,
+                                   _("Tree conflict can only be "
+                                     "resolved to 'working' state; "
+                                     "'%s' not resolved"),
+                                   svn_dirent_local_style(local_abspath,
+                                                          scratch_pool));
+        }
+      else
+        *did_resolve = TRUE;
     }
 
+  SVN_ERR_ASSERT(*did_resolve);
+
   SVN_ERR(svn_wc__db_op_mark_resolved(db, local_abspath, FALSE, FALSE, TRUE,
                                       NULL, scratch_pool));
   SVN_ERR(svn_wc__wq_run(db, local_abspath, cancel_func, cancel_baton,
@@ -2888,6 +2933,7 @@ struct conflict_status_walker_baton
   void *cancel_baton;
   svn_wc_notify_func2_t notify_func;
   void *notify_baton;
+  apr_hash_t *resolve_later;
 };
 
 /* Implements svn_wc_status4_t to walk all conflicts to resolve.
@@ -2957,13 +3003,15 @@ conflict_status_walker(void *baton,
                                                   db,
                                                   local_abspath,
                                                   my_choice,
+                                                  cswb->resolve_later,
                                                   cswb->notify_func,
                                                   cswb->notify_baton,
                                                   cswb->cancel_func,
                                                   cswb->cancel_baton,
                                                   iterpool));
 
-            resolved = TRUE;
+            if (did_resolve)
+              resolved = TRUE;
             break;
 
           case svn_wc_conflict_kind_text:
@@ -3045,6 +3093,8 @@ svn_wc__resolve_conflicts(svn_wc_context
   svn_node_kind_t kind;
   svn_boolean_t conflicted;
   struct conflict_status_walker_baton cswb;
+  apr_pool_t *iterpool = NULL;
+  svn_error_t *err;
 
   /* ### the underlying code does NOT support resolving individual
      ### properties. bail out if the caller tries it.  */
@@ -3084,6 +3134,8 @@ svn_wc__resolve_conflicts(svn_wc_context
   cswb.notify_func = notify_func;
   cswb.notify_baton = notify_baton;
 
+  cswb.resolve_later = apr_hash_make(scratch_pool);
+
   if (notify_func)
     notify_func(notify_baton,
                 svn_wc_create_notify(local_abspath,
@@ -3091,16 +3143,66 @@ svn_wc__resolve_conflicts(svn_wc_context
                                     scratch_pool),
                 scratch_pool);
 
-  SVN_ERR(svn_wc_walk_status(wc_ctx,
-                             local_abspath,
-                             depth,
-                             FALSE /* get_all */,
-                             FALSE /* no_ignore */,
-                             TRUE /* ignore_text_mods */,
-                             NULL /* ignore_patterns */,
-                             conflict_status_walker, &cswb,
-                             cancel_func, cancel_baton,
-                             scratch_pool));
+  err = svn_wc_walk_status(wc_ctx,
+                           local_abspath,
+                           depth,
+                           FALSE /* get_all */,
+                           FALSE /* no_ignore */,
+                           TRUE /* ignore_text_mods */,
+                           NULL /* ignore_patterns */,
+                           conflict_status_walker, &cswb,
+                           cancel_func, cancel_baton,
+                           scratch_pool);
+
+  while (!err && apr_hash_count(cswb.resolve_later))
+    {
+      apr_hash_index_t *hi;
+      svn_boolean_t cleared_one = FALSE;
+      const char *tc_abspath = NULL;
+
+      if (iterpool)
+        svn_pool_clear(iterpool);
+      else
+        iterpool = svn_pool_create(scratch_pool);
+
+      for (hi = apr_hash_first(scratch_pool, cswb.resolve_later);
+          hi && !err;
+          hi = apr_hash_next(hi))
+        {
+          tc_abspath = svn__apr_hash_index_key(hi);
+          svn_pool_clear(iterpool);
+
+          svn_hash_sets(cswb.resolve_later, tc_abspath, NULL);
+
+          err = svn_wc_walk_status(wc_ctx, tc_abspath, depth, FALSE, FALSE,
+                                   TRUE, NULL, conflict_status_walker, &cswb,
+                                   cancel_func, cancel_baton,
+                                   iterpool);
+
+          if (!err && !svn_hash_gets(cswb.resolve_later, tc_abspath))
+            cleared_one = TRUE;
+        }
+
+      if (!cleared_one && !err)
+        {
+          /* Return the error on one of the paths: The last one. */
+          err = svn_error_createf(
+                    SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
+                    _("Unable to resolve pending conflict on '%s'"),
+                    svn_dirent_local_style(tc_abspath, scratch_pool));
+        }
+    }
+
+  if (iterpool)
+    svn_pool_destroy(iterpool);
+
+  if (err && err->apr_err != SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE)
+    err = svn_error_createf(
+                SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, err,
+                _("Unable to resolve conflicts on '%s'"),
+                svn_dirent_local_style(local_abspath, scratch_pool));
+
+  SVN_ERR(err);
 
   if (notify_func)
     notify_func(notify_baton,

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_wc/diff.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_wc/diff.h?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_wc/diff.h (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_wc/diff.h Wed Nov 27 07:53:29 2013
@@ -38,7 +38,9 @@
 extern "C" {
 #endif /* __cplusplus */
 
-/* Reports the file LOCAL_ABSPATH as ADDED file with relpath RELPATH to
+/* A function to diff locally added and locally copied files.
+  
+   Reports the file LOCAL_ABSPATH as ADDED file with relpath RELPATH to
    PROCESSOR with as parent baton PROCESSOR_PARENT_BATON.
 
    The node is expected to have status svn_wc__db_status_normal, or
@@ -61,7 +63,9 @@ svn_wc__diff_local_only_file(svn_wc__db_
                              void *cancel_baton,
                              apr_pool_t *scratch_pool);
 
-/* Reports the directory LOCAL_ABSPATH and everything below it (limited by
+/* A function to diff locally added and locally copied directories.
+  
+   Reports the directory LOCAL_ABSPATH and everything below it (limited by
    DEPTH) as added with relpath RELPATH to PROCESSOR with as parent baton
    PROCESSOR_PARENT_BATON.
 

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_wc/diff_local.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_wc/diff_local.c?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_wc/diff_local.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_wc/diff_local.c Wed Nov 27 07:53:29 2013
@@ -115,16 +115,23 @@ ensure_state(struct diff_baton *eb,
   apr_pool_t *ns_pool;
   if (!eb->cur)
     {
-      if (!svn_dirent_is_ancestor(eb->anchor_abspath, local_abspath))
+      const char *relpath;
+
+      relpath = svn_dirent_skip_ancestor(eb->anchor_abspath, local_abspath);
+      if (! relpath)
         return SVN_NO_ERROR;
 
-      SVN_ERR(ensure_state(eb,
-                           svn_dirent_dirname(local_abspath,scratch_pool),
-                           FALSE,
-                           scratch_pool));
+      /* Don't recurse on the anchor, as that might loop infinately because
+            svn_dirent_dirname("/",...)   -> "/"
+            svn_dirent_dirname("C:/",...) -> "C:/" (Windows) */
+      if (*relpath)
+        SVN_ERR(ensure_state(eb,
+                             svn_dirent_dirname(local_abspath, scratch_pool),
+                             FALSE,
+                             scratch_pool));
     }
   else if (svn_dirent_is_child(eb->cur->local_abspath, local_abspath, NULL))
-    SVN_ERR(ensure_state(eb, svn_dirent_dirname(local_abspath,scratch_pool),
+    SVN_ERR(ensure_state(eb, svn_dirent_dirname(local_abspath, scratch_pool),
                          FALSE,
                          scratch_pool));
   else
@@ -390,7 +397,7 @@ diff_status_callback(void *baton,
           }
       }
 
-    if (local_only)
+    if (local_only && (db_status != svn_wc__db_status_deleted))
       {
         if (db_kind == svn_node_file)
           SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath,

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_wc/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_wc/status.c?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_wc/status.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_wc/status.c Wed Nov 27 07:53:29 2013
@@ -241,144 +241,7 @@ struct file_baton
 
 /** Code **/
 
-/* Fill in *INFO with the information it would contain if it were
-   obtained from svn_wc__db_read_children_info. */
-static svn_error_t *
-read_info(const struct svn_wc__db_info_t **info,
-          const char *local_abspath,
-          svn_wc__db_t *db,
-          apr_pool_t *result_pool,
-          apr_pool_t *scratch_pool)
-{
-  struct svn_wc__db_info_t *mtb = apr_pcalloc(result_pool, sizeof(*mtb));
-  const svn_checksum_t *checksum;
-  const char *original_repos_relpath;
-
-  SVN_ERR(svn_wc__db_read_info(&mtb->status, &mtb->kind,
-                               &mtb->revnum, &mtb->repos_relpath,
-                               &mtb->repos_root_url, &mtb->repos_uuid,
-                               &mtb->changed_rev, &mtb->changed_date,
-                               &mtb->changed_author, &mtb->depth,
-                               &checksum, NULL, &original_repos_relpath, NULL,
-                               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, NULL,
-                               db, local_abspath,
-                               result_pool, scratch_pool));
-
-  SVN_ERR(svn_wc__db_wclocked(&mtb->locked, db, local_abspath, scratch_pool));
-
-  /* Maybe we have to get some shadowed lock from BASE to make our test suite
-     happy... (It might be completely unrelated, but...) */
-  if (mtb->have_base
-      && (mtb->status == svn_wc__db_status_added
-          || mtb->status == svn_wc__db_status_deleted
-          || mtb->kind == svn_node_file))
-    {
-      svn_boolean_t update_root;
-      svn_wc__db_lock_t **lock_arg = NULL;
-
-      if (mtb->status == svn_wc__db_status_added
-          || mtb->status == svn_wc__db_status_deleted)
-        lock_arg = &mtb->lock;
-
-      SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, NULL, NULL, NULL,
-                                       NULL, NULL, NULL, NULL, NULL, NULL,
-                                       lock_arg, NULL, NULL, &update_root,
-                                       db, local_abspath,
-                                       result_pool, scratch_pool));
-
-      mtb->file_external = (update_root && mtb->kind == svn_node_file);
-
-      if (mtb->status == svn_wc__db_status_deleted)
-        {
-          const char *moved_to_abspath;
-          const char *moved_to_op_root_abspath;
-
-          /* NOTE: we can't use op-root-ness as a condition here since a base
-           * node can be the root of a move and still not be an explicit
-           * op-root (having a working node with op_depth == pathelements).
-           *
-           * Both these (almost identical) situations showcase this:
-           *   svn mv a/b bb
-           *   svn del a
-           * and
-           *   svn mv a aa
-           *   svn mv aa/b bb
-           * In both, 'bb' is moved from 'a/b', but 'a/b' has no op_depth>0
-           * node at all, as its parent 'a' is locally deleted. */
-
-          SVN_ERR(svn_wc__db_scan_deletion(NULL,
-                                           &moved_to_abspath,
-                                           NULL,
-                                           &moved_to_op_root_abspath,
-                                           db, local_abspath,
-                                           scratch_pool, scratch_pool));
-          if (moved_to_abspath != NULL
-              && moved_to_op_root_abspath != NULL
-              && strcmp(moved_to_abspath, moved_to_op_root_abspath) == 0)
-            {
-              mtb->moved_to_abspath = apr_pstrdup(result_pool,
-                                                  moved_to_abspath);
-            }
-          /* ### ^^^ THIS SUCKS. For at least two reasons:
-           * 1) We scan the node deletion and that's technically not necessary.
-           *    We'd be fine to know if this is an actual root of a move.
-           * 2) From the elaborately calculated results, we backwards-guess
-           *    whether this is a root.
-           * It works ok, and this code only gets called when a node is an
-           * explicit target of a 'status'. But it would be better to do this
-           * differently.
-           * We could return moved-to via svn_wc__db_base_get_info() (called
-           * just above), but as moved-to is only intended to be returned for
-           * roots of a move, that doesn't fit too well. */
-        }
-    }
-
-  /* ### svn_wc__db_read_info() could easily return the moved-here flag. But
-   * for now... (The per-dir query for recursive status is far more optimal.)
-   * Note that this actually scans around to get the full path, for a bool.
-   * This bool then gets returned, later is evaluated, and if true leads to
-   * the same paths being scanned again. We'd want to obtain this bool here as
-   * cheaply as svn_wc__db_read_children_info() does. */
-  if (mtb->status == svn_wc__db_status_added)
-    {
-      svn_wc__db_status_t status;
-
-      SVN_ERR(svn_wc__db_scan_addition(&status, NULL, NULL, NULL, NULL,
-                                       NULL, NULL, NULL, NULL,
-                                       db, local_abspath,
-                                       result_pool, scratch_pool));
 
-      mtb->moved_here = (status == svn_wc__db_status_moved_here);
-      mtb->incomplete = (status == svn_wc__db_status_incomplete);
-    }
-
-  mtb->has_checksum = (checksum != NULL);
-  mtb->copied = (original_repos_relpath != NULL);
-
-#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(&properties, db, local_abspath,
-                                      scratch_pool, scratch_pool));
-      else
-        SVN_ERR(svn_wc__db_read_pristine_props(&properties, db, local_abspath,
-                                               scratch_pool, scratch_pool));
-
-      mtb->special = (NULL != svn_hash_gets(properties, SVN_PROP_SPECIAL));
-    }
-#endif
-  *info = mtb;
-
-  return SVN_NO_ERROR;
-}
 
 /* Return *REPOS_RELPATH and *REPOS_ROOT_URL for LOCAL_ABSPATH using
    information in INFO if available, falling back on
@@ -492,7 +355,8 @@ assemble_status(svn_wc_status3_t **statu
 
 
   if (!info)
-    SVN_ERR(read_info(&info, local_abspath, db, result_pool, scratch_pool));
+    SVN_ERR(svn_wc__db_read_single_info(&info, db, local_abspath,
+                                        result_pool, scratch_pool));
 
   if (!info->repos_relpath || !parent_repos_relpath)
     switched_p = FALSE;
@@ -712,19 +576,21 @@ assemble_status(svn_wc_status3_t **statu
       && prop_status != svn_wc_status_none)
     node_status = prop_status;
 
-  /* 5. Easy out:  unless we're fetching -every- entry, don't bother
-     to allocate a struct for an uninteresting entry. */
+  /* 5. Easy out:  unless we're fetching -every- node, don't bother
+     to allocate a struct for an uninteresting node.
 
+     This filter should match the filter in is_sendable_status() */
   if (! get_all)
     if (((node_status == svn_wc_status_none)
          || (node_status == svn_wc_status_normal))
 
         && (! switched_p)
-        && (! info->locked )
+        && (! info->locked)
         && (! info->lock)
         && (! repos_lock)
         && (! info->changelist)
-        && (! conflicted))
+        && (! conflicted)
+        && (! info->moved_to))
       {
         *status = NULL;
         return SVN_NO_ERROR;
@@ -798,8 +664,11 @@ assemble_status(svn_wc_status3_t **statu
     stat->changelist = apr_pstrdup(result_pool, info->changelist);
 
   stat->moved_from_abspath = moved_from_abspath;
-  if (info->moved_to_abspath)
-    stat->moved_to_abspath = apr_pstrdup(result_pool, info->moved_to_abspath);
+
+  /* ### TODO: Handle multiple moved_to values properly */
+  if (info->moved_to)
+    stat->moved_to_abspath = apr_pstrdup(result_pool,
+                                         info->moved_to->moved_to_abspath);
 
   stat->file_external = info->file_external;
 
@@ -1344,8 +1213,8 @@ get_dir_status(const struct walk_status_
     SVN_ERR(err);
 
   if (!dir_info)
-    SVN_ERR(read_info(&dir_info, local_abspath, wb->db,
-                      scratch_pool, iterpool));
+      SVN_ERR(svn_wc__db_read_single_info(&dir_info, wb->db, local_abspath,
+                                          scratch_pool, iterpool));
 
   SVN_ERR(get_repos_root_url_relpath(&dir_repos_relpath, &dir_repos_root_url,
                                      &dir_repos_uuid, dir_info,
@@ -1505,8 +1374,9 @@ get_child_status(const struct walk_statu
   if (dirent->kind == svn_node_none)
     dirent = NULL;
 
-  SVN_ERR(read_info(&dir_info, parent_abspath, wb->db,
-                    scratch_pool, scratch_pool));
+  SVN_ERR(svn_wc__db_read_single_info(&dir_info,
+                                      wb->db, parent_abspath,
+                                      scratch_pool, scratch_pool));
 
   SVN_ERR(get_repos_root_url_relpath(&dir_repos_relpath, &dir_repos_root_url,
                                      &dir_repos_uuid, dir_info,
@@ -1901,6 +1771,8 @@ make_file_baton(struct dir_baton *parent
  * Return a boolean answer to the question "Is @a status something that
  * should be reported?".  @a no_ignore and @a get_all are the same as
  * svn_wc_get_status_editor4().
+ *
+ * This implementation should match the filter in assemble_status()
  */
 static svn_boolean_t
 is_sendable_status(const svn_wc_status3_t *status,
@@ -1948,6 +1820,9 @@ is_sendable_status(const svn_wc_status3_
   if (status->changelist)
     return TRUE;
 
+  if (status->moved_to_abspath)
+    return TRUE;
+
   /* Otherwise, don't send it. */
   return FALSE;
 }
@@ -2709,7 +2584,8 @@ svn_wc__internal_walk_status(svn_wc__db_
       ignore_patterns = ignores;
     }
 
-  err = read_info(&info, local_abspath, db, scratch_pool, scratch_pool);
+  err = svn_wc__db_read_single_info(&info, db, local_abspath,
+                                    scratch_pool, scratch_pool);
 
   if (err)
     {

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_wc/upgrade.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_wc/upgrade.c?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_wc/upgrade.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_wc/upgrade.c Wed Nov 27 07:53:29 2013
@@ -755,13 +755,13 @@ migrate_single_tree_conflict_data(svn_sq
         {
           /* There is an existing ACTUAL row, so just update it. */
           SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
-                                            STMT_UPDATE_ACTUAL_CONFLICT_DATA));
+                                            STMT_UPDATE_ACTUAL_CONFLICT));
         }
       else
         {
           /* We need to insert an ACTUAL row with the tree conflict data. */
           SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
-                                            STMT_INSERT_ACTUAL_CONFLICT_DATA));
+                                            STMT_INSERT_ACTUAL_CONFLICT));
         }
 
       SVN_ERR(svn_sqlite__bindf(stmt, "iss", wc_id, conflict_relpath,
@@ -1959,6 +1959,10 @@ svn_wc__upgrade_sdb(int *result_format,
       case SVN_WC__VERSION:
         /* already upgraded */
         *result_format = SVN_WC__VERSION;
+
+        SVN_SQLITE__WITH_LOCK(
+            svn_wc__db_install_schema_statistics(sdb, scratch_pool),
+            sdb);
     }
 
 #ifdef SVN_DEBUG

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_wc/wc-metadata.sql
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_wc/wc-metadata.sql?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_wc/wc-metadata.sql (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_wc/wc-metadata.sql Wed Nov 27 07:53:29 2013
@@ -573,6 +573,54 @@ CREATE UNIQUE INDEX I_EXTERNALS_DEFINED 
                                                       local_relpath);
 
 /* ------------------------------------------------------------------------- */
+/* This statement provides SQLite with the necessary information about our
+   indexes to make better decisions in the query planner.
+
+   For every interesting index this contains a number of rows where the
+   statistics ar calculated for and then for every column in the index the
+   average number of rows with the same value in all columns left of this
+   column including the column itself.
+
+   See http://www.sqlite.org/fileformat2.html#stat1tab for more details.
+
+   The important thing here is that this tells Sqlite that the wc_id column
+   of the NODES and ACTUAL_NODE table is usually a single value, so queries
+   should use more than one column for index usage.
+
+   The current hints describe NODES+ACTUAL_NODE as a working copy with
+   8000 nodes in 1 a single working copy(=wc_id), 10 nodes per directory
+   and an average of 2 op-depth layers per node.
+
+   The number of integers must be number of index columns + 1, which is
+   verified via the test_schema_statistics() test.
+ */
+-- STMT_INSTALL_SCHEMA_STATISTICS
+ANALYZE sqlite_master; /* Creates empty sqlite_stat1 if necessary */
+
+INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES
+    ('NODES', 'sqlite_autoindex_NODES_1',               '8000 8000 2 1');
+INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES
+    ('NODES', 'I_NODES_PARENT',                         '8000 8000 10 2 1');
+/* Tell a lie: We ignore that 99.9% of all moved_to values are NULL */
+INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES
+    ('NODES', 'I_NODES_MOVED',                          '8000 8000 1 1');
+
+INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES
+    ('ACTUAL_NODE', 'sqlite_autoindex_ACTUAL_NODE_1',   '8000 8000 1');
+INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES
+    ('ACTUAL_NODE', 'I_ACTUAL_PARENT',                  '8000 8000 10 1');
+
+INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES
+    ('LOCK', 'sqlite_autoindex_LOCK_1',                 '100 100 1');
+
+INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES
+    ('WC_LOCK', 'sqlite_autoindex_WC_LOCK_1',           '100 100 1');
+
+/* sqlite_autoindex_WORK_QUEUE_1 doesn't exist because WORK_QUEUE is
+   a INTEGER PRIMARY KEY AUTOINCREMENT table */
+
+ANALYZE sqlite_master; /* Loads sqlite_stat1 data for query optimizer */
+/* ------------------------------------------------------------------------- */
 
 /* Format 20 introduces NODES and removes BASE_NODE and WORKING_NODE */
 

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_wc/wc-queries.sql
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_wc/wc-queries.sql?rev=1545955&r1=1545954&r2=1545955&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_wc/wc-queries.sql Wed Nov 27 07:53:29 2013
@@ -72,6 +72,12 @@ WHERE wc_id = ?1 AND local_relpath = ?2 
 
 -- STMT_SELECT_BASE_CHILDREN_INFO
 SELECT local_relpath, nodes.repos_id, nodes.repos_path, presence, kind,
+  revision, depth, file_external
+FROM nodes
+WHERE wc_id = ?1 AND parent_relpath = ?2 AND op_depth = 0
+
+-- STMT_SELECT_BASE_CHILDREN_INFO_LOCK
+SELECT local_relpath, nodes.repos_id, nodes.repos_path, presence, kind,
   revision, depth, file_external,
   lock_token, lock_owner, lock_comment, lock_date
 FROM nodes
@@ -79,6 +85,7 @@ LEFT OUTER JOIN lock ON nodes.repos_id =
   AND nodes.repos_path = lock.repos_relpath
 WHERE wc_id = ?1 AND parent_relpath = ?2 AND op_depth = 0
 
+
 -- STMT_SELECT_WORKING_NODE
 SELECT op_depth, presence, kind, checksum, translated_size,
   changed_revision, changed_date, changed_author, depth, symlink_target,
@@ -118,8 +125,9 @@ WHERE wc_id = ?1 AND local_relpath = ?2
 -- STMT_SELECT_NODE_CHILDREN_INFO
 /* Getting rows in an advantageous order using
      ORDER BY local_relpath, op_depth DESC
-   turns out to be slower than getting rows in a random order and making the
-   C code handle it. */
+   doesn't work as the index is created without the DESC keyword.
+   Using both local_relpath and op_depth descending does work without any
+   performance penalty. */
 SELECT op_depth, nodes.repos_id, nodes.repos_path, presence, kind, revision,
   checksum, translated_size, changed_revision, changed_date, changed_author,
   depth, symlink_target, last_mod_time, properties, lock_token, lock_owner,
@@ -128,6 +136,7 @@ FROM nodes
 LEFT OUTER JOIN lock ON nodes.repos_id = lock.repos_id
   AND nodes.repos_path = lock.repos_relpath AND op_depth = 0
 WHERE wc_id = ?1 AND parent_relpath = ?2
+ORDER BY local_relpath DESC, op_depth DESC
 
 -- STMT_SELECT_NODE_CHILDREN_WALKER_INFO
 SELECT local_relpath, op_depth, presence, kind
@@ -191,7 +200,7 @@ WHERE wc_id = ?1
 -- STMT_DELETE_NODE
 DELETE
 FROM NODES
-WHERE wc_id = ?1 AND local_relpath = ?2
+WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth = ?3
 
 -- STMT_DELETE_ACTUAL_FOR_BASE_RECURSIVE
 /* The ACTUAL_NODE applies to BASE, unless there is in at least one op_depth
@@ -318,7 +327,7 @@ WHERE wc_id = ?1 AND op_depth = ?3
 -- STMT_COMMIT_DESCENDANTS_TO_BASE
 UPDATE NODES SET op_depth = 0,
                  repos_id = ?4,
-                 repos_path = ?5 || SUBSTR(local_relpath, LENGTH(?2)+1),
+                 repos_path = RELPATH_SKIP_JOIN(?2, ?5, local_relpath),
                  revision = ?6,
                  dav_cache = NULL,
                  moved_here = NULL,
@@ -417,25 +426,30 @@ LEFT OUTER JOIN nodes AS moved 
 WHERE work.wc_id = ?1 AND work.local_relpath = ?2 AND work.op_depth > 0
 LIMIT 1
 
--- STMT_SELECT_OP_DEPTH_MOVED_TO
-SELECT op_depth, moved_to, repos_path, revision
+-- STMT_SELECT_MOVED_TO_NODE
+SELECT op_depth, moved_to
 FROM nodes
-WHERE wc_id = ?1 AND local_relpath = ?2
- AND op_depth <= (SELECT MIN(op_depth) FROM nodes
-                  WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth > ?3)
+WHERE wc_id = ?1 AND local_relpath = ?2 AND moved_to IS NOT NULL
 ORDER BY op_depth DESC
 
+-- STMT_SELECT_OP_DEPTH_MOVED_TO
+SELECT n.op_depth, n.moved_to, p.repos_path, p.revision
+FROM nodes p
+LEFT JOIN nodes n
+  ON p.wc_id=n.wc_id AND p.local_relpath = n.local_relpath
+ AND  n.op_depth = (SELECT MIN(d.op_depth)
+                    FROM nodes d
+                    WHERE d.wc_id = ?1
+                      AND d.local_relpath = n.local_relpath
+                      AND d.op_depth > ?3)
+WHERE p.wc_id = ?1 AND p.local_relpath = ?2 AND p.op_depth = ?3
+LIMIT 1
+
 -- STMT_SELECT_MOVED_TO
 SELECT moved_to
 FROM nodes
 WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth = ?3
 
--- STMT_SELECT_MOVED_HERE
-SELECT moved_here, presence, repos_path, revision
-FROM nodes
-WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth >= ?3
-ORDER BY op_depth
-
 -- STMT_SELECT_MOVED_BACK
 SELECT u.local_relpath,
        u.presence, u.repos_id, u.repos_path, u.revision,
@@ -461,13 +475,6 @@ WHERE u.wc_id = ?1
   AND IS_STRICT_DESCENDANT_OF(u.local_relpath, ?2)
   AND u.op_depth = ?4
 
--- STMT_DELETE_MOVED_BACK
-DELETE FROM nodes
-WHERE wc_id = ?1
-  AND (local_relpath = ?2
-       OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2))
-  AND op_depth = ?3
-
 -- STMT_DELETE_LOCK
 DELETE FROM lock
 WHERE repos_id = ?1 AND repos_relpath = ?2
@@ -711,7 +718,7 @@ WHERE wc_id = ?1 AND local_relpath = ?2
                   WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth > ?3)
   AND presence = MAP_BASE_DELETED
 
--- STMT_DELETE_ALL_LAYERS
+-- STMT_DELETE_NODE_ALL_LAYERS
 DELETE FROM nodes
 WHERE wc_id = ?1 AND local_relpath = ?2
 
@@ -918,7 +925,7 @@ VALUES (?1, ?2, 0,
             AND op_depth = 0))
 
 -- STMT_INSTALL_WORKING_NODE_FOR_DELETE
-INSERT OR REPLACE INTO nodes (
+INSERT INTO nodes (
     wc_id, local_relpath, op_depth,
     parent_relpath, presence, kind)
 VALUES(?1, ?2, ?3, ?4, MAP_BASE_DELETED, ?5)
@@ -1207,14 +1214,6 @@ VALUES (?1, ?2, ?3, ?4, ?5, ?6)
 
 /* these are used in upgrade.c  */
 
--- STMT_UPDATE_ACTUAL_CONFLICT_DATA
-UPDATE actual_node SET conflict_data = ?3
-WHERE wc_id = ?1 AND local_relpath = ?2
-
--- STMT_INSERT_ACTUAL_CONFLICT_DATA
-INSERT INTO actual_node (wc_id, local_relpath, conflict_data, parent_relpath)
-VALUES (?1, ?2, ?3, ?4)
-
 -- STMT_SELECT_ALL_FILES
 SELECT local_relpath FROM nodes_current
 WHERE wc_id = ?1 AND parent_relpath = ?2 AND kind = MAP_FILE
@@ -1567,20 +1566,6 @@ UPDATE nodes SET moved_to = NULL
  WHERE wc_id = ?1
    AND IS_STRICT_DESCENDANT_OF(moved_to, ?2)
 
-
-/* This statement returns pairs of move-roots below the path ?2 in WC_ID ?1,
- * where the source of the move is within the subtree rooted at path ?2, and
- * the destination of the move is outside the subtree rooted at path ?2. */
--- STMT_SELECT_MOVED_PAIR2
-SELECT local_relpath, moved_to, op_depth FROM nodes
-WHERE wc_id = ?1
-  AND (local_relpath = ?2 OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2))
-  AND moved_to IS NOT NULL
-  AND NOT IS_STRICT_DESCENDANT_OF(moved_to, ?2)
-  AND op_depth >= (SELECT MAX(op_depth) FROM nodes o
-                    WHERE o.wc_id = ?1
-                      AND o.local_relpath = ?2)
-
 -- STMT_SELECT_MOVED_PAIR3
 SELECT local_relpath, moved_to, op_depth, kind FROM nodes
 WHERE wc_id = ?1
@@ -1597,12 +1582,17 @@ WHERE wc_id = ?1
   AND NOT IS_STRICT_DESCENDANT_OF(moved_to, ?2)
 
 -- STMT_SELECT_OP_DEPTH_MOVED_PAIR
-SELECT n.local_relpath, n.moved_to,
-       (SELECT o.repos_path FROM nodes AS o
-        WHERE o.wc_id = n.wc_id
-          AND o.local_relpath = n.local_relpath
-          AND o.op_depth < ?3 ORDER BY o.op_depth DESC LIMIT 1)
+SELECT n.local_relpath, p.kind, n.moved_to, p.repos_path
 FROM nodes AS n
+JOIN (SELECT local_relpath, kind, repos_path
+      FROM nodes AS o
+        WHERE o.wc_id = ?1
+          AND o.op_depth=(SELECT MAX(d.op_depth)
+                          FROM nodes AS d
+                          WHERE d.wc_id = ?1
+                            AND d.local_relpath = o.local_relpath
+                            AND d.op_depth < ?3)) AS p
+  ON n.local_relpath = p.local_relpath
 WHERE n.wc_id = ?1
   AND IS_STRICT_DESCENDANT_OF(n.local_relpath, ?2)
   AND n.op_depth = ?3
@@ -1624,12 +1614,8 @@ WHERE n.wc_id = ?1
   AND h.moved_to IS NOT NULL
 
 -- STMT_COMMIT_UPDATE_ORIGIN
-/* Note that the only reason this SUBSTR() trick is valid is that you
-   can move neither the working copy nor the repository root.
-
-   SUBSTR(local_relpath, LENGTH(?2)+1) includes the '/' of the path */
 UPDATE nodes SET repos_id = ?4,
-                 repos_path = ?5 || SUBSTR(local_relpath, LENGTH(?2)+1),
+                 repos_path = RELPATH_SKIP_JOIN(?2, ?5, local_relpath),
                  revision = ?6
 WHERE wc_id = ?1
   AND (local_relpath = ?2
@@ -1649,14 +1635,16 @@ ORDER BY local_relpath
 
 -- STMT_SELECT_HAS_NON_FILE_CHILDREN
 SELECT 1 FROM nodes
-WHERE wc_id = ?1 AND parent_relpath = ?2 AND op_depth = 0 AND kind != MAP_FILE
+WHERE wc_id = ?1 AND parent_relpath = ?2 AND op_depth = ?3 AND kind != MAP_FILE
+LIMIT 1
 
 -- STMT_SELECT_HAS_GRANDCHILDREN
 SELECT 1 FROM nodes
 WHERE wc_id = ?1
   AND IS_STRICT_DESCENDANT_OF(parent_relpath, ?2)
-  AND op_depth = 0
+  AND op_depth = ?3
   AND file_external IS NULL
+LIMIT 1
 
 /* ------------------------------------------------------------------------- */