Author: pburba
Date: Fri May 3 21:50:52 2013
New Revision: 1478987
URL: http://svn.apache.org/r1478987
Log:
A small bit of issue #4351 'improve automatic merge performance' work: Avoid
one to two network roundtrips to get the *same* mergeinfo catalogs while
calculating automatic merges.
* subversion/include/private/svn_client_private.h
(svn_client__mergeinfo_log): New, wrapper around
svn_client_mergeinfo_log2().
* subversion/libsvn_client/merge.c
(short_circuit_mergeinfo_log): Wrap svn_client__mergeinfo_log instead of
svn_client_mergeinfo_log2 (yes, it's a wrapper of a wrapper). Add a
in/out parameter for the target's mergeinfo catalog.
(find_last_merged_location): Update calls to short_circuit_mergeinfo_log().
On the first call, let the callee get the target's mergeinfo catalog. On
the second call, pass the callee the target's mergeinfo catalog, thus
preventing it from asking the repository the same question twice.
* subversion/libsvn_client/mergeinfo.c
(svn_client__mergeinfo_log): New, but mostly the old implementation of
svn_client_mergeinfo_log2().
(svn_client_mergeinfo_log2): Now just a wrapper around
svn_client__mergeinfo_log().
Modified:
subversion/trunk/subversion/include/private/svn_client_private.h
subversion/trunk/subversion/libsvn_client/merge.c
subversion/trunk/subversion/libsvn_client/mergeinfo.c
Modified: subversion/trunk/subversion/include/private/svn_client_private.h
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_client_private.h?rev=1478987&r1=1478986&r2=1478987&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_client_private.h (original)
+++ subversion/trunk/subversion/include/private/svn_client_private.h Fri May 3
21:50:52 2013
@@ -291,6 +291,39 @@ svn_client__copy_foreign(const char *url
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool);
+/* Same as the public svn_client_mergeinfo_log2 API, except for the addition
+ * of the TARGET_MERGEINFO_CATALOG and RESULT_POOL parameters.
+ *
+ * If TARGET_MERGEINFO_CATALOG is NULL then this acts exactly as the public
+ * API. If *TARGET_MERGEINFO_CATALOG is NULL, then *TARGET_MERGEINFO_CATALOG
+ * is set to the a mergeinfo catalog representing the mergeinfo on
+ * TARGET_PATH_OR_URL@TARGET_PEG_REVISION at DEPTH, (like the public API only
+ * depths of svn_depth_empty or svn_depth_infinity are supported) allocated in
+ * RESULT_POOL. Finally, if *TARGET_MERGEINFO_CATALOG is non-NULL, then it is
+ * assumed to be a mergeinfo catalog representing the mergeinfo on
+ * TARGET_PATH_OR_URL@TARGET_PEG_REVISION at DEPTH.
+ *
+ * The keys for the subtree mergeinfo are the repository root-relative
+ * paths of TARGET_PATH_OR_URL and/or its subtrees, regardless of whether
+ * TARGET_PATH_OR_URL is a URL or WC path.
+ */
+svn_error_t *
+svn_client__mergeinfo_log(svn_boolean_t finding_merged,
+ const char *target_path_or_url,
+ const svn_opt_revision_t *target_peg_revision,
+ svn_mergeinfo_catalog_t *target_mergeinfo_catalog,
+ const char *source_path_or_url,
+ const svn_opt_revision_t *source_peg_revision,
+ const svn_opt_revision_t *source_start_revision,
+ const svn_opt_revision_t *source_end_revision,
+ svn_log_entry_receiver_t log_receiver,
+ void *log_receiver_baton,
+ svn_boolean_t discover_changed_paths,
+ svn_depth_t depth,
+ const apr_array_header_t *revprops,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
#ifdef __cplusplus
}
Modified: subversion/trunk/subversion/libsvn_client/merge.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/merge.c?rev=1478987&r1=1478986&r2=1478987&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/merge.c (original)
+++ subversion/trunk/subversion/libsvn_client/merge.c Fri May 3 21:50:52 2013
@@ -12028,16 +12028,17 @@ operative_rev_receiver(void *baton,
return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, NULL);
}
-/* Wrapper around svn_client_mergeinfo_log2. All arguments are as per
- that API. The discover_changed_paths, depth, and revprops args to
- svn_client_mergeinfo_log2 are always TRUE, svn_depth_infinity_t,
+/* Wrapper around svn_client__mergeinfo_log. All arguments are as per
+ that private API. The discover_changed_paths, depth, and revprops args to
+ svn_client__mergeinfo_log are always TRUE, svn_depth_infinity_t,
and NULL respectively.
If RECEIVER raises a SVN_ERR_CEASE_INVOCATION error, but still sets
*REVISION to a valid revnum, then clear the error. Otherwise return
any error. */
static svn_error_t*
-short_circuit_mergeinfo_log(svn_boolean_t finding_merged,
+short_circuit_mergeinfo_log(svn_mergeinfo_catalog_t *target_mergeinfo_cat,
+ svn_boolean_t finding_merged,
const char *target_path_or_url,
const svn_opt_revision_t *target_peg_revision,
const char *source_path_or_url,
@@ -12047,18 +12048,21 @@ short_circuit_mergeinfo_log(svn_boolean_
svn_log_entry_receiver_t receiver,
svn_revnum_t *revision,
svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- svn_error_t *err = svn_client_mergeinfo_log2(finding_merged,
+ svn_error_t *err = svn_client__mergeinfo_log(finding_merged,
target_path_or_url,
target_peg_revision,
+ target_mergeinfo_cat,
source_path_or_url,
source_peg_revision,
source_start_revision,
source_end_revision,
receiver, revision,
TRUE, svn_depth_infinity,
- NULL, ctx, scratch_pool);
+ NULL, ctx, result_pool,
+ scratch_pool);
if (err)
{
@@ -12128,6 +12132,7 @@ find_last_merged_location(svn_client__pa
svn_opt_revision_t source_peg_rev, source_start_rev, source_end_rev,
target_opt_rev;
svn_revnum_t youngest_merged_rev = SVN_INVALID_REVNUM;
+ svn_mergeinfo_catalog_t target_mergeinfo_cat = NULL;
source_peg_rev.kind = svn_opt_revision_number;
source_peg_rev.value.number = source_branch->tip->rev;
@@ -12140,14 +12145,15 @@ find_last_merged_location(svn_client__pa
/* Find the youngest revision fully merged from SOURCE_BRANCH to TARGET,
if such a revision exists. */
- SVN_ERR(short_circuit_mergeinfo_log(TRUE, /* Find merged */
+ SVN_ERR(short_circuit_mergeinfo_log(&target_mergeinfo_cat,
+ TRUE, /* Find merged */
target->url, &target_opt_rev,
source_branch->tip->url,
&source_peg_rev,
&source_end_rev, &source_start_rev,
operative_rev_receiver,
&youngest_merged_rev,
- ctx, scratch_pool));
+ ctx, result_pool, scratch_pool));
if (!SVN_IS_VALID_REVNUM(youngest_merged_rev))
{
@@ -12174,14 +12180,15 @@ find_last_merged_location(svn_client__pa
(i.e. finding the youngest revision after the YCA where all revs have
been merged) that doesn't matter. */
source_end_rev.value.number = youngest_merged_rev;
- SVN_ERR(short_circuit_mergeinfo_log(FALSE, /* Find eligible */
+ SVN_ERR(short_circuit_mergeinfo_log(&target_mergeinfo_cat,
+ FALSE, /* Find eligible */
target->url, &target_opt_rev,
source_branch->tip->url,
&source_peg_rev,
&source_start_rev, &source_end_rev,
operative_rev_receiver,
&oldest_eligible_rev,
- ctx, scratch_pool));
+ ctx, scratch_pool, scratch_pool));
/* If there are revisions eligible for merging, use the oldest one
to calculate the base. Otherwise there are no operative revisions
Modified: subversion/trunk/subversion/libsvn_client/mergeinfo.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/mergeinfo.c?rev=1478987&r1=1478986&r2=1478987&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/mergeinfo.c (original)
+++ subversion/trunk/subversion/libsvn_client/mergeinfo.c Fri May 3 21:50:52
2013
@@ -1647,11 +1647,11 @@ svn_client_mergeinfo_get_merged(apr_hash
return SVN_NO_ERROR;
}
-
svn_error_t *
-svn_client_mergeinfo_log2(svn_boolean_t finding_merged,
+svn_client__mergeinfo_log(svn_boolean_t finding_merged,
const char *target_path_or_url,
const svn_opt_revision_t *target_peg_revision,
+ svn_mergeinfo_catalog_t *target_mergeinfo_catalog,
const char *source_path_or_url,
const svn_opt_revision_t *source_peg_revision,
const svn_opt_revision_t *source_start_revision,
@@ -1662,12 +1662,15 @@ svn_client_mergeinfo_log2(svn_boolean_t
svn_depth_t depth,
const apr_array_header_t *revprops,
svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
const char *log_target = NULL;
const char *repos_root;
const char *target_repos_relpath;
svn_mergeinfo_catalog_t target_mergeinfo_cat;
+ svn_ra_session_t *target_session = NULL;
+ svn_client__pathrev_t *pathrev;
/* A hash of paths, at or under TARGET_PATH_OR_URL, mapped to
rangelists. Not technically mergeinfo, so not using the
@@ -1684,6 +1687,7 @@ svn_client_mergeinfo_log2(svn_boolean_t
apr_hash_index_t *hi;
apr_pool_t *iterpool;
svn_boolean_t oldest_revs_first = TRUE;
+ apr_pool_t *subpool;
/* We currently only support depth = empty | infinity. */
if (depth != svn_depth_infinity && depth != svn_depth_empty)
@@ -1709,6 +1713,8 @@ svn_client_mergeinfo_log2(svn_boolean_t
&& (source_start_revision->kind != svn_opt_revision_unspecified))
return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL, NULL);
+ subpool = svn_pool_create(scratch_pool);
+
/* We need the union of TARGET_PATH_OR_URL@TARGET_PEG_REVISION's mergeinfo
and MERGE_SOURCE_URL's history. It's not enough to do path
matching, because renames in the history of MERGE_SOURCE_URL
@@ -1716,10 +1722,45 @@ svn_client_mergeinfo_log2(svn_boolean_t
the target, that vastly simplifies matters (we'll have nothing to
do). */
/* This get_mergeinfo() call doubles as a mergeinfo capabilities check. */
- SVN_ERR(get_mergeinfo(&target_mergeinfo_cat, &repos_root,
- target_path_or_url, target_peg_revision,
- depth == svn_depth_infinity, TRUE,
- ctx, scratch_pool, scratch_pool));
+ if (target_mergeinfo_catalog)
+ {
+ if (*target_mergeinfo_catalog)
+ {
+ /* The caller provided the mergeinfo catalog for
+ TARGET_PATH_OR_URL, so we don't need to accquire
+ it ourselves. We do need to get the repos_root
+ though, because get_mergeinfo() won't do it for us. */
+ target_mergeinfo_cat = *target_mergeinfo_catalog;
+ SVN_ERR(svn_client__ra_session_from_path2(&target_session, &pathrev,
+ target_path_or_url, NULL,
+ target_peg_revision,
+ target_peg_revision,
+ ctx, subpool));
+ SVN_ERR(svn_ra_get_repos_root2(target_session, &repos_root,
+ scratch_pool));
+ }
+ else
+ {
+ /* The caller didn't provide the mergeinfo catalog for
+ TARGET_PATH_OR_URL, but wants us to pass a copy back
+ when we get it, so use RESULT_POOL. */
+ SVN_ERR(get_mergeinfo(target_mergeinfo_catalog, &repos_root,
+ target_path_or_url, target_peg_revision,
+ depth == svn_depth_infinity, TRUE,
+ ctx, result_pool, scratch_pool));
+ target_mergeinfo_cat = *target_mergeinfo_catalog;
+ }
+ }
+ else
+ {
+ /* The caller didn't provide the mergeinfo catalog for
+ TARGET_PATH_OR_URL, nor does it want a copy, so we can use
+ nothing but SCRATCH_POOL. */
+ SVN_ERR(get_mergeinfo(&target_mergeinfo_cat, &repos_root,
+ target_path_or_url, target_peg_revision,
+ depth == svn_depth_infinity, TRUE,
+ ctx, scratch_pool, scratch_pool));
+ }
if (!svn_path_is_url(target_path_or_url))
{
@@ -1751,6 +1792,7 @@ svn_client_mergeinfo_log2(svn_boolean_t
history. */
if (finding_merged)
{
+ svn_pool_destroy(subpool);
return SVN_NO_ERROR;
}
else
@@ -1768,18 +1810,17 @@ svn_client_mergeinfo_log2(svn_boolean_t
* ### TODO: As the source and target must be in the same repository, we
* should share a single session, tracking the two URLs separately. */
{
- apr_pool_t *sesspool = svn_pool_create(scratch_pool);
- svn_ra_session_t *source_session, *target_session;
- svn_client__pathrev_t *pathrev;
+ svn_ra_session_t *source_session;
svn_revnum_t start_rev, end_rev, youngest_rev = SVN_INVALID_REVNUM;
if (! finding_merged)
{
- SVN_ERR(svn_client__ra_session_from_path2(&target_session, &pathrev,
- target_path_or_url, NULL,
- target_peg_revision,
- target_peg_revision,
- ctx, sesspool));
+ if (!target_session)
+ SVN_ERR(svn_client__ra_session_from_path2(&target_session, &pathrev,
+ target_path_or_url, NULL,
+ target_peg_revision,
+ target_peg_revision,
+ ctx, subpool));
SVN_ERR(svn_client__get_history_as_mergeinfo(&target_history, NULL,
pathrev,
SVN_INVALID_REVNUM,
@@ -1792,17 +1833,17 @@ svn_client_mergeinfo_log2(svn_boolean_t
source_path_or_url, NULL,
source_peg_revision,
source_peg_revision,
- ctx, sesspool));
+ ctx, subpool));
SVN_ERR(svn_client__get_revision_number(&start_rev, &youngest_rev,
ctx->wc_ctx, source_path_or_url,
source_session,
source_start_revision,
- sesspool));
+ subpool));
SVN_ERR(svn_client__get_revision_number(&end_rev, &youngest_rev,
ctx->wc_ctx, source_path_or_url,
source_session,
source_end_revision,
- sesspool));
+ subpool));
SVN_ERR(svn_client__get_history_as_mergeinfo(&source_history, NULL,
pathrev,
MAX(end_rev, start_rev),
@@ -1813,7 +1854,7 @@ svn_client_mergeinfo_log2(svn_boolean_t
oldest_revs_first = FALSE;
/* Close the source and target sessions. */
- svn_pool_destroy(sesspool);
+ svn_pool_destroy(subpool);
}
/* Separate the explicit or inherited mergeinfo on TARGET_PATH_OR_URL,
@@ -2086,6 +2127,31 @@ svn_client_mergeinfo_log2(svn_boolean_t
}
svn_error_t *
+svn_client_mergeinfo_log2(svn_boolean_t finding_merged,
+ const char *target_path_or_url,
+ const svn_opt_revision_t *target_peg_revision,
+ const char *source_path_or_url,
+ const svn_opt_revision_t *source_peg_revision,
+ const svn_opt_revision_t *source_start_revision,
+ const svn_opt_revision_t *source_end_revision,
+ svn_log_entry_receiver_t log_receiver,
+ void *log_receiver_baton,
+ svn_boolean_t discover_changed_paths,
+ svn_depth_t depth,
+ const apr_array_header_t *revprops,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *scratch_pool)
+{
+ return svn_client__mergeinfo_log(finding_merged, target_path_or_url,
+ target_peg_revision, NULL,
+ source_path_or_url, source_peg_revision,
+ source_start_revision, source_end_revision,
+ log_receiver, log_receiver_baton,
+ discover_changed_paths, depth, revprops,
+ ctx, scratch_pool, scratch_pool);
+}
+
+svn_error_t *
svn_client_suggest_merge_sources(apr_array_header_t **suggestions,
const char *path_or_url,
const svn_opt_revision_t *peg_revision,