mirror of
https://github.com/facebook/sapling.git
synced 2024-10-12 01:39:21 +03:00
bf577875b3
Summary:
Motivated by recent D7784903 which kills chg because it holds blackbox.log
file descriptor, and that patch is causing race conditions running with chg
(chg's sock atomic rename might fail if the directory is deleted).
There are other ways to solve the direct issue. This diff takes a more
aggressive but much cleaner approach. Basically, the `hg serve` framework is
too late for chg's usecase - the repo was already loaded, extension
side-effects have been already done at that time - chg has to use
workarounds to be compatible with that. Even with a best effort, it is still
possible to have weird interactions with shared repo because how hg loads
extensions.
The new approach is to pre-import a list of bundled extensions but do not
run their `uisetup`s. This solves a couple of hard problems:
- Compatibility - `uisetup` runs per request. That behaves exactly as what
an extension author expects.
- Less memory usage - there is no `repo` object is loaded in memory.
- Reduced process count - since extension config change does not require a
new chg server, the count of server processes would decrease (ex.
`--config extensions.blackbox=!` won't require a new chg server)
- Not holding fd to edenfs, since neither blackbox nor repo is loaded. This
makes it possible to remove the hacky killing chg logic in D7784903.
The downside is performance, since extension loading, and `uisetup` will run
every time. Benchmark shows that's could be 50ms-ish. But we could move
forward by moving extension logic to core incrementally to get rid of that
cost too.
This is basically a simplified version of my previous stack starting
with [1]. The original commit message was:
This is the beginning of a series that does a re-architect to chg mentioned
in [1], to achieve better compatibility.
The compatibility issues are mainly around "uisetup"s and "reposetup"s:
- Developers are usually unaware that uisetup runs only once per chg
process. We cannot reliably devel-warn them. The result is, potential
broken code are written. For example, it's really hard for chg to deal
with "experimental.evolution" changed from unset to manually set in
config files because setconfig is used if that config option is not set.
- An unnecessary "reposetup" caused by "hg serve" may have unwanted
side effects. This can become troublesome if the repo requires things
like remotefilelog or lz4revlog, and the user sets HGRCPATH to run
tests.
The current chg implementation assumes that "loading" an extension is not
side effect free - if extension related config has changed, a restart is
needed. The new idea is, "loading" = "importing" + "run ui/extsetup", the
"importing" part can be side-effect free for some extensions. And benchmark
shows "import" takes most of the time consumed, while "uisetup" is usually
very fast. We can afford running "uisetup"s per request.
To be able to (pre-)"import" extensions without running any "uisetup"s, a
different entry point is needed. Otherwise as long as we go through the
normal dispatch / runcommand ("hg serve") flow, "uisetup"s cannot be
avoided.
Aside from better compatibility, we can also remove some hacks:
- chg client: no longer needs to extract sensitive argv
- chg server: confighash can be changed to only hash environment variables
(reduce the number of server processes)
- chg server: srcui.walkconfig hack is no longer necessary
This patch adds a new script "chgserve" as the new entry point. Currently,
it is just a minimal implementation that makes "CHGHG=chgserve chg ..."
work, without doing any pre-importing. The change could also be done in the
"hg" script. But since chg is still experimental, let's keep "hg" untouched
for now.
[1]: www.mercurial-scm.org/pipermail/mercurial-devel/2016-July/085965.html
[1]: 6f91a1a69f
Reviewed By: singhsrb
Differential Revision: D7840237
fbshipit-source-id: e3d613b41fe4b721238b86c5bf84434d32cf0609
48 lines
1.4 KiB
Python
Executable File
48 lines
1.4 KiB
Python
Executable File
#!/usr/bin/env python
|
|
#
|
|
# mercurial - scalable distributed SCM
|
|
#
|
|
# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
|
|
#
|
|
# This software may be used and distributed according to the terms of the
|
|
# GNU General Public License version 2 or any later version.
|
|
from __future__ import absolute_import
|
|
|
|
import os
|
|
import sys
|
|
|
|
if os.environ.get('HGUNICODEPEDANTRY', False):
|
|
try:
|
|
reload(sys)
|
|
sys.setdefaultencoding("undefined")
|
|
except NameError:
|
|
pass
|
|
|
|
libdir = '@LIBDIR@'
|
|
|
|
if libdir != '@' 'LIBDIR' '@':
|
|
if not os.path.isabs(libdir):
|
|
libdir = os.path.join(os.path.dirname(os.path.realpath(__file__)),
|
|
libdir)
|
|
libdir = os.path.abspath(libdir)
|
|
sys.path.insert(0, libdir)
|
|
|
|
if (sys.argv[1:5] == ['serve', '--cmdserver', 'chgunix', '--address']
|
|
and sys.argv[6:8] == ['--daemon-postexec', 'chdir:/']
|
|
and 'CHGINTERNALMARK' in os.environ):
|
|
# Shortcut path for chg server
|
|
from mercurial import dispatch
|
|
dispatch.runchgserver()
|
|
else:
|
|
# Non-chg path
|
|
try:
|
|
if sys.version_info[0] < 3 or sys.version_info >= (3, 6):
|
|
import hgdemandimport; hgdemandimport.enable()
|
|
except ImportError:
|
|
sys.stderr.write("abort: couldn't find mercurial libraries in [%s]\n" %
|
|
' '.join(sys.path))
|
|
sys.stderr.write("(check your install and PYTHONPATH)\n")
|
|
sys.exit(-1)
|
|
from mercurial import dispatch
|
|
dispatch.run()
|