Hi,

See attached the patch to fix issue 4364.

[[[
Fix issue #4364: Correctly remove the stale entries from the lock table when 
committing deletions.

* subversion/libsvn_client/commit.c
  (post_process_commit_item): always pass the flag to remove locks for deleted 
and replaced items.

* subversion/libsvn_wc/wc-queries.sql
  Add a new query which removes all lock rows recursively for a node.

* subversion/libsvn_wc/wc_db.h
  (svn_wc__db_base_remove): Add a new parameter remove_locks to recursively 
remove the lock rows.

* subversion/libsvn_wc/wc_db.c
  (svn_wc__db_base_remove): Forward the new remove_locks parameter to 
db_base_remove.
  (db_base_remove): Add and implement remove_locks.
  (commit_node): Also remove the locks recursively for subnodes of the current 
node.
  (bump_node_revision): Pass FALSE for remove_locks to get the old default 
behaviour.

* subversion/libsvn_wc/adm_ops.c
  (process_committed_leaf): In the shortcut for deleted nodes, pass TRUE to 
remove the locks recursively.

* subversion/libsvn_wc/crop.c
  (crop_children): Pass FALSE for remove_locks to get the old default behaviour.

* subversion/libsvn_wc/externals.c
  (svn_wc__external_remove): Pass FALSE for remove_locks to get the old default 
behaviour.

* subversion/libsvn_wc/update_editor.c
  (delete_entry, close_edit): Pass FALSE for remove_locks to get the old 
default behaviour.

* subversion/libsvn_wc/workqueue.c
  (run_base_remove): Pass FALSE for remove_locks to get the old default 
behaviour.

* subversion/tests/libsvn_wc/op-depth-test.c
  (base_dir_insert_remove): Pass FALSE for remove_locks to get the old default 
behaviour.

* subversion/tests/cmdline/lock_tests.py
  (def drop_locks_on_parent_deletion): Provide a regression test which catches 
reappearing locks.

]]]


Best regards

Markus Schaber

(This email was sent from a mobile device...)

CODESYS® a trademark of 3S-Smart Software Solutions GmbH

Inspiring Automation Solutions
________________________________
3S-Smart Software Solutions GmbH
Dipl.-Inf. Markus Schaber | Product Development Core Technology
Memminger Str. 151 | 87439 Kempten | Germany
Tel. +49-831-54031-979 | Fax +49-831-54031-50

E-Mail: m.scha...@codesys.com | Web: codesys.com
CODESYS internet forum: forum.codesys.com

Managing Directors: Dipl.Inf. Dieter Hess, Dipl.Inf. Manfred Werner | Trade 
register: Kempten HRB 6186 | Tax ID No.: DE 167014915
Index: subversion/libsvn_client/commit.c
===================================================================
diff --git a/subversion/trunk/subversion/libsvn_client/commit.c 
b/subversion/trunk/subversion/libsvn_client/commit.c
--- a/subversion/trunk/subversion/libsvn_client/commit.c        (Revision 
1491372)
+++ b/subversion/trunk/subversion/libsvn_client/commit.c        (Arbeitskopie)
@@ -240,6 +240,12 @@ post_process_commit_item(svn_wc_committed_queue_t
   remove_lock = (! keep_locks && (item->state_flags
                                        & SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN));
 
+  // When the node was deleted (or replaced), we need to always remove the 
+  // locks, as they're invalidated on the server. We cannot honor the 
+  // SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN flag here because it does not tell
+  // us whether we have locked children.
+  remove_lock |= (item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE) != 0;
+
   return svn_wc_queue_committed3(queue, wc_ctx, item->path,
                                  loop_recurse, item->incoming_prop_changes,
                                  remove_lock, !keep_changelists,
Index: subversion/libsvn_wc/adm_ops.c
===================================================================
diff --git a/subversion/trunk/subversion/libsvn_wc/adm_ops.c 
b/subversion/trunk/subversion/libsvn_wc/adm_ops.c
--- a/subversion/trunk/subversion/libsvn_wc/adm_ops.c   (Revision 1491372)
+++ b/subversion/trunk/subversion/libsvn_wc/adm_ops.c   (Arbeitskopie)
@@ -148,6 +148,7 @@ process_committed_leaf(svn_wc__db_t *db,
                                 db, local_abspath,
                                 FALSE /* keep_as_working */,
                                 FALSE /* queue_deletes */,
+                                TRUE  /* remove_locks */,
                                 (! via_recurse)
                                     ? new_revnum : SVN_INVALID_REVNUM,
                                 NULL, NULL,
Index: subversion/libsvn_wc/crop.c
===================================================================
diff --git a/subversion/trunk/subversion/libsvn_wc/crop.c 
b/subversion/trunk/subversion/libsvn_wc/crop.c
--- a/subversion/trunk/subversion/libsvn_wc/crop.c      (Revision 1491372)
+++ b/subversion/trunk/subversion/libsvn_wc/crop.c      (Arbeitskopie)
@@ -110,6 +110,7 @@ crop_children(svn_wc__db_t *db,
             SVN_ERR(svn_wc__db_base_remove(db, child_abspath,
                                            FALSE /* keep_as_working */,
                                            FALSE /* queue_deletes */,
+                                           FALSE /* remove_locks */,
                                            SVN_INVALID_REVNUM,
                                            NULL, NULL, iterpool));
 
Index: subversion/libsvn_wc/externals.c
===================================================================
diff --git a/subversion/trunk/subversion/libsvn_wc/externals.c 
b/subversion/trunk/subversion/libsvn_wc/externals.c
--- a/subversion/trunk/subversion/libsvn_wc/externals.c (Revision 1491372)
+++ b/subversion/trunk/subversion/libsvn_wc/externals.c (Arbeitskopie)
@@ -1413,6 +1413,7 @@ svn_wc__external_remove(svn_wc_context_t *wc_ctx,
       SVN_ERR(svn_wc__db_base_remove(wc_ctx->db, local_abspath,
                                      FALSE /* keep_as_working */,
                                      TRUE /* queue_deletes */,
+                                     FALSE /* remove_locks */,
                                      SVN_INVALID_REVNUM,
                                      NULL, NULL, scratch_pool));
       SVN_ERR(svn_wc__wq_run(wc_ctx->db, local_abspath,
Index: subversion/libsvn_wc/update_editor.c
===================================================================
diff --git a/subversion/trunk/subversion/libsvn_wc/update_editor.c 
b/subversion/trunk/subversion/libsvn_wc/update_editor.c
--- a/subversion/trunk/subversion/libsvn_wc/update_editor.c     (Revision 
1491372)
+++ b/subversion/trunk/subversion/libsvn_wc/update_editor.c     (Arbeitskopie)
@@ -1813,6 +1813,7 @@ delete_entry(const char *path,
       SVN_ERR(svn_wc__db_base_remove(eb->db, local_abspath,
                                      FALSE /* keep_as_working */,
                                      FALSE /* queue_deletes */,
+                                     FALSE /* remove_locks */,
                                      SVN_INVALID_REVNUM /* not_present_rev */,
                                      NULL, NULL,
                                      scratch_pool));
@@ -1909,7 +1910,7 @@ delete_entry(const char *path,
     {
       /* Delete, and do not leave a not-present node.  */
       SVN_ERR(svn_wc__db_base_remove(eb->db, local_abspath,
-                                     keep_as_working, queue_deletes,
+                                     keep_as_working, queue_deletes, FALSE,
                                      SVN_INVALID_REVNUM /* not_present_rev */,
                                      tree_conflict, NULL,
                                      scratch_pool));
@@ -1918,7 +1919,7 @@ delete_entry(const char *path,
     {
       /* Delete, leaving a not-present node.  */
       SVN_ERR(svn_wc__db_base_remove(eb->db, local_abspath,
-                                     keep_as_working, queue_deletes,
+                                     keep_as_working, queue_deletes, FALSE,
                                      *eb->target_revision,
                                      tree_conflict, NULL,
                                      scratch_pool));
@@ -4701,6 +4702,7 @@ close_edit(void *edit_baton,
               SVN_ERR(svn_wc__db_base_remove(eb->db, eb->target_abspath,
                                              FALSE /* keep_as_working */,
                                              FALSE /* queue_deletes */,
+                                             FALSE /* remove_locks */,
                                              SVN_INVALID_REVNUM,
                                              NULL, NULL, scratch_pool));
             }
Index: subversion/libsvn_wc/wc-queries.sql
===================================================================
diff --git a/subversion/trunk/subversion/libsvn_wc/wc-queries.sql 
b/subversion/trunk/subversion/libsvn_wc/wc-queries.sql
--- a/subversion/trunk/subversion/libsvn_wc/wc-queries.sql      (Revision 
1491372)
+++ b/subversion/trunk/subversion/libsvn_wc/wc-queries.sql      (Arbeitskopie)
@@ -472,6 +472,10 @@ WHERE wc_id = ?1
 DELETE FROM lock
 WHERE repos_id = ?1 AND repos_relpath = ?2
 
+-- STMT_DELETE_LOCK_RECURSIVELY
+DELETE FROM lock
+WHERE repos_id = ?1 AND (repos_relpath = ?2 OR 
IS_STRICT_DESCENDANT_OF(repos_relpath, ?2))
+
 -- STMT_CLEAR_BASE_NODE_RECURSIVE_DAV_CACHE
 UPDATE nodes SET dav_cache = NULL
 WHERE dav_cache IS NOT NULL AND wc_id = ?1 AND op_depth = 0
Index: subversion/libsvn_wc/wc_db.c
===================================================================
diff --git a/subversion/trunk/subversion/libsvn_wc/wc_db.c 
b/subversion/trunk/subversion/libsvn_wc/wc_db.c
--- a/subversion/trunk/subversion/libsvn_wc/wc_db.c     (Revision 1491372)
+++ b/subversion/trunk/subversion/libsvn_wc/wc_db.c     (Arbeitskopie)
@@ -2086,6 +2086,7 @@ db_base_remove(svn_wc__db_wcroot_t *wcroot,
                svn_wc__db_t *db, /* For checking conflicts */
                svn_boolean_t keep_as_working,
                svn_boolean_t queue_deletes,
+               svn_boolean_t remove_locks,
                svn_revnum_t not_present_revision,
                svn_skel_t *conflict,
                svn_skel_t *work_items,
@@ -2106,6 +2107,16 @@ db_base_remove(svn_wc__db_wcroot_t *wcroot,
                                             wcroot, local_relpath,
                                             scratch_pool, scratch_pool));
 
+  if (remove_locks)
+    {
+      svn_sqlite__stmt_t *lock_stmt;
+
+      SVN_ERR(svn_sqlite__get_statement(&lock_stmt, wcroot->sdb,
+                                        STMT_DELETE_LOCK_RECURSIVELY));
+      SVN_ERR(svn_sqlite__bindf(lock_stmt, "is", repos_id, repos_relpath));
+      SVN_ERR(svn_sqlite__step_done(lock_stmt));
+    }
+
   if (status == svn_wc__db_status_normal
       && keep_as_working)
     {
@@ -2333,6 +2344,7 @@ svn_wc__db_base_remove(svn_wc__db_t *db,
                        const char *local_abspath,
                        svn_boolean_t keep_as_working,
                        svn_boolean_t queue_deletes,
+                       svn_boolean_t remove_locks,
                        svn_revnum_t not_present_revision,
                        svn_skel_t *conflict,
                        svn_skel_t *work_items,
@@ -2349,7 +2361,7 @@ svn_wc__db_base_remove(svn_wc__db_t *db,
 
   SVN_WC__DB_WITH_TXN(db_base_remove(wcroot, local_relpath,
                                      db, keep_as_working, queue_deletes,
-                                     not_present_revision,
+                                     remove_locks, not_present_revision,
                                      conflict, work_items, scratch_pool),
                       wcroot);
 
@@ -10814,7 +10826,7 @@ commit_node(svn_wc__db_wcroot_t *wcroot,
       svn_sqlite__stmt_t *lock_stmt;
 
       SVN_ERR(svn_sqlite__get_statement(&lock_stmt, wcroot->sdb,
-                                        STMT_DELETE_LOCK));
+                                        STMT_DELETE_LOCK_RECURSIVELY));
       SVN_ERR(svn_sqlite__bindf(lock_stmt, "is", repos_id, repos_relpath));
       SVN_ERR(svn_sqlite__step_done(lock_stmt));
     }
@@ -11058,7 +11070,7 @@ bump_node_revision(svn_wc__db_wcroot_t *wcroot,
               revision != new_rev)))
     {
       return svn_error_trace(db_base_remove(wcroot, local_relpath,
-                                            db, FALSE, FALSE,
+                                            db, FALSE, FALSE, FALSE,
                                             SVN_INVALID_REVNUM,
                                             NULL, NULL, scratch_pool));
     }
Index: subversion/libsvn_wc/wc_db.h
===================================================================
diff --git a/subversion/trunk/subversion/libsvn_wc/wc_db.h 
b/subversion/trunk/subversion/libsvn_wc/wc_db.h
--- a/subversion/trunk/subversion/libsvn_wc/wc_db.h     (Revision 1491372)
+++ b/subversion/trunk/subversion/libsvn_wc/wc_db.h     (Arbeitskopie)
@@ -702,6 +702,9 @@ svn_wc__db_base_add_not_present_node(svn_wc__db_t
    (With KEEP_AS_WORKING TRUE, this is a no-op, as everything is
     automatically shadowed by the created copy)
 
+   If REMOVE_LOCKS is TRUE, all locks of this node and any subnodes
+   are also removed. This is to be done during commit of deleted nodes.
+
    If NOT_PRESENT_REVISION specifies a valid revision a not-present
    node is installed in BASE node with kind NOT_PRESENT_KIND after
    deleting.
@@ -715,6 +718,7 @@ svn_wc__db_base_remove(svn_wc__db_t *db,
                        const char *local_abspath,
                        svn_boolean_t keep_as_working,
                        svn_boolean_t queue_deletes,
+                       svn_boolean_t remove_locks,
                        svn_revnum_t not_present_revision,
                        svn_skel_t *conflict,
                        svn_skel_t *work_items,
Index: subversion/libsvn_wc/workqueue.c
===================================================================
diff --git a/subversion/trunk/subversion/libsvn_wc/workqueue.c 
b/subversion/trunk/subversion/libsvn_wc/workqueue.c
--- a/subversion/trunk/subversion/libsvn_wc/workqueue.c (Revision 1491372)
+++ b/subversion/trunk/subversion/libsvn_wc/workqueue.c (Arbeitskopie)
@@ -143,6 +143,7 @@ run_base_remove(work_item_baton_t *wqb,
   SVN_ERR(svn_wc__db_base_remove(db, local_abspath,
                                  FALSE /* keep_as_working */,
                                  TRUE /* queue_deletes */,
+                                 FALSE /* remove_locks */,
                                  not_present_rev,
                                  NULL, NULL, scratch_pool));
 
Index: subversion/tests/cmdline/lock_tests.py
===================================================================
diff --git a/subversion/trunk/subversion/tests/cmdline/lock_tests.py 
b/subversion/trunk/subversion/tests/cmdline/lock_tests.py
--- a/subversion/trunk/subversion/tests/cmdline/lock_tests.py   (Revision 
1491372)
+++ b/subversion/trunk/subversion/tests/cmdline/lock_tests.py   (Arbeitskopie)
@@ -1840,6 +1840,56 @@ def commit_stolen_lock(sbox):
                                         err_re,
                                         wc_dir)
 
+# When removing directories, the locks of contained files were not 
+# correctly removed from the working copy database, thus they later 
+# magically reappeared when new files or directories with the same
+# pathes were added.
+@Issue(4364)
+def drop_locks_on_parent_deletion(sbox):
+  "drop locks when the parent is deleted"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  # lock some files, and remove them.
+  sbox.simple_lock('A/B/lambda')
+  sbox.simple_lock('A/B/E/alpha')
+  sbox.simple_lock('A/B/E/beta')
+  sbox.simple_rm('A/B')
+  
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.remove_subtree('A/B')
+  
+  svntest.actions.run_and_verify_commit(wc_dir,
+                                        [],
+                                        expected_status,
+                                        None,
+                                        wc_dir)
+
+  # now re-add entities to the deleted pathes.
+  sbox.simple_mkdir('A/B')
+  sbox.simple_add_text('new file replacing old file', 'A/B/lambda')
+  sbox.simple_add_text('file replacing former dir', 'A/B/F')
+  # The bug also resurrected locks on directories when their path
+  # matched a former file.
+  sbox.simple_mkdir('A/B/E', 'A/B/E/alpha')
+    
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.tweak('A/B',
+                                               'A/B/E',
+                                               'A/B/E/alpha',
+                                               'A/B/F',
+                                               'A/B/lambda',
+                                               wc_rev='3')
+  expected_status.remove('A/B/E/beta')
+   
+  svntest.actions.run_and_verify_commit(wc_dir,
+                                        [],
+                                        expected_status,
+                                        None,
+                                        wc_dir)
+       
+                                                                               
 ########################################################################
 # Run the tests
 
@@ -1892,6 +1942,7 @@ test_list = [ None,
               locks_stick_over_switch,
               lock_unlock_deleted,
               commit_stolen_lock,
+                         drop_locks_on_parent_deletion,
             ]
 
 if __name__ == '__main__':
Index: subversion/tests/libsvn_wc/op-depth-test.c
===================================================================
diff --git a/subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c 
b/subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c
--- a/subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c       
(Revision 1491372)
+++ b/subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c       
(Arbeitskopie)
@@ -1109,6 +1109,7 @@ base_dir_insert_remove(svn_test__sandbox_t *b,
   SVN_ERR(svn_wc__db_base_remove(b->wc_ctx->db, dir_abspath,
                                  FALSE /* keep_as_Working */,
                                  FALSE /* queue_deletes */,
+                                 FALSE /* remove_locks */,
                                  SVN_INVALID_REVNUM,
                                  NULL, NULL, b->pool));
   SVN_ERR(svn_wc__wq_run(b->wc_ctx->db, dir_abspath,

Reply via email to