On one CollabNet's forums a user reported that a single delete command
of 2000+ WC files took well over three hours to complete with 1.7.5
(see
http://subversion.open.collab.net/ds/viewMessage.do?dsForumId=4&dsMessageId=456214).
I'm able to replicate similar behavior with a partial checkout of
^/subversion/tags
My test WC:
WC Size: 437 MB 21,012 Files, 2,717 Folders
wc.db Size: 18,108,000 bytes
Deletion Targets: 2642 files
Using 1.7.5 this takes almost 27 minutes on my machine:
C:\SVN\sandbox\subversion-tags>timethis svn delete -q --targets
del-target.2463.txt
TimeThis : Command Line : svn delete -q --targets del-target.2463.txt
TimeThis : Start Time : Fri May 18 11:27:04 2012
TimeThis : Command Line : svn delete -q --targets del-target.2463.txt
TimeThis : Start Time : Fri May 18 11:27:04 2012
TimeThis : End Time : Fri May 18 11:53:58 2012
TimeThis : Elapsed Time : 00:26:53.758
trunk@1341851 is significantly faster, taking only 16 minutes:
C:\SVN\sandbox\subversion-tags>timethis svn delete -q --targets
del-target.2463.txt
TimeThis : Command Line : svn delete -q --targets del-target.2463.txt
TimeThis : Start Time : Wed May 23 10:56:41 2012
TimeThis : Command Line : svn delete -q --targets del-target.2463.txt
TimeThis : Start Time : Wed May 23 10:56:41 2012
TimeThis : End Time : Wed May 23 11:13:17 2012
TimeThis : Elapsed Time : 00:16:35.873
Using optimizations similar to what Bert used in r1341848 and creating
a new , the attach patch cuts this down to just over 4 seconds:
C:\SVN\sandbox\subversion-tags>timethis svn delete -q --targets
del-target.2463.txt
TimeThis : Command Line : svn delete -q --targets del-target.2463.txt
TimeThis : Start Time : Wed May 23 17:41:12 2012
TimeThis : Command Line : svn delete -q --targets del-target.2463.txt
TimeThis : Start Time : Wed May 23 17:41:12 2012
TimeThis : End Time : Wed May 23 17:41:16 2012
TimeThis : Elapsed Time : 00:00:04.116
...So, WCNG gurus, does this look ok?
[[[
Speed up WC deletions.
* subversion/libsvn_wc/wc-queries.sql
(STMT_DELETE_NODES_ABOVE_DEPTH_RECURSIVE,
STMT_INSERT_DELETE_FROM_NODE_RECURSIVE): Make the OR operation the
outer operation by duplicating some cheap tests.
(STMT_INSERT_DELETE_LIST_RECURSIVE,
STMT_INSERT_DELETE_LIST): Split old STMT_INSERT_DELETE_LIST into two
new versions, one recursive, and one not.
* subversion/libsvn_wc/wc_db.c
(delete_node): Use the faster non-recursive query when operating on a file.
]]]
--
Paul T. Burba
CollabNet, Inc. -- www.collab.net -- Enterprise Cloud Development
Skype: ptburba
Index: subversion/libsvn_wc/wc-queries.sql
===================================================================
--- subversion/libsvn_wc/wc-queries.sql (revision 1342072)
+++ subversion/libsvn_wc/wc-queries.sql (working copy)
@@ -587,11 +587,15 @@
WHERE wc_id = ?1 AND local_relpath = ?2
-- STMT_DELETE_NODES_ABOVE_DEPTH_RECURSIVE
+/* ### The Sqlite optimizer needs help here ###
+ * WHERE wc_id = ?1
+ * AND (local_relpath = ?2
+ * OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2))
+ * AND op_depth >= ?3 */
DELETE FROM nodes
-WHERE wc_id = ?1
- AND (local_relpath = ?2
- OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2))
- AND op_depth >= ?3
+WHERE (wc_id = ?1 AND local_relpath = ?2 AND op_depth >= ?3)
+ OR (wc_id = ?1 AND IS_STRICT_DESCENDANT_OF(local_relpath, ?2)
+ AND op_depth >= ?3)
-- STMT_DELETE_ACTUAL_NODE
DELETE FROM actual_node
@@ -828,16 +832,25 @@
/* If this query is updated, STMT_INSERT_DELETE_LIST should too. */
-- STMT_INSERT_DELETE_FROM_NODE_RECURSIVE
+/* ### The Sqlite optimizer needs help here ###
+ * WHERE wc_id = ?1
+ * AND (local_relpath = ?2
+ * OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2))
+ * AND op_depth = ?3
+ * AND presence NOT IN ('base-deleted', 'not-present', 'excluded',
+ * 'absent') */
INSERT INTO nodes (
wc_id, local_relpath, op_depth, parent_relpath, presence, kind)
SELECT wc_id, local_relpath, ?4 /*op_depth*/, parent_relpath, 'base-deleted',
kind
FROM nodes
-WHERE wc_id = ?1
- AND (local_relpath = ?2
- OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2))
- AND op_depth = ?3
- AND presence NOT IN ('base-deleted', 'not-present', 'excluded', 'absent')
+WHERE (wc_id = ?1 AND local_relpath = ?2 AND op_depth = ?3
+ AND presence NOT IN ('base-deleted', 'not-present', 'excluded',
+ 'absent'))
+ OR (wc_id = ?1 AND IS_STRICT_DESCENDANT_OF(local_relpath, ?2)
+ AND op_depth = ?3
+ AND presence NOT IN ('base-deleted', 'not-present', 'excluded',
+ 'absent'))
-- STMT_INSERT_WORKING_NODE_FROM_BASE_COPY
INSERT INTO nodes (
@@ -1229,7 +1242,7 @@
/* This matches the selection in STMT_INSERT_DELETE_FROM_NODE_RECURSIVE.
A subquery is used instead of nodes_current to avoid a table scan */
--- STMT_INSERT_DELETE_LIST
+-- STMT_INSERT_DELETE_LIST_RECURSIVE
INSERT INTO delete_list(local_relpath)
SELECT local_relpath FROM nodes AS n
WHERE wc_id = ?1
@@ -1241,6 +1254,17 @@
AND s.local_relpath = n.local_relpath)
AND presence NOT IN ('base-deleted', 'not-present', 'excluded', 'absent')
+-- STMT_INSERT_DELETE_LIST
+INSERT INTO delete_list(local_relpath)
+SELECT local_relpath FROM nodes AS n
+WHERE wc_id = ?1
+ AND (local_relpath = ?2)
+ AND op_depth >= ?3
+ AND op_depth = (SELECT MAX(s.op_depth) FROM nodes AS s
+ WHERE s.wc_id = ?1
+ AND s.local_relpath = n.local_relpath)
+ AND presence NOT IN ('base-deleted', 'not-present', 'excluded', 'absent')
+
-- STMT_SELECT_DELETE_LIST
SELECT local_relpath FROM delete_list
ORDER BY local_relpath
Index: subversion/libsvn_wc/wc_db.c
===================================================================
--- subversion/libsvn_wc/wc_db.c (revision 1342072)
+++ subversion/libsvn_wc/wc_db.c (working copy)
@@ -6728,8 +6728,15 @@
}
/* ### Put actual-only nodes into the list? */
- SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_INSERT_DELETE_LIST));
+ /* If LOCAL_RELPATH at SELECT_DEPTH is a file we can use
+ the (faster) non-recursive query. */
+ if (kind == svn_kind_file)
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_INSERT_DELETE_LIST));
+ else
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_INSERT_DELETE_LIST_RECURSIVE));
+
SVN_ERR(svn_sqlite__bindf(stmt, "isd",
wcroot->wc_id, local_relpath, select_depth));
SVN_ERR(svn_sqlite__step_done(stmt));