You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by pb...@apache.org on 2012/12/10 23:48:28 UTC

svn commit: r1419856 - /subversion/trunk/subversion/libsvn_client/merge.c

Author: pburba
Date: Mon Dec 10 22:48:27 2012
New Revision: 1419856

URL: http://svn.apache.org/viewvc?rev=1419856&view=rev
Log:
Partial fix for issue #4269 'subtree mergeinfo can degrade automatic merge
performance'.

This can buy substantial merge performance improvements in some limited
circumstances, see
http://subversion.tigris.org/issues/show_bug.cgi?id=4269#desc5

* subversion/libsvn_client/merge.c

  (remove_noop_subtree_ranges): If possible, limit the requested log to a
   subtree of the merge source, potentially giving a quicker turnaround.

Modified:
    subversion/trunk/subversion/libsvn_client/merge.c

Modified: subversion/trunk/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/merge.c?rev=1419856&r1=1419855&r2=1419856&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/merge.c (original)
+++ subversion/trunk/subversion/libsvn_client/merge.c Mon Dec 10 22:48:27 2012
@@ -8511,6 +8511,8 @@ remove_noop_subtree_ranges(const merge_s
   svn_merge_range_t *youngest_gap_rev;
   svn_rangelist_t *inoperative_ranges;
   apr_pool_t *iterpool;
+  const char *longest_common_subtree_ancestor = NULL;
+  svn_error_t *err;
 
   assert(session_url_is(ra_session, source->loc2->url, scratch_pool));
 
@@ -8549,6 +8551,19 @@ remove_noop_subtree_ranges(const merge_s
 
       svn_pool_clear(iterpool);
 
+      /* Issue #4269: Keep track of the longest common ancestor of all the
+         subtrees which require merges.  This may be a child of
+         TARGET->ABSPATH, which will allow us to narrow the log request
+         below. */
+      if (child->remaining_ranges && child->remaining_ranges->nelts)
+        {
+          if (longest_common_subtree_ancestor)
+            longest_common_subtree_ancestor = svn_dirent_get_longest_ancestor(
+              longest_common_subtree_ancestor, child->abspath, scratch_pool);
+          else
+            longest_common_subtree_ancestor = child->abspath;
+        }
+
       /* CHILD->REMAINING_RANGES will be NULL if child is absent. */
       if (child->remaining_ranges && child->remaining_ranges->nelts)
         SVN_ERR(svn_rangelist_merge2(subtree_remaining_ranges,
@@ -8589,24 +8604,53 @@ remove_noop_subtree_ranges(const merge_s
                                                   sizeof(svn_revnum_t *));
   log_gap_baton.pool = svn_pool_create(scratch_pool);
 
+  /* Find the longest common ancestor of all subtrees relative to
+     RA_SESSION's URL. */
+  if (longest_common_subtree_ancestor)
+    longest_common_subtree_ancestor =
+      svn_dirent_skip_ancestor(target->abspath,
+                               longest_common_subtree_ancestor);
+  else
+    longest_common_subtree_ancestor = "";
+
   /* Invoke the svn_log_entry_receiver_t receiver log_noop_revs() from
      oldest to youngest.  The receiver is optimized to add ranges to
      log_gap_baton.merged_ranges and log_gap_baton.operative_ranges, but
      requires that the revs arrive oldest to youngest -- see log_noop_revs()
      and rangelist_merge_revision(). */
-  SVN_ERR(get_log(ra_session, "", oldest_gap_rev->start + 1,
-                  youngest_gap_rev->end, TRUE,
-                  log_noop_revs, &log_gap_baton, scratch_pool));
-
-  inoperative_ranges = svn_rangelist__initialize(oldest_gap_rev->start,
-                                                 youngest_gap_rev->end,
-                                                 TRUE, scratch_pool);
-  SVN_ERR(svn_rangelist_remove(&(inoperative_ranges),
-                               log_gap_baton.operative_ranges,
-                               inoperative_ranges, FALSE, scratch_pool));
+  err = get_log(ra_session, longest_common_subtree_ancestor,
+                oldest_gap_rev->start + 1, youngest_gap_rev->end, TRUE,
+                log_noop_revs, &log_gap_baton, scratch_pool);
+
+  /* It's possible that the only subtrees with mergeinfo in TARGET don't have
+     any corresponding subtree in SOURCE between SOURCE->REV1 < SOURCE->REV2.
+     So it's also possible that we may ask for the logs of non-existent paths.
+     If we do, then assume that no subtree requires any ranges that are not
+     already required by the TARGET. */
+  if (err)
+    {
+      if (err->apr_err != SVN_ERR_FS_NOT_FOUND
+          && longest_common_subtree_ancestor[0] != '\0')
+        return svn_error_trace(err);
 
-  SVN_ERR(svn_rangelist_merge2(log_gap_baton.merged_ranges, inoperative_ranges,
-                               scratch_pool, scratch_pool));
+      /* Asked about a non-existent subtree in SOURCE. */
+      svn_error_clear(err);
+      log_gap_baton.merged_ranges =
+        svn_rangelist__initialize(oldest_gap_rev->start,
+                                  youngest_gap_rev->end,
+                                  TRUE, scratch_pool);
+    }
+  else
+    {
+      inoperative_ranges = svn_rangelist__initialize(oldest_gap_rev->start,
+                                                     youngest_gap_rev->end,
+                                                     TRUE, scratch_pool);
+      SVN_ERR(svn_rangelist_remove(&(inoperative_ranges),
+                                   log_gap_baton.operative_ranges,
+                                   inoperative_ranges, FALSE, scratch_pool));
+      SVN_ERR(svn_rangelist_merge2(log_gap_baton.merged_ranges, inoperative_ranges,
+                                   scratch_pool, scratch_pool));
+    }
 
   for (i = 1; i < children_with_mergeinfo->nelts; i++)
     {