A new ancestor algorithm

The old ancestor algorithm could get fooled into returning ancestors
closer to root than it ought to. Hopefully this one, which strictly
orders its search by distance from room, will be foolproof.
This commit is contained in:
mpm@selenic.com 2005-05-24 23:11:44 -08:00
parent cbe151d218
commit dba1a9fc73

View File

@ -8,7 +8,7 @@
# This software may be used and distributed according to the terms # This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference. # of the GNU General Public License, incorporated herein by reference.
import zlib, struct, sha, os, tempfile, binascii import zlib, struct, sha, os, tempfile, binascii, heapq
from mercurial import mdiff from mercurial import mdiff
def hex(node): return binascii.hexlify(node) def hex(node): return binascii.hexlify(node)
@ -276,38 +276,42 @@ class revlog:
return node return node
def ancestor(self, a, b): def ancestor(self, a, b):
def expand(list, map): # calculate the distance of every node from root
a = [] dist = {nullid: 0}
while list: for i in xrange(self.count()):
n = list.pop(0) n = self.node(i)
map[n] = 1 p1, p2 = self.parents(n)
yield n dist[n] = max(dist[p1], dist[p2]) + 1
for p in self.parents(n):
if p != nullid and p not in map: # traverse ancestors in order of decreasing distance from root
list.append(p) def ancestors(node):
yield nullid # we store negative distances because heap returns smallest member
h = [(-dist[node], node)]
seen = {}
earliest = self.count()
while h:
d, n = heapq.heappop(h)
r = self.rev(n)
if n not in seen:
seen[n] = 1
yield (-d, n)
for p in self.parents(n):
heapq.heappush(h, (-dist[p], p))
amap = {} x = ancestors(a)
bmap = {} y = ancestors(b)
ag = expand([a], amap) lx = x.next()
bg = expand([b], bmap) ly = y.next()
adone = bdone = 0
while not adone or not bdone: # increment each ancestor list until it is closer to root than
if not adone: # the other, or they match
an = ag.next() while 1:
if an == nullid: if lx == ly:
adone = 1 return lx[1]
elif an in bmap: elif lx < ly:
return an ly = y.next()
if not bdone: elif lx > ly:
bn = bg.next() lx = x.next()
if bn == nullid:
bdone = 1
elif bn in amap:
return bn
return nullid
def group(self, linkmap): def group(self, linkmap):
# given a list of changeset revs, return a set of deltas and # given a list of changeset revs, return a set of deltas and