Author: stsp
Date: Mon Mar 28 23:15:34 2011
New Revision: 1086438

URL: http://svn.apache.org/viewvc?rev=1086438&view=rev
Log:
During post-commit processing, rather than deleting any deleted child node
of a replaced directory, delete only those which were in fact deleted as
part of a replacement.

This is needed for upcoming work on issue #3699, "svn commit does not
respect --depth option for copied directories".

* subversion/libsvn_wc/wc-queries.sql
  (STMT_SELECT_REPLACED_CHILDREN_FOR_DELETION): New query.

* subversion/libsvn_wc/wc_db.c
  subversion/libsvn_wc/wc_db.h:
  (svn_wc__db_read_replaced_children): New function that lists all nodes
   beneath a replaced directory were deleted as part of the replacement.

* subversion/libsvn_wc/workqueue.c
  (log_do_committed): Let the svn_wc__db_read_replaced_children() figure out
   which children were deleted as part of a replacement, and delete them.
   Adjust various comments accordingly.
   Also note in a comment that a better approach might be to have the DB
   layer recursively delete these children itself.

Modified:
    subversion/trunk/subversion/libsvn_wc/wc-queries.sql
    subversion/trunk/subversion/libsvn_wc/wc_db.c
    subversion/trunk/subversion/libsvn_wc/wc_db.h
    subversion/trunk/subversion/libsvn_wc/workqueue.c

Modified: subversion/trunk/subversion/libsvn_wc/wc-queries.sql
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc-queries.sql?rev=1086438&r1=1086437&r2=1086438&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/trunk/subversion/libsvn_wc/wc-queries.sql Mon Mar 28 23:15:34 
2011
@@ -162,6 +162,14 @@ UNION
 SELECT 1 FROM ACTUAL_NODE
 WHERE wc_id = ?1 AND parent_relpath = ?2
 
+-- STMT_SELECT_REPLACED_CHILDREN_FOR_DELETION
+SELECT local_relpath FROM nodes
+WHERE wc_id = ?1 AND parent_relpath = ?2 AND op_depth <= ?3
+  AND presence = 'base-deleted'
+  AND local_relpath NOT IN (
+    SELECT local_relpath FROM nodes
+    WHERE wc_id = ?1 AND parent_relpath = ?2 AND op_depth > ?3)
+
 -- STMT_SELECT_NODE_CHILDREN
 /* Return all paths that are children of the directory (?1, ?2) in any
    op-depth, including children of any underlying, replaced directories. */

Modified: subversion/trunk/subversion/libsvn_wc/wc_db.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.c?rev=1086438&r1=1086437&r2=1086438&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db.c Mon Mar 28 23:15:34 2011
@@ -5753,6 +5753,61 @@ svn_wc__db_read_children_of_working_node
 
 
 svn_error_t *
+svn_wc__db_read_replaced_children(const apr_array_header_t **children,
+                                  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;
+  apr_int64_t op_depth;
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+  apr_array_header_t *result
+    = apr_array_make(result_pool, 0, sizeof(const char *));
+
+  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);
+
+  /* Gather deleted children with smaller or equal op_depth as this
+   * added node, for which no rows with greater op_depth exist.
+   *
+   * Any such children were deleted as part of a replace operation -- either
+   * on this directory (equal op_depth), or a parent directory (smaller
+   * op_depth; this implies that this added node is a nested replacement).
+   * Children deleted post-replace have a higher op_depth.
+   *
+   * It's OK if we find no children -- either this was a plain addition,
+   * or the replaced directory was empty. */
+  SVN_ERR(op_depth_of(&op_depth, wcroot, local_relpath));
+  SVN_ERR(svn_sqlite__get_statement(
+            &stmt, wcroot->sdb, STMT_SELECT_REPLACED_CHILDREN_FOR_DELETION));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isi", wcroot->wc_id, local_relpath,
+                            op_depth));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+  while (have_row)
+    {
+      const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
+
+      /* Allocate the name in RESULT_POOL so we won't have to copy it. */
+      APR_ARRAY_PUSH(result, const char *)
+        = svn_relpath_basename(child_relpath, result_pool);
+
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+    }
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  *children = result;
+  return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
 svn_wc__db_read_children(const apr_array_header_t **children,
                          svn_wc__db_t *db,
                          const char *local_abspath,

Modified: subversion/trunk/subversion/libsvn_wc/wc_db.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.h?rev=1086438&r1=1086437&r2=1086438&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db.h (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db.h Mon Mar 28 23:15:34 2011
@@ -1665,6 +1665,31 @@ svn_wc__db_read_children_of_working_node
                                          apr_pool_t *result_pool,
                                          apr_pool_t *scratch_pool);
 
+/* Set *CHILDREN to a new array of the (const char *) basenames of the
+   immediate children of the working node at LOCAL_ABSPATH in DB which
+   where deleted as part of a replacement.
+
+   Return every path that refers to a child of the working node at
+   LOCAL_ABSPATH. Do not include paths that were not deleted due to
+   the replacement of LOCAL_ABSPATH.
+
+   ### This function is used during post-commit processing of replaced
+   ### directories and should probably not be called from elsewhere.
+   ### No attempt is made to verify that LOCAL_ABSPATH has in fact been
+   ### replaced. This allows the post-commit code to traverse the replaced
+   ### tree top-down and delete parent nodes from the DB before their
+   ### children have been removed (scan_addition() would fail in this case
+   ### since parent nodes, including the op_root, have disappeared).
+
+   Allocate *CHILDREN in RESULT_POOL and do temporary allocations in
+   SCRATCH_POOL. */
+svn_error_t *
+svn_wc__db_read_replaced_children(const apr_array_header_t **children,
+                                  svn_wc__db_t *db,
+                                  const char *local_abspath,
+                                  apr_pool_t *result_pool,
+                                  apr_pool_t *scratch_pool);
+
 /* Like svn_wc__db_read_children_of_working_node(), except also include any
    path that was a child of a deleted directory that existed at
    LOCAL_ABSPATH, even if that directory is now scheduled to be replaced by

Modified: subversion/trunk/subversion/libsvn_wc/workqueue.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/workqueue.c?rev=1086438&r1=1086437&r2=1086438&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/workqueue.c (original)
+++ subversion/trunk/subversion/libsvn_wc/workqueue.c Mon Mar 28 23:15:34 2011
@@ -916,7 +916,7 @@ install_committed_file(svn_boolean_t *ov
 /* Set the base version of the node LOCAL_ABSPATH to be the same as its
  * working version currently is:
  *
- * - Remove children that are marked deleted (if it's a dir)
+ * - Remove children deleted as part of a replacement (if it's a dir)
  * - Install the new base props
  * - Install the new tree state
  * - Install the new base text (if it's a file)
@@ -986,57 +986,51 @@ log_do_committed(svn_wc__db_t *db,
      ### Thus, we're simply looking for status == svn_wc__db_status_added
 
      If "this dir" has been replaced (delete + add), remove those of
-     its children that are marked for deletion.
+     its children that were marked for deletion as part of the replace
+     operation of "this dir".
 
      All its immmediate children *must* be either scheduled for deletion
      (they were children of "this dir" during the "delete" phase of its
-     replacement), added (they are new children of the replaced dir),
+     replacement, in which case we delete them, or they were deleted
+     post-replace, in which case we leave them alone),
+     added (they are new children of the replaced dir),
      or replaced (they are new children of the replace dir that have
      the same names as children that were present during the "delete"
      phase of the replacement).
 
-     Children which are added or replaced will have been reported as
-     individual commit targets, and thus will be re-visited by
-     log_do_committed().  Children which were marked for deletion,
-     however, need to be outright removed from revision control.  */
+     Children which are added, or replaced, or deleted post-replace, will
+     have been reported as individual commit targets, and thus will be
+     re-visited by log_do_committed().  Children which were marked for
+     deletion as part of the replacement of "this dir", however, need to
+     be outright removed from revision control.  */
 
   if (status == svn_wc__db_status_added && kind == svn_wc__db_kind_dir)
     {
-      /* Loop over all children entries, look for items scheduled for
-         deletion. */
+      /* Loop over all replaced children. */
       const apr_array_header_t *children;
       int i;
       apr_pool_t *iterpool = svn_pool_create(pool);
 
-      SVN_ERR(svn_wc__db_read_children(&children, db, local_abspath,
-                                       pool, pool));
+      /* ### We should probably have a function that recursively deletes
+       * ### these children, instead of just listing them. */
+      SVN_ERR(svn_wc__db_read_replaced_children(&children, db, local_abspath,
+                                                pool, pool));
 
       for (i = 0; i < children->nelts; i++)
         {
           const char *child_name = APR_ARRAY_IDX(children, i, const char*);
           const char *child_abspath;
-          svn_wc__db_status_t child_status;
 
           svn_pool_clear(iterpool);
           child_abspath = svn_dirent_join(local_abspath, child_name, iterpool);
 
-          SVN_ERR(svn_wc__db_read_info(&child_status,
-                                       NULL, NULL, NULL, NULL, NULL,
-                                       NULL, NULL, NULL, NULL, NULL, NULL,
-                                       NULL, NULL, NULL, NULL, NULL, NULL,
-                                       NULL, NULL, NULL, NULL, NULL, NULL,
-                                       db, child_abspath, iterpool, iterpool));
-
           /* Committing a deletion should remove the local nodes.  */
-          if (child_status == svn_wc__db_status_deleted)
-            {
-              SVN_ERR(svn_wc__internal_remove_from_revision_control(
-                        db, child_abspath,
-                        FALSE /* destroy_wf */,
-                        FALSE /* instant_error */,
-                        cancel_func, cancel_baton,
-                        iterpool));
-            }
+          SVN_ERR(svn_wc__internal_remove_from_revision_control(
+                    db, child_abspath,
+                    FALSE /* destroy_wf */,
+                    FALSE /* instant_error */,
+                    cancel_func, cancel_baton,
+                    iterpool));
         }
 
       svn_pool_destroy(iterpool);


Reply via email to