localrepo: also fastpath access to working copy parents when possible
If the filter level guarantee that the working copy parents will be visible, we
allow fast path access to them. With this change multiple commands can now run
without triggering filtering.
After using the quick access mechanism introduced, the whole series results in
pretty good performance gain:
```
All benchmarks:
before after ratio
[
8e095512] [
36b2f659]
- 711±0.8ms 60.7±0.2ms 0.09 simple_command.read.diff.empty.time_bench('mercurial-filtered-2019-11-22', 'zstd', 'default', True, True, True, True, True, 1) [citrea/virtualenv-py2.7-pyyaml-HGMODULEPOLICYc-HGWITHRUSTEXTcpython]
- 712±0.8ms 61.6±0.2ms 0.09 simple_command.read.diff.empty.time_bench('mercurial-filtered-2019-11-22', 'zstd', 'default', True, True, True, True, True, 1) [citrea/virtualenv-py2.7-pyyaml-HGMODULEPOLICYrust+c-HGWITHRUSTEXTcpython]
- 690±1ms 93.5±0.3ms 0.14 simple_command.read.diff.empty.time_bench('mercurial-filtered-2019-11-22', 'zstd', 'default', True, True, True, True, True, 1) [citrea/virtualenv-py3.7-pyyaml-HGMODULEPOLICYc-HGWITHRUSTEXTcpython]
- 688±1ms 93.8±0.3ms 0.14 simple_command.read.diff.empty.time_bench('mercurial-filtered-2019-11-22', 'zstd', 'default', True, True, True, True, True, 1) [citrea/virtualenv-py3.7-pyyaml-HGMODULEPOLICYrust+c-HGWITHRUSTEXTcpython]
- 714±1ms 60.7±0.8ms 0.09 simple_command.read.diff.empty.time_bench('mercurial-filtered-2019-11-22', 'zstd', 'default', True, True, True, True, True, 2) [citrea/virtualenv-py2.7-pyyaml-HGMODULEPOLICYc-HGWITHRUSTEXTcpython]
- 713±1ms 60.9±0.3ms 0.09 simple_command.read.diff.empty.time_bench('mercurial-filtered-2019-11-22', 'zstd', 'default', True, True, True, True, True, 2) [citrea/virtualenv-py2.7-pyyaml-HGMODULEPOLICYrust+c-HGWITHRUSTEXTcpython]
- 689±1ms 93.7±0.2ms 0.14 simple_command.read.diff.empty.time_bench('mercurial-filtered-2019-11-22', 'zstd', 'default', True, True, True, True, True, 2) [citrea/virtualenv-py3.7-pyyaml-HGMODULEPOLICYc-HGWITHRUSTEXTcpython]
- 687±2ms 92.8±0.2ms 0.14 simple_command.read.diff.empty.time_bench('mercurial-filtered-2019-11-22', 'zstd', 'default', True, True, True, True, True, 2) [citrea/virtualenv-py3.7-pyyaml-HGMODULEPOLICYrust+c-HGWITHRUSTEXTcpython]
- 799±2ms 98.1±0.6ms 0.12 simple_command.read.export.bare.time_bench('mercurial-filtered-2019-11-22', 'zstd', 'default', True, True, True, True, True) [citrea/virtualenv-py2.7-pyyaml-HGMODULEPOLICYc-HGWITHRUSTEXTcpython]
- 800±0.8ms 100.0±0.4ms 0.12 simple_command.read.export.bare.time_bench('mercurial-filtered-2019-11-22', 'zstd', 'default', True, True, True, True, True) [citrea/virtualenv-py2.7-pyyaml-HGMODULEPOLICYrust+c-HGWITHRUSTEXTcpython]
- 711±0.9ms 111±0.2ms 0.16 simple_command.read.export.bare.time_bench('mercurial-filtered-2019-11-22', 'zstd', 'default', True, True, True, True, True) [citrea/virtualenv-py3.7-pyyaml-HGMODULEPOLICYc-HGWITHRUSTEXTcpython]
- 711±1ms 112±0.3ms 0.16 simple_command.read.export.bare.time_bench('mercurial-filtered-2019-11-22', 'zstd', 'default', True, True, True, True, True) [citrea/virtualenv-py3.7-pyyaml-HGMODULEPOLICYrust+c-HGWITHRUSTEXTcpython]
- 760±1ms 59.8±0.1ms 0.08 simple_command.read.status.wc_clean.default.time_bench('mercurial-filtered-2019-11-22', 'zstd', 'default', True, True, True, True, True, 1) [citrea/virtualenv-py2.7-pyyaml-HGMODULEPOLICYc-HGWITHRUSTEXTcpython]
- 763±2ms 62.2±0.3ms 0.08 simple_command.read.status.wc_clean.default.time_bench('mercurial-filtered-2019-11-22', 'zstd', 'default', True, True, True, True, True, 1) [citrea/virtualenv-py2.7-pyyaml-HGMODULEPOLICYrust+c-HGWITHRUSTEXTcpython]
- 689±1ms 93.1±0.3ms 0.14 simple_command.read.status.wc_clean.default.time_bench('mercurial-filtered-2019-11-22', 'zstd', 'default', True, True, True, True, True, 1) [citrea/virtualenv-py3.7-pyyaml-HGMODULEPOLICYc-HGWITHRUSTEXTcpython]
- 688±1ms 94.3±0.3ms 0.14 simple_command.read.status.wc_clean.default.time_bench('mercurial-filtered-2019-11-22', 'zstd', 'default', True, True, True, True, True, 1) [citrea/virtualenv-py3.7-pyyaml-HGMODULEPOLICYrust+c-HGWITHRUSTEXTcpython]
- 763±1ms 60.1±0.2ms 0.08 simple_command.read.status.wc_clean.default.time_bench('mercurial-filtered-2019-11-22', 'zstd', 'default', True, True, True, True, True, 2) [citrea/virtualenv-py2.7-pyyaml-HGMODULEPOLICYc-HGWITHRUSTEXTcpython]
- 763±1ms 62.1±0.4ms 0.08 simple_command.read.status.wc_clean.default.time_bench('mercurial-filtered-2019-11-22', 'zstd', 'default', True, True, True, True, True, 2) [citrea/virtualenv-py2.7-pyyaml-HGMODULEPOLICYrust+c-HGWITHRUSTEXTcpython]
- 689±0.8ms 93.2±0.2ms 0.14 simple_command.read.status.wc_clean.default.time_bench('mercurial-filtered-2019-11-22', 'zstd', 'default', True, True, True, True, True, 2) [citrea/virtualenv-py3.7-pyyaml-HGMODULEPOLICYc-HGWITHRUSTEXTcpython]
- 687±0.9ms 94.1±0.3ms 0.14 simple_command.read.status.wc_clean.default.time_bench('mercurial-filtered-2019-11-22', 'zstd', 'default', True, True, True, True, True, 2) [citrea/virtualenv-py3.7-pyyaml-HGMODULEPOLICYrust+c-HGWITHRUSTEXTcpython]
```
Differential Revision: https://phab.mercurial-scm.org/D7492
--- a/mercurial/context.py Thu Jan 16 08:41:38 2020 -0800
+++ b/mercurial/context.py Sun Nov 17 14:39:28 2019 +0100
@@ -1989,6 +1989,7 @@
for f in self.removed():
self._repo.dirstate.drop(f)
self._repo.dirstate.setparents(node)
+ self._repo._quick_access_changeid_invalidate()
# write changes out explicitly, because nesting wlock at
# runtime may prevent 'wlock.release()' in 'repo.commit()'
--- a/mercurial/localrepo.py Thu Jan 16 08:41:38 2020 -0800
+++ b/mercurial/localrepo.py Sun Nov 17 14:39:28 2019 +0100
@@ -1517,18 +1517,51 @@
narrowspec.save(self, newincludes, newexcludes)
self.invalidate(clearfilecache=True)
- @util.propertycache
+ @unfilteredpropertycache
+ def _quick_access_changeid_null(self):
+ return {
+ b'null': (nullrev, nullid),
+ nullrev: (nullrev, nullid),
+ nullid: (nullrev, nullid),
+ }
+
+ @unfilteredpropertycache
+ def _quick_access_changeid_wc(self):
+ # also fast path access to the working copy parents
+ # however, only do it for filter that ensure wc is visible.
+ quick = {}
+ cl = self.unfiltered().changelog
+ for node in self.dirstate.parents():
+ if node == nullid:
+ continue
+ rev = cl.index.get_rev(node)
+ if rev is None:
+ # unknown working copy parent case:
+ #
+ # skip the fast path and let higher code deal with it
+ continue
+ pair = (rev, node)
+ quick[rev] = pair
+ quick[node] = pair
+ return quick
+
+ @unfilteredmethod
+ def _quick_access_changeid_invalidate(self):
+ if '_quick_access_changeid_wc' in vars(self):
+ del self.__dict__['_quick_access_changeid_wc']
+
+ @property
def _quick_access_changeid(self):
"""an helper dictionnary for __getitem__ calls
This contains a list of symbol we can recognise right away without
further processing.
"""
- return {
- b'null': (nullrev, nullid),
- nullrev: (nullrev, nullid),
- nullid: (nullrev, nullid),
- }
+ mapping = self._quick_access_changeid_null
+ if self.filtername in repoview.filter_has_wc:
+ mapping = mapping.copy()
+ mapping.update(self._quick_access_changeid_wc)
+ return mapping
def __getitem__(self, changeid):
# dealing with special cases
@@ -1887,6 +1920,7 @@
def setparents(self, p1, p2=nullid):
self[None].setparents(p1, p2)
+ self._quick_access_changeid_invalidate()
def filectx(self, path, changeid=None, fileid=None, changectx=None):
"""changeid must be a changeset revision, if specified.
@@ -2484,6 +2518,7 @@
def invalidatevolatilesets(self):
self.filteredrevcache.clear()
obsolete.clearobscaches(self)
+ self._quick_access_changeid_invalidate()
def invalidatedirstate(self):
'''Invalidates the dirstate, causing the next call to dirstate
--- a/mercurial/scmutil.py Thu Jan 16 08:41:38 2020 -0800
+++ b/mercurial/scmutil.py Sun Nov 17 14:39:28 2019 +0100
@@ -1466,6 +1466,7 @@
if src not in newctx or dst in newctx or ds[dst] != b'a':
src = None
ds.copy(src, dst)
+ repo._quick_access_changeid_invalidate()
def writerequires(opener, requirements):
--- a/tests/test-repo-filters-tiptoe.t Thu Jan 16 08:41:38 2020 -0800
+++ b/tests/test-repo-filters-tiptoe.t Sun Nov 17 14:39:28 2019 +0100
@@ -62,7 +62,6 @@
Getting status of working copy
$ hg status
- debug.filters: computing revision filter for "visible"
M c
A d
R a
@@ -78,7 +77,6 @@
Getting working copy diff
$ hg diff
- debug.filters: computing revision filter for "visible"
diff -r c2932ca7786be30b67154d541a8764fae5532261 a
--- a/a Thu Jan 01 00:00:00 1970 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000