comparison mercurial/revlog.py @ 147:b6d8ed7aeba0

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.
author mpm@selenic.com
date Tue, 24 May 2005 23:11:44 -0800
parents f6d1f8a84372
children 083c38bdfa64 083c38bdfa64
comparison
equal deleted inserted replaced
146:4a828422247d 147:b6d8ed7aeba0
6 # Copyright 2005 Matt Mackall <mpm@selenic.com> 6 # Copyright 2005 Matt Mackall <mpm@selenic.com>
7 # 7 #
8 # This software may be used and distributed according to the terms 8 # This software may be used and distributed according to the terms
9 # of the GNU General Public License, incorporated herein by reference. 9 # of the GNU General Public License, incorporated herein by reference.
10 10
11 import zlib, struct, sha, os, tempfile, binascii 11 import zlib, struct, sha, os, tempfile, binascii, heapq
12 from mercurial import mdiff 12 from mercurial import mdiff
13 13
14 def hex(node): return binascii.hexlify(node) 14 def hex(node): return binascii.hexlify(node)
15 def bin(node): return binascii.unhexlify(node) 15 def bin(node): return binascii.unhexlify(node)
16 def short(node): return hex(node[:4]) 16 def short(node): return hex(node[:4])
274 274
275 self.cache = (node, n, text) 275 self.cache = (node, n, text)
276 return node 276 return node
277 277
278 def ancestor(self, a, b): 278 def ancestor(self, a, b):
279 def expand(list, map): 279 # calculate the distance of every node from root
280 a = [] 280 dist = {nullid: 0}
281 while list: 281 for i in xrange(self.count()):
282 n = list.pop(0) 282 n = self.node(i)
283 map[n] = 1 283 p1, p2 = self.parents(n)
284 yield n 284 dist[n] = max(dist[p1], dist[p2]) + 1
285 for p in self.parents(n): 285
286 if p != nullid and p not in map: 286 # traverse ancestors in order of decreasing distance from root
287 list.append(p) 287 def ancestors(node):
288 yield nullid 288 # we store negative distances because heap returns smallest member
289 289 h = [(-dist[node], node)]
290 amap = {} 290 seen = {}
291 bmap = {} 291 earliest = self.count()
292 ag = expand([a], amap) 292 while h:
293 bg = expand([b], bmap) 293 d, n = heapq.heappop(h)
294 adone = bdone = 0 294 r = self.rev(n)
295 295 if n not in seen:
296 while not adone or not bdone: 296 seen[n] = 1
297 if not adone: 297 yield (-d, n)
298 an = ag.next() 298 for p in self.parents(n):
299 if an == nullid: 299 heapq.heappush(h, (-dist[p], p))
300 adone = 1 300
301 elif an in bmap: 301 x = ancestors(a)
302 return an 302 y = ancestors(b)
303 if not bdone: 303 lx = x.next()
304 bn = bg.next() 304 ly = y.next()
305 if bn == nullid: 305
306 bdone = 1 306 # increment each ancestor list until it is closer to root than
307 elif bn in amap: 307 # the other, or they match
308 return bn 308 while 1:
309 309 if lx == ly:
310 return nullid 310 return lx[1]
311 elif lx < ly:
312 ly = y.next()
313 elif lx > ly:
314 lx = x.next()
311 315
312 def group(self, linkmap): 316 def group(self, linkmap):
313 # given a list of changeset revs, return a set of deltas and 317 # given a list of changeset revs, return a set of deltas and
314 # metadata corresponding to nodes. the first delta is 318 # metadata corresponding to nodes. the first delta is
315 # parent(nodes[0]) -> nodes[0] the receiver is guaranteed to 319 # parent(nodes[0]) -> nodes[0] the receiver is guaranteed to