Modified: subversion/branches/authzperf/subversion/libsvn_wc/diff_editor.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_wc/diff_editor.c?rev=1649205&r1=1649204&r2=1649205&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/libsvn_wc/diff_editor.c (original) +++ subversion/branches/authzperf/subversion/libsvn_wc/diff_editor.c Sat Jan 3 14:00:41 2015 @@ -115,9 +115,6 @@ struct edit_baton_t /* Possibly diff repos against text-bases instead of working files. */ svn_boolean_t diff_pristine; - /* Hash whose keys are const char * changelist names. */ - apr_hash_t *changelist_hash; - /* Cancel function/baton */ svn_cancel_func_t cancel_func; void *cancel_baton; @@ -239,11 +236,6 @@ struct file_baton_t * calculating diffs. USE_TEXT_BASE defines whether to compare * against working files or text-bases. REVERSE_ORDER defines which * direction to perform the diff. - * - * CHANGELIST_FILTER is a list of const char * changelist names, used to - * filter diff output responses to only those items in one of the - * specified changelists, empty (or NULL altogether) if no changelist - * filtering is requested. */ static svn_error_t * make_edit_baton(struct edit_baton_t **edit_baton, @@ -255,20 +247,14 @@ make_edit_baton(struct edit_baton_t **ed svn_boolean_t ignore_ancestry, svn_boolean_t use_text_base, svn_boolean_t reverse_order, - const apr_array_header_t *changelist_filter, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool) { - apr_hash_t *changelist_hash = NULL; struct edit_baton_t *eb; SVN_ERR_ASSERT(svn_dirent_is_absolute(anchor_abspath)); - if (changelist_filter && changelist_filter->nelts) - SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter, - pool)); - eb = apr_pcalloc(pool, sizeof(*eb)); eb->db = db; eb->anchor_abspath = apr_pstrdup(pool, anchor_abspath); @@ -278,7 +264,6 @@ make_edit_baton(struct edit_baton_t **ed eb->ignore_ancestry = ignore_ancestry; eb->local_before_remote = reverse_order; eb->diff_pristine = use_text_base; - eb->changelist_hash = changelist_hash; eb->cancel_func = cancel_func; eb->cancel_baton = cancel_baton; eb->pool = pool; @@ -392,7 +377,6 @@ svn_wc__diff_base_working_diff(svn_wc__d const char *local_abspath, const char *relpath, svn_revnum_t revision, - apr_hash_t *changelist_hash, const svn_diff_tree_processor_t *processor, void *processor_dir_baton, svn_boolean_t diff_pristine, @@ -419,12 +403,11 @@ svn_wc__diff_base_working_diff(svn_wc__d apr_hash_t *base_props; apr_hash_t *local_props; apr_array_header_t *prop_changes; - const char *changelist; SVN_ERR(svn_wc__db_read_info(&status, NULL, &db_revision, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &working_checksum, NULL, NULL, NULL, NULL, NULL, NULL, &recorded_size, - &recorded_time, &changelist, NULL, NULL, + &recorded_time, NULL, NULL, NULL, &had_props, &props_mod, NULL, NULL, NULL, db, local_abspath, scratch_pool, scratch_pool)); checksum = working_checksum; @@ -433,12 +416,6 @@ svn_wc__diff_base_working_diff(svn_wc__d || status == svn_wc__db_status_added || (status == svn_wc__db_status_deleted && diff_pristine)); - /* If the item is not a member of a specified changelist (and there are - some specified changelists), skip it. */ - if (changelist_hash && !svn_hash_gets(changelist_hash, changelist)) - return SVN_NO_ERROR; - - if (status != svn_wc__db_status_normal) { SVN_ERR(svn_wc__db_base_get_info(&base_status, NULL, &db_revision, @@ -768,7 +745,6 @@ walk_local_nodes_diff(struct edit_baton_ SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath, child_relpath, eb->processor, dir_baton, - eb->changelist_hash, eb->diff_pristine, eb->cancel_func, eb->cancel_baton, @@ -778,7 +754,6 @@ walk_local_nodes_diff(struct edit_baton_ child_relpath, depth_below_here, eb->processor, dir_baton, - eb->changelist_hash, eb->diff_pristine, eb->cancel_func, eb->cancel_baton, @@ -814,7 +789,6 @@ walk_local_nodes_diff(struct edit_baton_ db, child_abspath, child_relpath, eb->revnum, - eb->changelist_hash, eb->processor, dir_baton, eb->diff_pristine, eb->cancel_func, @@ -837,7 +811,6 @@ walk_local_nodes_diff(struct edit_baton_ SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath, child_relpath, eb->processor, dir_baton, - eb->changelist_hash, eb->diff_pristine, eb->cancel_func, eb->cancel_baton, @@ -846,7 +819,6 @@ walk_local_nodes_diff(struct edit_baton_ SVN_ERR(svn_wc__diff_local_only_dir(db, child_abspath, child_relpath, depth_below_here, eb->processor, dir_baton, - eb->changelist_hash, eb->diff_pristine, eb->cancel_func, eb->cancel_baton, @@ -858,13 +830,9 @@ walk_local_nodes_diff(struct edit_baton_ if (compared) return SVN_NO_ERROR; - /* Check for local property mods on this directory, if we haven't - already reported them and we aren't changelist-filted. - ### it should be noted that we do not currently allow directories - ### to be part of changelists, so if a changelist is provided, the - ### changelist check will always fail. */ + /* Check for local property mods on this directory, if we haven't + already reported them. */ if (! skip - && ! eb->changelist_hash && ! in_anchor_not_target && props_mod) { @@ -907,7 +875,6 @@ svn_wc__diff_local_only_file(svn_wc__db_ const char *relpath, const svn_diff_tree_processor_t *processor, void *processor_parent_baton, - apr_hash_t *changelist_hash, svn_boolean_t diff_pristine, svn_cancel_func_t cancel_func, void *cancel_baton, @@ -920,7 +887,6 @@ svn_wc__diff_local_only_file(svn_wc__db_ const svn_checksum_t *checksum; const char *original_repos_relpath; svn_revnum_t original_revision; - const char *changelist; svn_boolean_t had_props; svn_boolean_t props_mod; apr_hash_t *pristine_props; @@ -936,7 +902,7 @@ svn_wc__diff_local_only_file(svn_wc__db_ NULL, NULL, NULL, NULL, &checksum, NULL, &original_repos_relpath, NULL, NULL, &original_revision, NULL, NULL, NULL, - &changelist, NULL, NULL, &had_props, + NULL, NULL, NULL, &had_props, &props_mod, NULL, NULL, NULL, db, local_abspath, scratch_pool, scratch_pool)); @@ -947,10 +913,6 @@ svn_wc__diff_local_only_file(svn_wc__db_ || (status == svn_wc__db_status_deleted && diff_pristine))); - if (changelist && changelist_hash - && !svn_hash_gets(changelist_hash, changelist)) - return SVN_NO_ERROR; - if (status == svn_wc__db_status_deleted) { assert(diff_pristine); @@ -1053,7 +1015,6 @@ svn_wc__diff_local_only_dir(svn_wc__db_t svn_depth_t depth, const svn_diff_tree_processor_t *processor, void *processor_parent_baton, - apr_hash_t *changelist_hash, svn_boolean_t diff_pristine, svn_cancel_func_t cancel_func, void *cancel_baton, @@ -1075,9 +1036,6 @@ svn_wc__diff_local_only_dir(svn_wc__db_t svn_boolean_t skip_children = FALSE; svn_diff_source_t *right_src = svn_diff__source_create(SVN_INVALID_REVNUM, scratch_pool); - svn_depth_t depth_below_here = depth; - apr_hash_t *nodes; - apr_hash_t *conflicts; SVN_ERR(svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -1128,71 +1086,81 @@ svn_wc__diff_local_only_dir(svn_wc__db_t processor, scratch_pool, iterpool)); - SVN_ERR(svn_wc__db_read_children_info(&nodes, &conflicts, db, local_abspath, - FALSE /* base_tree_only */, - scratch_pool, iterpool)); - - if (depth_below_here == svn_depth_immediates) - depth_below_here = svn_depth_empty; - - children = svn_sort__hash(nodes, svn_sort_compare_items_lexically, - scratch_pool); - - for (i = 0; i < children->nelts; i++) + if ((depth > svn_depth_empty || depth == svn_depth_unknown) + && ! skip_children) { - svn_sort__item_t *item = &APR_ARRAY_IDX(children, i, svn_sort__item_t); - const char *name = item->key; - struct svn_wc__db_info_t *info = item->value; - const char *child_abspath; - const char *child_relpath; + svn_depth_t depth_below_here = depth; + apr_hash_t *nodes; + apr_hash_t *conflicts; + + if (depth_below_here == svn_depth_immediates) + depth_below_here = svn_depth_empty; - svn_pool_clear(iterpool); + SVN_ERR(svn_wc__db_read_children_info(&nodes, &conflicts, + db, local_abspath, + FALSE /* base_tree_only */, + scratch_pool, iterpool)); - if (cancel_func) - SVN_ERR(cancel_func(cancel_baton)); - child_abspath = svn_dirent_join(local_abspath, name, iterpool); + children = svn_sort__hash(nodes, svn_sort_compare_items_lexically, + scratch_pool); - if (NOT_PRESENT(info->status)) + for (i = 0; i < children->nelts; i++) { - continue; - } + svn_sort__item_t *item = &APR_ARRAY_IDX(children, i, svn_sort__item_t); + const char *name = item->key; + struct svn_wc__db_info_t *info = item->value; + const char *child_abspath; + const char *child_relpath; - /* If comparing against WORKING, skip entries that are - schedule-deleted - they don't really exist. */ - if (!diff_pristine && info->status == svn_wc__db_status_deleted) - continue; + svn_pool_clear(iterpool); - child_relpath = svn_relpath_join(relpath, name, iterpool); + if (cancel_func) + SVN_ERR(cancel_func(cancel_baton)); - switch (info->kind) - { - case svn_node_file: - case svn_node_symlink: - SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath, - child_relpath, - processor, pdb, - changelist_hash, - diff_pristine, - cancel_func, cancel_baton, - scratch_pool)); - break; + child_abspath = svn_dirent_join(local_abspath, name, iterpool); - case svn_node_dir: - if (depth > svn_depth_files || depth == svn_depth_unknown) + if (NOT_PRESENT(info->status)) { - SVN_ERR(svn_wc__diff_local_only_dir(db, child_abspath, - child_relpath, depth_below_here, - processor, pdb, - changelist_hash, - diff_pristine, - cancel_func, cancel_baton, - iterpool)); + continue; } - break; - default: - break; + /* If comparing against WORKING, skip entries that are + schedule-deleted - they don't really exist. */ + if (!diff_pristine && info->status == svn_wc__db_status_deleted) + continue; + + child_relpath = svn_relpath_join(relpath, name, iterpool); + + switch (info->kind) + { + case svn_node_file: + case svn_node_symlink: + SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath, + child_relpath, + processor, pdb, + diff_pristine, + cancel_func, cancel_baton, + scratch_pool)); + break; + + case svn_node_dir: + if (depth > svn_depth_files || depth == svn_depth_unknown) + { + SVN_ERR(svn_wc__diff_local_only_dir(db, child_abspath, + child_relpath, + depth_below_here, + processor, pdb, + diff_pristine, + cancel_func, + cancel_baton, + iterpool)); + } + break; + + default: + break; + } } } @@ -1282,7 +1250,6 @@ handle_local_only(struct dir_baton_t *pb svn_relpath_join(pb->relpath, name, scratch_pool), repos_delete ? svn_depth_infinity : depth, eb->processor, pb->pdb, - eb->changelist_hash, eb->diff_pristine, eb->cancel_func, eb->cancel_baton, scratch_pool)); @@ -1293,7 +1260,6 @@ handle_local_only(struct dir_baton_t *pb svn_dirent_join(pb->local_abspath, name, scratch_pool), svn_relpath_join(pb->relpath, name, scratch_pool), eb->processor, pb->pdb, - eb->changelist_hash, eb->diff_pristine, eb->cancel_func, eb->cancel_baton, scratch_pool)); @@ -2068,7 +2034,14 @@ close_file(void *file_baton, const char *repos_file; apr_hash_t *repos_props; - if (!fb->skip && expected_md5_digest != NULL) + if (fb->skip) + { + svn_pool_destroy(fb->pool); /* destroys scratch_pool and fb */ + SVN_ERR(maybe_done(pb)); + return SVN_NO_ERROR; + } + + if (expected_md5_digest != NULL) { svn_checksum_t *expected_checksum; const svn_checksum_t *result_checksum; @@ -2123,11 +2096,7 @@ close_file(void *file_baton, } } - if (fb->skip) - { - /* Diff processor requested skipping information */ - } - else if (fb->repos_only) + if (fb->repos_only) { SVN_ERR(eb->processor->file_deleted(fb->relpath, fb->left_src, @@ -2307,12 +2276,24 @@ svn_wc__get_diff_editor(const svn_delta_ SVN_ERR_ASSERT(svn_dirent_is_absolute(anchor_abspath)); + /* Apply changelist filtering to the output */ + if (changelist_filter && changelist_filter->nelts) + { + apr_hash_t *changelist_hash; + + SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter, + result_pool)); + diff_processor = svn_wc__changelist_filter_tree_processor_create( + diff_processor, wc_ctx, anchor_abspath, + changelist_hash, result_pool); + } + SVN_ERR(make_edit_baton(&eb, wc_ctx->db, anchor_abspath, target, diff_processor, depth, ignore_ancestry, - use_text_base, reverse_order, changelist_filter, + use_text_base, reverse_order, cancel_func, cancel_baton, result_pool)); @@ -2778,3 +2759,329 @@ svn_wc__wrap_diff_callbacks(const svn_di *diff_processor = processor; return SVN_NO_ERROR; } + +/* ===================================================================== + * A tree processor filter that filters by changelist membership + * ===================================================================== + * + * The current implementation queries the WC for the changelist of each + * file as it comes through, and sets the 'skip' flag for a non-matching + * file. + * + * (It doesn't set the 'skip' flag for a directory, as we need to receive + * the changed/added/deleted/closed call to know when it is closed, in + * order to preserve the strict open-close semantics for the wrapped tree + * processor.) + * + * It passes on the opening and closing of every directory, even if there + * are no file changes to be passed on inside that directory. + */ + +typedef struct filter_tree_baton_t +{ + const svn_diff_tree_processor_t *processor; + svn_wc_context_t *wc_ctx; + /* WC path of the root of the diff (where relpath = "") */ + const char *root_local_abspath; + /* Hash whose keys are const char * changelist names. */ + apr_hash_t *changelist_hash; +} filter_tree_baton_t; + +static svn_error_t * +filter_dir_opened(void **new_dir_baton, + svn_boolean_t *skip, + svn_boolean_t *skip_children, + const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + const svn_diff_source_t *copyfrom_source, + void *parent_dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + SVN_ERR(fb->processor->dir_opened(new_dir_baton, skip, skip_children, + relpath, + left_source, right_source, + copyfrom_source, + parent_dir_baton, + fb->processor, + result_pool, scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_dir_added(const char *relpath, + const svn_diff_source_t *copyfrom_source, + const svn_diff_source_t *right_source, + /*const*/ apr_hash_t *copyfrom_props, + /*const*/ apr_hash_t *right_props, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + SVN_ERR(fb->processor->dir_closed(relpath, + NULL, + right_source, + dir_baton, + fb->processor, + scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_dir_deleted(const char *relpath, + const svn_diff_source_t *left_source, + /*const*/ apr_hash_t *left_props, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + SVN_ERR(fb->processor->dir_closed(relpath, + left_source, + NULL, + dir_baton, + fb->processor, + scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_dir_changed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + /*const*/ apr_hash_t *left_props, + /*const*/ apr_hash_t *right_props, + const apr_array_header_t *prop_changes, + void *dir_baton, + const struct svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + SVN_ERR(fb->processor->dir_closed(relpath, + left_source, + right_source, + dir_baton, + fb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_dir_closed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + SVN_ERR(fb->processor->dir_closed(relpath, + left_source, + right_source, + dir_baton, + fb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_file_opened(void **new_file_baton, + svn_boolean_t *skip, + const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + const svn_diff_source_t *copyfrom_source, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + const char *local_abspath + = svn_dirent_join(fb->root_local_abspath, relpath, scratch_pool); + + /* Skip if not a member of a given changelist */ + if (! svn_wc__changelist_match(fb->wc_ctx, local_abspath, + fb->changelist_hash, scratch_pool)) + { + *skip = TRUE; + return SVN_NO_ERROR; + } + + SVN_ERR(fb->processor->file_opened(new_file_baton, + skip, + relpath, + left_source, + right_source, + copyfrom_source, + dir_baton, + fb->processor, + result_pool, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_file_added(const char *relpath, + const svn_diff_source_t *copyfrom_source, + const svn_diff_source_t *right_source, + const char *copyfrom_file, + const char *right_file, + /*const*/ apr_hash_t *copyfrom_props, + /*const*/ apr_hash_t *right_props, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + SVN_ERR(fb->processor->file_added(relpath, + copyfrom_source, + right_source, + copyfrom_file, + right_file, + copyfrom_props, + right_props, + file_baton, + fb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_file_deleted(const char *relpath, + const svn_diff_source_t *left_source, + const char *left_file, + /*const*/ apr_hash_t *left_props, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + SVN_ERR(fb->processor->file_deleted(relpath, + left_source, + left_file, + left_props, + file_baton, + fb->processor, + scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_file_changed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + const char *left_file, + const char *right_file, + /*const*/ apr_hash_t *left_props, + /*const*/ apr_hash_t *right_props, + svn_boolean_t file_modified, + const apr_array_header_t *prop_changes, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + SVN_ERR(fb->processor->file_changed(relpath, + left_source, + right_source, + left_file, + right_file, + left_props, + right_props, + file_modified, + prop_changes, + file_baton, + fb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_file_closed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + SVN_ERR(fb->processor->file_closed(relpath, + left_source, + right_source, + file_baton, + fb->processor, + scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_node_absent(const char *relpath, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + SVN_ERR(fb->processor->node_absent(relpath, + dir_baton, + fb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + +const svn_diff_tree_processor_t * +svn_wc__changelist_filter_tree_processor_create( + const svn_diff_tree_processor_t *processor, + svn_wc_context_t *wc_ctx, + const char *root_local_abspath, + apr_hash_t *changelist_hash, + apr_pool_t *result_pool) +{ + struct filter_tree_baton_t *fb; + svn_diff_tree_processor_t *filter; + + if (! changelist_hash) + return processor; + + fb = apr_pcalloc(result_pool, sizeof(*fb)); + fb->processor = processor; + fb->wc_ctx = wc_ctx; + fb->root_local_abspath = root_local_abspath; + fb->changelist_hash = changelist_hash; + + filter = svn_diff__tree_processor_create(fb, result_pool); + filter->dir_opened = filter_dir_opened; + filter->dir_added = filter_dir_added; + filter->dir_deleted = filter_dir_deleted; + filter->dir_changed = filter_dir_changed; + filter->dir_closed = filter_dir_closed; + + filter->file_opened = filter_file_opened; + filter->file_added = filter_file_added; + filter->file_deleted = filter_file_deleted; + filter->file_changed = filter_file_changed; + filter->file_closed = filter_file_closed; + + filter->node_absent = filter_node_absent; + + return filter; +} +
Modified: subversion/branches/authzperf/subversion/libsvn_wc/diff_local.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_wc/diff_local.c?rev=1649205&r1=1649204&r2=1649205&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/libsvn_wc/diff_local.c (original) +++ subversion/branches/authzperf/subversion/libsvn_wc/diff_local.c Sat Jan 3 14:00:41 2015 @@ -89,9 +89,6 @@ struct diff_baton /* Should this diff ignore node ancestry? */ svn_boolean_t ignore_ancestry; - /* Hash whose keys are const char * changelist names. */ - apr_hash_t *changelist_hash; - /* Cancel function/baton */ svn_cancel_func_t cancel_func; void *cancel_baton; @@ -249,11 +246,6 @@ diff_status_callback(void *baton, if (eb->cur && eb->cur->skip_children) return SVN_NO_ERROR; - if (eb->changelist_hash != NULL - && (!status->changelist - || ! svn_hash_gets(eb->changelist_hash, status->changelist))) - return SVN_NO_ERROR; /* Filtered via changelist */ - /* This code does about the same thing as the inner body of walk_local_nodes_diff() in diff_editor.c, except that it is already filtered by the status walker, doesn't have to @@ -358,7 +350,6 @@ diff_status_callback(void *baton, SVN_ERR(svn_wc__diff_base_working_diff(db, child_abspath, child_relpath, SVN_INVALID_REVNUM, - eb->changelist_hash, eb->processor, eb->cur ? eb->cur->baton @@ -402,7 +393,6 @@ diff_status_callback(void *baton, child_relpath, eb->processor, eb->cur ? eb->cur->baton : NULL, - eb->changelist_hash, FALSE, eb->cancel_func, eb->cancel_baton, @@ -412,7 +402,6 @@ diff_status_callback(void *baton, child_relpath, depth_below_here, eb->processor, eb->cur ? eb->cur->baton : NULL, - eb->changelist_hash, FALSE, eb->cancel_func, eb->cancel_baton, @@ -475,15 +464,23 @@ svn_wc__diff7(const char **root_relpath, if (root_is_dir) *root_is_dir = (kind == svn_node_dir); + /* Apply changelist filtering to the output */ + if (changelist_filter && changelist_filter->nelts) + { + apr_hash_t *changelist_hash; + + SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter, + result_pool)); + diff_processor = svn_wc__changelist_filter_tree_processor_create( + diff_processor, wc_ctx, local_abspath, + changelist_hash, result_pool); + } + eb.db = wc_ctx->db; eb.processor = diff_processor; eb.ignore_ancestry = ignore_ancestry; eb.pool = scratch_pool; - if (changelist_filter && changelist_filter->nelts) - SVN_ERR(svn_hash_from_cstring_keys(&eb.changelist_hash, changelist_filter, - scratch_pool)); - if (ignore_ancestry) get_all = TRUE; /* We need unmodified descendants of copies */ else Modified: subversion/branches/authzperf/subversion/libsvn_wc/externals.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_wc/externals.c?rev=1649205&r1=1649204&r2=1649205&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/libsvn_wc/externals.c (original) +++ subversion/branches/authzperf/subversion/libsvn_wc/externals.c Sat Jan 3 14:00:41 2015 @@ -159,7 +159,7 @@ find_and_remove_externals_revision(int * svn_error_t * svn_wc_parse_externals_description3(apr_array_header_t **externals_p, - const char *parent_directory, + const char *defining_directory, const char *desc, svn_boolean_t canonicalize_url, apr_pool_t *pool) @@ -167,8 +167,8 @@ svn_wc_parse_externals_description3(apr_ int i; apr_array_header_t *externals = NULL; apr_array_header_t *lines = svn_cstring_split(desc, "\n\r", TRUE, pool); - const char *parent_directory_display = svn_path_is_url(parent_directory) ? - parent_directory : svn_dirent_local_style(parent_directory, pool); + const char *defining_directory_display = svn_path_is_url(defining_directory) ? + defining_directory : svn_dirent_local_style(defining_directory, pool); /* If an error occurs halfway through parsing, *externals_p should stay * untouched. So, store the list in a local var first. */ @@ -231,7 +231,7 @@ svn_wc_parse_externals_description3(apr_ (SVN_ERR_CLIENT_INVALID_EXTERNALS_DESCRIPTION, NULL, _("Error parsing %s property on '%s': '%s'"), SVN_PROP_EXTERNALS, - parent_directory_display, + defining_directory_display, line); /* To make it easy to check for the forms, find and remove -r N @@ -242,7 +242,7 @@ svn_wc_parse_externals_description3(apr_ SVN_ERR(find_and_remove_externals_revision(&rev_idx, (const char **)line_parts, num_line_parts, item, - parent_directory_display, + defining_directory_display, line, pool)); token0 = line_parts[0]; @@ -258,7 +258,7 @@ svn_wc_parse_externals_description3(apr_ "cannot use two absolute URLs ('%s' and '%s') in an external; " "one must be a path where an absolute or relative URL is " "checked out to"), - SVN_PROP_EXTERNALS, parent_directory_display, token0, token1); + SVN_PROP_EXTERNALS, defining_directory_display, token0, token1); if (0 == rev_idx && token1_is_url) return svn_error_createf @@ -266,7 +266,7 @@ svn_wc_parse_externals_description3(apr_ _("Invalid %s property on '%s': " "cannot use a URL '%s' as the target directory for an external " "definition"), - SVN_PROP_EXTERNALS, parent_directory_display, token1); + SVN_PROP_EXTERNALS, defining_directory_display, token1); if (1 == rev_idx && token0_is_url) return svn_error_createf @@ -274,7 +274,7 @@ svn_wc_parse_externals_description3(apr_ _("Invalid %s property on '%s': " "cannot use a URL '%s' as the target directory for an external " "definition"), - SVN_PROP_EXTERNALS, parent_directory_display, token0); + SVN_PROP_EXTERNALS, defining_directory_display, token0); /* The appearance of -r N or -rN forces the type of external. If -r is at the beginning of the line or the first token is @@ -316,7 +316,7 @@ svn_wc_parse_externals_description3(apr_ _("Invalid %s property on '%s': " "target '%s' is an absolute path or involves '..'"), SVN_PROP_EXTERNALS, - parent_directory_display, + defining_directory_display, item->target_dir); if (canonicalize_url) @@ -943,29 +943,62 @@ close_edit(void *edit_baton, { struct edit_baton *eb = edit_baton; - if (!eb->file_closed - || eb->iprops) + if (!eb->file_closed) { - apr_hash_t *wcroot_iprops = NULL; + /* The file wasn't updated, but its url or revision might have... + e.g. switch between branches for relative externals. - if (eb->iprops) - { - wcroot_iprops = apr_hash_make(pool); - svn_hash_sets(wcroot_iprops, eb->local_abspath, eb->iprops); - } + Just bump the information as that is just as expensive as + investigating when we should and shouldn't update it... + and avoid hard to debug edge cases */ + + svn_node_kind_t kind; + const char *old_repos_relpath; + svn_revnum_t changed_rev; + apr_time_t changed_date; + const char *changed_author; + const svn_checksum_t *checksum; + apr_hash_t *pristine_props; + const char *repos_relpath = svn_uri_skip_ancestor(eb->repos_root_url, + eb->url, pool); + + SVN_ERR(svn_wc__db_base_get_info(NULL, &kind, NULL, &old_repos_relpath, + NULL, NULL, &changed_rev, &changed_date, + &changed_author, NULL, &checksum, NULL, + NULL, NULL, &pristine_props, NULL, + eb->db, eb->local_abspath, + pool, pool)); - /* The node wasn't updated, so we just have to bump its revision */ - SVN_ERR(svn_wc__db_op_bump_revisions_post_update(eb->db, - eb->local_abspath, - svn_depth_infinity, - NULL, NULL, NULL, - *eb->target_revision, - apr_hash_make(pool), - wcroot_iprops, - TRUE /* empty update */, - eb->notify_func, - eb->notify_baton, - pool)); + if (kind != svn_node_file) + return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL, + _("Node '%s' is no existing file external"), + svn_dirent_local_style(eb->local_abspath, + pool)); + + SVN_ERR(svn_wc__db_external_add_file( + eb->db, + eb->local_abspath, + eb->wri_abspath, + repos_relpath, + eb->repos_root_url, + eb->repos_uuid, + *eb->target_revision, + pristine_props, + eb->iprops, + eb->changed_rev, + eb->changed_date, + eb->changed_author, + checksum, + NULL /* clear dav props */, + eb->record_ancestor_abspath, + eb->recorded_repos_relpath, + eb->recorded_peg_revision, + eb->recorded_revision, + FALSE, NULL, + TRUE /* keep_recorded_info */, + NULL /* conflict_skel */, + NULL /* work_items */, + pool)); } return SVN_NO_ERROR; Modified: subversion/branches/authzperf/subversion/libsvn_wc/node.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_wc/node.c?rev=1649205&r1=1649204&r2=1649205&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/libsvn_wc/node.c (original) +++ subversion/branches/authzperf/subversion/libsvn_wc/node.c Sat Jan 3 14:00:41 2015 @@ -471,6 +471,7 @@ svn_wc__internal_walk_children(svn_wc__d svn_node_kind_t kind; svn_wc__db_status_t status; apr_hash_t *changelist_hash = NULL; + const char *changelist = NULL; SVN_ERR_ASSERT(walk_depth >= svn_depth_empty && walk_depth <= svn_depth_infinity); @@ -483,14 +484,17 @@ svn_wc__internal_walk_children(svn_wc__d SVN_ERR(svn_wc__db_read_info(&status, &db_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, + changelist_hash ? &changelist : NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, db, local_abspath, scratch_pool, scratch_pool)); SVN_ERR(convert_db_kind_to_node_kind(&kind, db_kind, status, show_hidden)); - if (svn_wc__internal_changelist_match(db, local_abspath, - changelist_hash, scratch_pool)) - SVN_ERR(walk_callback(local_abspath, kind, walk_baton, scratch_pool)); + if (!changelist_hash + || (changelist && svn_hash_gets(changelist_hash, changelist))) + { + SVN_ERR(walk_callback(local_abspath, kind, walk_baton, scratch_pool)); + } if (db_kind == svn_node_file || status == svn_wc__db_status_not_present @@ -632,7 +636,6 @@ svn_wc__node_get_base(svn_node_kind_t *k svn_wc_context_t *wc_ctx, const char *local_abspath, svn_boolean_t ignore_enoent, - svn_boolean_t show_hidden, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { @@ -652,9 +655,8 @@ svn_wc__node_get_base(svn_node_kind_t *k if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND) return svn_error_trace(err); else if (err - || (!err && !show_hidden - && (status != svn_wc__db_status_normal - && status != svn_wc__db_status_incomplete))) + || (status != svn_wc__db_status_normal + && status != svn_wc__db_status_incomplete)) { if (!ignore_enoent) { Modified: subversion/branches/authzperf/subversion/libsvn_wc/update_editor.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_wc/update_editor.c?rev=1649205&r1=1649204&r2=1649205&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/libsvn_wc/update_editor.c (original) +++ subversion/branches/authzperf/subversion/libsvn_wc/update_editor.c Sat Jan 3 14:00:41 2015 @@ -4342,7 +4342,7 @@ close_file(void *file_baton, || strcmp(fb->new_repos_relpath, fb->old_repos_relpath) == 0) { SVN_ERR_ASSERT(prop->value == NULL); - SVN_ERR(svn_wc__db_lock_remove(eb->db, fb->local_abspath, + SVN_ERR(svn_wc__db_lock_remove(eb->db, fb->local_abspath, NULL, scratch_pool)); lock_state = svn_wc_notify_lock_state_unlocked; Modified: subversion/branches/authzperf/subversion/libsvn_wc/wc.h URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_wc/wc.h?rev=1649205&r1=1649204&r2=1649205&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/libsvn_wc/wc.h (original) +++ subversion/branches/authzperf/subversion/libsvn_wc/wc.h Sat Jan 3 14:00:41 2015 @@ -249,52 +249,6 @@ svn_wc__context_create_with_db(svn_wc_co apr_pool_t * svn_wc__get_committed_queue_pool(const struct svn_wc_committed_queue_t *queue); - -/** Internal helper for svn_wc_process_committed_queue2(). - * - * ### If @a queue is NULL, then ...? - * ### else: - * Bump an item from @a queue (the one associated with @a - * local_abspath) to @a new_revnum after a commit succeeds, recursing - * if @a recurse is set. - * - * @a new_date is the (server-side) date of the new revision, or 0. - * - * @a rev_author is the (server-side) author of the new - * revision; it may be @c NULL. - * - * @a new_dav_cache is a hash of dav property changes to be made to - * the @a local_abspath. - * ### [JAF] Is it? See svn_wc_queue_committed3(). It ends up being - * ### assigned as a whole to wc.db:BASE_NODE:dav_cache. - * - * If @a no_unlock is set, don't release any user locks on @a - * local_abspath; otherwise release them as part of this processing. - * - * If @a keep_changelist is set, don't remove any changeset assignments - * from @a local_abspath; otherwise, clear it of such assignments. - * - * If @a sha1_checksum is non-NULL, use it to identify the node's pristine - * text. - * - * Set TOP_OF_RECURSE to TRUE to show that this the top of a possibly - * recursive commit operation. - */ -svn_error_t * -svn_wc__process_committed_internal(svn_wc__db_t *db, - const char *local_abspath, - svn_boolean_t recurse, - svn_boolean_t top_of_recurse, - svn_revnum_t new_revnum, - apr_time_t new_date, - const char *rev_author, - apr_hash_t *new_dav_cache, - svn_boolean_t no_unlock, - svn_boolean_t keep_changelist, - const svn_checksum_t *sha1_checksum, - const svn_wc_committed_queue_t *queue, - apr_pool_t *scratch_pool); - /*** Update traversals. ***/ Modified: subversion/branches/authzperf/subversion/libsvn_wc/wc_db.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_wc/wc_db.c?rev=1649205&r1=1649204&r2=1649205&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/libsvn_wc/wc_db.c (original) +++ subversion/branches/authzperf/subversion/libsvn_wc/wc_db.c Sat Jan 3 14:00:41 2015 @@ -4700,25 +4700,23 @@ struct op_copy_baton const char *dst_op_root_relpath; }; -/* Helper for svn_wc__db_op_copy(). - * - * Implements svn_sqlite__transaction_callback_t. */ +/* Helper for svn_wc__db_op_copy(). */ static svn_error_t * -op_copy_txn(void * baton, - svn_sqlite__db_t *sdb, +op_copy_txn(svn_wc__db_wcroot_t *wcroot, + struct op_copy_baton *ocb, apr_pool_t *scratch_pool) { - struct op_copy_baton *ocb = baton; int move_op_depth; - if (sdb != ocb->dst_wcroot->sdb) + if (wcroot != ocb->dst_wcroot) { /* Source and destination databases differ; so also start a lock - in the destination database, by calling ourself in a lock. */ + in the destination database, by calling ourself in an extra lock. */ - return svn_error_trace( - svn_sqlite__with_lock(ocb->dst_wcroot->sdb, - op_copy_txn, ocb, scratch_pool)); + SVN_WC__DB_WITH_TXN(op_copy_txn(ocb->dst_wcroot, ocb, scratch_pool), + ocb->dst_wcroot); + + return SVN_NO_ERROR; } /* From this point we can assume a lock in the src and dst databases */ @@ -4769,8 +4767,8 @@ svn_wc__db_op_copy(svn_wc__db_t *db, /* Call with the sdb in src_wcroot. It might call itself again to also obtain a lock in dst_wcroot */ - SVN_ERR(svn_sqlite__with_lock(ocb.src_wcroot->sdb, op_copy_txn, &ocb, - scratch_pool)); + SVN_WC__DB_WITH_TXN(op_copy_txn(ocb.src_wcroot, &ocb, scratch_pool), + ocb.src_wcroot); return SVN_NO_ERROR; } @@ -5212,15 +5210,12 @@ db_op_copy_shadowed_layer(svn_wc__db_wcr return SVN_NO_ERROR; } -/* Helper for svn_wc__db_op_copy_shadowed_layer(). - * - * Implements svn_sqlite__transaction_callback_t. */ +/* Helper for svn_wc__db_op_copy_shadowed_layer(). */ static svn_error_t * -op_copy_shadowed_layer_txn(void *baton, - svn_sqlite__db_t *sdb, +op_copy_shadowed_layer_txn(svn_wc__db_wcroot_t *wcroot, + struct op_copy_baton *ocb, apr_pool_t *scratch_pool) { - struct op_copy_baton *ocb = baton; const char *src_parent_relpath; const char *dst_parent_relpath; int src_op_depth; @@ -5230,15 +5225,16 @@ op_copy_shadowed_layer_txn(void *baton, apr_int64_t repos_id = INVALID_REPOS_ID; svn_revnum_t revision = SVN_INVALID_REVNUM; - if (sdb != ocb->dst_wcroot->sdb) + if (wcroot != ocb->dst_wcroot) { - /* Source and destination databases differ; so also start a lock - in the destination database, by calling ourself in a lock. */ + /* Source and destination databases differ; so also start a lock + in the destination database, by calling ourself in an extra lock. */ - return svn_error_trace( - svn_sqlite__with_lock(ocb->dst_wcroot->sdb, - op_copy_shadowed_layer_txn, - ocb, scratch_pool)); + SVN_WC__DB_WITH_TXN(op_copy_shadowed_layer_txn(ocb->dst_wcroot, ocb, + scratch_pool), + ocb->dst_wcroot); + + return SVN_NO_ERROR; } /* From this point we can assume a lock in the src and dst databases */ @@ -5320,9 +5316,9 @@ svn_wc__db_op_copy_shadowed_layer(svn_wc /* Call with the sdb in src_wcroot. It might call itself again to also obtain a lock in dst_wcroot */ - SVN_ERR(svn_sqlite__with_lock(ocb.src_wcroot->sdb, - op_copy_shadowed_layer_txn, - &ocb, scratch_pool)); + SVN_WC__DB_WITH_TXN(op_copy_shadowed_layer_txn(ocb.src_wcroot, &ocb, + scratch_pool), + ocb.src_wcroot); return SVN_NO_ERROR; } @@ -11925,6 +11921,7 @@ svn_wc__db_lock_add(svn_wc__db_t *db, static svn_error_t * lock_remove_txn(svn_wc__db_wcroot_t *wcroot, const char *local_relpath, + svn_skel_t *work_items, apr_pool_t *scratch_pool) { const char *repos_relpath; @@ -11944,6 +11941,8 @@ lock_remove_txn(svn_wc__db_wcroot_t *wcr SVN_ERR(svn_sqlite__step_done(stmt)); + SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool)); + return SVN_NO_ERROR; } @@ -11951,6 +11950,7 @@ lock_remove_txn(svn_wc__db_wcroot_t *wcr svn_error_t * svn_wc__db_lock_remove(svn_wc__db_t *db, const char *local_abspath, + svn_skel_t *work_items, apr_pool_t *scratch_pool) { svn_wc__db_wcroot_t *wcroot; @@ -11963,7 +11963,7 @@ svn_wc__db_lock_remove(svn_wc__db_t *db, VERIFY_USABLE_WCROOT(wcroot); SVN_WC__DB_WITH_TXN( - lock_remove_txn(wcroot, local_relpath, scratch_pool), + lock_remove_txn(wcroot, local_relpath, work_items, scratch_pool), wcroot); /* There may be some entries, and the lock info is now out of date. */ @@ -15521,3 +15521,514 @@ svn_wc__db_vacuum(svn_wc__db_t *db, return SVN_NO_ERROR; } + +/* Item queued with svn_wc__db_commit_queue_add */ +typedef struct commit_queue_item_t +{ + const char *local_relpath; + svn_boolean_t recurse; /* Use legacy recursion */ + svn_boolean_t committed; /* Process the node as committed */ + svn_boolean_t remove_lock; /* Remove existing lock on node */ + svn_boolean_t remove_changelist; /* Remove changelist on node */ + + /* The pristine text checksum. NULL if the old value should be kept + and for directories */ + const svn_checksum_t *new_sha1_checksum; + + apr_hash_t *new_dav_cache; /* New DAV cache for the node */ +} commit_queue_item_t; + +/* The queue definition for vn_wc__db_create_commit_queue, + svn_wc__db_commit_queue_add and finally svn_wc__db_process_commit_queue */ +struct svn_wc__db_commit_queue_t +{ + svn_wc__db_wcroot_t *wcroot; /* Wcroot for ITEMS */ + apr_array_header_t *items; /* List of commit_queue_item_t* */ + svn_boolean_t have_recurse; /* Is one or more item[x]->recurse TRUE? */ +}; + +/* Create a new svn_wc__db_commit_queue_t instance in RESULT_POOL for the + working copy specified with WRI_ABSPATH */ +svn_error_t * +svn_wc__db_create_commit_queue(svn_wc__db_commit_queue_t **queue, + svn_wc__db_t *db, + const char *wri_abspath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + svn_wc__db_wcroot_t *wcroot; + const char *local_relpath; + svn_wc__db_commit_queue_t *q; + + SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath)); + + SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db, + wri_abspath, result_pool, scratch_pool)); + VERIFY_USABLE_WCROOT(wcroot); + + q = apr_pcalloc(result_pool, sizeof(*q)); + + SVN_ERR_ASSERT(wcroot->sdb); + + q->wcroot = wcroot; + q->items = apr_array_make(result_pool, 64, + sizeof(commit_queue_item_t*)); + q->have_recurse = FALSE; + + *queue = q; + return SVN_NO_ERROR; +} + +svn_error_t * +svn_wc__db_commit_queue_add(svn_wc__db_commit_queue_t *queue, + const char *local_abspath, + svn_boolean_t recurse, + svn_boolean_t is_commited, + svn_boolean_t remove_lock, + svn_boolean_t remove_changelist, + const svn_checksum_t *new_sha1_checksum, + apr_hash_t *new_dav_cache, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + commit_queue_item_t *cqi; + const char *local_relpath; + + local_relpath = svn_dirent_skip_ancestor(queue->wcroot->abspath, + local_abspath); + + if (! local_relpath) + return svn_error_createf( + SVN_ERR_WC_PATH_NOT_FOUND, NULL, + _("The path '%s' is not in the working copy '%s'"), + svn_dirent_local_style(local_abspath, scratch_pool), + svn_dirent_local_style(queue->wcroot->abspath, scratch_pool)); + + cqi = apr_pcalloc(result_pool, sizeof(*cqi)); + cqi->local_relpath = local_relpath; + cqi->recurse = recurse; + cqi->committed = is_commited; + cqi->remove_lock = remove_lock; + cqi->remove_changelist = remove_changelist; + cqi->new_sha1_checksum = new_sha1_checksum; + cqi->new_dav_cache = new_dav_cache; + + queue->have_recurse |= recurse; + + APR_ARRAY_PUSH(queue->items, commit_queue_item_t *) = cqi; + return SVN_NO_ERROR; +} + +/*** Finishing updates and commits. ***/ + +/* Post process an item that is committed in the repository. Collapse layers into + * BASE. Queue work items that will finish a commit of the file or directory + * LOCAL_ABSPATH in DB: + */ +static svn_error_t * +process_committed_leaf(svn_wc__db_t *db, + svn_wc__db_wcroot_t *wcroot, + const char *local_relpath, + svn_boolean_t via_recurse, + svn_wc__db_status_t status, + svn_node_kind_t kind, + svn_boolean_t prop_mods, + const svn_checksum_t *old_checksum, + svn_revnum_t new_revnum, + apr_time_t new_changed_date, + const char *new_changed_author, + apr_hash_t *new_dav_cache, + svn_boolean_t remove_lock, + svn_boolean_t remove_changelist, + const svn_checksum_t *checksum, + apr_pool_t *scratch_pool) +{ + svn_revnum_t new_changed_rev = new_revnum; + svn_skel_t *work_item = NULL; + + { + const char *lock_relpath; + svn_boolean_t locked; + + if (kind == svn_node_dir) + lock_relpath = local_relpath; + else + lock_relpath = svn_relpath_dirname(local_relpath, scratch_pool); + + SVN_ERR(svn_wc__db_wclock_owns_lock_internal(&locked, wcroot, + lock_relpath, FALSE, + scratch_pool)); + + if (!locked) + return svn_error_createf(SVN_ERR_WC_NOT_LOCKED, NULL, + _("No write-lock in '%s'"), + path_for_error_message(wcroot, local_relpath, + scratch_pool)); + + SVN_ERR(flush_entries(wcroot, lock_relpath, svn_depth_empty, + scratch_pool)); + } + + if (status == svn_wc__db_status_deleted) + { + return svn_error_trace( + db_base_remove(wcroot, local_relpath, db, + FALSE /* keep_as_working */, + FALSE /* queue_deletes */, + TRUE /* remove_locks */, + (! via_recurse) + ? new_revnum : SVN_INVALID_REVNUM, + NULL, NULL, + scratch_pool)); + } + else if (status == svn_wc__db_status_not_present) + { + /* We are committing the leaf of a copy operation. + We leave the not-present marker to allow pulling in excluded + children of a copy. + + The next update will remove the not-present marker. */ + + return SVN_NO_ERROR; + } + + SVN_ERR_ASSERT(status == svn_wc__db_status_normal + || status == svn_wc__db_status_incomplete + || status == svn_wc__db_status_added); + + if (kind != svn_node_dir) + { + /* If we sent a delta (meaning: post-copy modification), + then this file will appear in the queue and so we should have + its checksum already. */ + if (checksum == NULL) + { + /* It was copied and not modified. We must have a text + base for it. And the node should have a checksum. */ + SVN_ERR_ASSERT(old_checksum != NULL); + + checksum = old_checksum; + + /* Is the node completely unmodified and are we recursing? */ + if (via_recurse && !prop_mods) + { + /* If a copied node itself is not modified, but the op_root of + the copy is committed we have to make sure that changed_rev, + changed_date and changed_author don't change or the working + copy used for committing will show different last modified + information then a clean checkout of exactly the same + revisions. (Issue #3676) */ + + SVN_ERR(svn_wc__db_read_info_internal( + NULL, NULL, NULL, NULL, NULL, + &new_changed_rev, + &new_changed_date, + &new_changed_author, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, + wcroot, local_relpath, + scratch_pool, scratch_pool)); + } + } + + SVN_ERR(svn_wc__wq_build_file_commit(&work_item, + db, svn_dirent_join(wcroot->abspath, + local_relpath, + scratch_pool), + prop_mods, + scratch_pool, scratch_pool)); + } + + /* The new text base will be found in the pristine store by its checksum. */ + SVN_ERR(commit_node(wcroot, local_relpath, + new_revnum, new_changed_rev, + new_changed_date, new_changed_author, + checksum, + NULL /* new_children */, + new_dav_cache, + !remove_changelist, + !remove_lock, + work_item, + scratch_pool)); + + return SVN_NO_ERROR; +} + +/** Internal helper for svn_wc_process_committed_queue2(). + * Bump a commit item, collapsing local changes with the new repository + * information to a new BASE node. + * + * @a new_date is the (server-side) date of the new revision, or 0. + * + * @a rev_author is the (server-side) author of the new + * revision; it may be @c NULL. + * + * @a new_dav_cache is a hash of all the new dav properties for LOCAL_RELPATH. + * + * If @a remove_lock is set, release any user locks on @a + * local_abspath; otherwise keep them during processing. + * + * If @a remove_changelist is set, clear any changeset assignments + * from @a local_abspath; otherwise, keep such assignments. + * + * If @a new_sha1_checksum is non-NULL, use it to identify the node's pristine + * text. + * + * Set TOP_OF_RECURSE to TRUE to show that this the top of a possibly + * recursive commit operation. (Part of the legacy recurse handling) + */ +static svn_error_t * +process_committed_internal(svn_wc__db_t *db, + svn_wc__db_wcroot_t *wcroot, + const char *local_relpath, + svn_boolean_t recurse, + svn_boolean_t top_of_recurse, + svn_revnum_t new_revnum, + apr_time_t new_date, + const char *rev_author, + apr_hash_t *new_dav_cache, + svn_boolean_t remove_lock, + svn_boolean_t remove_changelist, + const svn_checksum_t *new_sha1_checksum, + apr_hash_t *items_by_relpath, + apr_pool_t *scratch_pool) +{ + svn_wc__db_status_t status; + svn_node_kind_t kind; + const svn_checksum_t *old_checksum; + svn_boolean_t prop_mods; + + SVN_ERR(svn_wc__db_read_info_internal(&status, &kind, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, &old_checksum, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, &prop_mods, NULL, NULL, NULL, + wcroot, local_relpath, + scratch_pool, scratch_pool)); + + /* NOTE: be wary of making crazy semantic changes in this function, since + svn_wc_process_committed4() calls this. */ + + SVN_ERR(process_committed_leaf(db, wcroot, local_relpath, !top_of_recurse, + status, kind, prop_mods, old_checksum, + new_revnum, new_date, rev_author, + new_dav_cache, + remove_lock, remove_changelist, + new_sha1_checksum, + scratch_pool)); + + /* Only check for recursion on nodes that have children */ + if (kind != svn_node_dir + || status == svn_wc__db_status_not_present + || status == svn_wc__db_status_excluded + || status == svn_wc__db_status_server_excluded + /* Node deleted -> then no longer a directory */ + || status == svn_wc__db_status_deleted) + { + return SVN_NO_ERROR; + } + + if (recurse) + { + const apr_array_header_t *children; + apr_pool_t *iterpool = svn_pool_create(scratch_pool); + int i; + + /* Read PATH's entries; this is the absolute path. */ + SVN_ERR(gather_children(&children, wcroot, local_relpath, + scratch_pool, iterpool)); + + /* Recursively loop over all children. */ + for (i = 0; i < children->nelts; i++) + { + const char *name = APR_ARRAY_IDX(children, i, const char *); + const char *this_relpath; + const commit_queue_item_t *cqi; + + svn_pool_clear(iterpool); + + this_relpath = svn_dirent_join(local_relpath, name, iterpool); + + new_sha1_checksum = NULL; + cqi = svn_hash_gets(items_by_relpath, this_relpath); + + if (cqi != NULL) + new_sha1_checksum = cqi->new_sha1_checksum; + + /* Recurse. Pass NULL for NEW_DAV_CACHE, because the + ones present in the current call are only applicable to + this one committed item. */ + SVN_ERR(process_committed_internal( + db, wcroot, this_relpath, + TRUE /* recurse */, + FALSE /* top_of_recurse */, + new_revnum, new_date, + rev_author, + NULL /* new_dav_cache */, + FALSE /* remove_lock */, + remove_changelist, + new_sha1_checksum, + items_by_relpath, + iterpool)); + } + + svn_pool_destroy(iterpool); + } + + return SVN_NO_ERROR; +} + +/* Return TRUE if any item of QUEUE is a parent of ITEM and will be + processed recursively, return FALSE otherwise. + + The algorithmic complexity of this search implementation is O(queue + length), but it's quite quick. +*/ +static svn_boolean_t +have_recursive_parent(const apr_array_header_t *all_items, + const commit_queue_item_t *item, + apr_pool_t *scratch_pool) +{ + const char *local_relpath = item->local_relpath; + int i; + + for (i = 0; i < all_items->nelts; i++) + { + const commit_queue_item_t *qi + = APR_ARRAY_IDX(all_items, i, const commit_queue_item_t *); + + if (qi == item) + continue; + + if (qi->recurse && svn_relpath_skip_ancestor(qi->local_relpath, + local_relpath)) + { + return TRUE; + } + } + + return FALSE; +} + +/* Compare function for svn_sort__array */ +static int +compare_queue_items(const void *v1, + const void *v2) +{ + const commit_queue_item_t *cqi1 + = *(const commit_queue_item_t **)v1; + const commit_queue_item_t *cqi2 + = *(const commit_queue_item_t **)v2; + + return svn_path_compare_paths(cqi1->local_relpath, cqi2->local_relpath); +} + +/* Internal, locked version of svn_wc__db_process_commit_queue */ +static svn_error_t * +db_process_commit_queue(svn_wc__db_t *db, + svn_wc__db_commit_queue_t *queue, + svn_revnum_t new_revnum, + apr_time_t new_date, + const char *new_author, + apr_pool_t *scratch_pool) +{ + apr_hash_t *items_by_relpath = NULL; + int j; + apr_pool_t *iterpool = svn_pool_create(scratch_pool); + + svn_sort__array(queue->items, compare_queue_items); + + if (queue->have_recurse) + { + items_by_relpath = apr_hash_make(scratch_pool); + + for (j = 0; j < queue->items->nelts; j++) + { + commit_queue_item_t *cqi + = APR_ARRAY_IDX(queue->items, j, commit_queue_item_t *); + + svn_hash_sets(items_by_relpath, cqi->local_relpath, cqi); + } + } + + for (j = 0; j < queue->items->nelts; j++) + { + commit_queue_item_t *cqi + = APR_ARRAY_IDX(queue->items, j, commit_queue_item_t *); + + svn_pool_clear(iterpool); + + /* Skip this item if it is a child of a recursive item, because it has + been (or will be) accounted for when that recursive item was (or + will be) processed. */ + if (queue->have_recurse && have_recursive_parent(queue->items, cqi, + iterpool)) + continue; + + if (!cqi->committed) + { + if (cqi->remove_lock) + { + svn_skel_t *work_item; + + SVN_ERR(svn_wc__wq_build_sync_file_flags( + &work_item, + db, + svn_dirent_join( + queue->wcroot->abspath, + cqi->local_relpath, + iterpool), + iterpool, iterpool)); + + lock_remove_txn(queue->wcroot, cqi->local_relpath, work_item, + iterpool); + } + if (cqi->remove_changelist) + SVN_ERR(svn_wc__db_op_set_changelist(db, + svn_dirent_join( + queue->wcroot->abspath, + cqi->local_relpath, + iterpool), + NULL, NULL, + svn_depth_empty, + NULL, NULL, /* notify */ + NULL, NULL, /* cancel */ + iterpool)); + } + else + { + SVN_ERR(process_committed_internal( + db, queue->wcroot, cqi->local_relpath, + cqi->recurse, + TRUE /* top_of_recurse */, + new_revnum, new_date, new_author, + cqi->new_dav_cache, + cqi->remove_lock, + cqi->remove_changelist, + cqi->new_sha1_checksum, + items_by_relpath, + iterpool)); + } + } + + svn_pool_destroy(iterpool); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_wc__db_process_commit_queue(svn_wc__db_t *db, + svn_wc__db_commit_queue_t *queue, + svn_revnum_t new_revnum, + apr_time_t new_date, + const char *new_author, + apr_pool_t *scratch_pool) +{ + SVN_WC__DB_WITH_TXN(db_process_commit_queue(db, queue, + new_revnum, new_date, + new_author, scratch_pool), + queue->wcroot); + + return SVN_NO_ERROR; +} Modified: subversion/branches/authzperf/subversion/libsvn_wc/wc_db.h URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_wc/wc_db.h?rev=1649205&r1=1649204&r2=1649205&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/libsvn_wc/wc_db.h (original) +++ subversion/branches/authzperf/subversion/libsvn_wc/wc_db.h Sat Jan 3 14:00:41 2015 @@ -1261,6 +1261,53 @@ svn_wc__db_committable_externals_below(a apr_pool_t *result_pool, apr_pool_t *scratch_pool); +/* Opaque struct for svn_wc__db_create_commit_queue, svn_wc__db_commit_queue_add, + svn_wc__db_process_commit_queue */ +typedef struct svn_wc__db_commit_queue_t svn_wc__db_commit_queue_t; + +/* Create a new svn_wc__db_commit_queue_t instance in RESULT_POOL for the + working copy specified with WRI_ABSPATH */ +svn_error_t * +svn_wc__db_create_commit_queue(svn_wc__db_commit_queue_t **queue, + svn_wc__db_t *db, + const char *wri_abspath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + +/* Adds the specified path to the commit queue with the related information. + + See svn_wc_queue_committed4() for argument documentation. + + Note that this function currently DOESN'T copy the passed values to + RESULT_POOL, but expects them to be valid until processing. Otherwise the + only users memory requirements would +- double. + */ +svn_error_t * +svn_wc__db_commit_queue_add(svn_wc__db_commit_queue_t *queue, + const char *local_abspath, + svn_boolean_t recurse, + svn_boolean_t is_commited, + svn_boolean_t remove_lock, + svn_boolean_t remove_changelist, + const svn_checksum_t *new_sha1_checksum, + apr_hash_t *new_dav_cache, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + +/* Process the items in QUEUE in a single transaction. Commit workqueue items + for items that need post processing. + + Implementation detail of svn_wc_process_committed_queue2(). + */ +svn_error_t * +svn_wc__db_process_commit_queue(svn_wc__db_t *db, + svn_wc__db_commit_queue_t *queue, + svn_revnum_t new_revnum, + apr_time_t new_date, + const char *new_author, + apr_pool_t *scratch_pool); + + /* Gets a mapping from const char * local abspaths of externals to the const char * local abspath of where they are defined for all externals defined at or below LOCAL_ABSPATH. @@ -2633,10 +2680,12 @@ svn_wc__db_lock_add(svn_wc__db_t *db, apr_pool_t *scratch_pool); -/* Remove any lock for LOCAL_ABSPATH in DB. */ +/* Remove any lock for LOCAL_ABSPATH in DB and install WORK_ITEMS + (if not NULL) in DB */ svn_error_t * svn_wc__db_lock_remove(svn_wc__db_t *db, const char *local_abspath, + svn_skel_t *work_items, apr_pool_t *scratch_pool); Modified: subversion/branches/authzperf/subversion/libsvn_wc/workqueue.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_wc/workqueue.c?rev=1649205&r1=1649204&r2=1649205&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/libsvn_wc/workqueue.c (original) +++ subversion/branches/authzperf/subversion/libsvn_wc/workqueue.c Sat Jan 3 14:00:41 2015 @@ -1016,8 +1016,8 @@ svn_error_t * svn_wc__wq_build_dir_install(svn_skel_t **work_item, svn_wc__db_t *db, const char *local_abspath, - apr_pool_t *scratch_pool, - apr_pool_t *result_pool) + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { const char *local_relpath; Modified: subversion/branches/authzperf/subversion/libsvn_wc/workqueue.h URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_wc/workqueue.h?rev=1649205&r1=1649204&r2=1649205&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/libsvn_wc/workqueue.h (original) +++ subversion/branches/authzperf/subversion/libsvn_wc/workqueue.h Sat Jan 3 14:00:41 2015 @@ -215,8 +215,8 @@ svn_error_t * svn_wc__wq_build_dir_install(svn_skel_t **work_item, svn_wc__db_t *db, const char *local_abspath, - apr_pool_t *scratch_pool, - apr_pool_t *result_pool); + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); svn_error_t * svn_wc__wq_build_postupgrade(svn_skel_t **work_item, Modified: subversion/branches/authzperf/subversion/mod_authz_svn/mod_authz_svn.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/mod_authz_svn/mod_authz_svn.c?rev=1649205&r1=1649204&r2=1649205&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/mod_authz_svn/mod_authz_svn.c (original) +++ subversion/branches/authzperf/subversion/mod_authz_svn/mod_authz_svn.c Sat Jan 3 14:00:41 2015 @@ -361,7 +361,7 @@ get_access_conf(request_rec *r, authz_sv svn_error_t *svn_err = SVN_NO_ERROR; dav_error *dav_err; - dav_err = dav_svn_get_repos_path(r, conf->base_path, &repos_path); + dav_err = dav_svn_get_repos_path2(r, conf->base_path, &repos_path, scratch_pool); if (dav_err) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "%s", dav_err->desc); Modified: subversion/branches/authzperf/subversion/mod_dav_svn/deadprops.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/mod_dav_svn/deadprops.c?rev=1649205&r1=1649204&r2=1649205&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/mod_dav_svn/deadprops.c (original) +++ subversion/branches/authzperf/subversion/mod_dav_svn/deadprops.c Sat Jan 3 14:00:41 2015 @@ -323,7 +323,7 @@ db_open(apr_pool_t *p, db->p = svn_pool_create(p); /* ### temp hack */ - db->work = svn_stringbuf_ncreate("", 0, db->p); + db->work = svn_stringbuf_create_empty(db->p); /* make our path-based authz callback available to svn_repos_* funcs. */ arb = apr_pcalloc(p, sizeof(*arb)); Modified: subversion/branches/authzperf/subversion/mod_dav_svn/lock.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/mod_dav_svn/lock.c?rev=1649205&r1=1649204&r2=1649205&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/mod_dav_svn/lock.c (original) +++ subversion/branches/authzperf/subversion/mod_dav_svn/lock.c Sat Jan 3 14:00:41 2015 @@ -787,7 +787,31 @@ append_locks(dav_lockdb *lockdb, DAV_ERR_LOCK_SAVE_LOCK, "Anonymous lock creation is not allowed."); } - else if (serr && (serr->apr_err == SVN_ERR_REPOS_HOOK_FAILURE || + else if (serr && serr->apr_err == SVN_ERR_REPOS_POST_LOCK_HOOK_FAILED) + { + /* The lock was created in the repository, so we should report the node + as locked to the client */ + + /* First log the hook failure, for diagnostics. This clears serr */ + dav_svn__log_err(info->r, + dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, + "Post lock hook failure.", + resource->pool), + APLOG_WARNING); + + /* How can we report the error to the client? + + We can't return an error code, as that would make it impossible + to return the lock details? + + Add yet another custom header? + Just an header doesn't handle a full error chain... + + ### Current behavior: we don't report an error. + */ + + } + else if (serr && (svn_error_find_cause(serr, SVN_ERR_REPOS_HOOK_FAILURE) || serr->apr_err == SVN_ERR_FS_NO_SUCH_LOCK || serr->apr_err == SVN_ERR_FS_LOCK_EXPIRED || SVN_ERR_IS_LOCK_ERROR(serr))) @@ -897,6 +921,22 @@ remove_lock(dav_lockdb *lockdb, DAV_ERR_LOCK_SAVE_LOCK, "Anonymous lock removal is not allowed."); } + else if (serr && serr->apr_err == SVN_ERR_REPOS_POST_UNLOCK_HOOK_FAILED + && !resource->info->repos->is_svn_client) + { + /* Generic DAV clients don't understand the specific error code we + would produce here as being just a warning, so lets produce a + success result. We removed the lock anyway. */ + + /* First log the hook failure, for diagnostics. This clears serr */ + dav_svn__log_err(info->r, + dav_svn__convert_err(serr, + HTTP_INTERNAL_SERVER_ERROR, + "Post unlock hook failure.", + resource->pool), + APLOG_WARNING); + + } else if (serr) return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Failed to remove a lock.", @@ -1016,7 +1056,7 @@ refresh_locks(dav_lockdb *lockdb, DAV_ERR_LOCK_SAVE_LOCK, "Anonymous lock refreshing is not allowed."); } - else if (serr && (serr->apr_err == SVN_ERR_REPOS_HOOK_FAILURE || + else if (serr && (svn_error_find_cause(serr, SVN_ERR_REPOS_HOOK_FAILURE) || serr->apr_err == SVN_ERR_FS_NO_SUCH_LOCK || serr->apr_err == SVN_ERR_FS_LOCK_EXPIRED || SVN_ERR_IS_LOCK_ERROR(serr))) Modified: subversion/branches/authzperf/subversion/mod_dav_svn/mod_dav_svn.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/mod_dav_svn/mod_dav_svn.c?rev=1649205&r1=1649204&r2=1649205&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/mod_dav_svn/mod_dav_svn.c (original) +++ subversion/branches/authzperf/subversion/mod_dav_svn/mod_dav_svn.c Sat Jan 3 14:00:41 2015 @@ -662,9 +662,10 @@ dav_svn__get_fs_parent_path(request_rec AP_MODULE_DECLARE(dav_error *) -dav_svn_get_repos_path(request_rec *r, - const char *root_path, - const char **repos_path) +dav_svn_get_repos_path2(request_rec *r, + const char *root_path, + const char **repos_path, + apr_pool_t *pool) { const char *fs_path; @@ -692,19 +693,26 @@ dav_svn_get_repos_path(request_rec *r, /* Split the svn URI to get the name of the repository below the parent path. */ - derr = dav_svn_split_uri(r, r->uri, root_path, - &ignored_cleaned_uri, &ignored_had_slash, - &repos_name, - &ignored_relative, &ignored_path_in_repos); + derr = dav_svn_split_uri2(r, r->uri, root_path, + &ignored_cleaned_uri, &ignored_had_slash, + &repos_name, + &ignored_relative, &ignored_path_in_repos, pool); if (derr) return derr; /* Construct the full path from the parent path base directory and the repository name. */ - *repos_path = svn_dirent_join(fs_parent_path, repos_name, r->pool); + *repos_path = svn_dirent_join(fs_parent_path, repos_name, pool); return NULL; } +AP_MODULE_DECLARE(dav_error *) +dav_svn_get_repos_path(request_rec *r, + const char *root_path, + const char **repos_path) +{ + return dav_svn_get_repos_path2(r, root_path, repos_path, r->pool); +} const char * dav_svn__get_repo_name(request_rec *r) @@ -1324,8 +1332,8 @@ static const command_rec cmds[] = AP_INIT_TAKE1("SVNInMemoryCacheSize", SVNInMemoryCacheSize_cmd, NULL, RSRC_CONF, "specifies the maximum size in kB per process of Subversion's " - "in-memory object cache (default value is 16384; 0 deactivates " - "the cache)."), + "in-memory object cache (default value is 16384; 0 switches " + "to dynamically sized caches)."), /* per server */ AP_INIT_TAKE1("SVNCompressionLevel", SVNCompressionLevel_cmd, NULL, RSRC_CONF, Modified: subversion/branches/authzperf/subversion/mod_dav_svn/reports/deleted-rev.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/mod_dav_svn/reports/deleted-rev.c?rev=1649205&r1=1649204&r2=1649205&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/mod_dav_svn/reports/deleted-rev.c (original) +++ subversion/branches/authzperf/subversion/mod_dav_svn/reports/deleted-rev.c Sat Jan 3 14:00:41 2015 @@ -56,6 +56,9 @@ dav_svn__get_deleted_rev_report(const da dav_error *derr = NULL; /* Sanity check. */ + if (!resource->info->repos_path) + return dav_svn__new_error(resource->pool, HTTP_BAD_REQUEST, 0, + "The request does not specify a repository path"); ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE); if (ns == -1) return dav_svn__new_error_svn(resource->pool, HTTP_BAD_REQUEST, 0,
