comparison mercurial/dagop.py @ 44659:67f757ed86e0

dagop: fix subsetparentswalker to set p1/p2 chains at merge revision The previous implementation was wrong because the '1'/'2' key would be appended at a fork revision. Since we traverse the graph from heads, a merge revision is actually a branching point, where the sort key must be generated.
author Yuya Nishihara <yuya@tcha.org>
date Thu, 26 Mar 2020 22:31:17 +0900
parents 25436f83fb95
children 4ebc5f325bed
comparison
equal deleted inserted replaced
44658:25436f83fb95 44659:67f757ed86e0
389 # When a revision is visited, 'pointers[rev]' should be popped and 389 # When a revision is visited, 'pointers[rev]' should be popped and
390 # propagated to its parents accordingly. 390 # propagated to its parents accordingly.
391 # 391 #
392 # Once all pending paths have been resolved, 'pendingcnt[rev]' becomes 392 # Once all pending paths have been resolved, 'pendingcnt[rev]' becomes
393 # 0 and 'parents[rev]' contains the unsorted list of parent revisions 393 # 0 and 'parents[rev]' contains the unsorted list of parent revisions
394 # and p1/p2 chains (excluding linear paths.) 394 # and p1/p2 chains (excluding linear paths.) The p1/p2 chains will be
395 # used as a sort key preferring p1. 'len(chain)' should be the number
396 # of merges between two revisions.
395 397
396 subset = self._subset 398 subset = self._subset
397 tovisit = self._tovisit # heap queue of [-rev] 399 tovisit = self._tovisit # heap queue of [-rev]
398 pendingcnt = self._pendingcnt # {rev: count} for visited revisions 400 pendingcnt = self._pendingcnt # {rev: count} for visited revisions
399 pointers = self._pointers # {rev: [{unresolved_rev: chain}, resolved]} 401 pointers = self._pointers # {rev: [{unresolved_rev: chain}, resolved]}
456 parentpointers = [ 458 parentpointers = [
457 (unresolved, resolved), 459 (unresolved, resolved),
458 (unresolved.copy(), resolved.copy()), 460 (unresolved.copy(), resolved.copy()),
459 ] 461 ]
460 # 'rev' is a merge revision. increment the pending count 462 # 'rev' is a merge revision. increment the pending count
461 # as the 'unresolved' dict will be duplicated. 463 # as the 'unresolved' dict will be duplicated, and append
464 # p1/p2 code to the existing chains.
462 for r in unresolved: 465 for r in unresolved:
463 pendingcnt[r] += 1 466 pendingcnt[r] += 1
467 parentpointers[0][0][r] += b'1'
468 parentpointers[1][0][r] += b'2'
464 for i, p in enumerate(parentrevs): 469 for i, p in enumerate(parentrevs):
465 assert p < rev 470 assert p < rev
466 heapq.heappush(tovisit, -p) 471 heapq.heappush(tovisit, -p)
467 if p in pointers: 472 if p in pointers:
468 # 'p' is a fork revision. concatenate tracking pointers 473 # 'p' is a fork revision. concatenate tracking pointers
469 # and decrement the pending count accordingly. 474 # and decrement the pending count accordingly.
470 knownunresolved, knownresolved = pointers[p] 475 knownunresolved, knownresolved = pointers[p]
471 unresolved, resolved = parentpointers[i] 476 unresolved, resolved = parentpointers[i]
472 for r, c in unresolved.items(): 477 for r, c in unresolved.items():
473 c += [b'1', b'2'][i]
474 if r in knownunresolved: 478 if r in knownunresolved:
475 # unresolved at both paths 479 # unresolved at both paths
476 pendingcnt[r] -= 1 480 pendingcnt[r] -= 1
477 assert pendingcnt[r] > 0 481 assert pendingcnt[r] > 0
478 # take shorter chain 482 # take shorter chain
486 pointers[p] = parentpointers[i] 490 pointers[p] = parentpointers[i]
487 491
488 # then, populate the active parents directly and add the current 492 # then, populate the active parents directly and add the current
489 # 'rev' to the tracking pointers of the inactive parents. 493 # 'rev' to the tracking pointers of the inactive parents.
490 # 'pointers[p]' may be optimized out if both parents are active. 494 # 'pointers[p]' may be optimized out if both parents are active.
495 chaincodes = [b''] if len(parentrevs) <= 1 else [b'1', b'2']
491 if curactive and bothparentsactive: 496 if curactive and bothparentsactive:
492 for i, p in enumerate(parentrevs): 497 for i, p in enumerate(parentrevs):
493 c = [b'1', b'2'][i] 498 c = chaincodes[i]
494 parents[rev].append((c, p)) 499 parents[rev].append((c, p))
495 # no need to mark 'rev' as resolved since the 'rev' should 500 # no need to mark 'rev' as resolved since the 'rev' should
496 # be fully resolved (i.e. pendingcnt[rev] == 0) 501 # be fully resolved (i.e. pendingcnt[rev] == 0)
497 assert pendingcnt[rev] == 0 502 assert pendingcnt[rev] == 0
498 elif curactive: 503 elif curactive:
499 for i, p in enumerate(parentrevs): 504 for i, p in enumerate(parentrevs):
500 unresolved, resolved = pointers[p] 505 unresolved, resolved = pointers[p]
501 assert rev not in unresolved 506 assert rev not in unresolved
502 c = [b'1', b'2'][i] 507 c = chaincodes[i]
503 if p in subset: 508 if p in subset:
504 parents[rev].append((c, p)) 509 parents[rev].append((c, p))
505 # mark 'rev' as resolved through this path 510 # mark 'rev' as resolved through this path
506 resolved.add(rev) 511 resolved.add(rev)
507 else: 512 else: