[PATCH 2 of 2 STABLE] annotate: increase refcount of each revisions correctly (issue3841)

FUJIWARA Katsunori foozy at lares.dti.ne.jp
Thu Mar 28 05:36:58 CDT 2013


# HG changeset patch
# User FUJIWARA Katsunori <foozy at lares.dti.ne.jp>
# Date 1364464124 -32400
# Branch stable
# Node ID 294831b57a899d60d1165078f8adffadd0944850
# Parent  53691948fe037f64fe97d4eb7fad76ebda4edf6a
annotate: increase refcount of each revisions correctly (issue3841)

Before this patch, refcount (managed in "needed") of parents of each
revisions in "visit" is increased, only when parent is not annotated
yet (examined by "p not in hist").

But this causes less refcount of the revision like "A" in the tree
below ("A" is assumed as the second parent of "C"):

    A --- B --- C
      \       /
       \-----/

Steps of annotation for "C" in this case are shown below:

  1. for "C"
    1.1 increase refcount of "B"
    1.2 increase refcount of "A" (=> 1)
    1.3 defer annotation for "C"

  2. for "A"
    2.1 annotate for "A" (=> put result into "hist[A]")
    2.2 clear "pcache[A]" ("pcache[A] = []")

  3. for "B"
    3.1 not increase refcount of "A", because "A not in hist" is False
    3.2 annotate for "B"
    3.3 decrease refcount of "A" (=> 0)
    3.4 delete "hist[A]", even though "A" is still needed by "C"
    3.5 clear "pcache[B]"

  4. for "C", again
    4.1 not increase refcount of "B", because "B not in hist" is False
    4.2 increase refcount of "A" (=> 1)
    4.3 defer annotation for "C"

  5. for "A", again
    5.1 annotate for "A" (=> put result into "hist[A]", again)
    5.2 clear "pcache[A]"

  6. for "C", once again
    6.1 not increase refcount of "B", because "B not in hist" is False
    6.2 not increase refcount of "A", because "A not in hist" is False
    6.3 annotate for "C"
    6.4 decrease refcount of "A", and delete "hist[A]"
    6.5 decrease refcount of "B", and delete "hist[B]"
    6.6 clear "pcache[C]"

At step (5.1), annotation for "A" mis-recognizes that all lines are
created at "A", because "pcache[A]" already cleared at step (2.2)
prevents from scanning ancestors of "A".

So, annotation for "C" or its descendants loses information about "A"
or its ancestors.

The root cause of this problem is that refcount of "A" is decreased at
step (3.3), even though it isn't increased at step (3.1).

To increase refcount correctly, this patch increases refcount of each
parents of each revisions:

  - regardless of "p not in hist" or not, and
  - only once for each revisions in "visit" (by "not pcached")

In fact, this problem should occur only on legacy repositories which
include the merging between the revision and its ancestor, because:

  - tree is scanned in depth-first

    without such merging, revisions in "visit" refer different
    revisions as parent each other

  - recent Mercurial doesn't allow such merging

diff -r 53691948fe03 -r 294831b57a89 mercurial/context.py
--- a/mercurial/context.py	Thu Mar 28 18:48:44 2013 +0900
+++ b/mercurial/context.py	Thu Mar 28 18:48:44 2013 +0900
@@ -698,7 +698,8 @@
         needed = {base: 1}
         while visit:
             f = visit[-1]
-            if f not in pcache:
+            pcached = f in pcache
+            if not pcached:
                 pcache[f] = parents(f)
 
             ready = True
@@ -707,6 +708,7 @@
                 if p not in hist:
                     ready = False
                     visit.append(p)
+                if not pcached:
                     needed[p] = needed.get(p, 0) + 1
             if ready:
                 visit.pop()


More information about the Mercurial-devel mailing list