Modified: subversion/branches/reuse-ra-session/subversion/libsvn_client/resolved.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_client/resolved.c?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_client/resolved.c (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_client/resolved.c Fri Sep 11 15:51:30 2015 @@ -41,6 +41,9 @@ #include "private/svn_wc_private.h" #include "svn_private_config.h" + +#define ARRAY_LEN(ary) ((sizeof (ary)) / (sizeof ((ary)[0]))) + /*** Code. ***/ @@ -148,30 +151,1156 @@ svn_client_resolve(const char *path, /*** Dealing with conflicts. ***/ +struct svn_client_conflict_t +{ + const char *local_abspath; + svn_client_ctx_t *ctx; + apr_hash_t *prop_conflicts; + + /* Indicate which options were chosen to resolve a text or tree conflict + * on the conflited node. */ + svn_client_conflict_option_id_t resolution_text; + svn_client_conflict_option_id_t resolution_tree; + + /* A mapping from const char* property name to pointers to + * svn_client_conflict_option_t for all properties which had their + * conflicts resolved. Indicates which options were chosen to resolve + * the property conflicts. */ + apr_hash_t *resolved_props; + + /* For backwards compat. */ + const svn_wc_conflict_description2_t *legacy_text_conflict; + const svn_wc_conflict_description2_t *legacy_prop_conflict; + const svn_wc_conflict_description2_t *legacy_tree_conflict; +}; + +/* Resolves conflict to OPTION and sets CONFLICT->RESOLUTION accordingly. */ +typedef svn_error_t *(*conflict_option_resolve_func_t)( + svn_client_conflict_option_t *option, + svn_client_conflict_t *conflict, + apr_pool_t *scratch_pool); + +struct svn_client_conflict_option_t +{ + svn_client_conflict_option_id_t id; + const char *description; + + svn_client_conflict_t *conflict; + conflict_option_resolve_func_t do_resolve_func; + + /* Data which is specific to particular conflicts and options. */ + union { + struct { + /* Indicates the property to resolve in case of a property conflict. + * If set to "", all properties are resolved to this option. */ + const char *propname; + + /* A merged property value, if supplied by the API user, else NULL. */ + const svn_string_t *merged_propval; + } prop; + } type_data; + +}; + +/* + * Return a legacy conflict choice corresponding to OPTION_ID. + * Return svn_wc_conflict_choose_undefined if no corresponding + * legacy conflict choice exists. + */ +static svn_wc_conflict_choice_t +conflict_option_id_to_wc_conflict_choice( + svn_client_conflict_option_id_t option_id) +{ + + switch (option_id) + { + case svn_client_conflict_option_undefined: + return svn_wc_conflict_choose_undefined; + + case svn_client_conflict_option_postpone: + return svn_wc_conflict_choose_postpone; + + case svn_client_conflict_option_base_text: + return svn_wc_conflict_choose_base; + + case svn_client_conflict_option_incoming_new_text: + return svn_wc_conflict_choose_theirs_full; + + case svn_client_conflict_option_working_text: + return svn_wc_conflict_choose_mine_full; + + case svn_client_conflict_option_incoming_new_text_for_conflicted_hunks_only: + return svn_wc_conflict_choose_theirs_conflict; + + case svn_client_conflict_option_working_text_for_conflicted_hunks_only: + return svn_wc_conflict_choose_mine_conflict; + + case svn_client_conflict_option_merged_text: + return svn_wc_conflict_choose_merged; + + case svn_client_conflict_option_unspecified: + return svn_wc_conflict_choose_unspecified; + + default: + break; + } + + return svn_wc_conflict_choose_undefined; +} + +static void +add_legacy_desc_to_conflict(const svn_wc_conflict_description2_t *desc, + svn_client_conflict_t *conflict, + apr_pool_t *result_pool) +{ + switch (desc->kind) + { + case svn_wc_conflict_kind_text: + conflict->legacy_text_conflict = desc; + break; + + case svn_wc_conflict_kind_property: + conflict->legacy_prop_conflict = desc; + break; + + case svn_wc_conflict_kind_tree: + conflict->legacy_tree_conflict = desc; + break; + + default: + SVN_ERR_ASSERT_NO_RETURN(FALSE); /* unknown kind of conflict */ + } +} + +/* Set up a conflict object. If legacy conflict descriptor DESC is not NULL, + * set up the conflict object for backwards compatibility. */ +static svn_error_t * +conflict_get_internal(svn_client_conflict_t **conflict, + const char *local_abspath, + const svn_wc_conflict_description2_t *desc, + svn_client_ctx_t *ctx, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + const apr_array_header_t *descs; + int i; + + *conflict = apr_pcalloc(result_pool, sizeof(**conflict)); + + if (desc) + { + /* Add a single legacy conflict descriptor. */ + (*conflict)->local_abspath = desc->local_abspath; + (*conflict)->resolution_text = svn_client_conflict_option_undefined; + (*conflict)->resolution_tree = svn_client_conflict_option_undefined; + (*conflict)->resolved_props = apr_hash_make(result_pool); + add_legacy_desc_to_conflict(desc, *conflict, result_pool); + + return SVN_NO_ERROR; + } + + (*conflict)->local_abspath = apr_pstrdup(result_pool, local_abspath); + (*conflict)->resolution_text = svn_client_conflict_option_undefined; + (*conflict)->resolution_tree = svn_client_conflict_option_undefined; + (*conflict)->resolved_props = apr_hash_make(result_pool); + (*conflict)->ctx = ctx; + + /* Add all legacy conflict descriptors we can find. Eventually, this code + * path should stop relying on svn_wc_conflict_description2_t entirely. */ + SVN_ERR(svn_wc__read_conflict_descriptions2_t(&descs, ctx->wc_ctx, + local_abspath, + result_pool, scratch_pool)); + for (i = 0; i < descs->nelts; i++) + { + desc = APR_ARRAY_IDX(descs, i, const svn_wc_conflict_description2_t *); + if (desc->kind == svn_wc_conflict_kind_property) + { + if ((*conflict)->prop_conflicts == NULL) + (*conflict)->prop_conflicts = apr_hash_make(result_pool); + svn_hash_sets((*conflict)->prop_conflicts, desc->property_name, desc); + } + else + add_legacy_desc_to_conflict(desc, *conflict, result_pool); + } + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_client_conflict_get(svn_client_conflict_t **conflict, + const char *local_abspath, + svn_client_ctx_t *ctx, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + return svn_error_trace(conflict_get_internal(conflict, local_abspath, NULL, + ctx, result_pool, scratch_pool)); +} + +svn_error_t * +svn_client_conflict_from_wc_description2_t( + svn_client_conflict_t **conflict, + const svn_wc_conflict_description2_t *desc, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + return svn_error_trace(conflict_get_internal(conflict, NULL, desc, NULL, + result_pool, scratch_pool)); +} + +/* Baton type for conflict_resolver_func(). */ +struct conflict_resolver_baton_t { + + svn_client_conflict_walk_func_t *conflict_walk_func; + void *conflict_walk_func_baton; + svn_client_ctx_t *ctx; +}; + +/* Implements svn_wc_conflict_resolver_func2_t for now because + * libsvn_wc does not support our new conflict type yet. */ +static svn_error_t * +conflict_resolver_func(svn_wc_conflict_result_t **result, + const svn_wc_conflict_description2_t *description, + void *baton, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + struct conflict_resolver_baton_t *b = baton; + svn_client_conflict_t *conflict; + const char *local_abspath; + svn_client_conflict_option_id_t resolution; + svn_wc_conflict_choice_t conflict_choice; + + local_abspath = description->local_abspath; + SVN_ERR(svn_client_conflict_get(&conflict, local_abspath, b->ctx, + scratch_pool, scratch_pool)); + + SVN_ERR(b->conflict_walk_func(b->conflict_walk_func_baton, + conflict, scratch_pool)); + + /* Evaluate the conflict callback result based on which kind + * of conflict libsvn_wc has given us. */ + resolution = svn_client_conflict_option_undefined; + if (description->kind == svn_wc_conflict_kind_text) + resolution = conflict->resolution_text; + else if (description->kind == svn_wc_conflict_kind_tree) + resolution = conflict->resolution_tree; + else if (description->kind == svn_wc_conflict_kind_property) + { + svn_client_conflict_option_t *option; + + option = svn_hash_gets(conflict->resolved_props, + description->property_name); + if (option == NULL) + return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL, + _("No resolution provided for conflicted " + "property '%s' on path '%s'"), + description->property_name, + svn_dirent_local_style(local_abspath, + scratch_pool)); + + resolution = svn_client_conflict_option_get_id(option); + conflict_choice = conflict_option_id_to_wc_conflict_choice(resolution); + *result = svn_wc_create_conflict_result(conflict_choice, NULL, + result_pool); + if (resolution == svn_client_conflict_option_merged_text) + (*result)->merged_value = option->type_data.prop.merged_propval; + + return SVN_NO_ERROR; + } + else + return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL, + _("Unknown legacy conflict kind '%d'"), + description->kind); + + if (resolution == svn_client_conflict_option_undefined) + return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL, + _("No resolution for conflicted path '%s'"), + svn_dirent_local_style(local_abspath, + scratch_pool)); + + conflict_choice = conflict_option_id_to_wc_conflict_choice(resolution); + *result = svn_wc_create_conflict_result(conflict_choice, NULL, result_pool); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_client_conflict_walk(const char *local_abspath, + svn_depth_t depth, + svn_client_conflict_walk_func_t conflict_walk_func, + void *conflict_walk_func_baton, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool) +{ + struct conflict_resolver_baton_t b; + const char *lock_abspath; + svn_error_t *err; + + b.conflict_walk_func = conflict_walk_func; + b.conflict_walk_func_baton = conflict_walk_func_baton; + b.ctx = ctx; + + SVN_ERR(svn_wc__acquire_write_lock_for_resolve(&lock_abspath, ctx->wc_ctx, + local_abspath, + scratch_pool, scratch_pool)); + /* ### TODO: svn_wc__resolve_conflicts() should be changed to support + * ### iteration without relying on svn_wc_conflict_resolver_func2_t */ + err = svn_wc__resolve_conflicts(ctx->wc_ctx, local_abspath, + depth, + TRUE /* resolve_text */, + "" /* resolve_prop (ALL props) */, + TRUE /* resolve_tree */, + svn_wc_conflict_choose_unspecified, + conflict_resolver_func, &b, + ctx->cancel_func, ctx->cancel_baton, + ctx->notify_func2, ctx->notify_baton2, + scratch_pool); + + err = svn_error_compose_create(err, svn_wc__release_write_lock(ctx->wc_ctx, + lock_abspath, + scratch_pool)); + svn_io_sleep_for_timestamps(local_abspath, scratch_pool); + + + + return SVN_NO_ERROR; +} + +void +svn_client_conflict_option_set_merged_propval( + svn_client_conflict_option_t *option, + const svn_string_t *merged_propval) +{ + option->type_data.prop.merged_propval = merged_propval; +} + +/* + * Resolve the conflict at LOCAL_ABSPATH. Currently only supports + * an OPTION_ID which can be mapped to svn_wc_conflict_choice_t and + * maps a single option_id to text, prop, and/or tree conflicts. + */ +static svn_error_t * +resolve_conflict(svn_client_conflict_option_id_t option_id, + const char *local_abspath, + svn_boolean_t resolve_text, + const char * resolve_prop, + svn_boolean_t resolve_tree, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool) +{ + svn_wc_conflict_choice_t conflict_choice; + const char *lock_abspath; + svn_error_t *err; + + conflict_choice = conflict_option_id_to_wc_conflict_choice(option_id); + SVN_ERR(svn_wc__acquire_write_lock_for_resolve(&lock_abspath, ctx->wc_ctx, + local_abspath, + scratch_pool, scratch_pool)); + err = svn_wc__resolve_conflicts(ctx->wc_ctx, local_abspath, + svn_depth_empty, + resolve_text, resolve_prop, resolve_tree, + conflict_choice, + NULL, NULL, /* legacy conflict_func/baton */ + ctx->cancel_func, + ctx->cancel_baton, + ctx->notify_func2, + ctx->notify_baton2, + scratch_pool); + err = svn_error_compose_create(err, svn_wc__release_write_lock(ctx->wc_ctx, + lock_abspath, + scratch_pool)); + svn_io_sleep_for_timestamps(local_abspath, scratch_pool); + + return SVN_NO_ERROR; +} + +/* Implements conflict_option_resolve_func_t. */ +static svn_error_t * +resolve_text_conflict(svn_client_conflict_option_t *option, + svn_client_conflict_t *conflict, + apr_pool_t *scratch_pool) +{ + svn_client_conflict_option_id_t option_id; + const char *local_abspath; + + option_id = svn_client_conflict_option_get_id(option); + local_abspath = svn_client_conflict_get_local_abspath(conflict); + SVN_ERR(resolve_conflict(option_id, local_abspath, TRUE, NULL, FALSE, + conflict->ctx, scratch_pool)); + conflict->resolution_text = option_id; + + return SVN_NO_ERROR; +} + +/* Implements conflict_option_resolve_func_t. */ +static svn_error_t * +resolve_prop_conflict(svn_client_conflict_option_t *option, + svn_client_conflict_t *conflict, + apr_pool_t *scratch_pool) +{ + svn_client_conflict_option_id_t option_id; + const char *local_abspath; + const char *propname = option->type_data.prop.propname; + + option_id = svn_client_conflict_option_get_id(option); + local_abspath = svn_client_conflict_get_local_abspath(conflict); + SVN_ERR(resolve_conflict(option_id, local_abspath, + FALSE, propname, FALSE, + conflict->ctx, scratch_pool)); + + if (propname[0] == '\0') + { + apr_hash_index_t *hi; + + /* All properties have been resolved to the same option. */ + for (hi = apr_hash_first(scratch_pool, conflict->prop_conflicts); + hi; + hi = apr_hash_next(hi)) + { + const char *this_propname = apr_hash_this_key(hi); + + svn_hash_sets(conflict->resolved_props, + apr_pstrdup(apr_hash_pool_get(conflict->resolved_props), + this_propname), + option); + svn_hash_sets(conflict->prop_conflicts, this_propname, NULL); + } + } + else + { + svn_hash_sets(conflict->resolved_props, + apr_pstrdup(apr_hash_pool_get(conflict->resolved_props), + propname), + option); + svn_hash_sets(conflict->prop_conflicts, propname, NULL); + } + + return SVN_NO_ERROR; +} + +static svn_error_t * +/* Implements conflict_option_resolve_func_t. */ +resolve_tree_conflict(svn_client_conflict_option_t *option, + svn_client_conflict_t *conflict, + apr_pool_t *scratch_pool) +{ + svn_client_conflict_option_id_t option_id; + const char *local_abspath; + + option_id = svn_client_conflict_option_get_id(option); + local_abspath = svn_client_conflict_get_local_abspath(conflict); + SVN_ERR(resolve_conflict(option_id, local_abspath, FALSE, NULL, TRUE, + conflict->ctx, scratch_pool)); + conflict->resolution_tree = option_id; + + return SVN_NO_ERROR; +} + +/* Resolver options for a text conflict */ +static const svn_client_conflict_option_t text_conflict_options[] = +{ + { + svn_client_conflict_option_postpone, + N_("mark the conflict to be resolved later"), + NULL, + resolve_text_conflict + }, + + { + svn_client_conflict_option_incoming_new_text, + N_("accept incoming version of entire file"), + NULL, + resolve_text_conflict + }, + + { + svn_client_conflict_option_working_text, + N_("accept working copy version of entire file"), + NULL, + resolve_text_conflict + }, + + { + svn_client_conflict_option_incoming_new_text_for_conflicted_hunks_only, + N_("accept incoming version of all text conflicts in file"), + NULL, + resolve_text_conflict + }, + + { + svn_client_conflict_option_working_text_for_conflicted_hunks_only, + N_("accept working copy version of all text conflicts in file"), + NULL, + resolve_text_conflict + }, + +}; + +/* Resolver options for a binary file conflict */ +static const svn_client_conflict_option_t binary_conflict_options[] = +{ + { + svn_client_conflict_option_postpone, + N_("mark the conflict to be resolved later"), + NULL, + resolve_text_conflict, + }, + + { + svn_client_conflict_option_incoming_new_text, + N_("accept incoming version of binary file"), + NULL, + resolve_text_conflict + }, + + { + svn_client_conflict_option_working_text, + N_("accept working copy version of binary file"), + NULL, + resolve_text_conflict + }, + +}; + +/* Resolver options for a property conflict */ +static const svn_client_conflict_option_t prop_conflict_options[] = +{ + { + svn_client_conflict_option_postpone, + N_("mark the conflict to be resolved later"), + NULL, + resolve_prop_conflict + }, + + { + svn_client_conflict_option_incoming_new_text, + N_("accept incoming version of entire property value"), + NULL, + resolve_prop_conflict + }, + + { + svn_client_conflict_option_working_text, + N_("accept working copy version of entire property value"), + NULL, + resolve_prop_conflict + }, + +}; + +/* Resolver options for a tree conflict */ +static const svn_client_conflict_option_t tree_conflict_options[] = +{ + { + svn_client_conflict_option_postpone, + N_("mark the conflict to be resolved later"), + NULL, + resolve_tree_conflict + }, + + { + /* ### Use 'working text' for now since libsvn_wc does not know another + * ### choice to resolve to working yet. */ + svn_client_conflict_option_working_text, + N_("accept current working copy state"), + NULL, + resolve_tree_conflict + }, + +}; + +static svn_error_t * +assert_text_conflict(svn_client_conflict_t *conflict, apr_pool_t *scratch_pool) +{ + svn_boolean_t text_conflicted; + + SVN_ERR(svn_client_conflict_get_conflicted(&text_conflicted, NULL, NULL, + conflict, scratch_pool, + scratch_pool)); + + SVN_ERR_ASSERT(text_conflicted); /* ### return proper error? */ + + return SVN_NO_ERROR; +} + +static svn_error_t * +assert_prop_conflict(svn_client_conflict_t *conflict, apr_pool_t *scratch_pool) +{ + apr_array_header_t *props_conflicted; + + SVN_ERR(svn_client_conflict_get_conflicted(NULL, &props_conflicted, NULL, + conflict, scratch_pool, + scratch_pool)); + + /* ### return proper error? */ + SVN_ERR_ASSERT(props_conflicted && props_conflicted->nelts > 0); + + return SVN_NO_ERROR; +} + +static svn_error_t * +assert_tree_conflict(svn_client_conflict_t *conflict, apr_pool_t *scratch_pool) +{ + svn_boolean_t tree_conflicted; + + SVN_ERR(svn_client_conflict_get_conflicted(NULL, NULL, &tree_conflicted, + conflict, scratch_pool, + scratch_pool)); + + SVN_ERR_ASSERT(tree_conflicted); /* ### return proper error? */ + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_client_conflict_text_get_resolution_options(apr_array_header_t **options, + svn_client_conflict_t *conflict, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + const char *mime_type; + int i; + + SVN_ERR(assert_text_conflict(conflict, scratch_pool)); + + *options = apr_array_make(result_pool, ARRAY_LEN(text_conflict_options), + sizeof(svn_client_conflict_option_t *)); + + mime_type = svn_client_conflict_text_get_mime_type(conflict); + if (mime_type && svn_mime_type_is_binary(mime_type)) + { + for (i = 0; i < ARRAY_LEN(binary_conflict_options); i++) + { + APR_ARRAY_PUSH((*options), const svn_client_conflict_option_t *) = + &binary_conflict_options[i]; + } + } + else + { + for (i = 0; i < ARRAY_LEN(text_conflict_options); i++) + { + APR_ARRAY_PUSH((*options), const svn_client_conflict_option_t *) = + &text_conflict_options[i]; + } + } + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_client_conflict_prop_get_resolution_options(apr_array_header_t **options, + svn_client_conflict_t *conflict, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + int i; + + SVN_ERR(assert_prop_conflict(conflict, scratch_pool)); + + *options = apr_array_make(result_pool, ARRAY_LEN(prop_conflict_options), + sizeof(svn_client_conflict_option_t *)); + for (i = 0; i < ARRAY_LEN(prop_conflict_options); i++) + { + APR_ARRAY_PUSH((*options), const svn_client_conflict_option_t *) = + &prop_conflict_options[i]; + } + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_client_conflict_tree_get_resolution_options(apr_array_header_t **options, + svn_client_conflict_t *conflict, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + int i; + + SVN_ERR(assert_tree_conflict(conflict, scratch_pool)); + + *options = apr_array_make(result_pool, ARRAY_LEN(tree_conflict_options), + sizeof(svn_client_conflict_option_t *)); + for (i = 0; i < ARRAY_LEN(tree_conflict_options); i++) + { + APR_ARRAY_PUSH((*options), const svn_client_conflict_option_t *) = + &tree_conflict_options[i]; + } + + return SVN_NO_ERROR; +} + +svn_client_conflict_option_id_t +svn_client_conflict_option_get_id(svn_client_conflict_option_t *option) +{ + return option->id; +} + +svn_error_t * +svn_client_conflict_option_describe(const char **description, + svn_client_conflict_option_t *option, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + *description = apr_pstrdup(result_pool, option->description); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_client_conflict_text_resolve(svn_client_conflict_t *conflict, + svn_client_conflict_option_t *option, + apr_pool_t *scratch_pool) +{ + SVN_ERR(assert_text_conflict(conflict, scratch_pool)); + SVN_ERR(option->do_resolve_func(option, conflict, scratch_pool)); + + return SVN_NO_ERROR; +} + +svn_client_conflict_option_t * +svn_client_conflict_option_find_by_id(apr_array_header_t *options, + svn_client_conflict_option_id_t option_id) +{ + int i; + + for (i = 0; i < options->nelts; i++) + { + svn_client_conflict_option_t *this_option; + svn_client_conflict_option_id_t this_option_id; + + this_option = APR_ARRAY_IDX(options, i, svn_client_conflict_option_t *); + this_option_id = svn_client_conflict_option_get_id(this_option); + + if (this_option_id == option_id) + return this_option; + } + + return NULL; +} + +svn_error_t * +svn_client_conflict_text_resolve_by_id( + svn_client_conflict_t *conflict, + svn_client_conflict_option_id_t option_id, + apr_pool_t *scratch_pool) +{ + apr_array_header_t *resolution_options; + svn_client_conflict_option_t *option; + + SVN_ERR(svn_client_conflict_text_get_resolution_options( + &resolution_options, conflict, + scratch_pool, scratch_pool)); + option = svn_client_conflict_option_find_by_id(resolution_options, + option_id); + if (option == NULL) + return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL, + _("Inapplicable conflict resolution option " + "ID '%d' given for conflicted path '%s'"), + option_id, + svn_dirent_local_style(conflict->local_abspath, + scratch_pool)); + SVN_ERR(svn_client_conflict_text_resolve(conflict, option, scratch_pool)); + + return SVN_NO_ERROR; +} + +svn_client_conflict_option_id_t +svn_client_conflict_text_get_resolution(const svn_client_conflict_t *conflict) +{ + return conflict->resolution_text; +} + +svn_error_t * +svn_client_conflict_prop_resolve(svn_client_conflict_t *conflict, + const char *propname, + svn_client_conflict_option_t *option, + apr_pool_t *scratch_pool) +{ + SVN_ERR(assert_prop_conflict(conflict, scratch_pool)); + option->type_data.prop.propname = propname; + SVN_ERR(option->do_resolve_func(option, conflict, scratch_pool)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_client_conflict_prop_resolve_by_id( + svn_client_conflict_t *conflict, + const char *propname, + svn_client_conflict_option_id_t option_id, + apr_pool_t *scratch_pool) +{ + apr_array_header_t *resolution_options; + svn_client_conflict_option_t *option; + + SVN_ERR(svn_client_conflict_prop_get_resolution_options( + &resolution_options, conflict, + scratch_pool, scratch_pool)); + option = svn_client_conflict_option_find_by_id(resolution_options, + option_id); + if (option == NULL) + return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL, + _("Inapplicable conflict resolution option " + "ID '%d' given for conflicted path '%s'"), + option_id, + svn_dirent_local_style(conflict->local_abspath, + scratch_pool)); + SVN_ERR(svn_client_conflict_prop_resolve(conflict, propname, option, + scratch_pool)); + + return SVN_NO_ERROR; +} + +svn_client_conflict_option_id_t +svn_client_conflict_prop_get_resolution(const svn_client_conflict_t *conflict, + const char *propname) +{ + svn_client_conflict_option_t *option; + + option = svn_hash_gets(conflict->resolved_props, propname); + if (option == NULL) + return svn_client_conflict_option_undefined; + + return svn_client_conflict_option_get_id(option); +} + +svn_error_t * +svn_client_conflict_tree_resolve(svn_client_conflict_t *conflict, + svn_client_conflict_option_t *option, + apr_pool_t *scratch_pool) +{ + SVN_ERR(assert_tree_conflict(conflict, scratch_pool)); + SVN_ERR(option->do_resolve_func(option, conflict, scratch_pool)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_client_conflict_tree_resolve_by_id( + svn_client_conflict_t *conflict, + svn_client_conflict_option_id_t option_id, + apr_pool_t *scratch_pool) +{ + apr_array_header_t *resolution_options; + svn_client_conflict_option_t *option; + + SVN_ERR(svn_client_conflict_tree_get_resolution_options( + &resolution_options, conflict, + scratch_pool, scratch_pool)); + option = svn_client_conflict_option_find_by_id(resolution_options, + option_id); + if (option == NULL) + return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL, + _("Inapplicable conflict resolution option " + "ID '%d' given for conflicted path '%s'"), + option_id, + svn_dirent_local_style(conflict->local_abspath, + scratch_pool)); + SVN_ERR(svn_client_conflict_tree_resolve(conflict, option, scratch_pool)); + + return SVN_NO_ERROR; +} + +svn_client_conflict_option_id_t +svn_client_conflict_tree_get_resolution(const svn_client_conflict_t *conflict) +{ + return conflict->resolution_tree; +} + +/* Return the legacy conflict descriptor which is wrapped by CONFLICT. */ +static const svn_wc_conflict_description2_t * +get_conflict_desc2_t(const svn_client_conflict_t *conflict) +{ + if (conflict->legacy_text_conflict) + return conflict->legacy_text_conflict; + + if (conflict->legacy_tree_conflict) + return conflict->legacy_tree_conflict; + + if (conflict->legacy_prop_conflict) + return conflict->legacy_prop_conflict; + + return NULL; +} + +svn_wc_conflict_kind_t +svn_client_conflict_get_kind(const svn_client_conflict_t *conflict) +{ + return get_conflict_desc2_t(conflict)->kind; +} + +svn_error_t * +svn_client_conflict_get_conflicted(svn_boolean_t *text_conflicted, + apr_array_header_t **props_conflicted, + svn_boolean_t *tree_conflicted, + svn_client_conflict_t *conflict, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + if (text_conflicted) + *text_conflicted = (conflict->legacy_text_conflict != NULL); + + if (props_conflicted) + { + if (conflict->legacy_prop_conflict) + { + *props_conflicted = apr_array_make(result_pool, 1, + sizeof(const char*)); + APR_ARRAY_PUSH((*props_conflicted), const char *) = + conflict->legacy_prop_conflict->property_name; + } + else if (conflict->prop_conflicts) + SVN_ERR(svn_hash_keys(props_conflicted, conflict->prop_conflicts, + result_pool)); + else + *props_conflicted = NULL; + } + + if (tree_conflicted) + *tree_conflicted = (conflict->legacy_tree_conflict != NULL); + + return SVN_NO_ERROR; +} + const char * -svn_client_conflict_get_local_abspath( - const svn_wc_conflict_description2_t *conflict) +svn_client_conflict_get_local_abspath(const svn_client_conflict_t *conflict) { return conflict->local_abspath; } svn_wc_operation_t -svn_client_conflict_get_operation( - const svn_wc_conflict_description2_t *conflict) +svn_client_conflict_get_operation(const svn_client_conflict_t *conflict) { - return conflict->operation; + return get_conflict_desc2_t(conflict)->operation; } svn_wc_conflict_action_t -svn_client_conflict_get_incoming_change( - const svn_wc_conflict_description2_t *conflict) +svn_client_conflict_get_incoming_change(const svn_client_conflict_t *conflict) { - return conflict->action; + return get_conflict_desc2_t(conflict)->action; } svn_wc_conflict_reason_t -svn_client_conflict_get_local_change( - const svn_wc_conflict_description2_t *conflict) +svn_client_conflict_get_local_change(const svn_client_conflict_t *conflict) +{ + return get_conflict_desc2_t(conflict)->reason; +} + +svn_error_t * +svn_client_conflict_get_repos_info(const char **repos_root_url, + const char **repos_uuid, + const svn_client_conflict_t *conflict, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { - return conflict->reason; + if (repos_root_url) + { + if (get_conflict_desc2_t(conflict)->src_left_version) + *repos_root_url = + get_conflict_desc2_t(conflict)->src_left_version->repos_url; + else if (get_conflict_desc2_t(conflict)->src_right_version) + *repos_root_url = + get_conflict_desc2_t(conflict)->src_right_version->repos_url; + else + *repos_root_url = NULL; + } + + if (repos_uuid) + { + if (get_conflict_desc2_t(conflict)->src_left_version) + *repos_uuid = + get_conflict_desc2_t(conflict)->src_left_version->repos_uuid; + else if (get_conflict_desc2_t(conflict)->src_right_version) + *repos_uuid = + get_conflict_desc2_t(conflict)->src_right_version->repos_uuid; + else + *repos_uuid = NULL; + } + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_client_conflict_get_incoming_old_repos_location( + const char **incoming_old_repos_relpath, + svn_revnum_t *incoming_old_pegrev, + svn_node_kind_t *incoming_old_node_kind, + const svn_client_conflict_t *conflict, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + if (incoming_old_repos_relpath) + { + if (get_conflict_desc2_t(conflict)->src_left_version) + *incoming_old_repos_relpath = + get_conflict_desc2_t(conflict)->src_left_version->path_in_repos; + else + *incoming_old_repos_relpath = NULL; + } + + if (incoming_old_pegrev) + { + if (get_conflict_desc2_t(conflict)->src_left_version) + *incoming_old_pegrev = + get_conflict_desc2_t(conflict)->src_left_version->peg_rev; + else + *incoming_old_pegrev = SVN_INVALID_REVNUM; + } + + if (incoming_old_node_kind) + { + if (get_conflict_desc2_t(conflict)->src_left_version) + *incoming_old_node_kind = + get_conflict_desc2_t(conflict)->src_left_version->node_kind; + else + *incoming_old_node_kind = svn_node_none; + } + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_client_conflict_get_incoming_new_repos_location( + const char **incoming_new_repos_relpath, + svn_revnum_t *incoming_new_pegrev, + svn_node_kind_t *incoming_new_node_kind, + const svn_client_conflict_t *conflict, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + if (incoming_new_repos_relpath) + { + if (get_conflict_desc2_t(conflict)->src_right_version) + *incoming_new_repos_relpath = + get_conflict_desc2_t(conflict)->src_right_version->path_in_repos; + else + *incoming_new_repos_relpath = NULL; + } + + if (incoming_new_pegrev) + { + if (get_conflict_desc2_t(conflict)->src_right_version) + *incoming_new_pegrev = + get_conflict_desc2_t(conflict)->src_right_version->peg_rev; + else + *incoming_new_pegrev = SVN_INVALID_REVNUM; + } + + if (incoming_new_node_kind) + { + if (get_conflict_desc2_t(conflict)->src_right_version) + *incoming_new_node_kind = + get_conflict_desc2_t(conflict)->src_right_version->node_kind; + else + *incoming_new_node_kind = svn_node_none; + } + + return SVN_NO_ERROR; +} + +svn_node_kind_t +svn_client_conflict_tree_get_victim_node_kind( + const svn_client_conflict_t *conflict) +{ + SVN_ERR_ASSERT_NO_RETURN(svn_client_conflict_get_kind(conflict) + == svn_wc_conflict_kind_tree); + + return get_conflict_desc2_t(conflict)->node_kind; +} + +const char * +svn_client_conflict_prop_get_propname(const svn_client_conflict_t *conflict) +{ + SVN_ERR_ASSERT_NO_RETURN(svn_client_conflict_get_kind(conflict) + == svn_wc_conflict_kind_property); + + return get_conflict_desc2_t(conflict)->property_name; +} + +svn_error_t * +svn_client_conflict_prop_get_propvals(const svn_string_t **base_propval, + const svn_string_t **working_propval, + const svn_string_t **incoming_old_propval, + const svn_string_t **incoming_new_propval, + const svn_client_conflict_t *conflict, + apr_pool_t *result_pool) +{ + SVN_ERR_ASSERT(svn_client_conflict_get_kind(conflict) == + svn_wc_conflict_kind_property); + + if (base_propval) + *base_propval = + svn_string_dup(get_conflict_desc2_t(conflict)->prop_value_base, + result_pool); + + if (working_propval) + *working_propval = + svn_string_dup(get_conflict_desc2_t(conflict)->prop_value_working, + result_pool); + + if (incoming_old_propval) + *incoming_old_propval = + svn_string_dup(get_conflict_desc2_t(conflict)->prop_value_incoming_old, + result_pool); + + if (incoming_new_propval) + *incoming_new_propval = + svn_string_dup(get_conflict_desc2_t(conflict)->prop_value_incoming_new, + result_pool); + + return SVN_NO_ERROR; +} + +const char * +svn_client_conflict_prop_get_reject_abspath( + const svn_client_conflict_t *conflict) +{ + SVN_ERR_ASSERT_NO_RETURN(svn_client_conflict_get_kind(conflict) + == svn_wc_conflict_kind_property); + + /* svn_wc_conflict_description2_t stores this path in 'their_abspath' */ + return get_conflict_desc2_t(conflict)->their_abspath; +} + +const char * +svn_client_conflict_text_get_mime_type(const svn_client_conflict_t *conflict) +{ + SVN_ERR_ASSERT_NO_RETURN(svn_client_conflict_get_kind(conflict) + == svn_wc_conflict_kind_text); + + return get_conflict_desc2_t(conflict)->mime_type; +} + +svn_error_t * +svn_client_conflict_text_get_contents(const char **base_abspath, + const char **working_abspath, + const char **incoming_old_abspath, + const char **incoming_new_abspath, + const svn_client_conflict_t *conflict, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + SVN_ERR_ASSERT(svn_client_conflict_get_kind(conflict) + == svn_wc_conflict_kind_text); + + if (base_abspath) + { + if (svn_client_conflict_get_operation(conflict) == + svn_wc_operation_merge) + *base_abspath = NULL; /* ### WC base contents not available yet */ + else /* update/switch */ + *base_abspath = get_conflict_desc2_t(conflict)->base_abspath; + } + + if (working_abspath) + *working_abspath = get_conflict_desc2_t(conflict)->my_abspath; + + if (incoming_old_abspath) + *incoming_old_abspath = get_conflict_desc2_t(conflict)->base_abspath; + + if (incoming_new_abspath) + *incoming_new_abspath = get_conflict_desc2_t(conflict)->their_abspath; + + return SVN_NO_ERROR; }
Modified: subversion/branches/reuse-ra-session/subversion/libsvn_client/upgrade.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_client/upgrade.c?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_client/upgrade.c (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_client/upgrade.c Fri Sep 11 15:51:30 2015 @@ -83,11 +83,13 @@ fetch_repos_info(const char **repos_root } /* Forward definition. Upgrades svn:externals properties in the working copy - LOCAL_ABSPATH to the WC-NG storage. + LOCAL_ABSPATH to the WC-NG storage. INFO_BATON will be used to fetch + repository info using fetch_repos_info() function if needed. */ static svn_error_t * upgrade_externals_from_properties(svn_client_ctx_t *ctx, const char *local_abspath, + struct repos_info_baton *info_baton, apr_pool_t *scratch_pool); svn_error_t * @@ -172,7 +174,7 @@ svn_client_upgrade(const char *path, (There is no way to detect the difference from libsvn_client :( ) */ SVN_ERR(upgrade_externals_from_properties(ctx, local_abspath, - scratch_pool)); + &info_baton, scratch_pool)); } return SVN_NO_ERROR; } @@ -180,6 +182,7 @@ svn_client_upgrade(const char *path, static svn_error_t * upgrade_externals_from_properties(svn_client_ctx_t *ctx, const char *local_abspath, + struct repos_info_baton *info_baton, apr_pool_t *scratch_pool) { apr_hash_index_t *hi; @@ -187,7 +190,6 @@ upgrade_externals_from_properties(svn_cl apr_pool_t *iterpool2; apr_hash_t *externals; svn_opt_revision_t rev = {svn_opt_revision_unspecified, {0}}; - struct repos_info_baton info_baton; /* Now it's time to upgrade the externals too. We do it after the wc upgrade to avoid that errors in the externals causes the wc upgrade to @@ -345,7 +347,7 @@ upgrade_externals_from_properties(svn_cl { err = fetch_repos_info(&repos_root_url, &repos_uuid, - &info_baton, + info_baton, resolved_url, scratch_pool, scratch_pool); if (err) Modified: subversion/branches/reuse-ra-session/subversion/libsvn_diff/parse-diff.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_diff/parse-diff.c?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_diff/parse-diff.c (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_diff/parse-diff.c Fri Sep 11 15:51:30 2015 @@ -1352,17 +1352,22 @@ static struct transition transitions[] = { {"--- ", state_start, diff_minus}, {"+++ ", state_minus_seen, diff_plus}, + {"diff --git", state_start, git_start}, {"--- a/", state_git_diff_seen, git_minus}, {"--- a/", state_git_tree_seen, git_minus}, {"--- /dev/null", state_git_tree_seen, git_minus}, {"+++ b/", state_git_minus_seen, git_plus}, {"+++ /dev/null", state_git_minus_seen, git_plus}, + {"rename from ", state_git_diff_seen, git_move_from}, {"rename to ", state_move_from_seen, git_move_to}, + {"copy from ", state_git_diff_seen, git_copy_from}, {"copy to ", state_copy_from_seen, git_copy_to}, + {"new file ", state_git_diff_seen, git_new_file}, + {"deleted file ", state_git_diff_seen, git_deleted_file}, }; Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs/fs-loader.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs/fs-loader.c?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_fs/fs-loader.c (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_fs/fs-loader.c Fri Sep 11 15:51:30 2015 @@ -1773,8 +1773,7 @@ svn_fs_lock_target_create(const char *to svn_revnum_t current_rev, apr_pool_t *result_pool) { - svn_fs_lock_target_t *target = apr_palloc(result_pool, - sizeof(svn_fs_lock_target_t)); + svn_fs_lock_target_t *target = apr_palloc(result_pool, sizeof(*target)); target->token = token; target->current_rev = current_rev; Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs/fs-loader.h URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs/fs-loader.h?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_fs/fs-loader.h (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_fs/fs-loader.h Fri Sep 11 15:51:30 2015 @@ -22,8 +22,8 @@ */ -#ifndef LIBSVN_FS_FS_H -#define LIBSVN_FS_FS_H +#ifndef LIBSVN_FS_LOADER_H +#define LIBSVN_FS_LOADER_H #include "svn_types.h" #include "svn_fs.h" @@ -184,15 +184,9 @@ typedef svn_error_t *(*fs_init_func_t)(c to the create and open functions and these init functions (as well as the open and create functions) are globally serialized so that they have exclusive access to the common_pool. */ -svn_error_t *svn_fs_base__init(const svn_version_t *loader_version, - fs_library_vtable_t **vtable, - apr_pool_t* common_pool); -svn_error_t *svn_fs_fs__init(const svn_version_t *loader_version, - fs_library_vtable_t **vtable, - apr_pool_t* common_pool); -svn_error_t *svn_fs_x__init(const svn_version_t *loader_version, - fs_library_vtable_t **vtable, - apr_pool_t* common_pool); +#include "../libsvn_fs_base/fs_init.h" +#include "../libsvn_fs_fs/fs_init.h" +#include "../libsvn_fs_x/fs_init.h" @@ -569,4 +563,4 @@ struct svn_fs_lock_target_t } #endif /* __cplusplus */ -#endif +#endif /* LIBSVN_FS_LOADER_H */ Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_base/revs-txns.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_base/revs-txns.c?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_fs_base/revs-txns.c (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_base/revs-txns.c Fri Sep 11 15:51:30 2015 @@ -247,8 +247,10 @@ svn_fs_base__set_rev_prop(svn_fs_t *fs, { transaction_t *txn; const char *txn_id; + const svn_string_t *present_value; SVN_ERR(get_rev_txn(&txn, &txn_id, fs, rev, trail, pool)); + present_value = svn_hash_gets(txn->proplist, name); /* If there's no proplist, but we're just deleting a property, exit now. */ if ((! txn->proplist) && (! value)) @@ -262,7 +264,6 @@ svn_fs_base__set_rev_prop(svn_fs_t *fs, if (old_value_p) { const svn_string_t *wanted_value = *old_value_p; - const svn_string_t *present_value = svn_hash_gets(txn->proplist, name); if ((!wanted_value != !present_value) || (wanted_value && present_value && !svn_string_compare(wanted_value, present_value))) @@ -275,6 +276,13 @@ svn_fs_base__set_rev_prop(svn_fs_t *fs, } /* Fall through. */ } + + /* If the prop-set is a no-op, skip the actual write. */ + if ((!present_value && !value) + || (present_value && value + && svn_string_compare(present_value, value))) + return SVN_NO_ERROR; + svn_hash_sets(txn->proplist, name, value); /* Overwrite the revision. */ Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/cached_data.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/cached_data.c?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/cached_data.c (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/cached_data.c Fri Sep 11 15:51:30 2015 @@ -57,7 +57,7 @@ block_read(void **result, apr_pool_t *scratch_pool); -/* Defined this to enable access logging via dgb__log_access +/* Define this to enable access logging via dbg_log_access #define SVN_FS_FS__LOG_ACCESS */ @@ -91,7 +91,7 @@ dbg_log_access(svn_fs_t *fs, svn_fs_fs__revision_file_t *rev_file; SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&rev_file, fs, revision, - scratch_pool)); + scratch_pool, scratch_pool)); /* determine rev / pack file offset */ SVN_ERR(svn_fs_fs__item_offset(&offset, fs, rev_file, revision, NULL, @@ -158,7 +158,8 @@ dbg_log_access(svn_fs_t *fs, { /* reverse index lookup: get item description in ENTRY */ SVN_ERR(svn_fs_fs__p2l_entry_lookup(&entry, fs, rev_file, revision, - offset, scratch_pool)); + offset, scratch_pool, + scratch_pool)); if (entry) { /* more details */ @@ -183,6 +184,10 @@ dbg_log_access(svn_fs_t *fs, description); } + /* We don't know when SCRATCH_POOL will be cleared, so close the rev file + explicitly. */ + SVN_ERR(svn_fs_fs__close_revision_file(rev_file)); + #endif return SVN_NO_ERROR; @@ -2862,7 +2867,7 @@ svn_fs_fs__get_changes(apr_array_header_ svn_revnum_t rev, apr_pool_t *result_pool) { - apr_off_t changes_offset = SVN_FS_FS__ITEM_INDEX_CHANGES; + apr_off_t item_index = SVN_FS_FS__ITEM_INDEX_CHANGES; svn_fs_fs__revision_file_t *revision_file; svn_boolean_t found; fs_fs_data_t *ffd = fs->fsap_data; @@ -2897,17 +2902,26 @@ svn_fs_fs__get_changes(apr_array_header_ } else { + apr_off_t changes_offset; + /* Addressing is very different for old formats * (needs to read the revision trailer). */ if (svn_fs_fs__use_log_addressing(fs)) - SVN_ERR(svn_fs_fs__item_offset(&changes_offset, fs, - revision_file, rev, NULL, - SVN_FS_FS__ITEM_INDEX_CHANGES, - scratch_pool)); + { + SVN_ERR(svn_fs_fs__item_offset(&changes_offset, fs, + revision_file, rev, NULL, + SVN_FS_FS__ITEM_INDEX_CHANGES, + scratch_pool)); + } else - SVN_ERR(get_root_changes_offset(NULL, &changes_offset, - revision_file, fs, rev, - scratch_pool)); + { + SVN_ERR(get_root_changes_offset(NULL, &changes_offset, + revision_file, fs, rev, + scratch_pool)); + + /* This variable will be used for debug logging only. */ + item_index = changes_offset; + } /* Actual reading and parsing are the same, though. */ SVN_ERR(aligned_seek(fs, revision_file->file, NULL, changes_offset, @@ -2935,7 +2949,7 @@ svn_fs_fs__get_changes(apr_array_header_ SVN_ERR(svn_fs_fs__close_revision_file(revision_file)); } - SVN_ERR(dbg_log_access(fs, rev, changes_offset, *changes, + SVN_ERR(dbg_log_access(fs, rev, item_index, *changes, SVN_FS_FS__ITEM_TYPE_CHANGES, scratch_pool)); svn_pool_destroy(scratch_pool); Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/caching.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/caching.c?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/caching.c (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/caching.c Fri Sep 11 15:51:30 2015 @@ -274,7 +274,8 @@ init_callbacks(svn_cache__t *cache, * MEMBUFFER is not NULL. Fallbacks to inprocess cache if MEMCACHE and * MEMBUFFER are NULL and pages is non-zero. Sets *CACHE_P to NULL * otherwise. Use the given PRIORITY class for the new cache. If it - * is 0, then use the default priority class. + * is 0, then use the default priority class. HAS_NAMESPACE indicates + * whether we prefixed this cache instance with a namespace. * * Unless NO_HANDLER is true, register an error handler that reports errors * as warnings to the FS warning callback. @@ -292,6 +293,7 @@ create_cache(svn_cache__t **cache_p, apr_ssize_t klen, const char *prefix, apr_uint32_t priority, + svn_boolean_t has_namespace, svn_fs_t *fs, svn_boolean_t no_handler, apr_pool_t *result_pool, @@ -314,9 +316,12 @@ create_cache(svn_cache__t **cache_p, } else if (membuffer) { + /* We assume caches with namespaces to be relatively short-lived, + * i.e. their data will not be needed after a while. */ SVN_ERR(svn_cache__create_membuffer_cache( cache_p, membuffer, serializer, deserializer, - klen, prefix, priority, FALSE, result_pool, scratch_pool)); + klen, prefix, priority, FALSE, has_namespace, + result_pool, scratch_pool)); } else if (pages) { @@ -349,6 +354,7 @@ svn_fs_fs__initialize_caches(svn_fs_t *f svn_boolean_t cache_txdeltas; svn_boolean_t cache_fulltexts; const char *cache_namespace; + svn_boolean_t has_namespace; /* Evaluating the cache configuration. */ SVN_ERR(read_config(&cache_namespace, @@ -358,6 +364,7 @@ svn_fs_fs__initialize_caches(svn_fs_t *f pool)); prefix = apr_pstrcat(pool, "ns:", cache_namespace, ":", prefix, SVN_VA_NULL); + has_namespace = strlen(cache_namespace) > 0; membuffer = svn_cache__get_global_membuffer_cache(); @@ -386,34 +393,35 @@ svn_fs_fs__initialize_caches(svn_fs_t *f * commands, this is only going to contain a few entries (svnadmin * dump/verify is an exception here), so to reduce overhead let's * try to keep it to just one page. I estimate each entry has about - * 72 bytes of overhead (svn_revnum_t key, svn_fs_id_t + - * id_private_t + 3 strings for value, and the cache_entry); the - * default pool size is 8192, so about a hundred should fit - * comfortably. */ + * 130 bytes of overhead (svn_revnum_t key, ID struct, and the cache_entry); + * the default pool size is 8192, so about a fifty should fit comfortably. + */ SVN_ERR(create_cache(&(ffd->rev_root_id_cache), NULL, membuffer, - 1, 100, + 1, 50, svn_fs_fs__serialize_id, svn_fs_fs__deserialize_id, sizeof(svn_revnum_t), apr_pstrcat(pool, prefix, "RRI", SVN_VA_NULL), 0, + has_namespace, fs, no_handler, fs->pool, pool)); - /* Rough estimate: revision DAG nodes have size around 320 bytes, so - * let's put 16 on a page. */ + /* Rough estimate: revision DAG nodes have size around 1kBytes, so + * let's put 8 on a page. */ SVN_ERR(create_cache(&(ffd->rev_node_cache), NULL, membuffer, - 1024, 16, + 1, 8, svn_fs_fs__dag_serialize, svn_fs_fs__dag_deserialize, APR_HASH_KEY_STRING, apr_pstrcat(pool, prefix, "DAG", SVN_VA_NULL), SVN_CACHE__MEMBUFFER_LOW_PRIORITY, + has_namespace, fs, no_handler, fs->pool, pool)); @@ -425,28 +433,30 @@ svn_fs_fs__initialize_caches(svn_fs_t *f SVN_ERR(create_cache(&(ffd->dir_cache), NULL, membuffer, - 1024, 8, + 1, 8, svn_fs_fs__serialize_dir_entries, svn_fs_fs__deserialize_dir_entries, sizeof(pair_cache_key_t), apr_pstrcat(pool, prefix, "DIR", SVN_VA_NULL), SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY, + has_namespace, fs, no_handler, fs->pool, pool)); - /* Only 16 bytes per entry (a revision number + the corresponding offset). - Since we want ~8k pages, that means 512 entries per page. */ + /* 8 kBytes per entry (1000 revs / shared, one file offset per rev). + Covering about 8 pack files gives us an "o.k." hit rate. */ SVN_ERR(create_cache(&(ffd->packed_offset_cache), NULL, membuffer, - 32, 1, + 8, 1, svn_fs_fs__serialize_manifest, svn_fs_fs__deserialize_manifest, sizeof(svn_revnum_t), apr_pstrcat(pool, prefix, "PACK-MANIFEST", SVN_VA_NULL), SVN_CACHE__MEMBUFFER_HIGH_PRIORITY, + has_namespace, fs, no_handler, fs->pool, pool)); @@ -455,12 +465,13 @@ svn_fs_fs__initialize_caches(svn_fs_t *f SVN_ERR(create_cache(&(ffd->node_revision_cache), NULL, membuffer, - 32, 32, /* ~200 byte / entry; 1k entries total */ + 2, 16, /* ~500 byte / entry; 32 entries total */ svn_fs_fs__serialize_node_revision, svn_fs_fs__deserialize_node_revision, sizeof(pair_cache_key_t), apr_pstrcat(pool, prefix, "NODEREVS", SVN_VA_NULL), SVN_CACHE__MEMBUFFER_HIGH_PRIORITY, + has_namespace, fs, no_handler, fs->pool, pool)); @@ -469,12 +480,13 @@ svn_fs_fs__initialize_caches(svn_fs_t *f SVN_ERR(create_cache(&(ffd->rep_header_cache), NULL, membuffer, - 1, 1000, /* ~8 bytes / entry; 1k entries total */ + 1, 200, /* ~40 bytes / entry; 200 entries total */ svn_fs_fs__serialize_rep_header, svn_fs_fs__deserialize_rep_header, sizeof(pair_cache_key_t), apr_pstrcat(pool, prefix, "REPHEADER", SVN_VA_NULL), SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY, + has_namespace, fs, no_handler, fs->pool, pool)); @@ -489,6 +501,7 @@ svn_fs_fs__initialize_caches(svn_fs_t *f sizeof(svn_revnum_t), apr_pstrcat(pool, prefix, "CHANGES", SVN_VA_NULL), 0, + has_namespace, fs, no_handler, fs->pool, pool)); @@ -499,12 +512,13 @@ svn_fs_fs__initialize_caches(svn_fs_t *f SVN_ERR(create_cache(&(ffd->fulltext_cache), ffd->memcache, membuffer, - 0, 0, /* Do not use inprocess cache */ + 0, 0, /* Do not use the inprocess cache */ /* Values are svn_stringbuf_t */ NULL, NULL, sizeof(pair_cache_key_t), apr_pstrcat(pool, prefix, "TEXT", SVN_VA_NULL), SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY, + has_namespace, fs, no_handler, fs->pool, pool)); @@ -512,13 +526,14 @@ svn_fs_fs__initialize_caches(svn_fs_t *f SVN_ERR(create_cache(&(ffd->properties_cache), NULL, membuffer, - 0, 0, /* Do not use inprocess cache */ + 0, 0, /* Do not use the inprocess cache */ svn_fs_fs__serialize_properties, svn_fs_fs__deserialize_properties, sizeof(pair_cache_key_t), apr_pstrcat(pool, prefix, "PROP", SVN_VA_NULL), SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY, + has_namespace, fs, no_handler, fs->pool, pool)); @@ -526,13 +541,14 @@ svn_fs_fs__initialize_caches(svn_fs_t *f SVN_ERR(create_cache(&(ffd->mergeinfo_cache), NULL, membuffer, - 0, 0, /* Do not use inprocess cache */ + 0, 0, /* Do not use the inprocess cache */ svn_fs_fs__serialize_mergeinfo, svn_fs_fs__deserialize_mergeinfo, APR_HASH_KEY_STRING, apr_pstrcat(pool, prefix, "MERGEINFO", SVN_VA_NULL), 0, + has_namespace, fs, no_handler, fs->pool, pool)); @@ -540,13 +556,14 @@ svn_fs_fs__initialize_caches(svn_fs_t *f SVN_ERR(create_cache(&(ffd->mergeinfo_existence_cache), NULL, membuffer, - 0, 0, /* Do not use inprocess cache */ + 0, 0, /* Do not use the inprocess cache */ /* Values are svn_stringbuf_t */ NULL, NULL, APR_HASH_KEY_STRING, apr_pstrcat(pool, prefix, "HAS_MERGEINFO", SVN_VA_NULL), 0, + has_namespace, fs, no_handler, fs->pool, pool)); @@ -565,13 +582,14 @@ svn_fs_fs__initialize_caches(svn_fs_t *f SVN_ERR(create_cache(&(ffd->raw_window_cache), NULL, membuffer, - 0, 0, /* Do not use inprocess cache */ + 0, 0, /* Do not use the inprocess cache */ svn_fs_fs__serialize_raw_window, svn_fs_fs__deserialize_raw_window, sizeof(window_cache_key_t), apr_pstrcat(pool, prefix, "RAW_WINDOW", SVN_VA_NULL), SVN_CACHE__MEMBUFFER_LOW_PRIORITY, + has_namespace, fs, no_handler, fs->pool, pool)); @@ -579,13 +597,14 @@ svn_fs_fs__initialize_caches(svn_fs_t *f SVN_ERR(create_cache(&(ffd->txdelta_window_cache), NULL, membuffer, - 0, 0, /* Do not use inprocess cache */ + 0, 0, /* Do not use the inprocess cache */ svn_fs_fs__serialize_txdelta_window, svn_fs_fs__deserialize_txdelta_window, sizeof(window_cache_key_t), apr_pstrcat(pool, prefix, "TXDELTA_WINDOW", SVN_VA_NULL), SVN_CACHE__MEMBUFFER_LOW_PRIORITY, + has_namespace, fs, no_handler, fs->pool, pool)); @@ -593,13 +612,14 @@ svn_fs_fs__initialize_caches(svn_fs_t *f SVN_ERR(create_cache(&(ffd->combined_window_cache), NULL, membuffer, - 0, 0, /* Do not use inprocess cache */ + 0, 0, /* Do not use the inprocess cache */ /* Values are svn_stringbuf_t */ NULL, NULL, sizeof(window_cache_key_t), apr_pstrcat(pool, prefix, "COMBINED_WINDOW", SVN_VA_NULL), SVN_CACHE__MEMBUFFER_LOW_PRIORITY, + has_namespace, fs, no_handler, fs->pool, pool)); @@ -613,28 +633,34 @@ svn_fs_fs__initialize_caches(svn_fs_t *f SVN_ERR(create_cache(&(ffd->l2p_header_cache), NULL, membuffer, - 64, 16, /* entry size varies but we must cover - a reasonable number of revisions (1k) */ + 8, 16, /* entry size varies but we must cover a + reasonable number of rev / pack files + to allow for delta chains to be walked + efficiently etc. */ svn_fs_fs__serialize_l2p_header, svn_fs_fs__deserialize_l2p_header, sizeof(pair_cache_key_t), apr_pstrcat(pool, prefix, "L2P_HEADER", (char *)NULL), SVN_CACHE__MEMBUFFER_HIGH_PRIORITY, + has_namespace, fs, no_handler, fs->pool, pool)); SVN_ERR(create_cache(&(ffd->l2p_page_cache), NULL, membuffer, - 64, 16, /* entry size varies but we must cover - a reasonable number of revisions (1k) */ + 8, 16, /* entry size varies but we must cover a + reasonable number of rev / pack files + to allow for delta chains to be walked + efficiently etc. */ svn_fs_fs__serialize_l2p_page, svn_fs_fs__deserialize_l2p_page, sizeof(svn_fs_fs__page_cache_key_t), apr_pstrcat(pool, prefix, "L2P_PAGE", (char *)NULL), SVN_CACHE__MEMBUFFER_HIGH_PRIORITY, + has_namespace, fs, no_handler, fs->pool, pool)); @@ -648,19 +674,21 @@ svn_fs_fs__initialize_caches(svn_fs_t *f apr_pstrcat(pool, prefix, "P2L_HEADER", (char *)NULL), SVN_CACHE__MEMBUFFER_HIGH_PRIORITY, + has_namespace, fs, no_handler, fs->pool, pool)); SVN_ERR(create_cache(&(ffd->p2l_page_cache), NULL, membuffer, - 4, 16, /* Variably sized entries. Rarely used. */ + 4, 1, /* Variably sized entries. Rarely used. */ svn_fs_fs__serialize_p2l_page, svn_fs_fs__deserialize_p2l_page, sizeof(svn_fs_fs__page_cache_key_t), apr_pstrcat(pool, prefix, "P2L_PAGE", (char *)NULL), SVN_CACHE__MEMBUFFER_HIGH_PRIORITY, + has_namespace, fs, no_handler, fs->pool, pool)); @@ -807,6 +835,7 @@ svn_fs_fs__initialize_txn_caches(svn_fs_ apr_pstrcat(pool, prefix, "TXNDIR", SVN_VA_NULL), 0, + TRUE, /* The TXN-ID is our namespace. */ fs, TRUE, pool, pool)); Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/fs.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/fs.c?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/fs.c (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/fs.c Fri Sep 11 15:51:30 2015 @@ -134,6 +134,18 @@ fs_serialized_init(svn_fs_t *fs, apr_poo return SVN_NO_ERROR; } +svn_error_t * +svn_fs_fs__initialize_shared_data(svn_fs_t *fs, + svn_mutex__t *common_pool_lock, + apr_pool_t *pool, + apr_pool_t *common_pool) +{ + SVN_MUTEX__WITH_LOCK(common_pool_lock, + fs_serialized_init(fs, common_pool, pool)); + + return SVN_NO_ERROR; +} + /* This function is provided for Subversion 1.0.x compatibility. It @@ -480,28 +492,19 @@ fs_hotcopy(svn_fs_t *src_fs, apr_pool_t *pool, apr_pool_t *common_pool) { - /* Open the source repo as usual. */ SVN_ERR(fs_open(src_fs, src_path, common_pool_lock, pool, common_pool)); - if (cancel_func) - SVN_ERR(cancel_func(cancel_baton)); - /* Test target repo when in INCREMENTAL mode, initialize it when not. - * For this, we need our FS internal data structures to be temporarily - * available. */ + SVN_ERR(svn_fs__check_fs(dst_fs, FALSE)); SVN_ERR(initialize_fs_struct(dst_fs)); - SVN_ERR(svn_fs_fs__hotcopy_prepare_target(src_fs, dst_fs, dst_path, - incremental, pool)); - uninitialize_fs_struct(dst_fs); - - /* Now, the destination repo should open just fine. */ - SVN_ERR(fs_open(dst_fs, dst_path, common_pool_lock, pool, common_pool)); - if (cancel_func) - SVN_ERR(cancel_func(cancel_baton)); - - /* Now, we may copy data as needed ... */ - return svn_fs_fs__hotcopy(src_fs, dst_fs, incremental, - notify_func, notify_baton, - cancel_func, cancel_baton, pool); + + /* In INCREMENTAL mode, svn_fs_fs__hotcopy() will open DST_FS. + Otherwise, it's not an FS yet --- possibly just an empty dir --- so + can't be opened. + */ + return svn_fs_fs__hotcopy(src_fs, dst_fs, src_path, dst_path, + incremental, notify_func, notify_baton, + cancel_func, cancel_baton, common_pool_lock, + pool, common_pool); } Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/fs.h URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/fs.h?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/fs.h (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/fs.h Fri Sep 11 15:51:30 2015 @@ -82,8 +82,6 @@ extern "C" { /* Names of special files and file extensions for transactions */ #define PATH_CHANGES "changes" /* Records changes made so far */ #define PATH_TXN_PROPS "props" /* Transaction properties */ -#define PATH_TXN_PROPS_FINAL "props-final" /* Final transaction properties - before moving to revprops */ #define PATH_NEXT_IDS "next-ids" /* Next temporary ID assignments */ #define PATH_PREFIX_NODE "node." /* Prefix for node filename */ #define PATH_EXT_TXN ".txn" /* Extension of txn dir */ Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/fs_fs.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/fs_fs.c?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/fs_fs.c (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/fs_fs.c Fri Sep 11 15:51:30 2015 @@ -2010,7 +2010,7 @@ set_node_origins_for_file(svn_fs_t *fs, SVN_ERR(svn_stream_close(stream)); /* Rename the temp file as the real destination */ - return svn_io_file_rename(path_tmp, node_origins_path, pool); + return svn_io_file_rename2(path_tmp, node_origins_path, FALSE, pool); } @@ -2075,13 +2075,14 @@ change_rev_prop_body(void *baton, apr_po { struct change_rev_prop_baton *cb = baton; apr_hash_t *table; + const svn_string_t *present_value; SVN_ERR(svn_fs_fs__get_revision_proplist(&table, cb->fs, cb->rev, pool)); + present_value = svn_hash_gets(table, cb->name); if (cb->old_value_p) { const svn_string_t *wanted_value = *cb->old_value_p; - const svn_string_t *present_value = svn_hash_gets(table, cb->name); if ((!wanted_value != !present_value) || (wanted_value && present_value && !svn_string_compare(wanted_value, present_value))) @@ -2094,6 +2095,13 @@ change_rev_prop_body(void *baton, apr_po } /* Fall through. */ } + + /* If the prop-set is a no-op, skip the actual write. */ + if ((!present_value && !cb->value) + || (present_value && cb->value + && svn_string_compare(present_value, cb->value))) + return SVN_NO_ERROR; + svn_hash_sets(table, cb->name, cb->value); return svn_fs_fs__set_revision_proplist(cb->fs, cb->rev, table, pool); Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/fs_fs.h URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/fs_fs.h?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/fs_fs.h (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/fs_fs.h Fri Sep 11 15:51:30 2015 @@ -39,6 +39,15 @@ svn_error_t *svn_fs_fs__open(svn_fs_t *f const char *path, apr_pool_t *pool); +/* Initialize parts of the FS data that are being shared across multiple + filesystem objects. Use COMMON_POOL for process-wide and POOL for + temporary allocations. Use COMMON_POOL_LOCK to ensure that the + initialization is serialized. */ +svn_error_t *svn_fs_fs__initialize_shared_data(svn_fs_t *fs, + svn_mutex__t *common_pool_lock, + apr_pool_t *pool, + apr_pool_t *common_pool); + /* Upgrade the fsfs filesystem FS. Indicate progress via the optional * NOTIFY_FUNC callback using NOTIFY_BATON. The optional CANCEL_FUNC * will periodically be called with CANCEL_BATON to allow for preemption. Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/hotcopy.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/hotcopy.c?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/hotcopy.c (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/hotcopy.c Fri Sep 11 15:51:30 2015 @@ -982,6 +982,10 @@ hotcopy_body(void *baton, apr_pool_t *po if (kind == svn_node_file) { SVN_ERR(svn_sqlite__hotcopy(src_subdir, dst_subdir, pool)); + + /* The source might have r/o flags set on it - which would be + carried over to the copy. */ + SVN_ERR(svn_io_set_file_read_write(dst_subdir, FALSE, pool)); SVN_ERR(svn_fs_fs__del_rep_reference(dst_fs, src_youngest, pool)); } } @@ -991,65 +995,33 @@ hotcopy_body(void *baton, apr_pool_t *po SVN_ERR(svn_io_dir_file_copy(src_fs->path, dst_fs->path, PATH_TXN_CURRENT, pool)); - return SVN_NO_ERROR; -} - -/* Wrapper around hotcopy_body taking out all necessary source repository - * locks. - */ -static svn_error_t * -hotcopy_locking_src_body(void *baton, apr_pool_t *pool) -{ - struct hotcopy_body_baton *hbb = baton; - fs_fs_data_t *src_ffd = hbb->src_fs->fsap_data; + /* Hotcopied FS is complete. Stamp it with a format file. */ + SVN_ERR(svn_fs_fs__write_format(dst_fs, TRUE, pool)); - return src_ffd->format >= SVN_FS_FS__MIN_PACK_LOCK_FORMAT - ? svn_error_trace(svn_fs_fs__with_pack_lock(hbb->src_fs, hotcopy_body, - baton, pool)) - : hotcopy_body(baton, pool); + return SVN_NO_ERROR; } -/* Create an empty filesystem at DST_FS at DST_PATH with the same - * configuration as SRC_FS (uuid, format, and other parameters). - * After creation DST_FS has no revisions, not even revision zero. */ -static svn_error_t * -hotcopy_create_empty_dest(svn_fs_t *src_fs, - svn_fs_t *dst_fs, - const char *dst_path, - apr_pool_t *pool) +svn_error_t * +svn_fs_fs__hotcopy(svn_fs_t *src_fs, + svn_fs_t *dst_fs, + const char *src_path, + const char *dst_path, + svn_boolean_t incremental, + svn_fs_hotcopy_notify_t notify_func, + void *notify_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_mutex__t *common_pool_lock, + apr_pool_t *pool, + apr_pool_t *common_pool) { - fs_fs_data_t *src_ffd = src_fs->fsap_data; + struct hotcopy_body_baton hbb; - /* Create the DST_FS repository with the same layout as SRC_FS. */ - SVN_ERR(svn_fs_fs__create_file_tree(dst_fs, dst_path, src_ffd->format, - src_ffd->max_files_per_dir, - src_ffd->use_log_addressing, - pool)); - - /* Copy the UUID. Hotcopy destination receives a new instance ID, but - * has the same filesystem UUID as the source. */ - SVN_ERR(svn_fs_fs__set_uuid(dst_fs, src_fs->uuid, NULL, pool)); - - /* Remove revision 0 contents. Otherwise, it may not get overwritten - * due to having a newer timestamp. */ - SVN_ERR(hotcopy_remove_file(svn_fs_fs__path_rev(dst_fs, 0, pool), pool)); - SVN_ERR(hotcopy_remove_file(svn_fs_fs__path_revprops(dst_fs, 0, pool), - pool)); - - /* This filesystem is ready. Stamp it with a format number. Fail if - * the 'format' file should already exist. */ - SVN_ERR(svn_fs_fs__write_format(dst_fs, FALSE, pool)); + if (cancel_func) + SVN_ERR(cancel_func(cancel_baton)); - return SVN_NO_ERROR; -} + SVN_ERR(svn_fs_fs__open(src_fs, src_path, pool)); -svn_error_t * -svn_fs_fs__hotcopy_prepare_target(svn_fs_t *src_fs, - svn_fs_t *dst_fs, - const char *dst_path, - svn_boolean_t incremental, - apr_pool_t *pool) -{ if (incremental) { const char *dst_format_abspath; @@ -1061,39 +1033,51 @@ svn_fs_fs__hotcopy_prepare_target(svn_fs SVN_ERR(svn_io_check_path(dst_format_abspath, &dst_format_kind, pool)); if (dst_format_kind == svn_node_none) { - /* Destination doesn't exist yet. Perform a normal hotcopy to a - * empty destination using the same configuration as the source. */ - SVN_ERR(hotcopy_create_empty_dest(src_fs, dst_fs, dst_path, pool)); - } - else - { - /* Check the existing repository. */ - SVN_ERR(svn_fs_fs__open(dst_fs, dst_path, pool)); - SVN_ERR(hotcopy_incremental_check_preconditions(src_fs, dst_fs, - pool)); + /* No destination? Fallback to a non-incremental hotcopy. */ + incremental = FALSE; } } + + if (incremental) + { + /* Check the existing repository. */ + SVN_ERR(svn_fs_fs__open(dst_fs, dst_path, pool)); + SVN_ERR(hotcopy_incremental_check_preconditions(src_fs, dst_fs, pool)); + + SVN_ERR(svn_fs_fs__initialize_shared_data(dst_fs, common_pool_lock, + pool, common_pool)); + SVN_ERR(svn_fs_fs__initialize_caches(dst_fs, pool)); + } else { /* Start out with an empty destination using the same configuration * as the source. */ - SVN_ERR(hotcopy_create_empty_dest(src_fs, dst_fs, dst_path, pool)); + fs_fs_data_t *src_ffd = src_fs->fsap_data; + + /* Create the DST_FS repository with the same layout as SRC_FS. */ + SVN_ERR(svn_fs_fs__create_file_tree(dst_fs, dst_path, src_ffd->format, + src_ffd->max_files_per_dir, + src_ffd->use_log_addressing, + pool)); + + /* Copy the UUID. Hotcopy destination receives a new instance ID, but + * has the same filesystem UUID as the source. */ + SVN_ERR(svn_fs_fs__set_uuid(dst_fs, src_fs->uuid, NULL, pool)); + + /* Remove revision 0 contents. Otherwise, it may not get overwritten + * due to having a newer timestamp. */ + SVN_ERR(hotcopy_remove_file(svn_fs_fs__path_rev(dst_fs, 0, pool), + pool)); + SVN_ERR(hotcopy_remove_file(svn_fs_fs__path_revprops(dst_fs, 0, pool), + pool)); + + SVN_ERR(svn_fs_fs__initialize_shared_data(dst_fs, common_pool_lock, + pool, common_pool)); + SVN_ERR(svn_fs_fs__initialize_caches(dst_fs, pool)); } - return SVN_NO_ERROR; -} - -svn_error_t * -svn_fs_fs__hotcopy(svn_fs_t *src_fs, - svn_fs_t *dst_fs, - svn_boolean_t incremental, - svn_fs_hotcopy_notify_t notify_func, - void *notify_baton, - svn_cancel_func_t cancel_func, - void *cancel_baton, - apr_pool_t *pool) -{ - struct hotcopy_body_baton hbb; + if (cancel_func) + SVN_ERR(cancel_func(cancel_baton)); hbb.src_fs = src_fs; hbb.dst_fs = dst_fs; @@ -1102,8 +1086,15 @@ svn_fs_fs__hotcopy(svn_fs_t *src_fs, hbb.notify_baton = notify_baton; hbb.cancel_func = cancel_func; hbb.cancel_baton = cancel_baton; - SVN_ERR(svn_fs_fs__with_all_locks(dst_fs, hotcopy_locking_src_body, &hbb, - pool)); + + /* Lock the destination in the incremental mode. For a non-incremental + * hotcopy, don't take any locks. In that case the destination cannot be + * opened until the hotcopy finishes, and we don't have to worry about + * concurrency. */ + if (incremental) + SVN_ERR(svn_fs_fs__with_all_locks(dst_fs, hotcopy_body, &hbb, pool)); + else + SVN_ERR(hotcopy_body(&hbb, pool)); return SVN_NO_ERROR; } Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/hotcopy.h URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/hotcopy.h?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/hotcopy.h (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/hotcopy.h Fri Sep 11 15:51:30 2015 @@ -25,27 +25,23 @@ #include "fs.h" -/* Create an empty copy of the fsfs filesystem SRC_FS into a new DST_FS at - * DST_PATH. If INCREMENTAL is TRUE, perform a few pre-checks only if - * a repo already exists at DST_PATH. Use POOL for temporary allocations. */ -svn_error_t * -svn_fs_fs__hotcopy_prepare_target(svn_fs_t *src_fs, - svn_fs_t *dst_fs, - const char *dst_path, - svn_boolean_t incremental, - apr_pool_t *pool); - -/* Copy the fsfs filesystem SRC_FS into DST_FS. If INCREMENTAL is TRUE, do - * not re-copy data which already exists in DST_FS. Indicate progress via - * the optional NOTIFY_FUNC callback using NOTIFY_BATON. Use POOL for - * temporary allocations. */ +/* Copy the fsfs filesystem SRC_FS at SRC_PATH into a new copy DST_FS at + * DST_PATH. If INCREMENTAL is TRUE, do not re-copy data which already + * exists in DST_FS. Indicate progress via the optional NOTIFY_FUNC + * callback using NOTIFY_BATON. Use COMMON_POOL for process-wide and + * POOL for temporary allocations. Use COMMON_POOL_LOCK to ensure + * that the initialization of the shared data is serialized. */ svn_error_t * svn_fs_fs__hotcopy(svn_fs_t *src_fs, svn_fs_t *dst_fs, + const char *src_path, + const char *dst_path, svn_boolean_t incremental, svn_fs_hotcopy_notify_t notify_func, void *notify_baton, svn_cancel_func_t cancel_func, void *cancel_baton, - apr_pool_t *pool); + svn_mutex__t *common_pool_lock, + apr_pool_t *pool, + apr_pool_t *common_pool); #endif Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/id.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/id.c?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/id.c (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/id.c Fri Sep 11 15:51:30 2015 @@ -610,7 +610,9 @@ svn_fs_fs__id_serialize(svn_temp_seriali if (id == NULL) return; - /* serialize the id data struct itself */ + /* Serialize the id data struct itself. + * Note that the structure behind IN is actually larger than a mere + * svn_fs_id_t . */ svn_temp_serializer__add_leaf(context, (const void * const *)in, sizeof(fs_fs__id_t));
