Hi,

Automatic merge creates minimum 8 connection using code in trunk. The
RA cache framework implemented in reuse-ra-session reduce number of
used RA sessions to 3.

The attached patch for reuse-ra-session branch reworks merge.c a bit
to use just 2 RA sessions. It also resolves RA CACHE TODO: comment and
makes code  more clear IMO.

I'm pretty sure about the patch itself. But may be proposed changes
are out of scope ra-session-reuse branch. So this patch should be
committed to reuse-ra-session branch or to trunk after
reuse-ra-session branch will be merged to trunk. Any opinions?

[[[
Optimize and simplify RA session usage in merge code.

* subversion/libsvn_client/merge.c
  (normalize_merge_sources_internal): Open new temporary RA session if
   RA_SESSION argument is NULL. Update docstring to document new behavior.

  (ensure_ra_session_url): Remove now unused function.

  (do_merge): Remove SRC_SESSION argument and code to save/restore session
   URL for passed RA session. Open and release RA session for every merge
   source -- RA cache framework will reuse them if possible. All callers
   are updated.

  (merge_cousins_and_supplement_mergeinfo): Remove URL1_RA_SESSION and
   URL2_RA_SESSION arguments. Pass NULL as RA_SESSION argument to
   normalize_merge_sources_internal() -- it will open/release RA session
   internally. All callers are updated.

  (merge_locked): Remove SESSPOOL and release RA session early. Pass NULL
   as RA_SESSION argument to normalize_merge_sources_internal() -- it
   will open/release RA session internally.

  (merge_reintegrate_locked): Release temporary RA sessions early.

  (merge_peg_locked): Remove SESSPOOL and release RA session early.

  (do_automatic_merge_locked): Release RIGHT_RA_SESSION early. Pass NULL
   as RA_SESSION argument to normalize_merge_sources_internal().
]]]


-- 
Ivan Zhakov
CTO | VisualSVN | http://www.visualsvn.com
Index: subversion/libsvn_client/merge.c
===================================================================
--- subversion/libsvn_client/merge.c    (revision 1657782)
+++ subversion/libsvn_client/merge.c    (working copy)
@@ -7023,7 +7023,8 @@
 }
 
 /* Similar to normalize_merge_sources() except the input MERGE_RANGE_TS is a
- * rangelist.
+ * rangelist. RA_SESSION may be NULL, in this case temporary RA session will
+ * be opened using SOURCE_LOC->URL.
  */
 static svn_error_t *
 normalize_merge_sources_internal(apr_array_header_t **merge_sources_p,
@@ -7039,6 +7040,7 @@
   svn_revnum_t trim_revision = SVN_INVALID_REVNUM;
   apr_array_header_t *segments;
   int i;
+  svn_boolean_t new_ra_session = FALSE;
 
   /* Initialize our return variable. */
   *merge_sources_p = apr_array_make(result_pool, 1, sizeof(merge_source_t *));
@@ -7047,6 +7049,14 @@
   if (merge_range_ts->nelts == 0)
     return SVN_NO_ERROR;
 
+  if (!ra_session)
+    {
+      SVN_ERR(svn_client_open_ra_session2(&ra_session, source_loc->url,
+                                          NULL, ctx, scratch_pool,
+                                          scratch_pool));
+      new_ra_session = TRUE;
+    }
+
   /* Find the extremes of the revisions across our set of ranges. */
   merge_range_find_extremes(&oldest_requested, &youngest_requested,
                             merge_range_ts);
@@ -7173,6 +7183,9 @@
       apr_array_cat(*merge_sources_p, merge_sources);
     }
 
+  if (new_ra_session)
+    SVN_ERR(svn_client__ra_session_release(ctx, ra_session));
+
   return SVN_NO_ERROR;
 }
 
@@ -9595,41 +9608,6 @@
   return SVN_NO_ERROR;
 }
 
-/** Ensure that *RA_SESSION is opened to URL, either by reusing
- * *RA_SESSION if it is non-null and already opened to URL's
- * repository, or by allocating a new *RA_SESSION in POOL.
- * (RA_SESSION itself cannot be null, of course.)
- *
- * CTX is used as for svn_client_open_ra_session().
- */
-static svn_error_t *
-ensure_ra_session_url(svn_ra_session_t **ra_session,
-                      const char *url,
-                      const char *wri_abspath,
-                      svn_client_ctx_t *ctx,
-                      apr_pool_t *pool)
-{
-  svn_error_t *err = SVN_NO_ERROR;
-
-  if (*ra_session)
-    {
-      err = svn_ra_reparent(*ra_session, url, pool);
-    }
-
-  /* SVN_ERR_RA_ILLEGAL_URL is raised when url doesn't point to the same
-     repository as ra_session. */
-  if (! *ra_session || (err && err->apr_err == SVN_ERR_RA_ILLEGAL_URL))
-    {
-      svn_error_clear(err);
-      /* RA_CACHE TODO: release RA session */
-      err = svn_client_open_ra_session2(ra_session, url, wri_abspath,
-                                        ctx, pool, pool);
-    }
-  SVN_ERR(err);
-
-  return SVN_NO_ERROR;
-}
-
 /* Drive a merge of MERGE_SOURCES into working copy node TARGET
    and possibly record mergeinfo describing the merge -- see
    RECORD_MERGEINFO().
@@ -9709,7 +9687,6 @@
          svn_boolean_t *use_sleep,
          const apr_array_header_t *merge_sources,
          const merge_target_t *target,
-         svn_ra_session_t *src_session,
          svn_boolean_t sources_related,
          svn_boolean_t same_repos,
          svn_boolean_t ignore_mergeinfo,
@@ -9732,8 +9709,6 @@
   const char *preserved_exts_str;
   int i;
   svn_boolean_t checked_mergeinfo_capability = FALSE;
-  svn_ra_session_t *ra_session1 = NULL;
-  const char *old_src_session_url = NULL;
   apr_pool_t *iterpool;
   const svn_diff_tree_processor_t *processor;
 
@@ -9851,13 +9826,6 @@
     processor = merge_processor;
   }
 
-  if (src_session)
-    {
-      SVN_ERR(svn_ra_get_session_url(src_session, &old_src_session_url,
-                                     scratch_pool));
-      ra_session1 = src_session;
-    }
-
   for (i = 0; i < merge_sources->nelts; i++)
     {
       svn_node_kind_t src1_kind;
@@ -9864,6 +9832,7 @@
       merge_source_t *source =
         APR_ARRAY_IDX(merge_sources, i, merge_source_t *);
       single_range_conflict_report_t *conflicted_range_report;
+      svn_ra_session_t *ra_session1;
       svn_ra_session_t *ra_session2;
 
       svn_pool_clear(iterpool);
@@ -9875,8 +9844,9 @@
         continue;
 
       /* Establish RA sessions to our URLs, reuse where possible. */
-      SVN_ERR(ensure_ra_session_url(&ra_session1, source->loc1->url,
-                                    target->abspath, ctx, scratch_pool));
+      SVN_ERR(svn_client_open_ra_session2(&ra_session1, source->loc1->url,
+                                          target->abspath, ctx,
+                                          iterpool, iterpool));
 
       SVN_ERR(svn_client_open_ra_session2(&ra_session2, source->loc2->url,
                                           target->abspath, ctx, iterpool,
@@ -9957,6 +9927,7 @@
       while (source);
 
       SVN_ERR(svn_client__ra_session_release(ctx, ra_session2));
+      SVN_ERR(svn_client__ra_session_release(ctx, ra_session1));
 
       /* The final mergeinfo on TARGET_WCPATH may itself elide. */
       if (! dry_run)
@@ -10001,9 +9972,6 @@
                            merge_cmd_baton.tree_conflicted_abspaths);
     }
 
-  if (src_session)
-    SVN_ERR(svn_ra_reparent(src_session, old_src_session_url, iterpool));
-
   svn_pool_destroy(iterpool);
   return SVN_NO_ERROR;
 }
@@ -10016,9 +9984,8 @@
    Set *CONFLICT_REPORT to indicate if there were any conflicts, as in
    do_merge().
 
-   The diff to be merged is between SOURCE->loc1 (in URL1_RA_SESSION1)
-   and SOURCE->loc2 (in URL2_RA_SESSION2); YCA is their youngest
-   common ancestor.
+   The diff to be merged is between SOURCE->loc1 and SOURCE->loc2;
+   YCA is their youngest common ancestor.
 
    SAME_REPOS must be true if and only if the source URLs are in the same
    repository as the target working copy.
@@ -10036,8 +10003,6 @@
 merge_cousins_and_supplement_mergeinfo(conflict_report_t **conflict_report,
                                        svn_boolean_t *use_sleep,
                                        const merge_target_t *target,
-                                       svn_ra_session_t *URL1_ra_session,
-                                       svn_ra_session_t *URL2_ra_session,
                                        const merge_source_t *source,
                                        const svn_client__pathrev_t *yca,
                                        svn_boolean_t same_repos,
@@ -10060,9 +10025,6 @@
      subtree mergeinfo, then this will help keep memory use in check. */
   apr_pool_t *subpool = svn_pool_create(scratch_pool);
 
-  assert(session_url_is(URL1_ra_session, source->loc1->url, scratch_pool));
-  assert(session_url_is(URL2_ra_session, source->loc2->url, scratch_pool));
-
   SVN_ERR_ASSERT(svn_dirent_is_absolute(target->abspath));
   SVN_ERR_ASSERT(! source->ancestral);
 
@@ -10070,13 +10032,13 @@
             &remove_sources, source->loc1,
             svn_rangelist__initialize(source->loc1->rev, yca->rev, TRUE,
                                       scratch_pool),
-            URL1_ra_session, ctx, scratch_pool, subpool));
+            NULL, ctx, scratch_pool, subpool));
 
   SVN_ERR(normalize_merge_sources_internal(
             &add_sources, source->loc2,
             svn_rangelist__initialize(yca->rev, source->loc2->rev, TRUE,
                                       scratch_pool),
-            URL2_ra_session, ctx, scratch_pool, subpool));
+            NULL, ctx, scratch_pool, subpool));
 
   *conflict_report = NULL;
 
@@ -10091,7 +10053,7 @@
       APR_ARRAY_PUSH(faux_sources, const merge_source_t *) = source;
       SVN_ERR(do_merge(&modified_subtrees, NULL, conflict_report, use_sleep,
                        faux_sources, target,
-                       URL1_ra_session, TRUE, same_repos,
+                       TRUE, same_repos,
                        FALSE /*ignore_mergeinfo*/, diff_ignore_ancestry,
                        force_delete, dry_run, FALSE, NULL, TRUE,
                        FALSE, depth, merge_options, ctx,
@@ -10131,7 +10093,7 @@
       svn_pool_clear(subpool);
       SVN_ERR(do_merge(NULL, add_result_catalog, conflict_report, use_sleep,
                        add_sources, target,
-                       URL1_ra_session, TRUE, same_repos,
+                       TRUE, same_repos,
                        FALSE /*ignore_mergeinfo*/, diff_ignore_ancestry,
                        force_delete, dry_run, TRUE,
                        modified_subtrees, TRUE,
@@ -10146,7 +10108,7 @@
       svn_pool_clear(subpool);
       SVN_ERR(do_merge(NULL, remove_result_catalog, conflict_report, use_sleep,
                        remove_sources, target,
-                       URL1_ra_session, TRUE, same_repos,
+                       TRUE, same_repos,
                        FALSE /*ignore_mergeinfo*/, diff_ignore_ancestry,
                        force_delete, dry_run, TRUE,
                        modified_subtrees, TRUE,
@@ -10400,7 +10362,6 @@
   svn_error_t *err;
   svn_boolean_t use_sleep = FALSE;
   svn_client__pathrev_t *yca = NULL;
-  apr_pool_t *sesspool;
   svn_boolean_t same_repos;
 
   /* ### FIXME: This function really ought to do a history check on
@@ -10414,13 +10375,12 @@
 
   /* Open RA sessions to both sides of our merge source, and resolve URLs
    * and revisions. */
-  sesspool = svn_pool_create(scratch_pool);
   SVN_ERR(svn_client__ra_session_from_path2(
             &ra_session1, &source1_loc,
-            source1, NULL, revision1, revision1, ctx, sesspool));
+            source1, NULL, revision1, revision1, ctx, scratch_pool));
   SVN_ERR(svn_client__ra_session_from_path2(
             &ra_session2, &source2_loc,
-            source2, NULL, revision2, revision2, ctx, sesspool));
+            source2, NULL, revision2, revision2, ctx, scratch_pool));
 
   /* We can't do a diff between different repositories. */
   /* ### We should also insist that the root URLs of the two sources match,
@@ -10440,6 +10400,10 @@
                     &yca, source1_loc, source2_loc, ra_session1, ctx,
                     scratch_pool, scratch_pool));
 
+  /* Close our temporary RA sessions. */
+  SVN_ERR(svn_client__ra_session_release(ctx, ra_session2));
+  SVN_ERR(svn_client__ra_session_release(ctx, ra_session1));
+
   /* Check for a youngest common ancestor.  If we have one, we'll be
      doing merge tracking.
 
@@ -10471,7 +10435,7 @@
                     &merge_sources, source1_loc,
                     svn_rangelist__initialize(source1_loc->rev, yca->rev, TRUE,
                                               scratch_pool),
-                    ra_session1, ctx, scratch_pool, scratch_pool));
+                    NULL, ctx, scratch_pool, scratch_pool));
         }
       /* If the common ancestor matches the left side of our merge,
          then we only need to merge the right side. */
@@ -10482,7 +10446,7 @@
                     &merge_sources, source2_loc,
                     svn_rangelist__initialize(yca->rev, source2_loc->rev, TRUE,
                                               scratch_pool),
-                    ra_session2, ctx, scratch_pool, scratch_pool));
+                    NULL, ctx, scratch_pool, scratch_pool));
         }
       /* And otherwise, we need to do both: reverse merge the left
          side, and merge the right. */
@@ -10497,8 +10461,6 @@
           err = merge_cousins_and_supplement_mergeinfo(conflict_report,
                                                        &use_sleep,
                                                        target,
-                                                       ra_session1,
-                                                       ra_session2,
                                                        &source,
                                                        yca,
                                                        same_repos,
@@ -10510,10 +10472,6 @@
                                                        ctx,
                                                        result_pool,
                                                        scratch_pool);
-          /* Close our temporary RA sessions (this could've happened
-             after the second call to normalize_merge_sources() inside
-             the merge_cousins_and_supplement_mergeinfo() routine). */
-          svn_pool_destroy(sesspool);
 
           if (use_sleep)
             svn_io_sleep_for_timestamps(target->abspath, scratch_pool);
@@ -10532,19 +10490,11 @@
 
   err = do_merge(NULL, NULL, conflict_report, &use_sleep,
                  merge_sources, target,
-                 ra_session1, sources_related, same_repos,
+                 sources_related, same_repos,
                  ignore_mergeinfo, diff_ignore_ancestry, force_delete, dry_run,
                  record_only, NULL, FALSE, FALSE, depth, merge_options,
                  ctx, result_pool, scratch_pool);
 
-  /* Close our temporary RA sessions. */
-  if (!err)
-    {
-      SVN_ERR(svn_client__ra_session_release(ctx, ra_session2));
-      SVN_ERR(svn_client__ra_session_release(ctx, ra_session1));
-    }
-  svn_pool_destroy(sesspool);
-
   if (use_sleep)
     svn_io_sleep_for_timestamps(target->abspath, scratch_pool);
 
@@ -11677,6 +11627,9 @@
                                  target_ra_session, target,
                                  ctx, scratch_pool, scratch_pool));
 
+  SVN_ERR(svn_client__ra_session_release(ctx, source_ra_session));
+  SVN_ERR(svn_client__ra_session_release(ctx, target_ra_session));
+
   if (! source)
     {
       return SVN_NO_ERROR;
@@ -11692,8 +11645,6 @@
   err = merge_cousins_and_supplement_mergeinfo(conflict_report,
                                                &use_sleep,
                                                target,
-                                               target_ra_session,
-                                               source_ra_session,
                                                source, yc_ancestor,
                                                TRUE /* same_repos */,
                                                svn_depth_infinity,
@@ -11705,12 +11656,6 @@
                                                ctx,
                                                result_pool, scratch_pool);
 
-  if (!err)
-    {
-      SVN_ERR(svn_client__ra_session_release(ctx, source_ra_session));
-      SVN_ERR(svn_client__ra_session_release(ctx, target_ra_session));
-    }
-
   if (use_sleep)
     svn_io_sleep_for_timestamps(target_abspath, scratch_pool);
 
@@ -11779,7 +11724,6 @@
   svn_client__pathrev_t *source_loc;
   apr_array_header_t *merge_sources;
   svn_ra_session_t *ra_session;
-  apr_pool_t *sesspool;
   svn_boolean_t use_sleep = FALSE;
   svn_error_t *err;
   svn_boolean_t same_repos;
@@ -11790,14 +11734,11 @@
                          allow_mixed_rev, TRUE, TRUE,
                          ctx, scratch_pool, scratch_pool));
 
-  /* Create a short lived session pool */
-  sesspool = svn_pool_create(scratch_pool);
-
   /* Open an RA session to our source URL, and determine its root URL. */
   SVN_ERR(svn_client__ra_session_from_path2(
             &ra_session, &source_loc,
             source_path_or_url, NULL, source_peg_revision, source_peg_revision,
-            ctx, sesspool));
+            ctx, scratch_pool));
 
   /* Normalize our merge sources. */
   SVN_ERR(normalize_merge_sources(&merge_sources, source_path_or_url,
@@ -11808,20 +11749,18 @@
   /* Check for same_repos. */
   same_repos = is_same_repos(&target->loc, source_loc, TRUE /* strict_urls */);
 
+  /* We're done with our RA session. */
+  SVN_ERR(svn_client__ra_session_release(ctx, ra_session));
+
   /* Do the real merge!  (We say with confidence that our merge
      sources are both ancestral and related.) */
   err = do_merge(NULL, NULL, conflict_report, &use_sleep,
-                 merge_sources, target, ra_session,
+                 merge_sources, target,
                  TRUE /*sources_related*/, same_repos, ignore_mergeinfo,
                  diff_ignore_ancestry, force_delete, dry_run,
                  record_only, NULL, FALSE, FALSE, depth, merge_options,
                  ctx, result_pool, scratch_pool);
 
-  /* We're done with our RA session. */
-  if (!err)
-    SVN_ERR(svn_client__ra_session_release(ctx, ra_session));
-  svn_pool_destroy(sesspool);
-
   if (use_sleep)
     svn_io_sleep_for_timestamps(target_abspath, scratch_pool);
 
@@ -12650,8 +12589,6 @@
   if (reintegrate_like)
     {
       merge_source_t source;
-      svn_ra_session_t *base_ra_session;
-      svn_ra_session_t *right_ra_session;
 
       if (record_only)
         return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
@@ -12671,17 +12608,18 @@
                                   "and the force_delete option "
                                   "cannot be used with this kind of merge"));
 
-      SVN_ERR(svn_client_open_ra_session2(&right_ra_session, merge->right->url,
-                                          target->abspath, ctx, scratch_pool,
-                                          scratch_pool));
-
       /* Check for and reject any abnormalities -- such as revisions that
        * have not yet been merged in the opposite direction -- that a
        * 'reintegrate' merge would have rejected. */
       {
         merge_source_t *source2;
+        svn_ra_session_t *right_ra_session;
         svn_ra_session_t *target_ra_session;
 
+        SVN_ERR(svn_client_open_ra_session2(&right_ra_session, 
merge->right->url,
+                                            target->abspath, ctx, scratch_pool,
+                                            scratch_pool));
+
         SVN_ERR(svn_client_open_ra_session2(&target_ra_session,
                                             target->loc.url, target->abspath,
                                             ctx, scratch_pool, scratch_pool));
@@ -12692,6 +12630,7 @@
                                        ctx, scratch_pool, scratch_pool));
 
         SVN_ERR(svn_client__ra_session_release(ctx, target_ra_session));
+        SVN_ERR(svn_client__ra_session_release(ctx, right_ra_session));
       }
 
       source.loc1 = merge->base;
@@ -12698,16 +12637,9 @@
       source.loc2 = merge->right;
       source.ancestral = ! merge->is_reintegrate_like;
 
-      SVN_ERR(svn_client_open_ra_session2(&base_ra_session,
-                                          merge->base->url,
-                                          target->abspath, ctx, scratch_pool,
-                                          scratch_pool));
-
       err = merge_cousins_and_supplement_mergeinfo(conflict_report,
                                                    &use_sleep,
                                                    target,
-                                                   base_ra_session,
-                                                   right_ra_session,
                                                    &source, merge->yca,
                                                    TRUE /* same_repos */,
                                                    depth,
@@ -12717,11 +12649,6 @@
                                                    merge_options,
                                                    ctx,
                                                    result_pool, scratch_pool);
-      if (!err)
-        {
-          SVN_ERR(svn_client__ra_session_release(ctx, base_ra_session));
-          SVN_ERR(svn_client__ra_session_release(ctx, right_ra_session));
-        }
     }
   else /* ! merge->is_reintegrate_like */
     {
@@ -12735,28 +12662,22 @@
          find the base for each sutree, and then here use the oldest base
          among all subtrees. */
       apr_array_header_t *merge_sources;
-      svn_ra_session_t *ra_session;
 
       /* Normalize our merge sources, do_merge() requires this.  See the
          'MERGEINFO MERGE SOURCE NORMALIZATION' global comment. */
-      SVN_ERR(svn_client_open_ra_session2(&ra_session, merge->right->url,
-                                          target->abspath, ctx, scratch_pool,
-                                          scratch_pool));
       SVN_ERR(normalize_merge_sources_internal(
         &merge_sources, merge->right,
         svn_rangelist__initialize(merge->yca->rev, merge->right->rev, TRUE,
                                   scratch_pool),
-        ra_session, ctx, scratch_pool, scratch_pool));
+        NULL, ctx, scratch_pool, scratch_pool));
 
       err = do_merge(NULL, NULL, conflict_report, &use_sleep,
-                     merge_sources, target, ra_session,
+                     merge_sources, target,
                      TRUE /*related*/, TRUE /*same_repos*/,
                      FALSE /*ignore_mergeinfo*/, diff_ignore_ancestry,
                      force_delete, dry_run,
                      record_only, NULL, FALSE, FALSE, depth, merge_options,
                      ctx, result_pool, scratch_pool);
-      if (!err)
-        SVN_ERR(svn_client__ra_session_release(ctx, ra_session));
     }
 
   if (use_sleep)

Reply via email to