You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2012/07/26 15:54:31 UTC
svn commit: r1365997 - in /subversion/trunk/subversion:
libsvn_client/externals.c libsvn_wc/adm_ops.c libsvn_wc/crop.c
libsvn_wc/externals.c libsvn_wc/wc-queries.sql libsvn_wc/wc_db.c
libsvn_wc/wc_db.h
Author: rhuijben
Date: Thu Jul 26 13:54:30 2012
New Revision: 1365997
URL: http://svn.apache.org/viewvc?rev=1365997&view=rev
Log:
Replace the very wc-1.0 style svn_wc__internal_remove_from_revision_control
function with an atomic wc-ng function. This makes operations like reducing the
depth of a working copy or removing externals from a wc atomic by performing
a db operation and installing workqueue items.
* subversion/libsvn_client/externals.c
(relegate_dir_external): Obtain lock here that was obtained in the caller.
Properly handle working copy renames.
(switch_dir_external): Remove function that has been moved to the callee.
* subversion/libsvn_wc/adm_ops.c
(process_committed_leaf): Update caller.
* subversion/libsvn_wc/crop.c
(includes): Include workqueue.h.
(IGNORE_LOCAL_MOD): Remove now unused macro.
(crop_children): Use db operation directly.
(svn_wc_exclude): Use db operation directly. Avoid second db operation
by passing absent information.
(svn_wc_crop_tree2): Update caller. Run workqueue.
* subversion/libsvn_wc/externals.c
(svn_wc__external_remove): If we leave an external, leave the whole external
by using the fail early mode.
* subversion/libsvn_wc/wc-queries.sql
(STMT_SELECT_WORKING_PRESENT,
STMT_DELETE_NODE_RECURSIVE,
STMT_DELETE_NODE): New queries.
* subversion/libsvn_wc/wc_db.c
(remove_node_baton): Add fields for new options.
(remove_node_txn): Add code to create workqueue items for nodes that exist
on disk. Provide cancellation checking when checking for changes.
Allow setting excluded and not-present.
(svn_wc__db_op_remove_node): Update caller.
* subversion/libsvn_wc/wc_db.h
(svn_wc__db_op_remove_node): Update prototype and documentation.
Modified:
subversion/trunk/subversion/libsvn_client/externals.c
subversion/trunk/subversion/libsvn_wc/adm_ops.c
subversion/trunk/subversion/libsvn_wc/crop.c
subversion/trunk/subversion/libsvn_wc/externals.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
Modified: subversion/trunk/subversion/libsvn_client/externals.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/externals.c?rev=1365997&r1=1365996&r2=1365997&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/externals.c (original)
+++ subversion/trunk/subversion/libsvn_client/externals.c Thu Jul 26 13:54:30 2012
@@ -63,6 +63,9 @@ relegate_dir_external(svn_wc_context_t *
{
svn_error_t *err = SVN_NO_ERROR;
+ SVN_ERR(svn_wc__acquire_write_lock(NULL, wc_ctx, local_abspath,
+ FALSE, scratch_pool, scratch_pool));
+
err = svn_wc__external_remove(wc_ctx, wri_abspath, local_abspath, FALSE,
cancel_func, cancel_baton, scratch_pool);
if (err && (err->apr_err == SVN_ERR_WC_LEFT_LOCAL_MOD))
@@ -103,8 +106,21 @@ relegate_dir_external(svn_wc_context_t *
/* Do our best, but no biggy if it fails. The rename will fail. */
svn_error_clear(svn_io_remove_file2(new_path, TRUE, scratch_pool));
- /* Rename. */
- SVN_ERR(svn_io_file_rename(local_abspath, new_path, scratch_pool));
+ /* Rename. If this is still a working copy we should use the working
+ copy rename function (to release open handles) */
+ err = svn_wc__rename_wc(wc_ctx, local_abspath, new_path,
+ scratch_pool);
+
+ if (err && err->apr_err == SVN_ERR_WC_PATH_UNEXPECTED_STATUS)
+ {
+ svn_error_clear(err);
+
+ /* And if it is no longer a working copy, we should just rename
+ it */
+ err = svn_io_file_rename(local_abspath, new_path, scratch_pool);
+ }
+
+ /* ### TODO: We should notify the user about the rename */
}
return svn_error_trace(err);
@@ -247,9 +263,6 @@ switch_dir_external(const char *local_ab
if (kind == svn_node_dir)
{
/* Buh-bye, old and busted ... */
- SVN_ERR(svn_wc__acquire_write_lock(NULL, ctx->wc_ctx, local_abspath,
- FALSE, pool, pool));
-
SVN_ERR(relegate_dir_external(ctx->wc_ctx, defining_abspath,
local_abspath,
ctx->cancel_func, ctx->cancel_baton,
Modified: subversion/trunk/subversion/libsvn_wc/adm_ops.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/adm_ops.c?rev=1365997&r1=1365996&r2=1365997&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/adm_ops.c (original)
+++ subversion/trunk/subversion/libsvn_wc/adm_ops.c Thu Jul 26 13:54:30 2012
@@ -157,10 +157,15 @@ process_committed_leaf(svn_wc__db_t *db,
{
return svn_error_trace(
svn_wc__db_op_remove_node(
+ NULL,
db, local_abspath,
+ FALSE, FALSE,
(have_base && !via_recurse)
? new_revnum : SVN_INVALID_REVNUM,
+ svn_wc__db_status_not_present,
kind,
+ NULL, NULL,
+ NULL, NULL,
scratch_pool));
}
else if (status == svn_wc__db_status_not_present)
@@ -2326,196 +2331,40 @@ svn_wc__internal_remove_from_revision_co
void *cancel_baton,
apr_pool_t *scratch_pool)
{
- svn_error_t *err;
svn_boolean_t left_something = FALSE;
- svn_wc__db_status_t status;
- svn_kind_t kind;
-
- /* ### This whole function should be rewritten to run inside a transaction,
- ### to allow a stable cancel behavior.
- ###
- ### Subversion < 1.7 marked the directory as incomplete to allow updating
- ### it from a canceled state. But this would not work because update
- ### doesn't retrieve deleted items.
- ###
- ### WC-NG doesn't support a delete+incomplete state, but we can't build
- ### transactions over multiple databases yet. */
-
- SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+ svn_boolean_t is_root;
+ svn_error_t *err = NULL;
- /* Check cancellation here, so recursive calls get checked early. */
- if (cancel_func)
- SVN_ERR(cancel_func(cancel_baton));
+ SVN_ERR(svn_wc__db_is_wcroot(&is_root, db, local_abspath, scratch_pool));
- SVN_ERR(svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- db, local_abspath, scratch_pool, scratch_pool));
-
- if (kind == svn_kind_file || kind == svn_kind_symlink)
- {
- svn_boolean_t text_modified_p = FALSE;
-
- if (destroy_wf)
- {
- svn_node_kind_t on_disk;
- SVN_ERR(svn_io_check_path(local_abspath, &on_disk, scratch_pool));
- if (on_disk == svn_node_file)
- {
- /* Check for local mods. before removing entry */
- SVN_ERR(svn_wc__internal_file_modified_p(&text_modified_p, db,
- local_abspath, FALSE,
- scratch_pool));
- }
- }
+ SVN_ERR(svn_wc__db_op_remove_node(&left_something,
+ db, local_abspath,
+ destroy_wf /* destroy_wc */,
+ destroy_wf /* destroy_changes */,
+ SVN_INVALID_REVNUM,
+ svn_wc__db_status_not_present,
+ svn_kind_none,
+ NULL, NULL,
+ cancel_func, cancel_baton,
+ scratch_pool));
- /* Remove NAME from DB */
- SVN_ERR(svn_wc__db_op_remove_node(db, local_abspath,
- SVN_INVALID_REVNUM,
- svn_kind_unknown,
- scratch_pool));
-
- /* If we were asked to destroy the working file, do so unless
- it has local mods. */
- if (destroy_wf)
- {
- /* Don't kill local mods. */
- if (text_modified_p)
- return svn_error_create(SVN_ERR_WC_LEFT_LOCAL_MOD, NULL, NULL);
- else /* The working file is still present; remove it. */
- SVN_ERR(svn_io_remove_file2(local_abspath, TRUE, scratch_pool));
- }
+ SVN_ERR(svn_wc__wq_run(db, local_abspath,
+ cancel_func, cancel_baton,
+ scratch_pool));
- } /* done with file case */
- else /* looking at THIS_DIR */
+ if (is_root)
{
- apr_pool_t *iterpool = svn_pool_create(scratch_pool);
- const apr_array_header_t *children;
- int i;
-
- /* ### sanity check: check 2 places for DELETED flag? */
-
- /* Walk over every entry. */
- SVN_ERR(svn_wc__db_read_children(&children, db, local_abspath,
- scratch_pool, iterpool));
-
- for (i = 0; i < children->nelts; i++)
- {
- const char *node_name = APR_ARRAY_IDX(children, i, const char*);
- const char *node_abspath;
- svn_wc__db_status_t node_status;
- svn_kind_t node_kind;
-
- svn_pool_clear(iterpool);
-
- node_abspath = svn_dirent_join(local_abspath, node_name, iterpool);
-
- SVN_ERR(svn_wc__db_read_info(&node_status, &node_kind, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL,
- db, node_abspath,
- iterpool, iterpool));
-
- if (node_status == svn_wc__db_status_normal
- && node_kind == svn_kind_dir)
- {
- svn_boolean_t is_root;
-
- SVN_ERR(svn_wc__check_wc_root(&is_root, NULL, NULL,
- db, node_abspath, iterpool));
-
- if (is_root)
- continue; /* Just skip working copies as obstruction */
- }
-
- if (node_status != svn_wc__db_status_normal
- && node_status != svn_wc__db_status_added
- && node_status != svn_wc__db_status_incomplete)
- {
- /* The node is already 'deleted', so nothing to do on
- versioned nodes */
- SVN_ERR(svn_wc__db_op_remove_node(db, node_abspath,
- SVN_INVALID_REVNUM,
- svn_kind_unknown,
- iterpool));
-
- continue;
- }
-
- err = svn_wc__internal_remove_from_revision_control(
- db, node_abspath,
- destroy_wf,
- cancel_func, cancel_baton,
- iterpool);
-
- if (err && (err->apr_err == SVN_ERR_WC_LEFT_LOCAL_MOD))
- {
- svn_error_clear(err);
- left_something = TRUE;
- }
- else if (err)
- return svn_error_trace(err);
- }
-
- /* At this point, every directory below this one has been
- removed from revision control. */
-
- /* Remove self from parent's entries file, but only if parent is
- a working copy. If it's not, that's fine, we just move on. */
- {
- svn_boolean_t is_root;
-
- SVN_ERR(svn_wc__check_wc_root(&is_root, NULL, NULL,
- db, local_abspath, iterpool));
-
- /* If full_path is not the top of a wc, then its parent
- directory is also a working copy and has an entry for
- full_path. We need to remove that entry: */
- if (! is_root)
- {
- SVN_ERR(svn_wc__db_op_remove_node(db, local_abspath,
- SVN_INVALID_REVNUM,
- svn_kind_unknown,
- iterpool));
- }
- else
- {
- /* Remove the entire administrative .svn area, thereby removing
- _this_ dir from revision control too. */
- SVN_ERR(svn_wc__adm_destroy(db, local_abspath,
- cancel_func, cancel_baton, iterpool));
- }
- }
-
- /* If caller wants us to recursively nuke everything on disk, go
- ahead, provided that there are no dangling local-mod files
- below */
- if (destroy_wf && (! left_something))
- {
- /* If the dir is *truly* empty (i.e. has no unversioned
- resources, all versioned files are gone, all .svn dirs are
- gone, and contains nothing but empty dirs), then a
- *non*-recursive dir_remove should work. If it doesn't,
- no big deal. Just assume there are unversioned items in
- there and set "left_something" */
- err = svn_io_dir_remove_nonrecursive(local_abspath, iterpool);
- if (err)
- {
- if (!APR_STATUS_IS_ENOENT(err->apr_err))
- left_something = TRUE;
- svn_error_clear(err);
- }
- }
-
- svn_pool_destroy(iterpool);
+ /* Destroy the administrative area */
+ SVN_ERR(svn_wc__adm_destroy(db, local_abspath, cancel_func, cancel_baton,
+ scratch_pool));
- } /* end of directory case */
+ /* And if we didn't leave something interesting, remove the directory */
+ if (!left_something && destroy_wf)
+ err = svn_io_dir_remove_nonrecursive(local_abspath, scratch_pool);
+ }
- if (left_something)
- return svn_error_create(SVN_ERR_WC_LEFT_LOCAL_MOD, NULL, NULL);
+ if (left_something || err)
+ return svn_error_create(SVN_ERR_WC_LEFT_LOCAL_MOD, err, NULL);
return SVN_NO_ERROR;
}
Modified: subversion/trunk/subversion/libsvn_wc/crop.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/crop.c?rev=1365997&r1=1365996&r2=1365997&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/crop.c (original)
+++ subversion/trunk/subversion/libsvn_wc/crop.c Thu Jul 26 13:54:30 2012
@@ -31,24 +31,10 @@
#include "svn_path.h"
#include "wc.h"
+#include "workqueue.h"
#include "svn_private_config.h"
-/* Evaluate EXPR. If it returns an error, return that error, unless
- the error's code is SVN_ERR_WC_LEFT_LOCAL_MOD, in which case clear
- the error and do not return. */
-#define IGNORE_LOCAL_MOD(expr) \
- do { \
- svn_error_t *__temp = (expr); \
- if (__temp) \
- { \
- if (__temp->apr_err == SVN_ERR_WC_LEFT_LOCAL_MOD) \
- svn_error_clear(__temp); \
- else \
- return svn_error_trace(__temp); \
- } \
- } while (0)
-
/* Helper function that crops the children of the LOCAL_ABSPATH, under the
* constraint of NEW_DEPTH. The DIR_PATH itself will never be cropped. The
* whole subtree should have been locked.
@@ -135,13 +121,16 @@ crop_children(svn_wc__db_t *db,
also handle it. We only need to skip the notification in that
case. */
if (new_depth == svn_depth_empty)
- IGNORE_LOCAL_MOD(
- svn_wc__internal_remove_from_revision_control(
- db,
- child_abspath,
- TRUE, /* destroy */
- cancel_func, cancel_baton,
- iterpool));
+ SVN_ERR(svn_wc__db_op_remove_node(NULL,
+ db, child_abspath,
+ TRUE /* destroy */,
+ FALSE /* destroy_changes */,
+ SVN_INVALID_REVNUM,
+ svn_wc__db_status_not_present,
+ svn_kind_none,
+ NULL, NULL,
+ cancel_func, cancel_baton,
+ iterpool));
else
continue;
@@ -150,14 +139,16 @@ crop_children(svn_wc__db_t *db,
{
if (new_depth < svn_depth_immediates)
{
- IGNORE_LOCAL_MOD(
- svn_wc__internal_remove_from_revision_control(
- db,
- child_abspath,
- TRUE, /* destroy */
- cancel_func,
- cancel_baton,
- iterpool));
+ SVN_ERR(svn_wc__db_op_remove_node(NULL,
+ db, child_abspath,
+ TRUE /* destroy */,
+ FALSE /* destroy_changes */,
+ SVN_INVALID_REVNUM,
+ svn_wc__db_status_not_present,
+ svn_kind_none,
+ NULL, NULL,
+ cancel_func, cancel_baton,
+ iterpool));
}
else
{
@@ -269,26 +260,21 @@ svn_wc_exclude(svn_wc_context_t *wc_ctx,
break; /* Ok to exclude */
}
- /* ### This could use some kind of transaction */
-
/* Remove all working copy data below local_abspath */
- IGNORE_LOCAL_MOD(svn_wc__internal_remove_from_revision_control(
- wc_ctx->db,
- local_abspath,
+ SVN_ERR(svn_wc__db_op_remove_node(NULL,
+ wc_ctx->db, local_abspath,
TRUE /* destroy */,
+ FALSE /* destroy_changes */,
+ revision,
+ svn_wc__db_status_excluded,
+ kind,
+ NULL, NULL,
cancel_func, cancel_baton,
scratch_pool));
- SVN_ERR(svn_wc__db_base_add_excluded_node(wc_ctx->db,
- local_abspath,
- repos_relpath,
- repos_root,
- repos_uuid,
- revision,
- kind,
- svn_wc__db_status_excluded,
- NULL, NULL,
- scratch_pool));
+ SVN_ERR(svn_wc__wq_run(wc_ctx->db, local_abspath,
+ cancel_func, cancel_baton,
+ scratch_pool));
if (notify_func)
{
@@ -368,7 +354,11 @@ svn_wc_crop_tree2(svn_wc_context_t *wc_c
SVN_ERR_MALFUNCTION();
}
- return crop_children(db, local_abspath, dir_depth, depth,
- notify_func, notify_baton,
- cancel_func, cancel_baton, scratch_pool);
+ SVN_ERR(crop_children(db, local_abspath, dir_depth, depth,
+ notify_func, notify_baton,
+ cancel_func, cancel_baton, scratch_pool));
+
+ return svn_error_trace(svn_wc__wq_run(db, local_abspath,
+ cancel_func, cancel_baton,
+ scratch_pool));
}
Modified: subversion/trunk/subversion/libsvn_wc/externals.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/externals.c?rev=1365997&r1=1365996&r2=1365997&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/externals.c (original)
+++ subversion/trunk/subversion/libsvn_wc/externals.c Thu Jul 26 13:54:30 2012
@@ -1309,7 +1309,7 @@ svn_wc__external_remove(svn_wc_context_t
if (kind == svn_kind_dir)
SVN_ERR(svn_wc_remove_from_revision_control2(wc_ctx, local_abspath,
- TRUE, FALSE,
+ TRUE, TRUE,
cancel_func, cancel_baton,
scratch_pool));
else
Modified: subversion/trunk/subversion/libsvn_wc/wc-queries.sql
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc-queries.sql?rev=1365997&r1=1365996&r2=1365997&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/trunk/subversion/libsvn_wc/wc-queries.sql Thu Jul 26 13:54:30 2012
@@ -163,6 +163,28 @@ WHERE wc_id = ?1 AND IS_STRICT_DESCENDAN
AND op_depth > 0)
ORDER BY local_relpath DESC
+-- STMT_SELECT_WORKING_PRESENT
+SELECT local_relpath, kind, checksum, translated_size, last_mod_time
+FROM nodes n
+WHERE wc_id = ?1
+ AND IS_STRICT_DESCENDANT_OF(local_relpath, ?2)
+ AND presence in ('normal', 'incomplete')
+ AND op_depth = (SELECT MAX(op_depth)
+ FROM NODES w
+ WHERE w.wc_id = ?1
+ AND w.local_relpath = n.local_relpath)
+ORDER BY local_relpath DESC
+
+-- STMT_DELETE_NODE_RECURSIVE
+DELETE FROM NODES
+WHERE wc_id = ?1
+ AND IS_STRICT_DESCENDANT_OF(local_relpath, ?2)
+
+-- STMT_DELETE_NODE
+DELETE
+FROM NODES
+WHERE wc_id = ?1 AND local_relpath = ?2
+
-- 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 */
Modified: subversion/trunk/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.c?rev=1365997&r1=1365996&r2=1365997&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db.c Thu Jul 26 13:54:30 2012
@@ -6546,8 +6546,17 @@ svn_wc__db_revert_list_done(svn_wc__db_t
/* Baton for remove_node_txn */
struct remove_node_baton
{
+ svn_wc__db_t *db;
+ svn_boolean_t left_changes;
+ svn_boolean_t destroy_wc;
+ svn_boolean_t destroy_changes;
svn_revnum_t not_present_rev;
+ svn_wc__db_status_t not_present_status;
svn_kind_t not_present_kind;
+ const svn_skel_t *conflict;
+ const svn_skel_t *work_items;
+ svn_cancel_func_t cancel_func;
+ void *cancel_baton;
};
/* Implements svn_wc__db_txn_callback_t for svn_wc__db_op_remove_node */
@@ -6563,7 +6572,11 @@ remove_node_txn(void *baton,
apr_int64_t repos_id;
const char *repos_relpath;
- SVN_ERR_ASSERT(*local_relpath != '\0'); /* Never on a wcroot */
+ /* Note that unlike many similar functions it is a valid scenario for this
+ function to be called on a wcroot! */
+
+ /* db set when destroying wc */
+ SVN_ERR_ASSERT(!rnb->destroy_wc || rnb->db != NULL);
/* Need info for not_present node? */
if (SVN_IS_VALID_REVNUM(rnb->not_present_rev))
@@ -6573,14 +6586,189 @@ remove_node_txn(void *baton,
wcroot, local_relpath,
scratch_pool, scratch_pool));
- SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_DELETE_NODES_ABOVE_DEPTH_RECURSIVE));
+ if (rnb->destroy_wc
+ && (!rnb->destroy_changes || *local_relpath == '\0'))
+ {
+ svn_boolean_t have_row;
+ apr_pool_t *iterpool;
+ svn_error_t *err = NULL;
- /* Remove all nodes at or below local_relpath where op_depth >= 0 */
- SVN_ERR(svn_sqlite__bindf(stmt, "isd",
- wcroot->wc_id, local_relpath, 0));
+ /* Install WQ items for deleting the unmodified files and all dirs */
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_SELECT_WORKING_PRESENT));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is",
+ wcroot->wc_id, local_relpath));
+
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+ iterpool = svn_pool_create(scratch_pool);
+
+ while (have_row)
+ {
+ const char *child_relpath;
+ const char *child_abspath;
+ svn_kind_t child_kind;
+ svn_boolean_t have_checksum;
+ svn_filesize_t recorded_size;
+ apr_int64_t recorded_mod_time;
+ const svn_io_dirent2_t *dirent;
+ svn_boolean_t modified_p = TRUE;
+ svn_skel_t *work_item = NULL;
+
+ svn_pool_clear(iterpool);
+
+ child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
+ child_kind = svn_sqlite__column_token(stmt, 1, kind_map);
+
+ child_abspath = svn_dirent_join(wcroot->abspath, child_relpath,
+ iterpool);
+
+ if (child_kind == svn_kind_file)
+ {
+ have_checksum = !svn_sqlite__column_is_null(stmt, 2);
+ recorded_size = get_recorded_size(stmt, 3);
+ recorded_mod_time = svn_sqlite__column_int64(stmt, 4);
+ }
+
+ if (rnb->cancel_func)
+ err = rnb->cancel_func(rnb->cancel_baton);
+
+ if (err)
+ break;
+
+ err = svn_io_stat_dirent(&dirent, child_abspath, TRUE,
+ iterpool, iterpool);
+
+ if (err)
+ break;
+
+ if (rnb->destroy_changes
+ || dirent->kind != svn_node_file
+ || child_kind != svn_kind_file)
+ {
+ /* Not interested in keeping changes */
+ modified_p = FALSE;
+ }
+ else if (child_kind == svn_kind_file
+ && dirent->kind == svn_node_file
+ && dirent->filesize == recorded_size
+ && dirent->mtime == recorded_mod_time)
+ {
+ modified_p = FALSE; /* File matches recorded state */
+ }
+ else if (have_checksum)
+ err = svn_wc__internal_file_modified_p(&modified_p,
+ rnb->db, child_abspath,
+ FALSE, iterpool);
+
+ if (err)
+ break;
+
+ if (modified_p)
+ rnb->left_changes = TRUE;
+ else if (child_kind == svn_kind_dir)
+ {
+ err = svn_wc__wq_build_dir_remove(&work_item,
+ rnb->db, wcroot->abspath,
+ child_abspath, FALSE,
+ iterpool, iterpool);
+ }
+ else /* svn_kind_file || svn_kind_symlink */
+ {
+ err = svn_wc__wq_build_file_remove(&work_item,
+ rnb->db, wcroot->abspath,
+ child_abspath,
+ iterpool, iterpool);
+ }
+
+ if (err)
+ break;
+
+ if (work_item)
+ {
+ err = add_work_items(wcroot->sdb, work_item, iterpool);
+ if (err)
+ break;
+ }
+
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ }
+ svn_pool_destroy(iterpool);
+
+ SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
+ }
+
+ if (rnb->destroy_wc && *local_relpath != '\0')
+ {
+ /* Create work item for destroying the root */
+ svn_wc__db_status_t status;
+ svn_kind_t kind;
+ SVN_ERR(read_info(&status, &kind, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ wcroot, local_relpath,
+ scratch_pool, scratch_pool));
+
+ if (status == svn_wc__db_status_normal
+ || status == svn_wc__db_status_added
+ || status == svn_wc__db_status_incomplete)
+ {
+ svn_skel_t *work_item = NULL;
+ const char *local_abspath = svn_dirent_join(wcroot->abspath,
+ local_relpath,
+ scratch_pool);
+
+ if (kind == svn_kind_dir)
+ {
+ SVN_ERR(svn_wc__wq_build_dir_remove(&work_item,
+ rnb->db, wcroot->abspath,
+ local_abspath,
+ rnb->destroy_changes
+ /* recursive */,
+ scratch_pool, scratch_pool));
+ }
+ else
+ {
+ svn_boolean_t modified_p = FALSE;
+
+ if (!rnb->destroy_changes)
+ {
+ SVN_ERR(svn_wc__internal_file_modified_p(&modified_p,
+ rnb->db,
+ local_abspath,
+ FALSE,
+ scratch_pool));
+ }
+
+ if (!modified_p)
+ SVN_ERR(svn_wc__wq_build_file_remove(&work_item,
+ rnb->db, wcroot->abspath,
+ local_abspath,
+ scratch_pool,
+ scratch_pool));
+ else
+ rnb->left_changes = TRUE;
+ }
+
+ SVN_ERR(add_work_items(wcroot->sdb, work_item, scratch_pool));
+ }
+ }
+
+ /* Remove all nodes below local_relpath */
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_DELETE_NODE_RECURSIVE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath, 0));
SVN_ERR(svn_sqlite__step_done(stmt));
+ /* Delete the root NODE when this is not the working copy root */
+ if (local_relpath[0] != '\0')
+ {
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_DELETE_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath, 0));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+ }
+
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_ACTUAL_NODE_RECURSIVE));
@@ -6596,7 +6784,11 @@ remove_node_txn(void *baton,
blank_ibb(&ibb);
ibb.repos_id = repos_id;
- ibb.status = svn_wc__db_status_not_present;
+
+ SVN_ERR_ASSERT(rnb->not_present_status == svn_wc__db_status_not_present
+ || rnb->not_present_status == svn_wc__db_status_excluded);
+
+ ibb.status = rnb->not_present_status;
ibb.kind = rnb->not_present_kind;
ibb.repos_relpath = repos_relpath;
@@ -6605,14 +6797,26 @@ remove_node_txn(void *baton,
SVN_ERR(insert_base_node(&ibb, wcroot, local_relpath, scratch_pool));
}
+ SVN_ERR(add_work_items(wcroot->sdb, rnb->work_items, scratch_pool));
+ if (rnb->conflict)
+ SVN_ERR(mark_conflict(wcroot, local_relpath, rnb->conflict, scratch_pool));
+
return SVN_NO_ERROR;
}
svn_error_t *
-svn_wc__db_op_remove_node(svn_wc__db_t *db,
+svn_wc__db_op_remove_node(svn_boolean_t *left_changes,
+ svn_wc__db_t *db,
const char *local_abspath,
+ svn_boolean_t destroy_wc,
+ svn_boolean_t destroy_changes,
svn_revnum_t not_present_revision,
+ svn_wc__db_status_t not_present_status,
svn_kind_t not_present_kind,
+ const svn_skel_t *conflict,
+ const svn_skel_t *work_items,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
@@ -6625,8 +6829,17 @@ svn_wc__db_op_remove_node(svn_wc__db_t *
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
+ rnb.db = db;
+ rnb.left_changes = FALSE;
+ rnb.destroy_wc = destroy_wc;
+ rnb.destroy_changes = destroy_changes;
rnb.not_present_rev = not_present_revision;
+ rnb.not_present_status = not_present_status;
rnb.not_present_kind = not_present_kind;
+ rnb.conflict = conflict;
+ rnb.work_items = work_items;
+ rnb.cancel_func = cancel_func;
+ rnb.cancel_baton = cancel_baton;
SVN_ERR(svn_wc__db_with_txn(wcroot, local_relpath, remove_node_txn,
&rnb, scratch_pool));
@@ -6635,6 +6848,9 @@ svn_wc__db_op_remove_node(svn_wc__db_t *
SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_infinity,
scratch_pool));
+ if (left_changes)
+ *left_changes = rnb.left_changes;
+
return SVN_NO_ERROR;
}
Modified: subversion/trunk/subversion/libsvn_wc/wc_db.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.h?rev=1365997&r1=1365996&r2=1365997&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db.h (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db.h Thu Jul 26 13:54:30 2012
@@ -2838,19 +2838,39 @@ svn_wc__db_wclock_owns_lock(svn_boolean_
*/
/* Removes all references to LOCAL_ABSPATH from DB, while optionally leaving
- tree conflicts and/or a not present node.
+ a not present node.
This operation always recursively removes all nodes at and below
LOCAL_ABSPATH from NODES and ACTUAL.
If NOT_PRESENT_REVISION specifies a valid revision, leave a not_present
- BASE node at local_abspath. (Requires an existing BASE node before removing)
+ BASE node at local_abspath of the specified status and kind.
+ (Requires an existing BASE node before removing)
+
+ If DESTROY_WC is TRUE, this operation *installs* workqueue operations to
+ update the local filesystem after the database operation. If DESTROY_CHANGES
+ is FALSE, modified and unversioned files are left after running this
+ operation (and the WQ). If DESTROY_CHANGES and DESTROY_WC are TRUE,
+ LOCAL_ABSPATH and everything below it will be removed by the WQ.
+
+
+ Note: Unlike many similar functions it is a valid scenario for this
+ function to be called on a wcroot! In this case it will just leave the root
+ record in BASE
*/
svn_error_t *
-svn_wc__db_op_remove_node(svn_wc__db_t *db,
+svn_wc__db_op_remove_node(svn_boolean_t *left_changes,
+ svn_wc__db_t *db,
const char *local_abspath,
+ svn_boolean_t destroy_wc,
+ svn_boolean_t destroy_changes,
svn_revnum_t not_present_revision,
+ svn_wc__db_status_t not_present_status,
svn_kind_t not_present_kind,
+ const svn_skel_t *conflict,
+ const svn_skel_t *work_items,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
apr_pool_t *scratch_pool);
/* Sets the depth of LOCAL_ABSPATH in its working copy to DEPTH using DB.