Author: gstein
Date: Wed May 11 04:06:57 2011
New Revision: 1101738
URL: http://svn.apache.org/viewvc?rev=1101738&view=rev
Log:
Factor out the notification work for op_delete() and op_set_changelist()
into new callbacks, which are then used by a new utility function that
ensures the "finalization" statements are executed (to delete the
temporary tables and triggers).
* subversion/libsvn_wc/wc_db.c:
(with_triggers): ensure the DROP_TRIGGER statements are executed before
this function returns.
(work_callback_t): new type for the "work" callback from the
finalization utility. the work callback is where the notification code
will be executed.
(with_finalization): new utility function to run a transaction, run some
work (the notifications), and then ensure that cleanup is performed.
(set_changelist_txn): create the temporary table and triggers at the
start of the transaction.
(do_changelist_notify): factored out of svn_wc__db_op_set_changelist().
it runs all the notifications for the changelist changes (as a "work"
callback for with_finalization)
(svn_wc__db_op_set_changelist): factor out the notification t
do_changelist_notify, and rejigger to call with_finalization.
(svn_wc__db_op_revert): leave a note that the flush_entries() call is
insufficient for infinite-depth reverts.
(do_delete_notify): factored out of svn_wc__db_Op_delete(). it runs all
the notifications for the deletions (as a "work" callback for
with_finalization).
(svn_wc__db_op_delete): factor out the notifications and call
with_finalization.
* subversion/libsvn_wc/wc-queries.sql:
(STMT_DROP_CHANGELIST_LIST_TRIGGERS): removed. folded the DROP TRIGGER
statements into STMT_DROP_CHANGELIST_LIST
Modified:
subversion/trunk/subversion/libsvn_wc/wc-queries.sql
subversion/trunk/subversion/libsvn_wc/wc_db.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=1101738&r1=1101737&r2=1101738&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/trunk/subversion/libsvn_wc/wc-queries.sql Wed May 11 04:06:57
2011
@@ -421,16 +421,14 @@ BEGIN
VALUES (NEW.wc_id, NEW.local_relpath, 26, NEW.changelist);
END
--- STMT_DROP_CHANGELIST_LIST_TRIGGERS
-DROP TRIGGER IF EXISTS trigger_changelist_list_actual_cl_insert;
-DROP TRIGGER IF EXISTS trigger_changelist_list_actual_cl_set;
-DROP TRIGGER IF EXISTS trigger_changelist_list_actual_cl_clear
-
-- STMT_INSERT_CHANGELIST_LIST
INSERT INTO changelist_list(wc_id, local_relpath, notify, changelist)
VALUES (?1, ?2, ?3, ?4)
-- STMT_DROP_CHANGELIST_LIST
+DROP TRIGGER IF EXISTS trigger_changelist_list_actual_cl_insert;
+DROP TRIGGER IF EXISTS trigger_changelist_list_actual_cl_set;
+DROP TRIGGER IF EXISTS trigger_changelist_list_actual_cl_clear;
DROP TABLE IF EXISTS changelist_list
-- STMT_SELECT_CHANGELIST_LIST
Modified: subversion/trunk/subversion/libsvn_wc/wc_db.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.c?rev=1101738&r1=1101737&r2=1101738&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db.c Wed May 11 04:06:57 2011
@@ -2453,6 +2453,7 @@ depth_get_info(svn_wc__db_status_t *stat
return svn_error_compose_create(err, svn_sqlite__reset(stmt));
}
+
/* Helper for creating SQLite triggers, running the main transaction
callback, and then dropping the triggers. It guarantees that the
triggers will not survive the transaction. This could be used for
@@ -2465,6 +2466,7 @@ struct with_triggers_baton_t {
void *cb_baton;
};
+/* conforms to svn_wc__db_txn_callback_t */
static svn_error_t *
with_triggers(void *baton,
svn_wc__db_wcroot_t *wcroot,
@@ -2472,16 +2474,64 @@ with_triggers(void *baton,
apr_pool_t *scratch_pool)
{
struct with_triggers_baton_t *b = baton;
+ svn_error_t *err1;
+ svn_error_t *err2;
SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb, b->create_trigger));
- SVN_ERR(b->cb_func(b->cb_baton, wcroot, local_relpath, scratch_pool));
+ err1 = b->cb_func(b->cb_baton, wcroot, local_relpath, scratch_pool);
- SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb, b->drop_trigger));
+ err2 = svn_sqlite__exec_statements(wcroot->sdb, b->drop_trigger);
- return SVN_NO_ERROR;
+ return svn_error_return(svn_error_compose_create(err1, err2));
+}
+
+
+typedef svn_error_t * (*work_callback_t)(
+ void *baton,
+ svn_wc__db_wcroot_t *wcroot,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ svn_wc_notify_func2_t notify_func,
+ void *notify_baton,
+ apr_pool_t *scratch_pool);
+
+static svn_error_t *
+with_finalization(void *baton,
+ svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ svn_wc__db_txn_callback_t txn_cb,
+ void *txn_baton,
+ work_callback_t work_cb,
+ void *work_baton,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ svn_wc_notify_func2_t notify_func,
+ void *notify_baton,
+ int finalize_idx,
+ apr_pool_t *scratch_pool)
+{
+ svn_error_t *err1;
+ svn_error_t *err2;
+
+ err1 = svn_wc__db_with_txn(wcroot, local_relpath, txn_cb, txn_baton,
+ scratch_pool);
+
+ if (notify_func != NULL)
+ {
+ err2 = work_cb(work_baton, wcroot,
+ cancel_func, cancel_baton,
+ notify_func, notify_baton,
+ scratch_pool);
+ err1 = svn_error_compose_create(err1, err2);
+ }
+
+ err2 = svn_sqlite__exec_statements(wcroot->sdb, finalize_idx);
+
+ return svn_error_return(svn_error_compose_create(err1, err2));
}
+
static void
blank_ieb(insert_external_baton_t *ieb)
{
@@ -4915,6 +4965,9 @@ set_changelist_txn(void *baton,
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
+ SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb,
+ STMT_CREATE_CHANGELIST_LIST));
+
/* If we are filtering based on changelist_filter, we *must* already have
nodes, so we can skip this check. */
if (scb->changelist_filter && scb->changelist_filter->nelts > 0)
@@ -5000,75 +5053,24 @@ set_changelist_txn(void *baton,
}
-svn_error_t *
-svn_wc__db_op_set_changelist(svn_wc__db_t *db,
- const char *local_abspath,
- const char *new_changelist,
- const apr_array_header_t *changelist_filter,
- svn_depth_t depth,
- svn_wc_notify_func2_t notify_func,
- void *notify_baton,
- svn_cancel_func_t cancel_func,
- void *cancel_baton,
- apr_pool_t *scratch_pool)
+static svn_error_t *
+do_changelist_notify(void *baton,
+ svn_wc__db_wcroot_t *wcroot,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ svn_wc_notify_func2_t notify_func,
+ void *notify_baton,
+ apr_pool_t *scratch_pool)
{
- svn_wc__db_wcroot_t *wcroot;
- const char *local_relpath;
- struct set_changelist_baton_t scb = { new_changelist, changelist_filter };
- struct with_triggers_baton_t wtb = { STMT_CREATE_CHANGELIST_LIST,
- STMT_DROP_CHANGELIST_LIST_TRIGGERS,
- NULL, NULL };
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
- apr_pool_t *iterpool = svn_pool_create(scratch_pool);
-
- 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);
-
- switch (depth)
- {
- case svn_depth_empty:
- wtb.cb_func = set_changelist_txn;
- break;
-
- default:
- /* ### This is only implemented for depth = empty right now. */
- NOT_IMPLEMENTED();
- }
-
- wtb.cb_baton = &scb;
-
- /* ### fix up the code below: if the callback is invokved, then the
- ### 'changelist_list' table may exist. We should ensure it gets dropped
- ### before we exit this function. */
-
- SVN_ERR(svn_wc__db_with_txn(wcroot, local_relpath, with_triggers, &wtb,
- iterpool));
- SVN_ERR(flush_entries(wcroot, local_abspath, iterpool));
-
- /* ### can we unify this notification logic, in some way, with the
- ### similar logic in op_delete? ... I think we probably want a
- ### notify_callback that represents the inner loop. the statement
- ### selection and binding is probably similar (especially if we
- ### remove like_arg, as questioned below). the unification could
- ### look similar to db_with_txn or the with_triggers stuff. */
-
- /* ### why we do filter SOME of the changelist notifications? if a row
- ### is inserted, then don't we want to send a notification for it? */
-
- if (notify_func == NULL)
- {
- svn_pool_destroy(iterpool);
- return SVN_NO_ERROR;
- }
+ apr_pool_t *iterpool;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_CHANGELIST_LIST));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ iterpool = svn_pool_create(scratch_pool);
while (have_row)
{
/* ### wc_id is column 0. use it one day... */
@@ -5090,13 +5092,53 @@ svn_wc__db_op_set_changelist(svn_wc__db_
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
- SVN_ERR(svn_sqlite__reset(stmt));
+ svn_pool_destroy(iterpool);
- SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb, STMT_DROP_CHANGELIST_LIST));
+ return svn_error_return(svn_sqlite__reset(stmt));
+}
- svn_pool_destroy(iterpool);
- return SVN_NO_ERROR;
+svn_error_t *
+svn_wc__db_op_set_changelist(svn_wc__db_t *db,
+ const char *local_abspath,
+ const char *new_changelist,
+ const apr_array_header_t *changelist_filter,
+ svn_depth_t depth,
+ svn_wc_notify_func2_t notify_func,
+ void *notify_baton,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_wcroot_t *wcroot;
+ const char *local_relpath;
+ struct set_changelist_baton_t scb = { new_changelist, changelist_filter };
+
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+ SVN_ERR_ASSERT(depth == svn_depth_empty);
+
+ SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_WCROOT(wcroot);
+
+ /* Flush the entries before we do the work. Even if no work is performed,
+ the flush isn't a problem.
+
+ ### if DEPTH ever svn_depth_infinity, then we need to recursively
+ ### wipe out all the entries. */
+ SVN_ERR(flush_entries(wcroot, local_abspath, scratch_pool));
+
+ /* Perform the set-changelist operation (transactionally), perform any
+ notifications necessary, and then clean out our temporary tables. */
+ return svn_error_return(with_finalization(NULL,
+ wcroot, local_relpath,
+ set_changelist_txn, &scb,
+ do_changelist_notify, NULL,
+ cancel_func, cancel_baton,
+ notify_func, notify_baton,
+ STMT_DROP_CHANGELIST_LIST,
+ scratch_pool));
}
@@ -5482,6 +5524,8 @@ svn_wc__db_op_revert(svn_wc__db_t *db,
SVN_ERR(svn_wc__db_with_txn(wcroot, local_relpath, with_triggers, &wtb,
scratch_pool));
+ /* ### this is not good enough! when DEPTH is svn_depth_infinity, we need
+ ### to flush entries recursively. */
SVN_ERR(flush_entries(wcroot, local_abspath, scratch_pool));
return SVN_NO_ERROR;
@@ -6192,6 +6236,53 @@ op_delete_txn(void *baton,
}
+static svn_error_t *
+do_delete_notify(void *baton,
+ svn_wc__db_wcroot_t *wcroot,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ svn_wc_notify_func2_t notify_func,
+ void *notify_baton,
+ apr_pool_t *scratch_pool)
+{
+ svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
+ apr_pool_t *iterpool;
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_SELECT_DELETE_LIST));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+ iterpool = svn_pool_create(scratch_pool);
+ while (have_row)
+ {
+ const char *notify_relpath;
+ const char *notify_abspath;
+
+ svn_pool_clear(iterpool);
+
+ if (cancel_func)
+ SVN_ERR(cancel_func(cancel_baton));
+
+ notify_relpath = svn_sqlite__column_text(stmt, 0, NULL);
+ notify_abspath = svn_dirent_join(wcroot->abspath,
+ notify_relpath,
+ iterpool);
+
+ notify_func(notify_baton,
+ svn_wc_create_notify(notify_abspath,
+ svn_wc_notify_delete,
+ iterpool),
+ iterpool);
+
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ }
+ svn_pool_destroy(iterpool);
+
+ return svn_error_return(svn_sqlite__reset(stmt));
+}
+
+
svn_error_t *
svn_wc__db_op_delete(svn_wc__db_t *db,
const char *local_abspath,
@@ -6203,67 +6294,31 @@ svn_wc__db_op_delete(svn_wc__db_t *db,
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
- struct op_delete_baton_t b;
+ struct op_delete_baton_t odb;
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));
+ db, local_abspath,
+ scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
- b.delete_depth = relpath_depth(local_relpath);
-
- /* ### fix up the code below: if we call op_delete_txn(), then the
- ### 'delete_list' table may exist. We should ensure it gets dropped
- ### before we exit this function. */
+ odb.delete_depth = relpath_depth(local_relpath);
- SVN_ERR(svn_wc__db_with_txn(wcroot, local_relpath, op_delete_txn, &b,
- scratch_pool));
+ /* ### this is NOT good enough! ... we may need to flush entries
+ ### recursively. */
SVN_ERR(flush_entries(wcroot, local_abspath, scratch_pool));
- /* Now that we're outside of the SQLite transaction, we want to process
- the deletion notification list, then dump the table. */
- if (notify_func)
- {
- svn_sqlite__stmt_t *stmt;
- svn_boolean_t have_row;
- apr_pool_t *iterpool = svn_pool_create(scratch_pool);
-
- SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_SELECT_DELETE_LIST));
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
- while (have_row)
- {
- const char *notify_relpath;
- const char *notify_abspath;
-
- svn_pool_clear(iterpool);
-
- if (cancel_func)
- SVN_ERR(cancel_func(cancel_baton));
-
- notify_relpath = svn_sqlite__column_text(stmt, 0, NULL);
- notify_abspath = svn_dirent_join(wcroot->abspath,
- notify_relpath,
- iterpool);
-
- notify_func(notify_baton,
- svn_wc_create_notify(notify_abspath,
- svn_wc_notify_delete,
- iterpool),
- iterpool);
-
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
- }
-
- SVN_ERR(svn_sqlite__reset(stmt));
-
- svn_pool_destroy(iterpool);
- }
-
- SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb, STMT_DROP_DELETE_LIST));
-
- return SVN_NO_ERROR;
+ /* Perform the deletion operation (transactionally), perform any
+ notifications necessary, and then clean out our temporary tables. */
+ return svn_error_return(with_finalization(NULL,
+ wcroot, local_relpath,
+ op_delete_txn, &odb,
+ do_delete_notify, NULL,
+ cancel_func, cancel_baton,
+ notify_func, notify_baton,
+ STMT_DROP_DELETE_LIST,
+ scratch_pool));
}