Mercurial > hg
comparison mercurial/tags.py @ 42237:9f45d3d526f9
hgtagsfnodescache: inherit fnode from parent when possible
If a changeset does not update the content of `.hgtags`, it means it will use
the same file-node (for `.hgtags`) as its parents. In this case we can
directly reuse the parent's file-node.
We use this property when updating the `hgtagsfnodescache` taking a faster path
if we already have a cached value for the parents of the node we are looking
at.
Doing so provides a large performance boost when looking at a lot of fnodes,
especially on repository with very large manifest:
timing for `tagsmod.fnoderevs(ui, repo, repo.changelog.revs())`
mercurial: (41907 revisions, 1923 files)
before: 6.9 seconds
after: 2.7 seconds (-54%)
pypy: (96266 revisions, 5198 files)
before: 80 seconds
after: 20 seconds (-75%)
mozilla-central: (463411 revisions, 272080 files)
before: 7166.4 seconds
after: 47.8 seconds (-99%, x150 speedup)
On a copy of mozilla-try with about 35K heads ans 1.7M changesets, this moves
the computation from many hours to a couple of minutes, making it more
interesting to do a full warm up of this cache before computing tags (from a
cold cache).
There seems to be other performance low hanging fruits, like avoiding the use of
changectx or a more revision centric logic. However, the new code is fast enough
for my needs right now.
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Mon, 11 Mar 2019 01:10:20 +0100 |
parents | 2930b31383af |
children | 6770df6e4365 |
comparison
equal
deleted
inserted
replaced
42236:2930b31383af | 42237:9f45d3d526f9 |
---|---|
16 | 16 |
17 from .node import ( | 17 from .node import ( |
18 bin, | 18 bin, |
19 hex, | 19 hex, |
20 nullid, | 20 nullid, |
21 nullrev, | |
21 short, | 22 short, |
22 ) | 23 ) |
23 from .i18n import _ | 24 from .i18n import _ |
24 from . import ( | 25 from . import ( |
25 encoding, | 26 encoding, |
716 # If we get here, the entry is either missing or invalid. | 717 # If we get here, the entry is either missing or invalid. |
717 | 718 |
718 if not computemissing: | 719 if not computemissing: |
719 return None | 720 return None |
720 | 721 |
721 # Populate missing entry. | 722 fnode = None |
722 try: | 723 cl = self._repo.changelog |
723 fnode = ctx.filenode('.hgtags') | 724 p1rev, p2rev = cl._uncheckedparentrevs(rev) |
724 except error.LookupError: | 725 p1node = cl.node(p1rev) |
725 # No .hgtags file on this revision. | 726 p1fnode = self.getfnode(p1node, computemissing=False) |
726 fnode = nullid | 727 if p2rev != nullrev: |
728 # There is some no-merge changeset where p1 is null and p2 is set | |
729 # Processing them as merge is just slower, but still gives a good | |
730 # result. | |
731 p2node = cl.node(p1rev) | |
732 p2fnode = self.getfnode(p2node, computemissing=False) | |
733 if p1fnode != p2fnode: | |
734 # we cannot rely on readfast because we don't know against what | |
735 # parent the readfast delta is computed | |
736 p1fnode = None | |
737 if p1fnode is not None: | |
738 mctx = ctx.manifestctx() | |
739 fnode = mctx.readfast().get('.hgtags') | |
740 if fnode is None: | |
741 fnode = p1fnode | |
742 if fnode is None: | |
743 # Populate missing entry. | |
744 try: | |
745 fnode = ctx.filenode('.hgtags') | |
746 except error.LookupError: | |
747 # No .hgtags file on this revision. | |
748 fnode = nullid | |
727 | 749 |
728 self._writeentry(offset, properprefix, fnode) | 750 self._writeentry(offset, properprefix, fnode) |
729 return fnode | 751 return fnode |
730 | 752 |
731 def setfnode(self, node, fnode): | 753 def setfnode(self, node, fnode): |