Rev 4448: Change how the steps in annotate work. in http://bazaar.launchpad.net/~jameinel/bzr/1.17-annotate-bug387952

John Arbash Meinel john at arbash-meinel.com
Tue Jun 16 20:18:50 BST 2009


At http://bazaar.launchpad.net/~jameinel/bzr/1.17-annotate-bug387952

------------------------------------------------------------
revno: 4448
revision-id: john at arbash-meinel.com-20090616191846-0pmawq2s1pic88hi
parent: pqm at pqm.ubuntu.com-20090616132232-4s8a3v00nfzh3i8w
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: 1.17-annotate-bug387952
timestamp: Tue 2009-06-16 14:18:46 -0500
message:
  Change how the steps in annotate work.
  
  Instead of first matching on the annotated lines, we now first match on the
  unannotated lines. And then for each line in the result, we check to see
  if the annotations match or needs to be resolved.
  Performance will likely suffer, because we are doing lots of comparisons,
  and calling .append for every common line. But we'll address that next.
-------------- next part --------------
=== modified file 'bzrlib/annotate.py'
--- a/bzrlib/annotate.py	2009-04-08 13:13:30 +0000
+++ b/bzrlib/annotate.py	2009-06-16 19:18:46 +0000
@@ -398,6 +398,44 @@
         last_child_idx = child_idx + match_len
 
 
+def _resolve_matching_region(output_lines, annotated_match_subset,
+                             right_parent_subset, heads_provider,
+                             new_revision_id):
+    # Shortcut the case when the two sides match exactly
+    # if annotated_match_subset == right_parent_subset:
+    #     output_lines.extend(annotated_match_subset)
+    #     return
+    append = output_lines.append
+    assert len(annotated_match_subset) == len(right_parent_subset)
+    for idx in xrange(len(annotated_match_subset)):
+        new_line = annotated_match_subset[idx]
+        right_line = right_parent_subset[idx]
+        assert new_line[1] == right_line[1]
+        if new_line[0] == right_line[0]:
+            # These have identical annotations, just go with it
+            append(new_line)
+        elif new_line[0] == new_revision_id:
+            # the new annotation claims 'this' modified it, but it just simply
+            # comes from the right parent
+            append(right_line)
+        else:
+            # Both new and right parent lay claim to this line, resolve
+            if heads_provider is None:
+                append((new_revision_id, right_line[1]))
+            else:
+                heads = heads_provider.heads((new_line[0], right_line[0]))
+                if len(heads) == 1:
+                    for head in heads:
+                        break
+                    append((head, new_line[1]))
+                else:
+                    # Both claim different origins, get a stable result.
+                    # If the result is not stable, there is a risk a
+                    # performance degradation as criss-cross merges will
+                    # flip-flop the attribution.
+                    append(_break_annotation_tie([new_line, right_line]))
+
+
 def _reannotate_annotated(right_parent_lines, new_lines, new_revision_id,
                           annotated_lines, heads_provider):
     """Update the annotations for a node based on another parent.
@@ -414,33 +452,30 @@
     """
     if len(new_lines) != len(annotated_lines):
         raise AssertionError("mismatched new_lines and annotated_lines")
-    # First compare the newly annotated lines with the right annotated lines.
-    # Lines which were not changed in left or right should match. This tends to
-    # be the bulk of the lines, and they will need no further processing.
+    # Compare the unannotated right_parent_lines with new_lines
+    plain_parent_lines = [l for r, l in right_parent_lines]
+    matching_parent_and_new = _get_matching_blocks(plain_parent_lines,
+                                                   new_lines)
     lines = []
     lines_extend = lines.extend
-    last_right_idx = 0 # The line just after the last match from the right side
-    last_left_idx = 0
-    matching_left_and_right = _get_matching_blocks(right_parent_lines,
-                                                   annotated_lines)
-    for right_idx, left_idx, match_len in matching_left_and_right:
-        # annotated lines from last_left_idx to left_idx did not match the
-        # lines from last_right_idx to right_idx, the raw lines should be
-        # compared to determine what annotations need to be updated
-        if last_right_idx == right_idx or last_left_idx == left_idx:
-            # One of the sides is empty, so this is a pure insertion
-            lines_extend(annotated_lines[last_left_idx:left_idx])
-        else:
-            # We need to see if any of the unannotated lines match
-            _find_matching_unannotated_lines(lines,
-                                             new_lines, annotated_lines,
-                                             last_left_idx, left_idx,
-                                             right_parent_lines,
-                                             last_right_idx, right_idx,
-                                             heads_provider,
-                                             new_revision_id)
-        last_right_idx = right_idx + match_len
-        last_left_idx = left_idx + match_len
-        # If left and right agree on a range, just push that into the output
-        lines_extend(annotated_lines[left_idx:left_idx + match_len])
+    last_new_idx = 0
+    for parent_idx, new_idx, match_len in matching_parent_and_new:
+        # The lines from last_new_idx to new_idx did not match anything in
+        # plain_parent_lines
+        # For these lines, we just carry across the annotations from parent
+        lines_extend(annotated_lines[last_new_idx:new_idx])
+        # for the lines which *did* match, we need to determine if we have
+        # conflicts between what the right_parent_lines would claim as the
+        # annotation, and what the current annotated_lines claims is the
+        # annotation
+        # Note that 'new_revision_id' is always superseded by annotated_lines
+        annotated_match_subset = annotated_lines[new_idx:new_idx + match_len]
+        right_parent_subset = right_parent_lines[parent_idx:parent_idx +
+                                                 match_len]
+        _resolve_matching_region(lines, annotated_match_subset,
+                                 right_parent_subset, heads_provider,
+                                 new_revision_id)
+
+        last_parent_idx = parent_idx + match_len
+        last_new_idx = new_idx + match_len
     return lines



More information about the bazaar-commits mailing list