Author: rhuijben
Date: Thu Mar 31 12:18:23 2011
New Revision: 1087274

URL: http://svn.apache.org/viewvc?rev=1087274&view=rev
Log:
Simplify the recursion in the commit harvester a bit by moving it to a wc-ng
like code style. Remove the adds_only mode that obfuscates the harvestion by
using a bit more information that is available in wc_db, but was not yet
exposed to the client code.

* subversion/include/private/svn_wc_private.h
  (svn_wc__node_get_commit_status): Add two output arguments.

* subversion/libsvn_client/commit_util.c
  (harvest_committables): Remove client_ctx and add_mode arguments. Add
    cancel and skip arguments. Use svn_wc__node_get_commit_status to get the
    real replacement status instead of using add_mode. Recurse on all children
    to remove an extra sqlite read transaction for every committed node.

* subversion/libsvn_wc/node.c
  (svn_wc__node_get_commit_status): Check replacement and excluded status.

Modified:
    subversion/trunk/subversion/include/private/svn_wc_private.h
    subversion/trunk/subversion/libsvn_client/commit_util.c
    subversion/trunk/subversion/libsvn_wc/node.c

Modified: subversion/trunk/subversion/include/private/svn_wc_private.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_wc_private.h?rev=1087274&r1=1087273&r2=1087274&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_wc_private.h (original)
+++ subversion/trunk/subversion/include/private/svn_wc_private.h Thu Mar 31 
12:18:23 2011
@@ -901,7 +901,9 @@ svn_error_t *
 svn_wc__node_get_commit_status(svn_node_kind_t *kind,
                                svn_boolean_t *added,
                                svn_boolean_t *deleted,
+                               svn_boolean_t *replaced,
                                svn_boolean_t *not_present,
+                               svn_boolean_t *excluded,
                                svn_boolean_t *is_op_root,
                                svn_boolean_t *symlink,
                                svn_revnum_t *revision,

Modified: subversion/trunk/subversion/libsvn_client/commit_util.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/commit_util.c?rev=1087274&r1=1087273&r2=1087274&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/commit_util.c (original)
+++ subversion/trunk/subversion/libsvn_client/commit_util.c Thu Mar 31 12:18:23 
2011
@@ -298,9 +298,9 @@ bail_on_tree_conflicted_ancestor(svn_wc_
 }
 
 
-/* Recursively search for commit candidates in (and under) LOCAL_ABSPATH
-   and add those candidates to COMMITTABLES.  If in ADDS_ONLY modes, only
-   new additions are recognized.
+/* Recursively search for commit candidates in (and under) LOCAL_ABSPATH using
+   WC_CTX and add those candidates to COMMITTABLES.  If in ADDS_ONLY modes,
+   only new additions are recognized.
 
    DEPTH indicates how to treat files and subdirectories of LOCAL_ABSPATH
    when LOCAL_ABSPATH is itself a directory; see
@@ -322,24 +322,27 @@ bail_on_tree_conflicted_ancestor(svn_wc_
    when harvesting committables; that is, don't add a path to
    COMMITTABLES unless it's a member of one of those changelists.
 
-   If CTX->CANCEL_FUNC is non-null, call it with CTX->CANCEL_BATON to see
+   If CANCEL_FUNC is non-null, call it with CANCEL_BATON to see
    if the user has cancelled the operation.
 
    Any items added to COMMITTABLES are allocated from the COMITTABLES
    hash pool, not POOL.  SCRATCH_POOL is used for temporary allocations. */
 static svn_error_t *
-harvest_committables(apr_hash_t *committables,
-                     apr_hash_t *lock_tokens,
+harvest_committables(svn_wc_context_t *wc_ctx,
                      const char *local_abspath,
+                     apr_hash_t *committables,
+                     apr_hash_t *lock_tokens,
                      const char *repos_root_url,
                      const char *commit_relpath,
-                     svn_boolean_t adds_only,
                      svn_boolean_t copy_mode,
                      svn_boolean_t copy_mode_root,
                      svn_depth_t depth,
                      svn_boolean_t just_locked,
                      apr_hash_t *changelists,
-                     svn_client_ctx_t *ctx,
+                     svn_boolean_t skip_files,
+                     svn_boolean_t skip_dirs,
+                     svn_cancel_func_t cancel_func,
+                     void *cancel_baton,
                      apr_pool_t *result_pool,
                      apr_pool_t *scratch_pool)
 {
@@ -357,14 +360,16 @@ harvest_committables(apr_hash_t *committ
   svn_boolean_t is_file_external;
   svn_boolean_t is_added;
   svn_boolean_t is_deleted;
+  svn_boolean_t is_replaced;
   svn_boolean_t is_not_present;
+  svn_boolean_t is_excluded;
+  svn_boolean_t is_op_root;
   svn_boolean_t is_symlink;
   svn_boolean_t conflicted;
   const char *node_changelist;
   svn_boolean_t is_update_root;
   const char *node_copyfrom_relpath;
   svn_revnum_t node_copyfrom_rev;
-  svn_wc_context_t *wc_ctx = ctx->wc_ctx;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
@@ -377,22 +382,27 @@ harvest_committables(apr_hash_t *committ
   SVN_ERR_ASSERT((copy_mode_root && copy_mode) || ! copy_mode_root);
   SVN_ERR_ASSERT((just_locked && lock_tokens) || !just_locked);
 
-  if (ctx->cancel_func)
-    SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
+  if (cancel_func)
+    SVN_ERR(cancel_func(cancel_baton));
 
   /* Return error on unknown path kinds.  We check both the entry and
      the node itself, since a path might have changed kind since its
      entry was written. */
   SVN_ERR(svn_wc__node_get_commit_status(&db_kind, &is_added, &is_deleted,
-                                         &is_not_present, NULL, &is_symlink,
+                                         &is_replaced,
+                                         &is_not_present, &is_excluded,
+                                         &is_op_root, &is_symlink,
                                          &entry_rev, &entry_relpath,
                                          NULL, NULL,
                                          &conflicted,
                                          &node_changelist,
                                          &prop_mod, &is_update_root,
-                                         ctx->wc_ctx, local_abspath,
+                                         wc_ctx, local_abspath,
                                          scratch_pool, scratch_pool));
 
+  if ((skip_files && db_kind == svn_node_file) || is_excluded)
+    return SVN_NO_ERROR;
+
   if (!entry_relpath && commit_relpath)
     entry_relpath = commit_relpath;
 
@@ -447,7 +457,7 @@ harvest_committables(apr_hash_t *committ
 
   if (is_update_root)
     {
-      SVN_ERR(svn_wc__node_is_file_external(&is_file_external, ctx->wc_ctx,
+      SVN_ERR(svn_wc__node_is_file_external(&is_file_external, wc_ctx,
                                             local_abspath, scratch_pool));
       if (is_file_external && copy_mode)
         return SVN_NO_ERROR;
@@ -459,7 +469,7 @@ harvest_committables(apr_hash_t *committ
     {
       svn_boolean_t tc, pc, treec;
 
-      SVN_ERR(svn_wc_conflicted_p3(&tc, &pc, &treec, ctx->wc_ctx,
+      SVN_ERR(svn_wc_conflicted_p3(&tc, &pc, &treec, wc_ctx,
                                    local_abspath, scratch_pool));
       if (tc || pc || treec)
         {
@@ -470,65 +480,23 @@ harvest_committables(apr_hash_t *committ
         }
     }
 
-  SVN_ERR(bail_on_tree_conflicted_children(ctx->wc_ctx, local_abspath,
-                                           db_kind, depth, changelists,
-                                           scratch_pool));
-
   if (entry_relpath == NULL)
     SVN_ERR(svn_wc__node_get_repos_relpath(&entry_relpath,
-                                           ctx->wc_ctx, local_abspath,
+                                           wc_ctx, local_abspath,
                                            scratch_pool, scratch_pool));
   /* Our own URL wins if not in COPY_MODE.  In COPY_MODE the
      telescoping URLs are used. */
   if (! copy_mode)
     commit_relpath = entry_relpath;
 
-  /* Check for the deletion case.  Deletes occur only when not in
-     "adds-only mode".  We use the SVN_CLIENT_COMMIT_ITEM_DELETE flag
-     to represent two slightly different conditions:
-
-     - The entry is marked as 'deleted'.  When copying a mixed-rev wc,
-       we still need to send a delete for that entry, otherwise the
-       object will wrongly exist in the repository copy.
-
-     - The entry is scheduled for deletion or replacement, which case
-       we need to send a delete either way.
-  */
-  if (! adds_only)
-    {
-      svn_boolean_t is_replaced;
-
-      /* ### There is room for optimization here, but let's keep it plain
-       * while this function is in flux. */
-
-      if (!is_added)
-        is_replaced = FALSE;
-      else
-        SVN_ERR(svn_wc__node_is_replaced(&is_replaced, ctx->wc_ctx,
-                                       local_abspath, scratch_pool));
-
-      /* ### Catch a mixed-rev copy that replaces. The mixed-rev children are
-       * each regarded as op-roots of the replace and result in currently
-       * unexpected behaviour. Model wc-1 behaviour, seeing only one copy
-       * target at the root of a mixed-rev copy, via
-       * svn_wc__node_get_copyfrom_info(). */
-      if (is_replaced)
-        {
-          const char *is_copy;
-          svn_boolean_t is_copy_target;
-          /* ### TODO: sensibly align this call of get_copyfrom_info() with
-           * the same call below (when checking added nodes). */
-          SVN_ERR(svn_wc__node_get_copyfrom_info(NULL, NULL, &is_copy, NULL,
-                                                 &is_copy_target, ctx->wc_ctx,
-                                                 local_abspath, scratch_pool,
-                                                 scratch_pool));
-          if (is_copy && ! is_copy_target)
-            is_replaced = FALSE;
-        }
+  /* Check for the deletion case.
+     * We delete explicitly deleted nodes (duh!)
+     * We delete not-present children of copies
+     * We delete nodes that directly replace a node in it's ancestor
+   */
 
-      if (is_deleted || is_replaced || is_not_present)
-        state_flags |= SVN_CLIENT_COMMIT_ITEM_DELETE;
-    }
+  if (is_deleted || is_not_present || is_replaced)
+    state_flags |= SVN_CLIENT_COMMIT_ITEM_DELETE;
 
   /* Check for the trivial addition case.  Adds can be explicit
      (schedule == add) or implicit (schedule == replace ::= delete+add).
@@ -548,12 +516,10 @@ harvest_committables(apr_hash_t *committ
           state_flags |= SVN_CLIENT_COMMIT_ITEM_IS_COPY;
           cf_relpath = node_copyfrom_relpath;
           cf_rev = node_copyfrom_rev;
-          adds_only = FALSE;
         }
       else if (!node_copyfrom_relpath)
         {
           state_flags |= SVN_CLIENT_COMMIT_ITEM_ADD;
-          adds_only = TRUE;
         }
       else
         {
@@ -579,7 +545,6 @@ harvest_committables(apr_hash_t *committ
               state_flags |= SVN_CLIENT_COMMIT_ITEM_IS_COPY;
               cf_relpath = node_copyfrom_relpath;
               cf_rev = node_copyfrom_rev;
-              adds_only = FALSE;
             }
         }
     }
@@ -595,7 +560,7 @@ harvest_committables(apr_hash_t *committ
       svn_revnum_t dir_rev;
 
       if (!copy_mode_root)
-        SVN_ERR(svn_wc__node_get_base_rev(&dir_rev, ctx->wc_ctx,
+        SVN_ERR(svn_wc__node_get_base_rev(&dir_rev, wc_ctx,
                                           svn_dirent_dirname(local_abspath,
                                                              scratch_pool),
                                           scratch_pool));
@@ -608,17 +573,13 @@ harvest_committables(apr_hash_t *committ
               state_flags |= SVN_CLIENT_COMMIT_ITEM_IS_COPY;
               cf_relpath = node_copyfrom_relpath;
               cf_rev = node_copyfrom_rev;
-              adds_only = FALSE;
             }
           else if (entry_rev != SVN_INVALID_REVNUM)
             {
               state_flags |= SVN_CLIENT_COMMIT_ITEM_IS_COPY;
               cf_relpath = entry_relpath;
               cf_rev = entry_rev;
-              adds_only = FALSE;
             }
-          else
-            adds_only = TRUE;
         }
     }
 
@@ -641,7 +602,7 @@ harvest_committables(apr_hash_t *committ
       /* If there are property modifications, check if eol-style changed. */
       if (prop_mod)
         SVN_ERR(check_prop_mods(&prop_mod, &eol_prop_changed, local_abspath,
-                                ctx->wc_ctx, scratch_pool));
+                                wc_ctx, scratch_pool));
 
       /* Regular adds of files have text mods, but for copies we have
          to test for textual mods.  Directories simply don't have text! */
@@ -654,7 +615,7 @@ harvest_committables(apr_hash_t *committ
              prop was changed, we might have to send new text to the
              server to match the new newline style.  */
           if (state_flags & SVN_CLIENT_COMMIT_ITEM_IS_COPY)
-            SVN_ERR(svn_wc_text_modified_p2(&text_mod, ctx->wc_ctx,
+            SVN_ERR(svn_wc_text_modified_p2(&text_mod, wc_ctx,
                                             local_abspath, eol_prop_changed,
                                             scratch_pool));
           else
@@ -672,7 +633,7 @@ harvest_committables(apr_hash_t *committ
       /* See if there are property modifications to send. */
       if (prop_mod)
         SVN_ERR(check_prop_mods(&prop_mod, &eol_prop_changed, local_abspath,
-                                ctx->wc_ctx, scratch_pool));
+                                wc_ctx, scratch_pool));
       else
         eol_prop_changed = FALSE;
 
@@ -683,7 +644,7 @@ harvest_committables(apr_hash_t *committ
          changed, we might have to send new text to the server to
          match the new newline style.  */
       if (db_kind == svn_node_file)
-        SVN_ERR(svn_wc_text_modified_p2(&text_mod, ctx->wc_ctx, local_abspath,
+        SVN_ERR(svn_wc_text_modified_p2(&text_mod, wc_ctx, local_abspath,
                                         eol_prop_changed, scratch_pool));
     }
 
@@ -699,7 +660,7 @@ harvest_committables(apr_hash_t *committ
   if (lock_tokens && (state_flags || just_locked))
     {
       SVN_ERR(svn_wc__node_get_lock_info(&entry_lock_token, NULL, NULL, NULL,
-                                         ctx->wc_ctx, local_abspath,
+                                         wc_ctx, local_abspath,
                                          apr_hash_pool_get(lock_tokens),
                                          scratch_pool));
       if (entry_lock_token)
@@ -728,102 +689,73 @@ harvest_committables(apr_hash_t *committ
         }
     }
 
-  /* For directories, recursively handle each entry according to depth
-     (except when the directory is being deleted, unless the deletion
-     is part of a replacement ... how confusing).  */
-  if ((db_kind == svn_node_dir) && (depth > svn_depth_empty)
-      && ((! (state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE))
-          || (state_flags & SVN_CLIENT_COMMIT_ITEM_ADD)))
+  if (db_kind != svn_node_dir || depth <= svn_depth_empty)
+    return SVN_NO_ERROR;
+
+  SVN_ERR(bail_on_tree_conflicted_children(wc_ctx, local_abspath,
+                                           db_kind, depth, changelists,
+                                           scratch_pool));
+
+  /* Recursively handle each node according to depth, except when the
+     node is only being deleted. */
+  if ((! (state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE))
+      || (state_flags & SVN_CLIENT_COMMIT_ITEM_ADD))
     {
       const apr_array_header_t *children;
       apr_pool_t *iterpool = svn_pool_create(scratch_pool);
       int i;
+      svn_boolean_t skip_files;
+      svn_boolean_t skip_dirs;
+      svn_depth_t depth_below_here = depth;
+
+      skip_files = (depth < svn_depth_files);
+      skip_dirs = (depth < svn_depth_immediates);
+
+      if (depth < svn_depth_infinity)
+        depth_below_here = svn_depth_empty; /* Stop recursing */
 
       SVN_ERR(svn_wc__node_get_children_of_working_node(
-                &children, ctx->wc_ctx, local_abspath, copy_mode,
+                &children, wc_ctx, local_abspath, copy_mode,
                 scratch_pool, iterpool));
       for (i = 0; i < children->nelts; i++)
         {
           const char *this_abspath = APR_ARRAY_IDX(children, i, const char *);
           const char *name = svn_dirent_basename(this_abspath, NULL);
-          const char *this_repos_relpath;
-          
-          svn_node_kind_t this_kind;
+          const char *this_commit_relpath;
 
           svn_pool_clear(iterpool);
 
-          /* In copy-mode we see hidden nodes, so we have to filter them.*/
-          if (copy_mode)
-            {
-              svn_boolean_t this_excluded;
-
-              /* Skip excluded nodes. */
-              SVN_ERR(svn_wc__node_is_status_excluded(&this_excluded,
-                                                      ctx->wc_ctx,
-                                                      this_abspath, iterpool));
-              if (this_excluded)
-                continue;
-            }
-
-          this_repos_relpath = svn_relpath_join(commit_relpath, name,
-                                                iterpool);
-
-          /* Recurse. */
-          SVN_ERR(svn_wc_read_kind(&this_kind, ctx->wc_ctx, this_abspath,
-                                   TRUE, iterpool));
-          if (this_kind == svn_node_dir)
-            {
-              if (depth <= svn_depth_files)
-                {
-                  /* Don't bother with any of this if it's a directory
-                     and depth says not to go there. */
-                  continue;
-                }
-            }
-
-          {
-            svn_depth_t depth_below_here = depth;
-
-            /* If depth is svn_depth_files, then we must be recursing
-               into a file, or else we wouldn't be here -- either way,
-               svn_depth_empty is the right depth to use.  On the
-               other hand, if depth is svn_depth_immediates, then we
-               could be recursing into a directory or a file -- in
-               which case svn_depth_empty is *still* the right depth
-               to use.  I know that sounds bizarre (one normally
-               expects to just do depth - 1) but it's correct. */
-            if (depth == svn_depth_immediates
-                || depth == svn_depth_files)
-              depth_below_here = svn_depth_empty;
-
-            SVN_ERR(harvest_committables(committables, lock_tokens,
-                                         this_abspath,
-                                         repos_root_url,
-                                         copy_mode ? this_repos_relpath : NULL,
-                                         adds_only,
-                                         copy_mode,
-                                         FALSE, /* COPY_MODE_ROOT */
-                                         depth_below_here,
-                                         just_locked,
-                                         changelists,
-                                         ctx,
-                                         result_pool,
-                                         iterpool));
-          }
+          if (commit_relpath != NULL)
+            this_commit_relpath = svn_relpath_join(commit_relpath, name,
+                                                   iterpool);
+
+          SVN_ERR(harvest_committables(wc_ctx, this_abspath,
+                                       committables, lock_tokens,
+                                       repos_root_url,
+                                       copy_mode ? this_commit_relpath : NULL,
+                                       copy_mode,
+                                       FALSE, /* COPY_MODE_ROOT */
+                                       depth_below_here,
+                                       just_locked,
+                                       changelists,
+                                       skip_files, skip_dirs,
+                                       cancel_func, cancel_baton,
+                                       result_pool,
+                                       iterpool));
         }
 
       svn_pool_destroy(iterpool);
     }
 
   /* Fetch lock tokens for descendants of deleted directories. */
-  if (lock_tokens && db_kind == svn_node_dir
+  if (lock_tokens
       && (state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE))
     {
       apr_hash_t *local_relpath_tokens;
       apr_hash_index_t *hi;
 
       SVN_ERR(svn_wc__node_get_lock_tokens_recursive(
-                  &local_relpath_tokens, ctx->wc_ctx, local_abspath,
+                  &local_relpath_tokens, wc_ctx, local_abspath,
                   scratch_pool, scratch_pool));
 
       /* Map local_relpaths to URLs. */
@@ -836,10 +768,10 @@ harvest_committables(apr_hash_t *committ
           const char *item_url;
           apr_pool_t *token_pool = apr_hash_pool_get(lock_tokens);
 
-          if (ctx->cancel_func)
-            SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
+          if (cancel_func)
+            SVN_ERR(cancel_func(cancel_baton));
 
-          SVN_ERR(svn_wc__node_get_url(&item_url, ctx->wc_ctx, item_abspath,
+          SVN_ERR(svn_wc__node_get_url(&item_url, wc_ctx, item_abspath,
                                        token_pool, scratch_pool));
           if (item_url)
             apr_hash_set(lock_tokens, item_url, APR_HASH_KEY_STRING,
@@ -1021,13 +953,15 @@ svn_client__harvest_committables(apr_has
       SVN_ERR(bail_on_tree_conflicted_ancestor(ctx->wc_ctx, target_abspath,
                                                iterpool));
 
-      SVN_ERR(harvest_committables(*committables, *lock_tokens, target_abspath,
+      SVN_ERR(harvest_committables(ctx->wc_ctx, target_abspath,
+                                   *committables, *lock_tokens, 
                                    repos_root_url, NULL,
-                                   FALSE, /* ADDS_ONLY */
                                    FALSE, /* COPY_MODE */
                                    FALSE, /* COPY_MODE_ROOT */
                                    depth, just_locked, changelist_hash,
-                                   ctx, result_pool, iterpool));
+                                   FALSE, FALSE,
+                                   ctx->cancel_func, ctx->cancel_baton,
+                                   result_pool, iterpool));
     }
 
   /* Make sure that every path in danglers is part of the commit. */
@@ -1068,15 +1002,18 @@ harvest_copy_committables(void *baton, v
                                        pool);
 
   /* Handle this SRC. */
-  return harvest_committables(btn->committables, NULL,
+  return harvest_committables(btn->ctx->wc_ctx,
                               pair->src_abspath_or_url,
+                              btn->committables, NULL,
                               repos_root_url, commit_relpath,
-                              FALSE, /* ADDS_ONLY */
                               TRUE,  /* COPY_MODE */
                               TRUE,  /* COPY_MODE_ROOT */
                               svn_depth_infinity,
                               FALSE,  /* JUST_LOCKED */
-                              NULL, btn->ctx,
+                              NULL,
+                              FALSE, FALSE, /* skip files, dirs */
+                              btn->ctx->cancel_func,
+                              btn->ctx->cancel_baton,
                               btn->result_pool, pool);
 }
 

Modified: subversion/trunk/subversion/libsvn_wc/node.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/node.c?rev=1087274&r1=1087273&r2=1087274&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/node.c (original)
+++ subversion/trunk/subversion/libsvn_wc/node.c Thu Mar 31 12:18:23 2011
@@ -1594,7 +1594,9 @@ svn_error_t *
 svn_wc__node_get_commit_status(svn_node_kind_t *kind,
                                svn_boolean_t *added,
                                svn_boolean_t *deleted,
+                               svn_boolean_t *is_replace_root,
                                svn_boolean_t *not_present,
+                               svn_boolean_t *excluded,
                                svn_boolean_t *is_op_root,
                                svn_boolean_t *symlink,
                                svn_revnum_t *revision,
@@ -1638,6 +1640,18 @@ svn_wc__node_get_commit_status(svn_node_
     *deleted = (status == svn_wc__db_status_deleted);
   if (not_present)
     *not_present = (status == svn_wc__db_status_not_present);
+  if (excluded)
+    *excluded = (status == svn_wc__db_status_excluded);
+
+  if (is_replace_root)
+    {
+      if (status == svn_wc__db_status_added)
+        SVN_ERR(svn_wc__db_node_check_replace(is_replace_root, NULL, NULL,
+                                              wc_ctx->db, local_abspath,
+                                              scratch_pool));
+      else
+        *is_replace_root = FALSE;
+    }
 
   if (is_op_root)
     {


Reply via email to