Author: rhuijben
Date: Wed Feb 4 10:07:04 2015
New Revision: 1657083
URL: http://svn.apache.org/r1657083
Log:
Replace some wc-db queries per node during 'svn revert -R' with queries per
directory, by using a bit of the status and workqueue helper code.
This saves about 25% actual time of 'svn revert -R WC-ROOT' time for me
on a huge multibranch checkout on a network drive, where the WC doesn't
have changes.
* subversion/libsvn_wc/revert.c
(revert_wc_data): Add argument for per dir wq handling.
(revert_restore): Add run_wq and info arguments. Read info for the children
instead of just the names. Notify descendants just for dirs, as caller
will take care of the rest.
(revert_wc_data): Use the workqueue as a queue to optimize nr of queries.
(revert): Update caller. Add some tracing.
Modified:
subversion/trunk/subversion/libsvn_wc/revert.c
Modified: subversion/trunk/subversion/libsvn_wc/revert.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/revert.c?rev=1657083&r1=1657082&r2=1657083&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/revert.c (original)
+++ subversion/trunk/subversion/libsvn_wc/revert.c Wed Feb 4 10:07:04 2015
@@ -248,7 +248,8 @@ revert_restore_handle_copied_dirs(svn_bo
/* Forward definition */
static svn_error_t *
-revert_wc_data(svn_boolean_t *notify_required,
+revert_wc_data(svn_boolean_t *run_wq,
+ svn_boolean_t *notify_required,
svn_wc__db_t *db,
const char *local_abspath,
svn_wc__db_status_t status,
@@ -269,21 +270,28 @@ revert_wc_data(svn_boolean_t *notify_req
REVERT_ROOT is true for explicit revert targets and FALSE for targets
reached via recursion.
+
+ Sets *RUN_WQ to TRUE when the caller should (eventually) run the workqueue.
+ (The function sets it to FALSE when it has run the WQ itself)
+
+ If INFO is NULL, LOCAL_ABSPATH doesn't exist in DB. Otherwise INFO
+ specifies the state of LOCAL_ABSPATH in DB.
*/
static svn_error_t *
-revert_restore(svn_wc__db_t *db,
+revert_restore(svn_boolean_t *run_wq,
+ svn_wc__db_t *db,
const char *local_abspath,
svn_depth_t depth,
svn_boolean_t metadata_only,
svn_boolean_t use_commit_times,
svn_boolean_t revert_root,
+ const struct svn_wc__db_info_t *info,
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_error_t *err;
svn_wc__db_status_t status;
svn_node_kind_t kind;
svn_boolean_t notify_required;
@@ -323,17 +331,15 @@ revert_restore(svn_wc__db_t *db,
db, local_abspath,
scratch_pool, scratch_pool));
- err = svn_wc__db_read_info(&status, &kind,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- &recorded_size, &recorded_time, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- db, local_abspath, scratch_pool, scratch_pool);
-
- if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+ if (info)
+ {
+ status = info->status;
+ kind = info->kind;
+ recorded_size = info->recorded_size;
+ recorded_time = info->recorded_time;
+ }
+ else
{
- svn_error_clear(err);
-
if (!copied_here)
{
if (notify_func && notify_required)
@@ -360,18 +366,19 @@ revert_restore(svn_wc__db_t *db,
recorded_time = 0;
}
}
- else
- SVN_ERR(err);
if (!metadata_only)
{
- SVN_ERR(revert_wc_data(¬ify_required,
+ SVN_ERR(revert_wc_data(run_wq,
+ ¬ify_required,
db, local_abspath, status, kind,
reverted_kind, recorded_size, recorded_time,
copied_here, use_commit_times,
cancel_func, cancel_baton, scratch_pool));
}
+ /* We delete these marker files even though they are not strictly metadata.
+ But for users that use revert as an API with metadata_only, these are. */
if (conflict_files)
{
int i;
@@ -393,46 +400,59 @@ revert_restore(svn_wc__db_t *db,
if (depth == svn_depth_infinity && kind == svn_node_dir)
{
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
- const apr_array_header_t *children;
- int i;
+ apr_hash_t *children, *conflicts;
+ apr_hash_index_t *hi;
SVN_ERR(revert_restore_handle_copied_dirs(NULL, db, local_abspath, FALSE,
cancel_func, cancel_baton,
iterpool));
- SVN_ERR(svn_wc__db_read_children_of_working_node(&children, db,
- local_abspath,
- scratch_pool,
- iterpool));
- for (i = 0; i < children->nelts; ++i)
+ SVN_ERR(svn_wc__db_read_children_info(&children, &conflicts,
+ db, local_abspath, FALSE,
+ scratch_pool, iterpool));
+
+ for (hi = apr_hash_first(scratch_pool, children);
+ hi;
+ hi = apr_hash_next(hi))
{
+ const char *child_name = apr_hash_this_key(hi);
const char *child_abspath;
svn_pool_clear(iterpool);
- child_abspath = svn_dirent_join(local_abspath,
- APR_ARRAY_IDX(children, i,
- const char *),
- iterpool);
+ child_abspath = svn_dirent_join(local_abspath, child_name, iterpool);
- SVN_ERR(revert_restore(db, child_abspath, depth, metadata_only,
+ SVN_ERR(revert_restore(run_wq,
+ db, child_abspath, depth, metadata_only,
use_commit_times, FALSE /* revert root */,
+ apr_hash_this_val(hi),
cancel_func, cancel_baton,
notify_func, notify_baton,
iterpool));
}
+ /* Run the queue per directory */
+ if (*run_wq)
+ {
+ SVN_ERR(svn_wc__wq_run(db, local_abspath, cancel_func, cancel_baton,
+ iterpool));
+ *run_wq = FALSE;
+ }
+
+ if (notify_func)
+ SVN_ERR(svn_wc__db_revert_list_notify(notify_func, notify_baton,
+ db, local_abspath, iterpool));
+
svn_pool_destroy(iterpool);
}
- if (notify_func)
- SVN_ERR(svn_wc__db_revert_list_notify(notify_func, notify_baton,
- db, local_abspath, scratch_pool));
return SVN_NO_ERROR;
}
+/* Perform the in-working copy revert of LOCAL_ABSPATH, to what is stored in
DB */
static svn_error_t *
-revert_wc_data(svn_boolean_t *notify_required,
+revert_wc_data(svn_boolean_t *run_wq,
+ svn_boolean_t *notify_required,
svn_wc__db_t *db,
const char *local_abspath,
svn_wc__db_status_t status,
@@ -453,6 +473,9 @@ revert_wc_data(svn_boolean_t *notify_req
svn_boolean_t special;
#endif
+ /* Would be nice to use svn_io_dirent2_t here, but the performance
+ improvement that provides doesn't work, because we need the read
+ only and executable bits later on, in the most likely code path */
err = svn_io_stat(&finfo, local_abspath,
APR_FINFO_TYPE | APR_FINFO_LINK
| APR_FINFO_SIZE | APR_FINFO_MTIME
@@ -578,14 +601,14 @@ revert_wc_data(svn_boolean_t *notify_req
modified = FALSE;
}
else
+ /* Side effect: fixes recorded timestamps */
SVN_ERR(svn_wc__internal_file_modified_p(&modified,
db, local_abspath,
TRUE, scratch_pool));
if (modified)
{
- SVN_ERR(svn_io_remove_file2(local_abspath, FALSE,
- scratch_pool));
+ /* Install will replace the file */
on_disk = svn_node_none;
}
else
@@ -664,14 +687,12 @@ revert_wc_data(svn_boolean_t *notify_req
{
svn_skel_t *work_item;
- /* ### Get the checksum from read_info above and pass in here? */
SVN_ERR(svn_wc__wq_build_file_install(&work_item, db, local_abspath,
NULL, use_commit_times, TRUE,
scratch_pool, scratch_pool));
SVN_ERR(svn_wc__db_wq_add(db, local_abspath, work_item,
scratch_pool));
- SVN_ERR(svn_wc__wq_run(db, local_abspath, cancel_func, cancel_baton,
- scratch_pool));
+ *run_wq = TRUE;
}
*notify_required = TRUE;
}
@@ -694,6 +715,8 @@ revert(svn_wc__db_t *db,
apr_pool_t *scratch_pool)
{
svn_error_t *err;
+ const struct svn_wc__db_info_t *info = NULL;
+ svn_boolean_t run_queue = FALSE;
SVN_ERR_ASSERT(depth == svn_depth_empty || depth == svn_depth_infinity);
@@ -713,15 +736,37 @@ revert(svn_wc__db_t *db,
SVN_ERR(svn_wc__write_check(db, dir_abspath, scratch_pool));
}
- err = svn_wc__db_op_revert(db, local_abspath, depth, clear_changelists,
- scratch_pool, scratch_pool);
+ err = svn_error_trace(
+ svn_wc__db_op_revert(db, local_abspath, depth, clear_changelists,
+ scratch_pool, scratch_pool));
if (!err)
- err = revert_restore(db, local_abspath, depth, metadata_only,
- use_commit_times, TRUE /* revert root */,
- cancel_func, cancel_baton,
- notify_func, notify_baton,
- scratch_pool);
+ {
+ err = svn_error_trace(
+ svn_wc__db_read_single_info(&info, db, local_abspath, FALSE,
+ scratch_pool, scratch_pool));
+
+ if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+ {
+ svn_error_clear(err);
+ err = NULL;
+ info = NULL;
+ }
+ }
+
+ if (!err)
+ err = svn_error_trace(
+ revert_restore(&run_queue, db, local_abspath, depth,
metadata_only,
+ use_commit_times, TRUE /* revert root */,
+ info, cancel_func, cancel_baton,
+ notify_func, notify_baton,
+ scratch_pool));
+
+ if (run_queue)
+ err = svn_error_compose_create(err,
+ svn_wc__wq_run(db, local_abspath,
+ cancel_func, cancel_baton,
+ scratch_pool));
err = svn_error_compose_create(err,
svn_wc__db_revert_list_done(db,