Author: rhuijben
Date: Thu Jul 5 11:30:37 2012
New Revision: 1357558
URL: http://svn.apache.org/viewvc?rev=1357558&view=rev
Log:
Transform the base-remove workqueue operation into an atomic wc_db operation
that dynamically creates multiple workqueue operations that transform the
local working copy later.
This removes the last place in the workqueue that may change the NODE
presence/status during its operations. (Except for legacy and upgrade).
This patch removes several ugly corner cases around actual only nodes in
the original implementation of the db function.
* subversion/libsvn_wc/externals.c
(svn_wc__external_remove): Update caller. Run workqueue instead of manually
removing a file.
* subversion/libsvn_wc/update_editor.c
(delete_entry): Handle all changes via a single call to
svn_wc__db_base_remove, instead of applying multiple small operations.
* subversion/libsvn_wc/wc-queries.sql
(STMT_SELECT_BASE_PRESENT,
STMT_DELETE_ACTUAL_FOR_BASE_RECURSIVE,
STMT_DELETE_WORKING_BASE_DELETE,
STMT_DELETE_WORKING_RECURSIVE,
STMT_DELETE_BASE_RECURSIVE): New queries.
* subversion/libsvn_wc/wc_db.c
(base_get_info): Add prototype.
(base_remove_baton): Add new arguments.
(db_base_remove): Implement as recursive operation via several new Sqlite
statements.
(svn_wc__db_base_remove): Pass arguments via baton.
(svn_wc__db_base_remove): Update caller.
* subversion/libsvn_wc/wc_db.h
(svn_wc__db_base_remove): Update prototype and documentation.
* subversion/libsvn_wc/workqueue.c
(names): Add OP_DIRECTORY_REMOVE. Sort legacy items at the bottom.
(remove_base_node): Remove function.
(run_base_remove): Just call svn_wc__db_base_remove.
(svn_wc__wq_build_base_remove): Remove function.
(run_dir_remove,
svn_wc__wq_build_dir_remove): New function.
(dispatch_table): Add OP_DIRECTORY_REMOVE. Sort legacy items at the bottom.
* subversion/libsvn_wc/workqueue.h
(svn_wc__wq_build_dir_remove): New function.
(svn_wc__wq_build_base_remove): Remove function.
* subversion/tests/libsvn_wc/op-depth-test.c
(includes): Add workqueue.h.
(base_dir_insert_remove): Run workqueue to avoid an error on closing
the db.
Modified:
subversion/trunk/subversion/libsvn_wc/externals.c
subversion/trunk/subversion/libsvn_wc/update_editor.c
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
subversion/trunk/subversion/libsvn_wc/workqueue.h
subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c
Modified: subversion/trunk/subversion/libsvn_wc/externals.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/externals.c?rev=1357558&r1=1357557&r2=1357558&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/externals.c (original)
+++ subversion/trunk/subversion/libsvn_wc/externals.c Thu Jul 5 11:30:37 2012
@@ -1310,8 +1310,12 @@ svn_wc__external_remove(svn_wc_context_t
scratch_pool));
else
{
- SVN_ERR(svn_wc__db_base_remove(wc_ctx->db, local_abspath, scratch_pool));
- SVN_ERR(svn_io_remove_file2(local_abspath, TRUE, scratch_pool));
+ SVN_ERR(svn_wc__db_base_remove(wc_ctx->db, local_abspath,
+ FALSE, SVN_INVALID_REVNUM,
+ NULL, NULL, scratch_pool));
+ SVN_ERR(svn_wc__wq_run(wc_ctx->db, local_abspath,
+ cancel_func, cancel_baton,
+ scratch_pool));
}
return SVN_NO_ERROR;
Modified: subversion/trunk/subversion/libsvn_wc/update_editor.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/update_editor.c?rev=1357558&r1=1357557&r2=1357558&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/update_editor.c (original)
+++ subversion/trunk/subversion/libsvn_wc/update_editor.c Thu Jul 5 11:30:37
2012
@@ -1701,11 +1701,11 @@ delete_entry(const char *path,
svn_boolean_t have_base;
svn_boolean_t have_work;
svn_skel_t *tree_conflict = NULL;
- svn_skel_t *work_item = NULL;
svn_wc__db_status_t status;
svn_wc__db_status_t base_status;
apr_pool_t *scratch_pool;
svn_boolean_t deleting_target;
+ svn_boolean_t keep_as_working = FALSE;
if (pb->skip_this)
return SVN_NO_ERROR;
@@ -1785,7 +1785,10 @@ delete_entry(const char *path,
|| base_status == svn_wc__db_status_excluded
|| base_status == svn_wc__db_status_server_excluded)
{
- SVN_ERR(svn_wc__db_base_remove(eb->db, local_abspath, scratch_pool));
+ SVN_ERR(svn_wc__db_base_remove(eb->db, local_abspath,
+ FALSE, SVN_INVALID_REVNUM,
+ NULL, NULL,
+ scratch_pool));
if (deleting_target)
eb->target_deleted = TRUE;
@@ -1843,8 +1846,7 @@ delete_entry(const char *path,
* To prepare the "accept mine" resolution for the tree conflict,
* we must schedule the existing content for re-addition as a copy
* of what it was, but with its local modifications preserved. */
- SVN_ERR(svn_wc__db_temp_op_make_copy(eb->db, local_abspath,
- scratch_pool));
+ keep_as_working = TRUE;
/* Fall through to remove the BASE_NODEs properly, with potentially
keeping a not-present marker */
@@ -1892,33 +1894,21 @@ delete_entry(const char *path,
if (! deleting_target)
{
/* Delete, and do not leave a not-present node. */
- SVN_ERR(svn_wc__wq_build_base_remove(&work_item,
- eb->db, local_abspath,
- SVN_INVALID_REVNUM,
- svn_kind_unknown,
- scratch_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_base_remove(eb->db, local_abspath,
+ keep_as_working, SVN_INVALID_REVNUM,
+ tree_conflict, NULL,
+ scratch_pool));
}
else
{
/* Delete, leaving a not-present node. */
- SVN_ERR(svn_wc__wq_build_base_remove(&work_item,
- eb->db, local_abspath,
- *eb->target_revision,
- base_kind,
- scratch_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_base_remove(eb->db, local_abspath,
+ keep_as_working, *eb->target_revision,
+ tree_conflict, NULL,
+ scratch_pool));
eb->target_deleted = TRUE;
}
- if (tree_conflict)
- {
- SVN_ERR(svn_wc__db_op_mark_conflict(eb->db, local_abspath,
- tree_conflict, work_item,
- scratch_pool));
- }
- else
- SVN_ERR(svn_wc__db_wq_add(eb->db, pb->local_abspath, work_item,
- scratch_pool));
-
SVN_ERR(svn_wc__wq_run(eb->db, pb->local_abspath,
eb->cancel_func, eb->cancel_baton,
scratch_pool));
@@ -4756,7 +4746,8 @@ close_edit(void *edit_baton,
If so, we should get rid of this excluded node now. */
SVN_ERR(svn_wc__db_base_remove(eb->db, eb->target_abspath,
- scratch_pool));
+ FALSE, SVN_INVALID_REVNUM,
+ NULL, NULL, scratch_pool));
}
}
}
Modified: subversion/trunk/subversion/libsvn_wc/wc-queries.sql
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc-queries.sql?rev=1357558&r1=1357557&r2=1357558&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/trunk/subversion/libsvn_wc/wc-queries.sql Thu Jul 5 11:30:37
2012
@@ -153,6 +153,51 @@ INSERT OR REPLACE INTO nodes (
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14,
?15, ?16, ?17, ?18, ?19, ?20, ?21, ?22)
+-- STMT_SELECT_BASE_PRESENT
+SELECT local_relpath, kind FROM nodes n
+WHERE wc_id = ?1 AND IS_STRICT_DESCENDANT_OF(local_relpath, ?2)
+ AND op_depth = 0
+ AND presence in ('normal', 'incomplete')
+ AND NOT EXISTS(SELECT 1 FROM NODES w
+ WHERE w.wc_id = ?1 AND w.local_relpath = n.local_relpath
+ AND op_depth > 0)
+ORDER BY local_relpath DESC
+
+-- STMT_DELETE_ACTUAL_FOR_BASE_RECURSIVE
+/* The ACTUAL_NODE applies to BASE, unless there is in at least one op_depth
+ a WORKING node that could have a conflict */
+DELETE FROM actual_node
+WHERE wc_id = ?1 AND IS_STRICT_DESCENDANT_OF(local_relpath, ?2)
+ AND EXISTS(SELECT 1 FROM NODES b
+ WHERE b.wc_id = ?1
+ AND b.local_relpath = actual_node.local_relpath
+ AND op_depth = 0)
+ AND NOT EXISTS(SELECT 1 FROM NODES w
+ WHERE w.wc_id = ?1
+ AND w.local_relpath = actual_node.local_relpath
+ AND op_depth > 0
+ AND presence in ('normal', 'incomplete', 'not-present'))
+
+-- STMT_DELETE_WORKING_BASE_DELETE
+DELETE FROM nodes
+WHERE wc_id = ?1 AND IS_STRICT_DESCENDANT_OF(local_relpath, ?2)
+ AND presence = 'base-deleted'
+ AND op_depth > 0
+ AND op_depth = (SELECT MIN(op_depth) FROM nodes n
+ WHERE n.wc_id = ?1
+ AND n.local_relpath = nodes.local_relpath
+ AND op_depth > 0)
+
+-- STMT_DELETE_WORKING_RECURSIVE
+DELETE FROM nodes
+WHERE wc_id = ?1 AND IS_STRICT_DESCENDANT_OF(local_relpath, ?2)
+ AND op_depth > 0
+
+-- STMT_DELETE_BASE_RECURSIVE
+DELETE FROM nodes
+WHERE wc_id = ?1 AND IS_STRICT_DESCENDANT_OF(local_relpath, ?2)
+ AND op_depth = 0
+
-- STMT_SELECT_OP_DEPTH_CHILDREN
SELECT local_relpath FROM nodes
WHERE wc_id = ?1 AND parent_relpath = ?2 AND op_depth = ?3
Modified: subversion/trunk/subversion/libsvn_wc/wc_db.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.c?rev=1357558&r1=1357557&r2=1357558&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db.c Thu Jul 5 11:30:37 2012
@@ -336,6 +336,26 @@ db_read_pristine_props(apr_hash_t **prop
apr_pool_t *scratch_pool);
static svn_error_t *
+base_get_info(svn_wc__db_status_t *status,
+ svn_kind_t *kind,
+ svn_revnum_t *revision,
+ const char **repos_relpath,
+ apr_int64_t *repos_id,
+ svn_revnum_t *changed_rev,
+ apr_time_t *changed_date,
+ const char **changed_author,
+ svn_depth_t *depth,
+ const svn_checksum_t **checksum,
+ const char **target,
+ svn_wc__db_lock_t **lock,
+ svn_boolean_t *had_props,
+ svn_boolean_t *update_root,
+ svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+static svn_error_t *
read_info(svn_wc__db_status_t *status,
svn_kind_t *kind,
svn_revnum_t *revision,
@@ -1958,7 +1978,11 @@ svn_wc__db_base_add_not_present_node(svn
/* Baton for db_base_remove */
struct base_remove_baton
{
- svn_wc__db_t *db;
+ svn_wc__db_t *db; /* For checking conflicts */
+ svn_boolean_t keep_as_working;
+ svn_revnum_t not_present_revision;
+ svn_skel_t *conflict;
+ svn_skel_t *work_items;
};
/* This implements svn_wc__db_txn_callback_t */
@@ -1970,76 +1994,193 @@ db_base_remove(void *baton,
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
-#if SVN_WC__VERSION >= SVN_WC__USES_CONFLICT_SKELS
struct base_remove_baton *rb = baton;
-#endif
-
- SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_DELETE_BASE_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
- SVN_ERR(svn_sqlite__step_done(stmt));
+ svn_wc__db_status_t status;
+ apr_int64_t repos_id;
+ const char *repos_relpath;
+ svn_kind_t kind;
+ svn_boolean_t keep_working;
- SVN_ERR(retract_parent_delete(wcroot, local_relpath, scratch_pool));
+ SVN_ERR(base_get_info(&status, &kind, NULL, &repos_relpath, &repos_id,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL,
+ wcroot, local_relpath,
+ scratch_pool, scratch_pool));
- /* If there is no working node then any actual node must be deleted,
- unless it marks a conflict */
- SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_SELECT_WORKING_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
- SVN_ERR(svn_sqlite__reset(stmt));
- if (!have_row)
+ /* ### This function should be turned into a helper of this function,
+ as this is the only valid caller */
+ if (status == svn_wc__db_status_normal
+ && rb->keep_as_working)
+ {
+ SVN_ERR(svn_wc__db_temp_op_make_copy(rb->db,
+ svn_dirent_join(wcroot->abspath,
+ local_relpath,
+ scratch_pool),
+ scratch_pool));
+ keep_working = TRUE;
+ }
+ else
{
+ /* Check if there is already a working node */
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_SELECT_ACTUAL_NODE));
+ STMT_SELECT_WORKING_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ SVN_ERR(svn_sqlite__step(&keep_working, stmt));
+ SVN_ERR(svn_sqlite__reset(stmt));
+ }
- if (! have_row)
- SVN_ERR(svn_sqlite__reset(stmt));
- else
+ /* Step 1: Create workqueue operations to remove files and dirs in the
+ local-wc */
+ if (!keep_working
+ && (status == svn_wc__db_status_normal
+ || status == svn_wc__db_status_incomplete))
+ {
+ svn_skel_t *work_item;
+ const char *local_abspath;
+
+ local_abspath = svn_dirent_join(wcroot->abspath, local_relpath,
+ scratch_pool);
+ if (kind == svn_kind_dir)
{
- svn_boolean_t tree_conflicted;
-#if SVN_WC__VERSION >= SVN_WC__USES_CONFLICT_SKELS
- apr_size_t conflict_len;
- const void *conflict_data;
-#endif
+ apr_pool_t *iterpool;
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_SELECT_BASE_PRESENT));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
-#if SVN_WC__VERSION < SVN_WC__USES_CONFLICT_SKELS
- tree_conflicted = !svn_sqlite__column_is_null(stmt, 7);
-#else
- conflict_data = svn_sqlite__column_blob(stmt, 2, &conflict_len,
- NULL);
+ iterpool = svn_pool_create(scratch_pool);
- if (! conflict_data)
- tree_conflicted = FALSE;
- else
- {
- const svn_skel_t *conflicts;
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
- conflicts = svn_skel__parse(conflict_data, conflict_len,
- scratch_pool);
+ while (have_row)
+ {
+ const char *node_relpath = svn_sqlite__column_text(stmt, 0,
NULL);
+ svn_kind_t node_kind = svn_sqlite__column_token(stmt, 1,
+ kind_map);
+ const char *node_abspath;
- SVN_ERR(svn_wc__conflict_read_info(NULL, NULL, NULL, NULL,
- &tree_conflicted,
- rb->db, wcroot->abspath,
- conflicts,
- scratch_pool, scratch_pool));
+ svn_pool_clear(iterpool);
+
+ node_abspath = svn_dirent_join(wcroot->abspath, node_relpath,
+ iterpool);
+
+ if (node_kind == svn_kind_dir)
+ SVN_ERR(svn_wc__wq_build_dir_remove(&work_item,
+ rb->db, wcroot->abspath,
+ node_abspath, FALSE,
+ iterpool, iterpool));
+ else
+ SVN_ERR(svn_wc__wq_build_file_remove(&work_item,
+ rb->db,
+ /* wcroot->abspath, */
+ node_abspath,
+ iterpool, iterpool));
+
+ SVN_ERR(add_work_items(wcroot->sdb, work_item, iterpool));
+
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
-#endif
+
SVN_ERR(svn_sqlite__reset(stmt));
- if (! tree_conflicted)
- {
- SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_DELETE_ACTUAL_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
- local_relpath));
- SVN_ERR(svn_sqlite__step_done(stmt));
- }
+ SVN_ERR(svn_wc__wq_build_dir_remove(&work_item,
+ rb->db, wcroot->abspath,
+ local_abspath, FALSE,
+ scratch_pool, iterpool));
+ svn_pool_destroy(iterpool);
}
+ else
+ SVN_ERR(svn_wc__wq_build_file_remove(&work_item,
+ rb->db, /* wcroot->abspath, */
+ local_abspath,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR(add_work_items(wcroot->sdb, work_item, scratch_pool));
+ }
+
+ /* Step 2: Delete ACTUAL nodes */
+ if (! keep_working)
+ {
+ /* There won't be a record in NODE left for this node, so we want
+ to remove *all* ACTUAL nodes, including ACTUAL ONLY. */
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_DELETE_ACTUAL_NODE_RECURSIVE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+ }
+ else if (! rb->keep_as_working)
+ {
+ /* Delete only the ACTUAL nodes that apply to a delete of a BASE node */
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_DELETE_ACTUAL_FOR_BASE_RECURSIVE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+ }
+ /* Else: Everything has been turned into a copy, so we want to keep all
+ ACTUAL_NODE records */
+
+ /* Step 3: Delete WORKING nodes */
+ if (keep_working)
+ {
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_DELETE_WORKING_BASE_DELETE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+ }
+ else
+ {
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_DELETE_WORKING_RECURSIVE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step_done(stmt));
}
+ /* Step 4: Delete the BASE node descendants */
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_DELETE_BASE_RECURSIVE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+
+ /* Step 5: handle the BASE node itself */
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_DELETE_BASE_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+
+ SVN_ERR(retract_parent_delete(wcroot, local_relpath, scratch_pool));
+
+ /* Step 6: Delete actual node if we don't keep working */
+ if (! keep_working)
+ {
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_DELETE_ACTUAL_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+ }
+
+ if (SVN_IS_VALID_REVNUM(rb->not_present_revision))
+ {
+ struct insert_base_baton_t ibb;
+ blank_ibb(&ibb);
+
+ ibb.repos_id = repos_id;
+ ibb.status = svn_wc__db_status_not_present;
+ ibb.kind = kind;
+ ibb.repos_relpath = repos_relpath;
+ ibb.revision = rb->not_present_revision;
+
+ /* Depending upon KIND, any of these might get used. */
+ ibb.children = NULL;
+ ibb.depth = svn_depth_unknown;
+ ibb.checksum = NULL;
+ ibb.target = NULL;
+
+ SVN_ERR(insert_base_node(&ibb, wcroot, local_relpath, scratch_pool));
+ }
+
+ SVN_ERR(add_work_items(wcroot->sdb, rb->work_items, scratch_pool));
+ if (rb->conflict)
+ SVN_ERR(mark_conflict(wcroot, local_relpath, rb->conflict, scratch_pool));
+
return SVN_NO_ERROR;
}
@@ -2047,12 +2188,15 @@ db_base_remove(void *baton,
svn_error_t *
svn_wc__db_base_remove(svn_wc__db_t *db,
const char *local_abspath,
+ svn_boolean_t keep_as_working,
+ svn_revnum_t not_present_revision,
+ svn_skel_t *conflict,
+ svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
struct base_remove_baton rb;
- rb.db = db;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
@@ -2060,6 +2204,12 @@ svn_wc__db_base_remove(svn_wc__db_t *db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
+ rb.db = db;
+ rb.keep_as_working = keep_as_working;
+ rb.not_present_revision = not_present_revision;
+ rb.conflict = conflict;
+ rb.work_items = work_items;
+
SVN_ERR(svn_wc__db_with_txn(wcroot, local_relpath, db_base_remove, &rb,
scratch_pool));
@@ -9714,6 +9864,11 @@ bump_node_revision(svn_wc__db_wcroot_t *
{
struct base_remove_baton rb;
rb.db = db;
+ rb.keep_as_working = FALSE;
+ rb.not_present_revision = SVN_INVALID_REVNUM;
+ rb.conflict = NULL;
+ rb.work_items = NULL;
+
return svn_error_trace(db_base_remove(&rb, wcroot, local_relpath,
scratch_pool));
}
Modified: subversion/trunk/subversion/libsvn_wc/wc_db.h
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.h?rev=1357558&r1=1357557&r2=1357558&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db.h (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db.h Thu Jul 5 11:30:37 2012
@@ -636,13 +636,15 @@ svn_wc__db_base_add_not_present_node(svn
apr_pool_t *scratch_pool);
-/* Remove a node from the BASE tree.
+/* Remove a node and all its descendants from the BASE tree. This handles
+ the deletion of a tree from the update editor and some file external
+ scenarios.
The node to remove is indicated by LOCAL_ABSPATH from the local
filesystem.
- Note that no changes are made to the local filesystem; LOCAL_ABSPATH
- is merely the key to figure out which BASE node to remove.
+ This operation *installs* workqueue operations to update the local
+ filesystem after the database operation.
To maintain a consistent database this function will also remove
any working node that marks LOCAL_ABSPATH as base-deleted. If this
@@ -650,12 +652,24 @@ svn_wc__db_base_add_not_present_node(svn
actual node will be removed if the actual node does not mark a
conflict.
- Note the caller is responsible for removing base node
- children before calling this function (this may change).
+ If KEEP_AS_WORKING is TRUE, then the base tree is copied to higher
+ layers as a copy of itself before deleting the BASE 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.
+
+ If CONFLICT and/or WORK_ITEMS are passed they are installed as part
+ of the operation, after the work items inserted by the operation
+ itself.
*/
svn_error_t *
svn_wc__db_base_remove(svn_wc__db_t *db,
const char *local_abspath,
+ svn_boolean_t keep_as_working,
+ svn_revnum_t not_present_revision,
+ svn_skel_t *conflict,
+ svn_skel_t *work_items,
apr_pool_t *scratch_pool);
Modified: subversion/trunk/subversion/libsvn_wc/workqueue.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/workqueue.c?rev=1357558&r1=1357557&r2=1357558&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/workqueue.c (original)
+++ subversion/trunk/subversion/libsvn_wc/workqueue.c Thu Jul 5 11:30:37 2012
@@ -42,7 +42,6 @@
/* Workqueue operation names. */
-#define OP_BASE_REMOVE "base-remove"
#define OP_FILE_COMMIT "file-commit"
#define OP_FILE_INSTALL "file-install"
#define OP_FILE_REMOVE "file-remove"
@@ -50,10 +49,15 @@
#define OP_FILE_COPY_TRANSLATED "file-translate"
#define OP_SYNC_FILE_FLAGS "sync-file-flags"
#define OP_PREJ_INSTALL "prej-install"
+#define OP_DIRECTORY_REMOVE "dir-remove"
+
+#define OP_POSTUPGRADE "postupgrade"
+
+/* Legacy items */
+#define OP_BASE_REMOVE "base-remove"
#define OP_RECORD_FILEINFO "record-fileinfo"
#define OP_TMP_SET_TEXT_CONFLICT_MARKERS "tmp-set-text-conflict-markers"
#define OP_TMP_SET_PROPERTY_CONFLICT_MARKER "tmp-set-property-conflict-marker"
-#define OP_POSTUPGRADE "postupgrade"
/* For work queue debugging. Generates output about its operation. */
/* #define SVN_DEBUG_WORK_QUEUE */
@@ -100,110 +104,7 @@ get_and_record_fileinfo(svn_wc__db_t *db
/* Removes a BASE_NODE and all it's data, leaving any adds and copies as is.
Do this as a depth first traversal to make sure than any parent still exists
on error conditions.
-
- ### This function needs review for 4th tree behavior.*/
-static svn_error_t *
-remove_base_node(svn_wc__db_t *db,
- const char *local_abspath,
- svn_cancel_func_t cancel_func,
- void *cancel_baton,
- apr_pool_t *scratch_pool)
-{
- svn_wc__db_status_t base_status, wrk_status;
- svn_kind_t base_kind, wrk_kind;
- svn_boolean_t have_base, have_work;
- svn_error_t *err;
-
- if (cancel_func)
- SVN_ERR(cancel_func(cancel_baton));
-
- err = svn_wc__db_read_info(&wrk_status, &wrk_kind, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL,
- &have_base, NULL, &have_work,
- db, local_abspath, scratch_pool, scratch_pool);
- if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
- {
- /* No node to delete, this can happen when the wq item is rerun. */
- svn_error_clear(err);
- return SVN_NO_ERROR;
- }
-
- if(! have_base)
- /* No base node to delete, this can happen when the wq item is rerun. */
- return SVN_NO_ERROR;
-
- if (wrk_status == svn_wc__db_status_normal
- || wrk_status == svn_wc__db_status_not_present
- || wrk_status == svn_wc__db_status_server_excluded)
- {
- base_status = wrk_status;
- base_kind = wrk_kind;
- }
- else
- SVN_ERR(svn_wc__db_base_get_info(&base_status, &base_kind, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- db, local_abspath,
- scratch_pool, scratch_pool));
-
- /* Children first */
- if (base_kind == svn_kind_dir
- && (base_status == svn_wc__db_status_normal
- || base_status == svn_wc__db_status_incomplete))
- {
- const apr_array_header_t *children;
- apr_pool_t *iterpool = svn_pool_create(scratch_pool);
- int i;
-
- SVN_ERR(svn_wc__db_base_get_children(&children, db, local_abspath,
- scratch_pool, iterpool));
-
- for (i = 0; i < children->nelts; i++)
- {
- const char *child_name = APR_ARRAY_IDX(children, i, const char *);
- const char *child_abspath;
-
- svn_pool_clear(iterpool);
-
- child_abspath = svn_dirent_join(local_abspath, child_name, iterpool);
-
- SVN_ERR(remove_base_node(db, child_abspath, cancel_func,
cancel_baton,
- iterpool));
- }
-
- svn_pool_destroy(iterpool);
- }
-
- if (base_status == svn_wc__db_status_normal
- && wrk_status != svn_wc__db_status_added
- && wrk_status != svn_wc__db_status_excluded)
- {
- if (wrk_status != svn_wc__db_status_deleted
- && (base_kind == svn_kind_file
- || base_kind == svn_kind_symlink))
- {
- SVN_ERR(svn_io_remove_file2(local_abspath, TRUE, scratch_pool));
- }
- else if (base_kind == svn_kind_dir
- && wrk_status != svn_wc__db_status_deleted)
- {
- err = svn_io_dir_remove_nonrecursive(local_abspath, scratch_pool);
- if (err && (APR_STATUS_IS_ENOENT(err->apr_err)
- || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err)
- || APR_STATUS_IS_ENOTEMPTY(err->apr_err)))
- svn_error_clear(err);
- else
- SVN_ERR(err);
- }
- }
-
- SVN_ERR(svn_wc__db_base_remove(db, local_abspath, scratch_pool));
-
- return SVN_NO_ERROR;
-}
-
+ */
/* Process the OP_REMOVE_BASE work item WORK_ITEM.
* See svn_wc__wq_build_remove_base() which generates this work item.
@@ -220,8 +121,6 @@ run_base_remove(svn_wc__db_t *db,
const char *local_relpath;
const char *local_abspath;
svn_revnum_t not_present_rev = SVN_INVALID_REVNUM;
- svn_kind_t not_present_kind;
- const char *repos_relpath, *repos_root_url, *repos_uuid;
apr_int64_t val;
local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len);
@@ -234,23 +133,6 @@ run_base_remove(svn_wc__db_t *db,
not_present_rev = (svn_revnum_t)val;
SVN_ERR(svn_skel__parse_int(&val, arg1->next->next, scratch_pool));
- not_present_kind = (svn_kind_t)val;
-
- if (SVN_IS_VALID_REVNUM(not_present_rev))
- {
- const char *dir_abspath, *name;
-
- /* This wq operation is restartable, so we can't assume the node
- to be here. But we can assume that the parent is still there */
- svn_dirent_split(&dir_abspath, &name, local_abspath, scratch_pool);
-
- SVN_ERR(svn_wc__db_scan_base_repos(&repos_relpath, &repos_root_url,
- &repos_uuid,
- db, dir_abspath,
- scratch_pool, scratch_pool));
-
- repos_relpath = svn_relpath_join(repos_relpath, name, scratch_pool);
- }
}
else
{
@@ -262,9 +144,9 @@ run_base_remove(svn_wc__db_t *db,
if (keep_not_present)
{
- SVN_ERR(svn_wc__db_base_get_info(NULL, ¬_present_kind,
- ¬_present_rev, &repos_relpath,
- &repos_root_url, &repos_uuid, NULL,
+ SVN_ERR(svn_wc__db_base_get_info(NULL, NULL,
+ ¬_present_rev, NULL,
+ NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL,
db, local_abspath,
@@ -272,45 +154,8 @@ run_base_remove(svn_wc__db_t *db,
}
}
- SVN_ERR(remove_base_node(db, local_abspath,
- cancel_func, cancel_baton,
- scratch_pool));
-
- if (SVN_IS_VALID_REVNUM(not_present_rev))
- {
- SVN_ERR(svn_wc__db_base_add_not_present_node(db, local_abspath,
- repos_relpath,
- repos_root_url,
- repos_uuid,
- not_present_rev,
- not_present_kind,
- NULL,
- NULL,
- scratch_pool));
- }
-
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_wc__wq_build_base_remove(svn_skel_t **work_item,
- svn_wc__db_t *db,
- const char *local_abspath,
- svn_revnum_t not_present_revision,
- svn_kind_t not_present_kind,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- const char *local_relpath;
- *work_item = svn_skel__make_empty_list(result_pool);
-
- SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, local_abspath,
- local_abspath, result_pool, scratch_pool));
-
- svn_skel__prepend_int(not_present_kind, *work_item, result_pool);
- svn_skel__prepend_int(not_present_revision, *work_item, result_pool);
- svn_skel__prepend_str(local_relpath, *work_item, result_pool);
- svn_skel__prepend_str(OP_BASE_REMOVE, *work_item, result_pool);
+ SVN_ERR(svn_wc__db_base_remove(db, local_abspath, FALSE, not_present_rev,
+ NULL, NULL, scratch_pool));
return SVN_NO_ERROR;
}
@@ -912,6 +757,87 @@ svn_wc__wq_build_file_remove(svn_skel_t
/* ------------------------------------------------------------------------ */
+/* OP_DIRECTORY_REMOVE */
+
+/* Process the OP_FILE_REMOVE work item WORK_ITEM.
+ * See svn_wc__wq_build_file_remove() which generates this work item.
+ * Implements (struct work_item_dispatch).func. */
+static svn_error_t *
+run_dir_remove(svn_wc__db_t *db,
+ const svn_skel_t *work_item,
+ const char *wri_abspath,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool)
+{
+ const svn_skel_t *arg1 = work_item->children->next;
+ const char *local_relpath;
+ const char *local_abspath;
+ svn_boolean_t recursive;
+
+ local_relpath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len);
+ SVN_ERR(svn_wc__db_from_relpath(&local_abspath, db, wri_abspath,
+ local_relpath, scratch_pool, scratch_pool));
+
+ recursive = FALSE;
+ if (arg1->next)
+ {
+ apr_int64_t val;
+ SVN_ERR(svn_skel__parse_int(&val, arg1->next, scratch_pool));
+
+ recursive = (val != 0);
+ }
+
+ /* Remove the path, no worrying if it isn't there. */
+ if (recursive)
+ return svn_error_trace(
+ svn_io_remove_dir2(local_abspath, TRUE,
+ cancel_func, cancel_baton,
+ scratch_pool));
+ else
+ {
+ svn_error_t *err;
+
+ err = svn_io_dir_remove_nonrecursive(local_abspath, scratch_pool);
+
+ if (err && (APR_STATUS_IS_ENOENT(err->apr_err)
+ || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err)
+ || APR_STATUS_IS_ENOTEMPTY(err->apr_err)))
+ {
+ svn_error_clear(err);
+ err = NULL;
+ }
+
+ return svn_error_trace(err);
+ }
+}
+
+svn_error_t *
+svn_wc__wq_build_dir_remove(svn_skel_t **work_item,
+ svn_wc__db_t *db,
+ const char *wri_abspath,
+ const char *local_abspath,
+ svn_boolean_t recursive,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const char *local_relpath;
+ *work_item = svn_skel__make_empty_list(result_pool);
+
+ SVN_ERR(svn_wc__db_to_relpath(&local_relpath, db, wri_abspath,
+ local_abspath, result_pool, scratch_pool));
+
+ if (recursive)
+ svn_skel__prepend_int(TRUE, *work_item, result_pool);
+
+ svn_skel__prepend_str(local_relpath, *work_item, result_pool);
+ svn_skel__prepend_str(OP_DIRECTORY_REMOVE, *work_item, result_pool);
+
+ return SVN_NO_ERROR;
+}
+
+/* ------------------------------------------------------------------------ */
+
/* OP_FILE_MOVE */
/* Process the OP_FILE_MOVE work item WORK_ITEM.
@@ -1442,14 +1368,17 @@ static const struct work_item_dispatch d
{ OP_FILE_COPY_TRANSLATED, run_file_copy_translated },
{ OP_SYNC_FILE_FLAGS, run_sync_file_flags },
{ OP_PREJ_INSTALL, run_prej_install },
- { OP_RECORD_FILEINFO, run_record_fileinfo },
- { OP_BASE_REMOVE, run_base_remove },
- { OP_TMP_SET_TEXT_CONFLICT_MARKERS, run_set_text_conflict_markers },
- { OP_TMP_SET_PROPERTY_CONFLICT_MARKER, run_set_property_conflict_marker },
+ { OP_DIRECTORY_REMOVE, run_dir_remove },
/* Upgrade steps */
{ OP_POSTUPGRADE, run_postupgrade },
+ /* Legacy workqueue items. No longer created */
+ { OP_BASE_REMOVE, run_base_remove },
+ { OP_RECORD_FILEINFO, run_record_fileinfo },
+ { OP_TMP_SET_TEXT_CONFLICT_MARKERS, run_set_text_conflict_markers },
+ { OP_TMP_SET_PROPERTY_CONFLICT_MARKER, run_set_property_conflict_marker },
+
/* Sentinel. */
{ NULL }
};
Modified: subversion/trunk/subversion/libsvn_wc/workqueue.h
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/workqueue.h?rev=1357558&r1=1357557&r2=1357558&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/workqueue.h (original)
+++ subversion/trunk/subversion/libsvn_wc/workqueue.h Thu Jul 5 11:30:37 2012
@@ -122,6 +122,18 @@ svn_wc__wq_build_file_remove(svn_skel_t
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
+/* Set *WORK_ITEM to a new work item that will remove a single
+ directory or if RECURSIVE is TRUE a directory with all its
+ descendants. */
+svn_error_t *
+svn_wc__wq_build_dir_remove(svn_skel_t **work_item,
+ svn_wc__db_t *db,
+ const char *wri_abspath,
+ const char *local_abspath,
+ svn_boolean_t recursive,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
/* Set *WORK_ITEM to a new work item that describes a move of
a file or directory from SRC_ABSPATH to DST_ABSPATH, ready for
storing in the working copy managing DST_ABSPATH.
@@ -182,24 +194,6 @@ svn_wc__wq_build_prej_install(svn_skel_t
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
-/* Set *WORK_ITEM to a new work item that will remove all the data of
- the BASE_NODE of LOCAL_ABSPATH and all it's descendants, but keeping
- any WORKING_NODE data.
-
- This function doesn't check for local modifications of the text files
- as these would have triggered a tree conflict before.
-
- ### This is only used from update_editor.c's do_entry_deletion().
- */
-svn_error_t *
-svn_wc__wq_build_base_remove(svn_skel_t **work_item,
- svn_wc__db_t *db,
- const char *local_abspath,
- svn_revnum_t not_present_revision,
- svn_kind_t not_present_kind,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool);
-
/* Handle the final post-commit step of retranslating and recording the
working copy state of a committed file.
Modified: subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c?rev=1357558&r1=1357557&r2=1357558&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c Thu Jul 5
11:30:37 2012
@@ -43,6 +43,7 @@
#include "private/svn_dep_compat.h"
#include "../../libsvn_wc/wc.h"
#include "../../libsvn_wc/wc_db.h"
+#include "../../libsvn_wc/workqueue.h"
#define SVN_WC__I_AM_WC_DB
#include "../../libsvn_wc/wc_db_private.h"
@@ -1295,7 +1296,11 @@ base_dir_insert_remove(svn_test__sandbox
SVN_ERR(check_db_rows(b, "", after));
- SVN_ERR(svn_wc__db_base_remove(b->wc_ctx->db, dir_abspath, b->pool));
+ SVN_ERR(svn_wc__db_base_remove(b->wc_ctx->db, dir_abspath,
+ FALSE, SVN_INVALID_REVNUM,
+ NULL, NULL, b->pool));
+ SVN_ERR(svn_wc__wq_run(b->wc_ctx->db, dir_abspath,
+ NULL, NULL, b->pool));
SVN_ERR(check_db_rows(b, "", before));