Mercurial > public > mercurial-scm > hg
comparison mercurial/localrepo.py @ 16745:27b2e1823e83
branchcache: backout 0311a6abd38a
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Thu, 17 May 2012 15:34:59 -0500 |
parents | e825a89de5d7 |
children | b3435385f99f |
comparison
equal
deleted
inserted
replaced
16744:1c9f58a6c8f1 | 16745:27b2e1823e83 |
---|---|
548 for l in lines: | 548 for l in lines: |
549 if not l: | 549 if not l: |
550 continue | 550 continue |
551 node, label = l.split(" ", 1) | 551 node, label = l.split(" ", 1) |
552 label = encoding.tolocal(label.strip()) | 552 label = encoding.tolocal(label.strip()) |
553 if not node in self: | |
554 raise ValueError('invalidating branch cache because node '+ | |
555 '%s does not exist' % node) | |
556 partial.setdefault(label, []).append(bin(node)) | 553 partial.setdefault(label, []).append(bin(node)) |
557 except KeyboardInterrupt: | 554 except KeyboardInterrupt: |
558 raise | 555 raise |
559 except Exception, inst: | 556 except Exception, inst: |
560 if self.ui.debugflag: | 557 if self.ui.debugflag: |
572 f.close() | 569 f.close() |
573 except (IOError, OSError): | 570 except (IOError, OSError): |
574 pass | 571 pass |
575 | 572 |
576 def _updatebranchcache(self, partial, ctxgen): | 573 def _updatebranchcache(self, partial, ctxgen): |
577 """Given a branchhead cache, partial, that may have extra nodes or be | |
578 missing heads, and a generator of nodes that are at least a superset of | |
579 heads missing, this function updates partial to be correct. | |
580 """ | |
581 # collect new branch entries | 574 # collect new branch entries |
582 newbranches = {} | 575 newbranches = {} |
583 for c in ctxgen: | 576 for c in ctxgen: |
584 newbranches.setdefault(c.branch(), []).append(c.node()) | 577 newbranches.setdefault(c.branch(), []).append(c.node()) |
585 # if older branchheads are reachable from new ones, they aren't | 578 # if older branchheads are reachable from new ones, they aren't |
586 # really branchheads. Note checking parents is insufficient: | 579 # really branchheads. Note checking parents is insufficient: |
587 # 1 (branch a) -> 2 (branch b) -> 3 (branch a) | 580 # 1 (branch a) -> 2 (branch b) -> 3 (branch a) |
588 for branch, newnodes in newbranches.iteritems(): | 581 for branch, newnodes in newbranches.iteritems(): |
589 bheads = partial.setdefault(branch, []) | 582 bheads = partial.setdefault(branch, []) |
590 bheads.extend(newnodes) | 583 bheads.extend(newnodes) |
591 # Remove duplicates - nodes that are in newnodes and are already in | 584 if len(bheads) <= 1: |
592 # bheads. This can happen if you strip a node and its parent was | 585 continue |
593 # already a head (because they're on different branches). | 586 bheads = sorted(bheads, key=lambda x: self[x].rev()) |
594 bheads = set(bheads) | 587 # starting from tip means fewer passes over reachable |
595 | 588 while newnodes: |
596 # Remove candidate heads that no longer are in the repo (e.g., as | 589 latest = newnodes.pop() |
597 # the result of a strip that just happened). | 590 if latest not in bheads: |
598 # avoid using 'bhead in self' here because that dives down into | 591 continue |
599 # branchcache code somewhat recrusively. | 592 minbhnode = self[bheads[0]].node() |
600 bheads = [bhead for bhead in bheads \ | 593 reachable = self.changelog.reachable(latest, minbhnode) |
601 if self.changelog.hasnode(bhead)] | 594 reachable.remove(latest) |
602 if len(bheads) > 1: | 595 if reachable: |
603 bheads = sorted(bheads, key=lambda x: self[x].rev()) | 596 bheads = [b for b in bheads if b not in reachable] |
604 # starting from tip means fewer passes over reachable | |
605 while newnodes: | |
606 latest = newnodes.pop() | |
607 if latest not in bheads: | |
608 continue | |
609 minbhnode = self[bheads[0]].node() | |
610 reachable = self.changelog.reachable(latest, minbhnode) | |
611 reachable.remove(latest) | |
612 if reachable: | |
613 bheads = [b for b in bheads if b not in reachable] | |
614 partial[branch] = bheads | 597 partial[branch] = bheads |
615 | |
616 # There may be branches that cease to exist when the last commit in the | |
617 # branch was stripped. This code filters them out. Note that the | |
618 # branch that ceased to exist may not be in newbranches because | |
619 # newbranches is the set of candidate heads, which when you strip the | |
620 # last commit in a branch will be the parent branch. | |
621 for branch in partial.keys(): | |
622 nodes = [head for head in partial[branch] \ | |
623 if self.changelog.hasnode(head)] | |
624 if len(nodes) < 1: | |
625 del partial[branch] | |
626 | 598 |
627 def lookup(self, key): | 599 def lookup(self, key): |
628 return self[key].node() | 600 return self[key].node() |
629 | 601 |
630 def lookupbranch(self, key, remote=None): | 602 def lookupbranch(self, key, remote=None): |
884 ui.status(_('working directory now based on ' | 856 ui.status(_('working directory now based on ' |
885 'revisions %d and %d\n') % parents) | 857 'revisions %d and %d\n') % parents) |
886 else: | 858 else: |
887 ui.status(_('working directory now based on ' | 859 ui.status(_('working directory now based on ' |
888 'revision %d\n') % parents) | 860 'revision %d\n') % parents) |
889 # TODO: if we know which new heads may result from this rollback, pass | |
890 # them to destroy(), which will prevent the branchhead cache from being | |
891 # invalidated. | |
892 self.destroyed() | 861 self.destroyed() |
893 return 0 | 862 return 0 |
894 | 863 |
895 def invalidatecaches(self): | 864 def invalidatecaches(self): |
896 def delcache(name): | 865 def delcache(name): |
1330 finally: | 1299 finally: |
1331 if tr: | 1300 if tr: |
1332 tr.release() | 1301 tr.release() |
1333 lock.release() | 1302 lock.release() |
1334 | 1303 |
1335 def destroyed(self, newheadrevs=None): | 1304 def destroyed(self): |
1336 '''Inform the repository that nodes have been destroyed. | 1305 '''Inform the repository that nodes have been destroyed. |
1337 Intended for use by strip and rollback, so there's a common | 1306 Intended for use by strip and rollback, so there's a common |
1338 place for anything that has to be done after destroying history. | 1307 place for anything that has to be done after destroying history.''' |
1339 | 1308 # XXX it might be nice if we could take the list of destroyed |
1340 If you know the branchheadcache was uptodate before nodes were removed | 1309 # nodes, but I don't see an easy way for rollback() to do that |
1341 and you also know the set of candidate set of new heads that may have | |
1342 resulted from the destruction, you can set newheadrevs. This will | |
1343 enable the code to update the branchheads cache, rather than having | |
1344 future code decide it's invalid and regenrating it. | |
1345 ''' | |
1346 if newheadrevs: | |
1347 tiprev = len(self) - 1 | |
1348 ctxgen = (self[rev] for rev in newheadrevs) | |
1349 self._updatebranchcache(self._branchcache, ctxgen) | |
1350 self._writebranchcache(self._branchcache, self.changelog.tip(), | |
1351 tiprev) | |
1352 else: | |
1353 # No info to update the cache. If nodes were destroyed, the cache | |
1354 # is stale and this will be caught the next time it is read. | |
1355 pass | |
1356 | 1310 |
1357 # Ensure the persistent tag cache is updated. Doing it now | 1311 # Ensure the persistent tag cache is updated. Doing it now |
1358 # means that the tag cache only has to worry about destroyed | 1312 # means that the tag cache only has to worry about destroyed |
1359 # heads immediately after a strip/rollback. That in turn | 1313 # heads immediately after a strip/rollback. That in turn |
1360 # guarantees that "cachetip == currenttip" (comparing both rev | 1314 # guarantees that "cachetip == currenttip" (comparing both rev |