Mercurial > public > mercurial-scm > hg
diff hgext/fastannotate/__init__.py @ 39210:1ddb296e0dee
fastannotate: initial import from Facebook's hg-experimental
I made as few changes as I could to get the tests to pass, but this
was a bit involved due to some churn in the blame code since someone
last gave fastannotate any TLC.
There's still follow-up work here to rip out support for old versions
of hg and to integrate the protocol with modern standards.
Some performance numbers (all on my 2016 MacBook Pro with a 2.6Ghz i7):
Mercurial mercurial/manifest.py
traditional blame
time: real 1.050 secs (user 0.990+0.000 sys 0.060+0.000)
build cache
time: real 5.900 secs (user 5.720+0.000 sys 0.110+0.000)
fastannotate
time: real 0.120 secs (user 0.100+0.000 sys 0.020+0.000)
Mercurial mercurial/localrepo.py
traditional blame
time: real 3.330 secs (user 3.220+0.000 sys 0.070+0.000)
build cache
time: real 30.610 secs (user 30.190+0.000 sys 0.230+0.000)
fastannotate
time: real 0.180 secs (user 0.160+0.000 sys 0.020+0.000)
mozilla-central dom/ipc/ContentParent.cpp
traditional blame
time: real 7.640 secs (user 7.210+0.000 sys 0.380+0.000)
build cache
time: real 98.650 secs (user 97.000+0.000 sys 0.950+0.000)
fastannotate
time: real 1.580 secs (user 1.340+0.000 sys 0.240+0.000)
mozilla-central dom/base/nsDocument.cpp
traditional blame
time: real 17.110 secs (user 16.490+0.000 sys 0.500+0.000)
build cache
time: real 399.750 secs (user 394.520+0.000 sys 2.610+0.000)
fastannotate
time: real 1.780 secs (user 1.530+0.000 sys 0.240+0.000)
So building the cache is expensive (but might be faster with xdiff
enabled), but the blame results are *way* faster.
Differential Revision: https://phab.mercurial-scm.org/D3994
author | Augie Fackler <augie@google.com> |
---|---|
date | Mon, 30 Jul 2018 22:50:00 -0400 |
parents | |
children | ca053fc7efc5 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hgext/fastannotate/__init__.py Mon Jul 30 22:50:00 2018 -0400 @@ -0,0 +1,185 @@ +# Copyright 2016-present Facebook. All Rights Reserved. +# +# fastannotate: faster annotate implementation using linelog +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. +"""yet another annotate implementation that might be faster (EXPERIMENTAL) + +The fastannotate extension provides a 'fastannotate' command that makes +use of the linelog data structure as a cache layer and is expected to +be faster than the vanilla 'annotate' if the cache is present. + +In most cases, fastannotate requires a setup that mainbranch is some pointer +that always moves forward, to be most efficient. + +Using fastannotate together with linkrevcache would speed up building the +annotate cache greatly. Run "debugbuildlinkrevcache" before +"debugbuildannotatecache". + +:: + + [fastannotate] + # specify the main branch head. the internal linelog will only contain + # the linear (ignoring p2) "mainbranch". since linelog cannot move + # backwards without a rebuild, this should be something that always moves + # forward, usually it is "master" or "@". + mainbranch = master + + # fastannotate supports different modes to expose its feature. + # a list of combination: + # - fastannotate: expose the feature via the "fastannotate" command which + # deals with everything in a most efficient way, and provides extra + # features like --deleted etc. + # - fctx: replace fctx.annotate implementation. note: + # a. it is less efficient than the "fastannotate" command + # b. it will make it practically impossible to access the old (disk + # side-effect free) annotate implementation + # c. it implies "hgweb". + # - hgweb: replace hgweb's annotate implementation. conflict with "fctx". + # (default: fastannotate) + modes = fastannotate + + # default format when no format flags are used (default: number) + defaultformat = changeset, user, date + + # serve the annotate cache via wire protocol (default: False) + # tip: the .hg/fastannotate directory is portable - can be rsynced + server = True + + # build annotate cache on demand for every client request (default: True) + # disabling it could make server response faster, useful when there is a + # cronjob building the cache. + serverbuildondemand = True + + # update local annotate cache from remote on demand + # (default: True for remotefilelog repo, False otherwise) + client = True + + # path to use when connecting to the remote server (default: default) + remotepath = default + + # share sshpeer with remotefilelog. this would allow fastannotate to peek + # into remotefilelog internals, and steal its sshpeer, or in the reversed + # direction: donate its sshpeer to remotefilelog. disable this if + # fastannotate and remotefilelog should not share a sshpeer when their + # endpoints are different and incompatible. (default: True) + clientsharepeer = True + + # minimal length of the history of a file required to fetch linelog from + # the server. (default: 10) + clientfetchthreshold = 10 + + # use flock instead of the file existence lock + # flock may not work well on some network filesystems, but they avoid + # creating and deleting files frequently, which is faster when updating + # the annotate cache in batch. if you have issues with this option, set it + # to False. (default: True if flock is supported, False otherwise) + useflock = True + + # for "fctx" mode, always follow renames regardless of command line option. + # this is a BC with the original command but will reduced the space needed + # for annotate cache, and is useful for client-server setup since the + # server will only provide annotate cache with default options (i.e. with + # follow). do not affect "fastannotate" mode. (default: True) + forcefollow = True + + # for "fctx" mode, always treat file as text files, to skip the "isbinary" + # check. this is consistent with the "fastannotate" command and could help + # to avoid a file fetch if remotefilelog is used. (default: True) + forcetext = True + + # use unfiltered repo for better performance. + unfilteredrepo = True + + # sacrifice correctness in some corner cases for performance. it does not + # affect the correctness of the annotate cache being built. the option + # is experimental and may disappear in the future (default: False) + perfhack = True +""" + +from __future__ import absolute_import + +from mercurial.i18n import _ +from mercurial import ( + error as hgerror, + localrepo, + registrar, + util, +) + +from . import ( + commands, + context, + protocol, +) + +# Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for +# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should +# be specifying the version(s) of Mercurial they are tested with, or +# leave the attribute unspecified. +testedwith = 'ships-with-hg-core' + +cmdtable = commands.cmdtable + +configtable = {} +configitem = registrar.configitem(configtable) + +configitem('fastannotate', 'modes', default=['fastannotate']) +configitem('fastannotate', 'server', default=False) +configitem('fastannotate', 'useflock', default=True) +configitem('fastannotate', 'client') +configitem('fastannotate', 'unfilteredrepo', default=True) +configitem('fastannotate', 'defaultformat', default=['number']) +configitem('fastannotate', 'perfhack', default=False) +configitem('fastannotate', 'mainbranch') +configitem('fastannotate', 'forcetext', default=True) +configitem('fastannotate', 'forcefollow', default=True) +configitem('fastannotate', 'clientfetchthreshold', default=10) +configitem('fastannotate', 'clientsharepeer', default=True) +configitem('fastannotate', 'serverbuildondemand', default=True) +configitem('fastannotate', 'remotepath', default='default') + +def _flockavailable(): + try: + import fcntl + fcntl.flock + except StandardError: + return False + else: + return True + +def uisetup(ui): + modes = set(ui.configlist('fastannotate', 'modes')) + if 'fctx' in modes: + modes.discard('hgweb') + for name in modes: + if name == 'fastannotate': + commands.registercommand() + elif name == 'hgweb': + from . import support + support.replacehgwebannotate() + elif name == 'fctx': + from . import support + support.replacefctxannotate() + support.replaceremotefctxannotate() + commands.wrapdefault() + else: + raise hgerror.Abort(_('fastannotate: invalid mode: %s') % name) + + if ui.configbool('fastannotate', 'server'): + protocol.serveruisetup(ui) + + if ui.configbool('fastannotate', 'useflock', _flockavailable()): + context.pathhelper.lock = context.pathhelper._lockflock + + # fastannotate has its own locking, without depending on repo lock + localrepo.localrepository._wlockfreeprefix.add('fastannotate/') + +def reposetup(ui, repo): + client = ui.configbool('fastannotate', 'client', default=None) + if client is None: + if util.safehasattr(repo, 'requirements'): + client = 'remotefilelog' in repo.requirements + if client: + protocol.clientreposetup(ui, repo)