Sun, 18 Dec 2016 16:16:54 -0800 repair: implement requirements checking for upgrades
Gregory Szorc <gregory.szorc@gmail.com> [Sun, 18 Dec 2016 16:16:54 -0800] rev 30775
repair: implement requirements checking for upgrades This commit introduces functionality for upgrading a repository in place. The first part that's implemented is testing for upgrade "compatibility." This is done by examining repository requirements. There are 5 functions returning sets of requirements that control upgrading. Why so many functions? Mainly to support extensions. Functions are easier to monkeypatch than module variables. Astute readers will see that we don't support "manifestv2" and "treemanifest" requirements in the upgrade mechanism. I don't have a great answer for why other than this is a complex set of patches and I don't want to deal with the complexity of these experimental features just yet. We can teach the upgrade mechanism about them later, once the basic upgrade mechanism is in place. This commit also introduces the "upgraderepo" function. This will be our main routine for performing an in-place upgrade. Currently, it just implements requirements checking. The structure of some code in this function may look a bit weird (e.g. the inline function that is only called once). But this will make sense after future commits.
Thu, 24 Nov 2016 16:24:09 -0800 debugcommands: stub for debugupgraderepo command
Gregory Szorc <gregory.szorc@gmail.com> [Thu, 24 Nov 2016 16:24:09 -0800] rev 30774
debugcommands: stub for debugupgraderepo command Currently, if Mercurial introduces a new repository/store feature or changes behavior of an existing feature, users must perform an `hg clone` to create a new repository with hopefully the correct/optimal settings. Unfortunately, even `hg clone` may not give the correct results. For example, if you do a local `hg clone`, you may get hardlinks to revlog files that inherit the old state. If you `hg clone` from a remote or `hg clone --pull`, changegroup application may bypass some optimization, such as converting to generaldelta. Optimizing a repository is harder than it seems and requires more than a simple `hg` command invocation. This commit starts the process of changing that. We introduce `hg debugupgraderepo`, a command that performs an in-place upgrade of a repository to use new, optimal features. The command is just a stub right now. Features will be added in subsequent commits. This commit does foreshadow some of the behavior of the new command, notably that it doesn't do anything by default and that it takes arguments that influence what actions it performs. These will be explained more in subsequent commits.
Wed, 11 Jan 2017 21:47:19 -0500 util: teach stringmatcher to handle forced case insensitive matches
Matt Harbison <matt_harbison@yahoo.com> [Wed, 11 Jan 2017 21:47:19 -0500] rev 30773
util: teach stringmatcher to handle forced case insensitive matches The 'author' and 'desc' revsets are documented to be case insensitive. Unfortunately, this was implemented in 'author' by forcing the input to lowercase, including for regex like '\B'. (This actually inverts the meaning of the sequence.) For backward compatibility, we will keep that a case insensitive regex, but by using matcher options instead of brute force. This doesn't preclude future hypothetical 'icase-literal:' style prefixes that can be provided by the user. Such user specified cases can probably be handled up front by stripping 'icase-', setting the variable, and letting it drop through the existing code.
Wed, 11 Jan 2017 23:13:51 -0500 revset: point to 'grep' in the 'keyword' help for regex searches
Matt Harbison <matt_harbison@yahoo.com> [Wed, 11 Jan 2017 23:13:51 -0500] rev 30772
revset: point to 'grep' in the 'keyword' help for regex searches The help for 'grep' already points to 'keyword'.
Wed, 11 Jan 2017 23:13:00 -0800 help: explain that revsets can be used where 1 or 2 revs are wanted
Martin von Zweigbergk <martinvonz@google.com> [Wed, 11 Jan 2017 23:13:00 -0800] rev 30771
help: explain that revsets can be used where 1 or 2 revs are wanted We did not seem to document that one can do things like "hg up :@" where the last revision of the revset ":@".
Wed, 11 Jan 2017 22:46:07 -0800 help: explain what the term "revset" means
Martin von Zweigbergk <martinvonz@google.com> [Wed, 11 Jan 2017 22:46:07 -0800] rev 30770
help: explain what the term "revset" means We refer to revsets in a few places (e.g. in "hg help config"), but we never explained what they are. Until now.
Wed, 11 Jan 2017 11:37:38 -0800 help: merge revsets.txt into revisions.txt
Martin von Zweigbergk <martinvonz@google.com> [Wed, 11 Jan 2017 11:37:38 -0800] rev 30769
help: merge revsets.txt into revisions.txt Selecting single and multiple revisions is closely related, so let's put it in one place, so users can easily find it. We actually did not even point to "hg help revsets" from "hg help revisions", but now that they're on a single page, that won't be necessary.
Wed, 11 Jan 2017 11:40:40 -0800 tests: use `hg help dates` instead of `hg help revs` in test
Martin von Zweigbergk <martinvonz@google.com> [Wed, 11 Jan 2017 11:40:40 -0800] rev 30768
tests: use `hg help dates` instead of `hg help revs` in test The revisions help is already long and will get longer, so switch to another short and stable topic.
Wed, 11 Jan 2017 11:28:54 -0800 help: use a single paragraph to describe full and abbreviated nodeids
Martin von Zweigbergk <martinvonz@google.com> [Wed, 11 Jan 2017 11:28:54 -0800] rev 30767
help: use a single paragraph to describe full and abbreviated nodeids The texts describing 40-digit strings and the abbreviated form are closely related, so make it a single paragraph.
Tue, 10 Jan 2017 23:37:08 -0800 hgweb: support Content Security Policy
Gregory Szorc <gregory.szorc@gmail.com> [Tue, 10 Jan 2017 23:37:08 -0800] rev 30766
hgweb: support Content Security Policy Content-Security-Policy (CSP) is a web security feature that allows servers to declare what loaded content is allowed to do. For example, a policy can prevent loading of images, JavaScript, CSS, etc unless the source of that content is whitelisted (by hostname, URI scheme, hashes of content, etc). It's a nifty security feature that provides extra mitigation against some attacks, notably XSS. Mitigation against these attacks is important for Mercurial because hgweb renders repository data, which is commonly untrusted. While we make attempts to escape things, etc, there's the possibility that malicious data could be injected into the site content. If this happens today, the full power of the web browser is available to that malicious content. A restrictive CSP policy (defined by the server operator and sent in an HTTP header which is outside the control of malicious content), could restrict browser capabilities and mitigate security problems posed by malicious data. CSP works by emitting an HTTP header declaring the policy that browsers should apply. Ideally, this header would be emitted by a layer above Mercurial (likely the HTTP server doing the WSGI "proxying"). This works for some CSP policies, but not all. For example, policies to allow inline JavaScript may require setting a "nonce" attribute on <script>. This attribute value must be unique and non-guessable. And, the value must be present in the HTTP header and the HTML body. This means that coordinating the value between Mercurial and another HTTP server could be difficult: it is much easier to generate and emit the nonce in a central location. This commit introduces support for emitting a Content-Security-Policy header from hgweb. A config option defines the header value. If present, the header is emitted. A special "%nonce%" syntax in the value triggers generation of a nonce and inclusion in <script> elements in templates. The inclusion of a nonce does not occur unless "%nonce%" is present. This makes this commit completely backwards compatible and the feature opt-in. The nonce is a type 4 UUID, which is the flavor that is randomly generated. It has 122 random bits, which should be plenty to satisfy the guarantees of a nonce.
Tue, 10 Jan 2017 20:47:48 -0800 hgweb: call process_dates() via DOM event listener
Gregory Szorc <gregory.szorc@gmail.com> [Tue, 10 Jan 2017 20:47:48 -0800] rev 30765
hgweb: call process_dates() via DOM event listener All the hgweb templates include mercurial.js in their header. All the hgweb templates have the same <script> boilerplate to run process_dates(). This patch factors that function call into mercurial.js as part of a DOMContentLoaded event listener.
Sat, 24 Dec 2016 15:29:32 -0700 protocol: send application/mercurial-0.2 responses to capable clients
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 24 Dec 2016 15:29:32 -0700] rev 30764
protocol: send application/mercurial-0.2 responses to capable clients With this commit, the HTTP transport now parses the X-HgProto-<N> header to determine what media type and compression engine to use for responses. So far, we only compress responses that are already being compressed with zlib today (stream response types to specific commands). We can expand things to cover additional response types later. The practical side-effect of this commit is that non-zlib compression engines will be used if both ends support them. This means if both ends have zstd support, zstd - not zlib - will be used to compress data! When cloning the mozilla-unified repository between a local HTTP server and client, the benefits of non-zlib compression are quite noticeable: engine server CPU (s) client CPU (s) bundle size zlib (l=6) 174.1 283.2 1,148,547,026 zstd (l=1) 99.2 267.3 1,127,513,841 zstd (l=3) 103.1 266.9 1,018,861,363 zstd (l=7) 128.3 269.7 919,190,278 zstd (l=10) 162.0 - 894,547,179 none 95.3 277.2 4,097,566,064 The default zstd compression level is 3. So if you deploy zstd capable Mercurial to your clients and servers and CPU time on your server is dominated by "getbundle" requests (clients cloning and pulling) - and my experience at Mozilla tells me this is often the case - this commit could drastically reduce your server-side CPU usage *and* save on bandwidth costs! Another benefit of this change is that server operators can install *any* compression engine. While it isn't enabled by default, the "none" compression engine can now be used to disable wire protocol compression completely. Previously, commands like "getbundle" always zlib compressed output, adding considerable overhead to generating responses. If you are on a high speed network and your server is under high load, it might be advantageous to trade bandwidth for CPU. Although, zstd at level 1 doesn't use that much CPU, so I'm not convinced that disabling compression wholesale is worthwhile. And, my data seems to indicate a slow down on the client without compression. I suspect this is due to a lack of buffering resulting in an increase in socket read() calls and/or the fact we're transferring an extra 3 GB of data (parsing HTTP chunked transfer and processing extra TCP packets can add up). This is definitely worth investigating and optimizing. But since the "none" compressor isn't enabled by default, I'm inclined to punt on this issue. This commit introduces tons of tests. Some of these should arguably have been implemented on previous commits. But it was difficult to test without the server functionality in place.
Sat, 24 Dec 2016 15:22:18 -0700 httppeer: advertise and support application/mercurial-0.2
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 24 Dec 2016 15:22:18 -0700] rev 30763
httppeer: advertise and support application/mercurial-0.2 Now that servers expose a capability indicating they support application/mercurial-0.2 and compression, clients can key off this to say they support responses that are compressed with various compression formats. After this commit, the HTTP wire protocol client now sends an "X-HgProto-<N>" request header indicating its support for "application/mercurial-0.2" media type and various compression formats. This commit also implements support for handling "application/mercurial-0.2" responses. It simply reads the header compression engine identifier then routes the remainder of the response to the appropriate decompressor. There were some test changes, but only to logging. That points to an obvious gap in our test coverage. This will be addressed in a subsequent commit once server support is in place (it is hard to test without server support).
Sat, 24 Dec 2016 15:21:46 -0700 wireproto: advertise supported media types and compression formats
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 24 Dec 2016 15:21:46 -0700] rev 30762
wireproto: advertise supported media types and compression formats This commit introduces support for advertising a server's support for media types and compression formats in accordance with the spec defined in internals.wireproto. The bulk of the new code is a helper function in wireproto.py to obtain a prioritized list of compression engines available to the wire protocol. While not utilized yet, we implement support for obtaining the list of compression engines advertised by the client. The upcoming HTTP protocol enhancements are a bit lower-level than existing tests (most existing tests are command centric). So, this commit establishes a new test file that will be appropriate for holding tests around the functionality of the HTTP protocol itself. Rounding out this change, `hg debuginstall` now prints compression engines available to the server.
Sat, 24 Dec 2016 13:51:12 -0700 util: declare wire protocol support of compression engines
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 24 Dec 2016 13:51:12 -0700] rev 30761
util: declare wire protocol support of compression engines This patch implements a new compression engine API allowing compression engines to declare support for the wire protocol. Support is declared by returning a compression format string identifier that will be added to payloads to signal the compression type of data that follows and default integer priorities of the engine. Accessor methods have been added to the compression engine manager class to facilitate use. Note that the "none" and "bz2" engines declare wire protocol support but aren't enabled by default due to their priorities being 0. It is essentially free from a coding perspective to support these compression formats, so we do it in case anyone may derive use from it.
Sat, 24 Dec 2016 13:56:36 -0700 internals: document compression negotiation
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 24 Dec 2016 13:56:36 -0700] rev 30760
internals: document compression negotiation As part of adding zstd support to all of the things, we'll need to teach the wire protocol to support non-zlib compression formats. This commit documents how we'll implement that. To understand how we arrived at this proposal, let's look at how things are done today. The wire protocol today doesn't have a unified format. Instead, there is a limited facility for differentiating replies as successful or not. And, each command essentially defines its own response format. A significant deficiency in the current protocol is the lack of payload framing over the SSH transport. In the HTTP transport, chunked transfer is used and the end of an HTTP response body (and the end of a Mercurial command response) can be identified by a 0 length chunk. This is how HTTP chunked transfer works. But in the SSH transport, there is no such framing, at least for certain responses (notably the response to "getbundle" requests). Clients can't simply read until end of stream because the socket is persistent and reused for multiple requests. Clients need to know when they've encountered the end of a request but there is nothing simple for them to key off of to detect this. So what happens is the client must decode the payload (as opposed to being dumb and forwarding frames/packets). This means the payload itself needs to support identifying end of stream. In some cases (bundle2), it also means the payload can encode "error" or "interrupt" events telling the client to e.g. abort processing. The lack of framing on the SSH transport and the transfer of its responsibilities to e.g. bundle2 is a massive layering violation and a wart on the protocol architecture. It needs to be fixed someday by inventing a proper framing protocol. So about compression. The client transport abstractions have a "_callcompressable()" API. This API is called to invoke a remote command that will send a compressible response. The response is essentially a "streaming" response (no framing data at the Mercurial layer) that is fed into a decompressor. On the HTTP transport, the decompressor is zlib and only zlib. There is currently no mechanism for the client to specify an alternate compression format. And, clients don't advertise what compression formats they support or ask the server to send a specific compression format. Instead, it is assumed that non-error responses to "compressible" commands are zlib compressed. On the SSH transport, there is no compression at the Mercurial protocol layer. Instead, compression must be handled by SSH itself (e.g. `ssh -C`) or within the payload data (e.g. bundle compression). For the HTTP transport, adding new compression formats is pretty straightforward. Once you know what decompressor to use, you can stream data into the decompressor until you reach a 0 size HTTP chunk, at which point you are at end of stream. So our wire protocol changes for the HTTP transport are pretty straightforward: the client and server advertise what compression formats they support and an appropriate compression format is chosen. We introduce a new HTTP media type to hold compressed payloads. The header of the payload defines the compression format being used. Whoever is on the receiving end can sniff the first few bytes route to an appropriate decompressor. Support for multiple compression formats is advertised on both server and client. The server advertises a "compression" capability saying which compression formats it supports and in what order they are preferred. Clients advertise their support for multiple compression formats and media types via the introduced "X-HgProto" request header. Strictly speaking, servers don't need to advertise which compression formats they support. But doing so allows clients to fail fast if they don't support any of the formats the server does. This is useful in situations like sending bundles, where the client may have to perform expensive computation before sending data to the server. Rather than simply advertise a list of supported compression formats, we introduce an additional "httpmediatype" server capability advertising which media types the server supports. This means servers are explicit about what formats they exchange. IMO, this is superior to inferring support from other capabilities (like "compression"). By advertising compression support on each request in the "X-HgProto" header and media type and direction at the server level, we are able to gradually transition existing commands/responses to the new media type and possibly compression. Contrast with the old world, where we only supported a single media type and the use of compression was built-in to the semantics of the command on both client and server. In the new world, if "application/mercurial-0.2" is supported, compression is supported. It's that simple. It's worth noting that we explicitly don't use "Accept," "Accept-Encoding," "Content-Encoding," or "Transfer-Encoding" for content negotiation and compression. People knowledgeable of the HTTP specifications will say that we should use these because that's what they are designed to be used for. They have a point and I sympathize with the argument. Earlier versions of this commit even defined supported media types in the "Accept" header. However, my years of experience rolling out services leveraging HTTP has taught me to not trust the HTTP layer, especially if you are going outside the normal spec (such as using a custom "Content-Encoding" value to represent zstd streams). I've seen load balancers, proxies, and other network devices do very bad and unexpected things to HTTP messages (like insisting zlib compressed content is decoded and then re-encoded at a different compression level or even stripping compression completely). I've found that the best way to avoid surprises when writing protocols on top of HTTP is to use HTTP as a dumb transport as much as possible to minimize the chances that an "intelligent" agent between endpoints will muck with your data. While the widespread use of TLS is mitigating many intermediate network agents interfering with HTTP, there are still problems at the edges, with e.g. the origin HTTP server needing to convert HTTP to and from WSGI and buggy or feature-lacking HTTP client implementations. I've found the best way to avoid these problems is to avoid using headers like "Content-Encoding" and to bake as much logic as possible into media types and HTTP message bodies. The protocol changes in this commit do rely on a custom HTTP request header and the "Content-Type" headers. But we used them before, so we shouldn't be increasing our exposure to "bad" HTTP agents. For the SSH transport, we can't easily implement content negotiation to determine compression formats because the SSH transport has no content negotiation capabilities today. And without a framing protocol, we don't know how much data to feed into a decompressor. So in order to implement compression support on the SSH transport, we'd need to invent a mechanism to represent content types and an outer framing protocol to stream data robustly. While I'm fully capable of doing that, it is a lot of work and not something that should be undertaken lightly. My opinion is that if we're going to change the SSH transport protocol, we should take a long hard look at implementing a grand unified protocol that attempts to address all the deficiencies with the existing protocol. While I want this to happen, that would be massive scope bloat standing in the way of zstd support. So, I've decided to take the easy solution: the SSH transport will not gain support for multiple compression formats. Keep in mind it doesn't support *any* compression today. So essentially nothing is changing on the SSH front.
Sat, 24 Dec 2016 14:46:02 -0700 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 24 Dec 2016 14:46:02 -0700] rev 30759
httppeer: extract code for HTTP header spanning A second consumer of HTTP header spanning will soon be introduced. Factor out the code to do this so it can be reused.
Tue, 10 Jan 2017 11:20:32 -0800 commands: config option to control bundle compression level
Gregory Szorc <gregory.szorc@gmail.com> [Tue, 10 Jan 2017 11:20:32 -0800] rev 30758
commands: config option to control bundle compression level Currently, bundle compression uses the default compression level for the active compression engine. The default compression level is tuned as a compromise between speed and size. Some scenarios may call for a different compression level. For example, with clone bundles, bundles are generated once and used several times. Since the cost to generate is paid infrequently, server operators may wish to trade extra CPU time for better compression ratios. This patch introduces an experimental and undocumented config option to control the bundle compression level. As the inline comment says, this approach is a bit hacky. I'd prefer for the compression level to be encoded in the bundle spec. e.g. "zstd-v2;complevel=15." However, given that the 4.1 freeze is imminent, I'm not comfortable implementing this user-facing change without much time to test and consider the implications. So, we're going with the quick and dirty solution for now. Having this option in the 4.1 release will enable Mozilla to easily produce and test zlib and zstd bundles with non-default compression levels in production. This will help drive future development of the feature and zstd integration with Mercurial.
Tue, 10 Jan 2017 11:19:37 -0800 bundle2: allow compression options to be passed to compressor
Gregory Szorc <gregory.szorc@gmail.com> [Tue, 10 Jan 2017 11:19:37 -0800] rev 30757
bundle2: allow compression options to be passed to compressor Compression engines allow options to be passed to them to control behavior. This patch exposes an argument to bundle2.writebundle() that passes options to the compression engine when writing compressed bundles. The argument is honored for both bundle1 and bundle2, the latter requiring a bit of plumbing to pass the value around.
Wed, 11 Jan 2017 23:39:24 +0800 chg: check snprintf result strictly
Jun Wu <quark@fb.com> [Wed, 11 Jan 2017 23:39:24 +0800] rev 30756
chg: check snprintf result strictly This makes the program more robust when somebody changes hgclient's maxdatasize in the future.
Tue, 10 Jan 2017 09:32:27 +0100 rebase: provide detailed hint to abort message if working dir is not clean
Valters Vingolds <valters@vingolds.ch> [Tue, 10 Jan 2017 09:32:27 +0100] rev 30755
rebase: provide detailed hint to abort message if working dir is not clean Detailed hint message is now provided when 'pull --rebase' operation detects unclean working dir, for example: abort: uncommitted changes (cannot pull with rebase: please commit or shelve your changes first) Added tests for uncommitted merge, and for subrepo support verifying that same hint is also passed to subrepo state check.
Mon, 09 Jan 2017 16:02:56 +0900 revset: parse variable-length arguments of followlines() by getargsdict()
Yuya Nishihara <yuya@tcha.org> [Mon, 09 Jan 2017 16:02:56 +0900] rev 30754
revset: parse variable-length arguments of followlines() by getargsdict()
Mon, 09 Jan 2017 15:25:52 +0900 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org> [Mon, 09 Jan 2017 15:25:52 +0900] rev 30753
parser: extend buildargsdict() to support variable-length positional args This can simplify the argument parsing of followlines(). Tests are added by the next patch.
Mon, 09 Jan 2017 15:15:21 +0900 parser: make buildargsdict() precompute position where keyword args start
Yuya Nishihara <yuya@tcha.org> [Mon, 09 Jan 2017 15:15:21 +0900] rev 30752
parser: make buildargsdict() precompute position where keyword args start This prepares for adding *varargs support. See the next patch.
Wed, 11 Jan 2017 07:40:52 +0800 chg: change server's process title
Jun Wu <quark@fb.com> [Wed, 11 Jan 2017 07:40:52 +0800] rev 30751
chg: change server's process title This patch uses the newly introduced "setprocname" interface to update the process title server-side, to make it easier to tell what a worker is actually doing. The new title is "chg[worker/$PID]", where PID is the process ID of the connected client. It can be directly observed using "ps -AF" under Linux, or "ps -A" under FreeBSD.
Wed, 11 Jan 2017 07:36:48 +0800 chgserver: add the setprocname interface
Jun Wu <quark@fb.com> [Wed, 11 Jan 2017 07:36:48 +0800] rev 30750
chgserver: add the setprocname interface This allows clients to change its process title freely.
Tue, 10 Jan 2017 23:41:58 +0800 hgweb: use archivespecs for links on repo index page too
Anton Shestakov <av6@dwimlabs.net> [Tue, 10 Jan 2017 23:41:58 +0800] rev 30749
hgweb: use archivespecs for links on repo index page too Moving archivespecs to the module level allows using it from other modules (such as hgwebdir_mod), and keeping a reference to it in requestcontext allows current code to just work.
Tue, 10 Jan 2017 23:34:39 +0800 hgweb: use util.sortdict for archivespecs
Anton Shestakov <av6@dwimlabs.net> [Tue, 10 Jan 2017 23:34:39 +0800] rev 30748
hgweb: use util.sortdict for archivespecs Thus we allow dict-like indexing and "in" checks, and also preserve the order of archive types and can generate links in a certain order (so requestcontext.archives is no longer needed).
Wed, 11 Jan 2017 01:25:07 +0800 hgweb: test the order of archive links
Anton Shestakov <av6@dwimlabs.net> [Wed, 11 Jan 2017 01:25:07 +0800] rev 30747
hgweb: test the order of archive links
Thu, 05 Jan 2017 17:16:51 +0000 revlog: REVIDX_EXTSTORED flag
Remi Chaintron <remi@fb.com> [Thu, 05 Jan 2017 17:16:51 +0000] rev 30746
revlog: REVIDX_EXTSTORED flag This flag will be used by the lfs extension to mark the revision data as stored externally.
(0) -30000 -10000 -3000 -1000 -300 -100 -50 -30 +30 +50 +100 +300 +1000 +3000 +10000 tip