Author: stefan2 Date: Mon May 16 00:02:05 2011 New Revision: 1103578 URL: http://svn.apache.org/viewvc?rev=1103578&view=rev Log: Eliminate unnecessary stat calls during checkout, part 1 of 2. Most c/o will be to an otherwise empty directory. In that case, we don't need to check for obstructions.
* subversion/include/svn_wc.h (svn_wc_get_update_editor4): add clean_checkout parameter * subversion/libsvn_wc/deprecated.c (svn_wc_get_update_editor3): disable optimization for legacy API * subversion/libsvn_wc/update_editor.c (edit_baton): add clean_checkout flag (add_file): skip obstruction checks if that flag has been set (make_editor): add clean_checkout parameter and pass it on to baton (svn_wc_get_update_editor4): pass clean_checkout through to make_editor (svn_wc_get_switch_editor4): disable optimization for switch ops * subversion/libsvn_client/update.c (is_empty_wc): new utility function (update_internal): detect applicability of "clean c/o" optimization and parametrize update_editor accordingly Modified: subversion/trunk/subversion/include/svn_wc.h subversion/trunk/subversion/libsvn_client/update.c subversion/trunk/subversion/libsvn_wc/deprecated.c subversion/trunk/subversion/libsvn_wc/update_editor.c Modified: subversion/trunk/subversion/include/svn_wc.h URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_wc.h?rev=1103578&r1=1103577&r2=1103578&view=diff ============================================================================== --- subversion/trunk/subversion/include/svn_wc.h (original) +++ subversion/trunk/subversion/include/svn_wc.h Mon May 16 00:02:05 2011 @@ -5439,6 +5439,7 @@ svn_wc_get_update_editor4(const svn_delt svn_boolean_t allow_unver_obstructions, svn_boolean_t adds_as_modification, svn_boolean_t server_performs_filtering, + svn_boolean_t clean_checkout, const char *diff3_cmd, const apr_array_header_t *preserved_exts, svn_wc_dirents_func_t fetch_dirents_func, @@ -5465,8 +5466,8 @@ svn_wc_get_update_editor4(const svn_delt * All locks, both those in @a anchor and newly acquired ones, will be * released when the editor driver calls @c close_edit. * - * Always sets @a adds_as_modification to TRUE and @a server_performs_filtering - * to FALSE. + * Always sets @a adds_as_modification to TRUE, @a server_performs_filtering + * and @a clean_checkout to FALSE. * * Uses a svn_wc_conflict_resolver_func_t conflict resolver instead of a * svn_wc_conflict_resolver_func2_t. Modified: subversion/trunk/subversion/libsvn_client/update.c URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/update.c?rev=1103578&r1=1103577&r2=1103578&view=diff ============================================================================== --- subversion/trunk/subversion/libsvn_client/update.c (original) +++ subversion/trunk/subversion/libsvn_client/update.c Mon May 16 00:02:05 2011 @@ -92,6 +92,59 @@ svn_client__dirent_fetcher(void *baton, /*** Code. ***/ +/* Set *CLEAN_CHECKOUT to FALSE only if LOCAL_ABSPATH is a non-empty + folder. ANCHOR_ABSPATH is the w/c root and LOCAL_ABSPATH will still + be considered empty, if it is equal to ANCHOR_ABSPATH and only + contains the admin sub-folder. + */ +static svn_error_t * +is_empty_wc(const char *local_abspath, + const char *anchor_abspath, + svn_boolean_t *clean_checkout, + apr_pool_t *pool) +{ + apr_dir_t *dir; + apr_finfo_t finfo; + svn_error_t *err; + + /* "clean" until found dirty */ + *clean_checkout = TRUE; + + /* open directory. If it does not exist, yet, a clean one will + be created by the caller. If it cannot be openend for other + reasons, the caller will detect and report those as well. */ + err = svn_io_dir_open(&dir, local_abspath, pool); + if (err) + { + svn_error_clear(err); + return SVN_NO_ERROR; + } + + for (err = svn_io_dir_read(&finfo, APR_FINFO_NAME, dir, pool); + err == SVN_NO_ERROR; + err = svn_io_dir_read(&finfo, APR_FINFO_NAME, dir, pool)) + { + /* Ignore entries for this dir and its parent, robustly. + (APR promises that they'll come first, so technically + this guard could be moved outside the loop. But Ryan Bloom + says he doesn't believe it, and I believe him. */ + if (! (finfo.name[0] == '.' + && (finfo.name[1] == '\0' + || (finfo.name[1] == '.' && finfo.name[2] == '\0')))) + { + if ( ! svn_wc_is_adm_dir(finfo.name, pool) + || strcmp(local_abspath, anchor_abspath) != 0) + { + *clean_checkout = FALSE; + break; + } + } + } + + svn_error_clear(err); + return svn_io_dir_close(dir); +} + /* This is a helper for svn_client__update_internal(), which see for an explanation of most of these parameters. Some stuff that's unique is as follows: @@ -134,6 +187,7 @@ update_internal(svn_revnum_t *result_rev svn_boolean_t use_commit_times; svn_boolean_t sleep_here = FALSE; svn_boolean_t *use_sleep = timestamp_sleep ? timestamp_sleep : &sleep_here; + svn_boolean_t clean_checkout = FALSE; const char *diff3_cmd; svn_ra_session_t *ra_session; const char *preserved_exts_str; @@ -211,6 +265,9 @@ update_internal(svn_revnum_t *result_rev } } + /* check whether the "clean c/o" optimization is applicable */ + SVN_ERR(is_empty_wc(local_abspath, anchor_abspath, &clean_checkout, pool)); + /* Get the external diff3, if any. */ svn_config_get(cfg, &diff3_cmd, SVN_CONFIG_SECTION_HELPERS, SVN_CONFIG_OPTION_DIFF3_CMD, NULL); @@ -299,6 +356,7 @@ update_internal(svn_revnum_t *result_rev depth_is_sticky, allow_unver_obstructions, adds_as_modification, server_supports_depth, + clean_checkout, diff3_cmd, preserved_exts, svn_client__dirent_fetcher, &dfb, ctx->conflict_func2, ctx->conflict_baton2, Modified: subversion/trunk/subversion/libsvn_wc/deprecated.c URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/deprecated.c?rev=1103578&r1=1103577&r2=1103578&view=diff ============================================================================== --- subversion/trunk/subversion/libsvn_wc/deprecated.c (original) +++ subversion/trunk/subversion/libsvn_wc/deprecated.c Mon May 16 00:02:05 2011 @@ -3097,6 +3097,7 @@ svn_wc_get_update_editor3(svn_revnum_t * allow_unver_obstructions, TRUE /* adds_as_modification */, FALSE /* server_performs_filtering */, + FALSE /* clean_checkout */, diff3_cmd, preserved_exts, NULL, NULL, /* fetch_dirents_func, baton */ Modified: subversion/trunk/subversion/libsvn_wc/update_editor.c URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/update_editor.c?rev=1103578&r1=1103577&r2=1103578&view=diff ============================================================================== --- subversion/trunk/subversion/libsvn_wc/update_editor.c (original) +++ subversion/trunk/subversion/libsvn_wc/update_editor.c Mon May 16 00:02:05 2011 @@ -190,6 +190,10 @@ struct edit_baton /* Handle local additions as modifications of new nodes */ svn_boolean_t adds_as_modification; + /* If set, we check out into an empty directory. This allows for a number + of conflict checks to be omitted. */ + svn_boolean_t clean_checkout; + /* If this is a 'switch' operation, the new relpath of target_abspath, else NULL. */ const char *switch_relpath; @@ -2807,14 +2811,14 @@ add_file(const char *path, struct dir_baton *pb = parent_baton; struct edit_baton *eb = pb->edit_baton; struct file_baton *fb; - svn_node_kind_t kind; - svn_wc__db_kind_t wc_kind; - svn_wc__db_status_t status; + svn_node_kind_t kind = svn_node_none; + svn_wc__db_kind_t wc_kind = svn_wc__db_kind_unknown; + svn_wc__db_status_t status = svn_wc__db_status_normal; apr_pool_t *scratch_pool; - svn_boolean_t conflicted; - svn_boolean_t versioned_locally_and_present; + svn_boolean_t conflicted = FALSE; + svn_boolean_t versioned_locally_and_present = FALSE; svn_wc_conflict_description2_t *tree_conflict = NULL; - svn_error_t *err; + svn_error_t *err = SVN_NO_ERROR; SVN_ERR_ASSERT(! (copyfrom_path || SVN_IS_VALID_REVNUM(copyfrom_rev))); @@ -2839,14 +2843,17 @@ add_file(const char *path, "administrative directory"), svn_dirent_local_style(fb->local_abspath, pool)); - SVN_ERR(svn_io_check_path(fb->local_abspath, &kind, scratch_pool)); + if (!eb->clean_checkout) + { + SVN_ERR(svn_io_check_path(fb->local_abspath, &kind, scratch_pool)); - err = svn_wc__db_read_info(&status, &wc_kind, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, - &conflicted, NULL, NULL, NULL, NULL, NULL, NULL, - eb->db, fb->local_abspath, - scratch_pool, scratch_pool); + err = svn_wc__db_read_info(&status, &wc_kind, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + &conflicted, NULL, NULL, NULL, NULL, NULL, NULL, + eb->db, fb->local_abspath, + scratch_pool, scratch_pool); + } if (err) { @@ -2855,7 +2862,6 @@ add_file(const char *path, svn_error_clear(err); wc_kind = svn_wc__db_kind_unknown; - status = svn_wc__db_status_normal; conflicted = FALSE; versioned_locally_and_present = FALSE; @@ -4344,6 +4350,7 @@ make_editor(svn_revnum_t *target_revisio svn_boolean_t allow_unver_obstructions, svn_boolean_t adds_as_modification, svn_boolean_t server_performs_filtering, + svn_boolean_t clean_checkout, svn_wc_notify_func2_t notify_func, void *notify_baton, svn_cancel_func_t cancel_func, @@ -4428,6 +4435,7 @@ make_editor(svn_revnum_t *target_revisio eb->conflict_baton = conflict_baton; eb->allow_unver_obstructions = allow_unver_obstructions; eb->adds_as_modification = adds_as_modification; + eb->clean_checkout = clean_checkout; eb->skipped_trees = apr_hash_make(edit_pool); eb->dir_dirents = apr_hash_make(edit_pool); eb->ext_patterns = preserved_exts; @@ -4609,6 +4617,7 @@ svn_wc_get_update_editor4(const svn_delt svn_boolean_t allow_unver_obstructions, svn_boolean_t adds_as_modification, svn_boolean_t server_performs_filtering, + svn_boolean_t clean_checkout, const char *diff3_cmd, const apr_array_header_t *preserved_exts, svn_wc_dirents_func_t fetch_dirents_func, @@ -4628,6 +4637,7 @@ svn_wc_get_update_editor4(const svn_delt target_basename, use_commit_times, NULL, depth, depth_is_sticky, allow_unver_obstructions, adds_as_modification, server_performs_filtering, + clean_checkout, notify_func, notify_baton, cancel_func, cancel_baton, fetch_dirents_func, fetch_dirents_baton, @@ -4673,6 +4683,7 @@ svn_wc_get_switch_editor4(const svn_delt depth, depth_is_sticky, allow_unver_obstructions, FALSE /* adds_as_modification */, server_performs_filtering, + FALSE /* clean_checkout */, notify_func, notify_baton, cancel_func, cancel_baton, fetch_dirents_func, fetch_dirents_baton,