Raphaël Gomès <rgomes@octobus.net> [Thu, 18 Jul 2024 12:37:13 +0200] rev 51691
hghave: update detection of black version to a newer minimum
The CI has moved to version 23.3.0, which is the last one to support 3.7 at
runtime.
Raphaël Gomès <rgomes@octobus.net> [Thu, 18 Jul 2024 12:36:12 +0200] rev 51690
black: format the codebase with 23.3.0
The CI has moved to 23.3.0, which is the last version that supports 3.7
at runtime, so we should honor this change.
# skip-blame mass-reformating only
Raphaël Gomès <rgomes@octobus.net> [Thu, 18 Jul 2024 12:03:29 +0200] rev 51689
pytype: work around wrong ImportError flagging
As documented in https://github.com/google/pytype/issues/163, newer versions
of Pytype do not understand caught `ImportError`, so we temporarily ignore
them where applicable.
Raphaël Gomès <rgomes@octobus.net> [Thu, 18 Jul 2024 12:02:01 +0200] rev 51688
zeroconf: fix boolean return value
This was (wrongly) flagged by Pytype as being undefined since it doesn't
seem to understand `try` blocks. However, the caller is expecting a boolean
and the fix to appease Pytype is simple, so we do both.
Matt Harbison <matt_harbison@yahoo.com> [Thu, 11 Jul 2024 21:54:02 -0400] rev 51687
convert: fix various leaked file descriptors
Some of these only leaked if an exception occurred between the open and close,
but a lot of these leaked unconditionally.
A type hint is added to `parsesplicemap` because otherwise this change caused
pytype to change the return type from this to `Dict[nothing, nothing]`.
Matt Harbison <matt_harbison@yahoo.com> [Thu, 11 Jul 2024 21:16:45 -0400] rev 51686
convert: stringify `shlex` class argument
The documentation is handwavy, but typeshed says this should be `str`[1]. I'm
not sure if this is the correct encoding (vs `fsencode` or "latin1" like the
tokens returned by the proxy class).
While we're here, we can add a few more type hints that would have caused pytype
to flag the problem.
[1] https://github.com/python/typeshed/blob/
6a9b53e719a139c2d6b41cf265ed0990cf438192/stdlib/shlex.pyi#L51
Matt Harbison <matt_harbison@yahoo.com> [Thu, 11 Jul 2024 20:54:06 -0400] rev 51685
typing: add trivial type hints to the convert extension's common modules
This started as ensuring that the `encoding` and `orig_encoding` attributes has
a type other than `Any`, so pytype can catch problems where it needs to be str
for stdlib encoding and decoding. It turns out that adding the hint in
`mercurial.encoding` is what was needed, but I picked a bunch of low hanging
fruit while here. There's definitely more to do, and I see a problem where
`shlex.shlex` is being fed bytes instead of str, but there are not enough type
hints yet to make pytype notice.
Matt Harbison <matt_harbison@yahoo.com> [Thu, 11 Jul 2024 14:46:00 -0400] rev 51684
convert: drop a duplicate implementation of `dateutil.makedate()`
I noticed this because the signature generated by pytype recently changed to be
less specific. When the method was introduced back in
337d728e644f,
`util.makedate()` didn't take an optional timestamp arg. But now it does, and
the methods are the same (except the `dateutil` version validates that the
timestamp isn't a negative value). I left the old method in place in case
anyone has custom convert code that monkey patches it.
Pierre-Yves David <pierre-yves.david@octobus.net> [Mon, 08 Jul 2024 15:48:34 +0200] rev 51683
revlog: use mmap by default is pre-population is available
Using mmap has a great impact of memory usage on server, and a good impact on
performance in multiple case. Now that we pre-populate memory mapping by
default, there is case where it using mmap is slower. So we use it by default
(if pre-population is available).
Further work to reduce the performance impact of the pre-population will be done
later.
Some benchmark below (using the same setup as
522b4d729e89):
As for
522b4d729e89 the impact on small repository like Mercurial or Pypy is
tiny, ~1% best. However for large repositories we see some performance
improvement without seeing the performance regression that we could have without
pre-populate.
##### For netbeans
### data-env-vars.name = netbeans-2018-08-01-zstd-sparse-revlog
## benchmark.name = hg.command.log
# bin-env-vars.hg.flavor = rust
# benchmark.variants.limit-rev = 1
# benchmark.variants.patch = yes
no-mmap: 0.171579
mmap: 0.166311 (-3.07%, -0.01)
# bin-env-vars.hg.flavor = default
no-mmap: 0.170716
mmap: 0.165218 (-3.22%, -0.01)
# benchmark.variants.patch = no
# benchmark.variants.rev = tip
no-mmap: 0.140862
mmap: 0.137566 (-2.34%, -0.00)
## benchmark.name = hg.command.unbundle
# bin-env-vars.hg.flavor = rust
# benchmark.variants.
issue6528 = disabled
# benchmark.variants.reuse-external-delta-parent = yes
# benchmark.variants.revs = any-1-extra-rev
# benchmark.variants.source = unbundle
no-mmap: 0.238038
mmap: 0.239912
no-populate: 0.cbd4c9 (+11.71%, +0.03)
#### For Mozilla
### data-env-vars.name = mozilla-try-2019-02-18-ds2-pnm
# benchmark.name = hg.command.log
# bin-env-vars.hg.flavor = rust
# bin-env-vars.hg.py-re2-module = default
# benchmark.variants.limit-rev = 1
# benchmark.variants.patch = yes
no-mmap: 0.258440
mmap: 0.237813 (-7.98%, -0.02)
# benchmark.variants.limit-rev = 10
no-mmap: 1.235323
mmap: 1.213578 (-1.76%, -0.02)
## benchmark.name = hg.command.push
# bin-env-vars.hg.flavor = rust
# bin-env-vars.hg.py-re2-module = default
# benchmark.variants.explicit-rev = none
# benchmark.variants.
issue6528 = disabled
# benchmark.variants.protocol = ssh
# benchmark.variants.reuse-external-delta-parent = yes
# benchmark.variants.revs = any-1-extra-rev
no-mmap: 4.790135
mmap: 4.668971 (-2.53%, -0.12)
no-populate: 4.841141 (+1.06%, +0.05)
### data-env-vars.name = mozilla-try-2019-02-18-zstd-sparse-revlog
## benchmark.name = hg.command.log
# bin-env-vars.hg.flavor = default
# benchmark.variants.limit-rev = 1000
# benchmark.variants.rev = tip
no-mmap: 0.206187
mmap: 0.197348 (-4.29%, -0.01)
## benchmark.name = hg.command.push
# bin-env-vars.hg.flavor = default
# benchmark.variants.explicit-rev = none
# benchmark.variants.
issue6528 = disabled
# benchmark.variants.protocol = ssh
# benchmark.variants.reuse-external-delta-parent = yes
# benchmark.variants.revs = any-1-extra-rev
no-mmap: 4.768259
mmap: 4.798632
no-populate: 4.953295 (+3.88%, +0.19)
# benchmark.variants.revs = any-100-extra-rev
no-mmap: 4.785946
mmap: 4.903618
no-populate: 5.014963 (+4.79%, +0.23)
## benchmark.name = hg.command.unbundle
# bin-env-vars.hg.flavor = default
# benchmark.variants.
issue6528 = disabled
# benchmark.variants.reuse-external-delta-parent = yes
# benchmark.variants.revs = any-1-extra-rev
# benchmark.variants.source = unbundle
no-mmap: 1.400121
mmap: 1.423411
no-populate: 1.585365 (+13.23%, +0.19)
Pierre-Yves David <pierre-yves.david@octobus.net> [Mon, 08 Jul 2024 17:02:27 +0200] rev 51682
revlog: use an explicit config option to enable mmap usage for index
We replace the `experimental.mmapindexthreshold` with two options:
The `storage.revlog.mmap.index` is a boolean option to enable or disable the
feature. The `storage.revlog.mmap.index:size-threshold` is a bytes option that
control when we will be using mmap instead of plain reading.
Pierre-Yves David <pierre-yves.david@octobus.net> [Thu, 11 Apr 2024 00:02:07 +0200] rev 51681
mmap: populate the mapping by default
Without pre-population, accessing all data through a mmap can result in many
pagefault, reducing performance significantly. If the mmap is prepopulated, the
performance can no longer get slower than a full read.
(See benchmark number below)
In some cases were very few data is read, prepopulating can be overkill and
slower than populating on access (through page fault). So that behavior can be
controlled when the caller can pre-determine the best behavior.
(See benchmark number below)
In addition, testing with populating in a secondary thread yield great result
combining the best of each approach. This might be implemented in later
changesets.
In all cases, using mmap has a great effect on memory usage when many processes
run in parallel on the same machine.
### Benchmarks
# What did I run
A couple of month back I ran a large benchmark campaign to assess the impact of
various approach for using mmap with the revlog (and other files), it
highlighted a few benchmarks that capture the impact of the changes well. So to
validate this change I checked the following:
- log command displaying various revisions
(read the changelog index)
- log command displaying the patch of listed revisions
(read the changelog index, the manifest index and a few files indexes)
- unbundling a few revisions
(read and write changelog, manifest and few files indexes, and walk the graph
to update some cache)
- pushing a few revisions
(read and write changelog, manifest and few files indexes, walk the graph to
update some cache, performs various accesses locally and remotely during
discovery)
Benchmarks were run using the default module policy (c+py) and the rust one. No
significant difference were found between the two implementation, so we will
present result using the default policy (unless otherwise specified).
I ran them on a few repositories :
- mercurial: a "public changeset only" copy of mercurial from 2018-08-01 using
zstd compression and sparse-revlog
- pypy: a copy of pypy from 2018-08-01 using zstd compression and sparse-revlog
- netbeans: a copy of netbeans from 2018-08-01 using zstd compression and
sparse-revlog
- mozilla-try: a copy of mozilla-try from 2019-02-18 using zstd compression and
sparse-revlog
- mozilla-try persistent-nodemap: Same as the above but with a persistent
nodemap. Used for the log --patch benchmark only
# Results
For the smaller repositories (mercurial, pypy), the impact of mmap is almost
imperceptible, other cost dominating the operation. The impact of prepopulating
is undiscernible in the benchmark we ran.
For larger repositories the benchmark support explanation given above:
On netbeans, the log can be about 1% faster without repopulation (for a
difference < 100ms) but unbundle becomes a bit slower, even when small.
### data-env-vars.name = netbeans-2018-08-01-zstd-sparse-revlog
# benchmark.name = hg.command.unbundle
# benchmark.variants.
issue6528 = disabled
# benchmark.variants.reuse-external-delta-parent = yes
# benchmark.variants.revs = any-1-extra-rev
# benchmark.variants.source = unbundle
# benchmark.variants.verbosity = quiet
with-populate: 0.240157
no-populate: 0.265087 (+10.38%, +0.02)
# benchmark.variants.revs = any-100-extra-rev
with-populate: 1.459518
no-populate: 1.481290 (+1.49%, +0.02)
## benchmark.name = hg.command.push
# benchmark.variants.explicit-rev = none
# benchmark.variants.
issue6528 = disabled
# benchmark.variants.protocol = ssh
# benchmark.variants.reuse-external-delta-parent = yes
# benchmark.variants.revs = any-1-extra-rev
with-populate: 0.771919
no-populate: 0.792025 (+2.60%, +0.02)
# benchmark.variants.revs = any-100-extra-rev
with-populate: 1.459518
no-populate: 1.481290 (+1.49%, +0.02)
For mozilla-try, the "slow down" from pre-populate for small `hg log` is more
visible, but still small in absolute time. (using rust value for the persistent
nodemap value to be relevant).
### data-env-vars.name = mozilla-try-2019-02-18-ds2-pnm
# benchmark.name = hg.command.log
# bin-env-vars.hg.flavor = rust
# benchmark.variants.patch = yes
# benchmark.variants.limit-rev = 1
with-populate: 0.237813
no-populate: 0.229452 (-3.52%, -0.01)
# benchmark.variants.limit-rev = 10
# benchmark.variants.patch = yes
with-populate: 1.213578
no-populate: 1.205189
### data-env-vars.name = mozilla-try-2019-02-18-zstd-sparse-revlog
# benchmark.variants.limit-rev = 1000
# benchmark.variants.patch = no
# benchmark.variants.rev = tip
with-populate: 0.198607
no-populate: 0.195038 (-1.80%, -0.00)
However pre-populating provide a significant boost on more complex operations
like unbundle or push:
### data-env-vars.name = mozilla-try-2019-02-18-zstd-sparse-revlog
# benchmark.name = hg.command.push
# benchmark.variants.explicit-rev = none
# benchmark.variants.
issue6528 = disabled
# benchmark.variants.protocol = ssh
# benchmark.variants.reuse-external-delta-parent = yes
# benchmark.variants.revs = any-1-extra-rev
with-populate: 4.798632
no-populate: 4.953295 (+3.22%, +0.15)
# benchmark.variants.revs = any-100-extra-rev
with-populate: 4.903618
no-populate: 5.014963 (+2.27%, +0.11)
## benchmark.name = hg.command.unbundle
# benchmark.variants.revs = any-1-extra-rev
with-populate: 1.423411
no-populate: 1.585365 (+11.38%, +0.16)
# benchmark.variants.revs = any-100-extra-rev
with-populate: 1.537909
no-populate: 1.688489 (+9.79%, +0.15)
Matt Harbison <matt_harbison@yahoo.com> [Thu, 11 Jul 2024 11:10:40 -0400] rev 51680
win32mbcs: use str for encoding value
This was reported to the TortoiseHg tracker as:
https://foss.heptapod.net/mercurial/tortoisehg/thg/-/issues/5980
It doesn't look like we have any tests for this extension, but the explicit
type hints are enough to convince pytype that the module level `_encoding` attr
is str. The `encode()` and `decode()` methods are too complex to add type hints
for them.
Matt Harbison <matt_harbison@yahoo.com> [Wed, 10 Jul 2024 18:44:55 -0400] rev 51679
typing: add a trivial type hint to `mercurial/vfs.py`
Since hg
3dbc7b1ecaba, pytype stopped seeing the return value of `rmtree` as
`None`, and substituted `Any`.
Matt Harbison <matt_harbison@yahoo.com> [Wed, 10 Jul 2024 18:34:47 -0400] rev 51678
typing: add a few trivial type hints to `mercurial/templater.py`
Since hg
3dbc7b1ecaba, pytype started inferring that the second value in the
tuple is `BinaryIO`, but still hasn't been able to figure out the rest of
`open_template()`. We can be more precise.
Matt Harbison <matt_harbison@yahoo.com> [Wed, 10 Jul 2024 18:19:32 -0400] rev 51677
typing: add a few type hints to `mercurial/revlog.py`
Somewhere between hg
3dbc7b1ecaba and hg
8e3f6b5bf720, pytype stopped being able
to infer the type for `_docket_file` and `compress()`. Lock those types in
before they get lost.
Matt Harbison <matt_harbison@yahoo.com> [Wed, 10 Jul 2024 18:05:40 -0400] rev 51676
typing: add a trivial type hint to `mercurial/posix.py` to avoid an @overload
Since hg
3dbc7b1ecaba, pytype added an `@overload` for this function, without a
type on the parameter. That's wrong, and undermines the hints on the
non-trivial functions.
Matt Harbison <matt_harbison@yahoo.com> [Wed, 10 Jul 2024 17:55:14 -0400] rev 51675
typing: add some trivial type hints to `mercurial/match.py`
These were new methods since hg
3dbc7b1ecaba, but surprisingly pytype couldn't
figure them out.
Matt Harbison <matt_harbison@yahoo.com> [Wed, 10 Jul 2024 17:44:49 -0400] rev 51674
typing: add a type hint to `mercurial/hg.py`
Somewhere between hg
3dbc7b1ecaba and hg
8e3f6b5bf720, the first value of the
tuple changed from bytes to str. Let's lock this in, so that pytype flags it
if someone mistakenly adds a tuple with bytes somewhere.
Matt Harbison <matt_harbison@yahoo.com> [Wed, 10 Jul 2024 17:37:35 -0400] rev 51673
typing: restore `encoding.encoding` and `encoding.encodingmode` to bytes
Somewhere between hg
3dbc7b1ecaba and hg
8e3f6b5bf720, pytype determined the
signature of these fields changed from `bytes` to `Any`. Not sure why- the type
of `environ` then and now is: `Union[WindowsEnviron, Dict[bytes, bytes], os._Environ[bytes]]`
That said, PyCharm wasn't able to figure out the type of `environ`, and the
`WindowsEnviron` class extends `MutableMapping` without specifying bytes for the
key and value types in py3.9. But that's not changed in my setup, so I can't
explain it.
Matt Harbison <matt_harbison@yahoo.com> [Wed, 10 Jul 2024 17:16:19 -0400] rev 51672
typing: add some trivial type hints to `mercurial/bundlecaches.py`
The function is meant for extensions, but it wasn't obvious what was expected
without looking through the code. Also, pytype couldn't figure it out either.
Matt Harbison <matt_harbison@yahoo.com> [Wed, 10 Jul 2024 17:09:34 -0400] rev 51671
typing: add some type hints for bundle2 capabilities
Somewhere between hg
3dbc7b1ecaba and hg
8e3f6b5bf720, pytype determined the
signature of `bundle20.capabilities` changed from `Dict[bytes, Tuple[bytes]]` to
`Dict[bytes, Union[List[bytes], Tuple[bytes]]]`.
First, I did try to simply be explicit about the previously inferred type, but
it does seem to mix and match list/tuple now (e.g. in `writenewbundle()`). I
tried changing the new list usage to tuple, but a couple of things complained,
(and I think lists of one item are a little more clear to read anyway). So then
I typed the dict value as `Sequence[bytes]`, which worked fine. But there's
also a module level `capabilities` field, and when that's typed, pytype
complains about `Sequence[bytes]` lacking `__add__`[1]. So I gave up, and just
assigned it the type it wanted, with an alias. If somebody feels motivated to
make the type consistent, it's simple enough to change the alias.
The mutable default value to the constructor was removed to appease PyCharm's
type checking on the field. (I didn't bother running the code through pytype
prior to changing it, because we've previously made an effort to remove this
pattern anyway.)
I'm not sure why `getrepocaps()` has a default value for `role` that apparently
raises an exception. It's just flagged for now so this series can land without
risking additional problems.
[1] https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/2466903
Matt Harbison <matt_harbison@yahoo.com> [Wed, 10 Jul 2024 16:04:53 -0400] rev 51670
typing: add a few type hints to `mercurial/utils/urlutil.py`
Somewhere between hg
3dbc7b1ecaba and hg
8e3f6b5bf720, `_pathsuboptions` changed
from `Dict[bytes, Tuple[bytes, Any]]` to `Dict[bytes, Tuple[str, Any]]`, and it
caught my attention from diffing the local *.pyi files. The change is correct
based on the assertion, so let's get pytype to check for this instead of relying
on the assertion alone.
Matt Harbison <matt_harbison@yahoo.com> [Wed, 10 Jul 2024 15:49:16 -0400] rev 51669
typing: add type hints to `mercurial/utils/resourceutil.py`
The `except` path requires byte args (because of the byte based manipulation in
`_package_path()`), while the `else` case tolerates `AnyStr`. Pytype was unable
to figure this out, and we should make sure the interface is the same for all
environments.
Anton Shestakov <av6@dwimlabs.net> [Fri, 12 Jul 2024 15:29:35 +0400] rev 51668
copyright: update to 2024
Raphaël Gomès <rgomes@octobus.net> [Mon, 08 Jul 2024 17:56:54 +0200] rev 51666
branching: merge stable into default for 6.9 cycle
Raphaël Gomès <rgomes@octobus.net> [Mon, 08 Jul 2024 17:52:08 +0200] rev 51665
Added signature for changeset
11f41248595b
Raphaël Gomès <rgomes@octobus.net> [Mon, 08 Jul 2024 17:51:56 +0200] rev 51664
Added tag 6.8 for changeset
11f41248595b
Raphaël Gomès <rgomes@octobus.net> [Mon, 08 Jul 2024 17:51:04 +0200] rev 51663
relnotes: add 6.8
Pierre-Yves David <pierre-yves.david@octobus.net> [Mon, 08 Jul 2024 16:44:07 +0200] rev 51662
test-check: don't report distutils as a local import
On python 3.12 this is wrongly reported as a local import. So we adjust the
checker to avoid it.
Raphaël Gomès <rgomes@octobus.net> [Mon, 08 Jul 2024 16:20:04 +0200] rev 51661
Backed out changeset
f28c52a9f7b4
This backout and the previous are due to a large performance regression
detected in repositories with a lot of obsmarkers when performing a clone.
A better fix will come along at the start of the next cycle.
Raphaël Gomès <rgomes@octobus.net> [Mon, 08 Jul 2024 16:19:33 +0200] rev 51660
Backed out changeset
ff523675cd69
Raphaël Gomès <rgomes@octobus.net> [Mon, 08 Jul 2024 16:02:54 +0200] rev 51659
rust: use `cpython` 0.7.2 crate to add support for Python 3.12
This will give us more headroom until we can migrate to PyO3 some day.
Pierre-Yves David <pierre-yves.david@octobus.net> [Mon, 08 Jul 2024 15:52:01 +0200] rev 51658
revbranchcache: disable mmap access by default
The revbranchcache can be truncated (if some part of it is detected as invalid).
Using mmap on file we truncate is not an option at access to truncated part
would result in a SIGBUS signal.
So we disable the mmap by default until we fix this issue.
Joerg Sonnenberger <joerg@bec.de> [Mon, 24 Jun 2024 18:54:59 +0200] rev 51657
portability: fix build on Solaris-derived systemd
Current Illumos and older Solaris require _XOPEN_SOURCE for
msg_control. O_DIRECTORY doesn't exist on older systems either,
so fallback to O_RDONLY. It's good enough as a repository will
require both R and X permission anyway.
Pierre-Yves David <pierre-yves.david@octobus.net> [Wed, 03 Jul 2024 12:32:57 +0200] rev 51656
mmap: only use mmap to read revlog persistent nodemap if it is safe
Cf `is_mmap_safe` docstring.
Pierre-Yves David <pierre-yves.david@octobus.net> [Wed, 03 Jul 2024 12:47:08 +0200] rev 51655
mmap: fix another instance of reverse mmap logic in persistent nodemap
This fix the same kind of issue as
85d96517e650
Pierre-Yves David <pierre-yves.david@octobus.net> [Wed, 03 Jul 2024 12:31:21 +0200] rev 51654
mmap: only use mmap to read rev-branch-cache data if it is safe
Cf `is_mmap_safe` docstring.
Pierre-Yves David <pierre-yves.david@octobus.net> [Wed, 03 Jul 2024 12:26:57 +0200] rev 51653
mmap: only use mmap to read revlog index if it is safe
Cf `is_mmap_safe` docstring.
Pierre-Yves David <pierre-yves.david@octobus.net> [Wed, 03 Jul 2024 12:22:48 +0200] rev 51652
mmap: add a `is_mmap_safe` method to vfs
This will be useful to safeguard mmap usage to void SIGBUS when repositories
lives on a NFS drive.
Raphaël Gomès <rgomes@octobus.net> [Mon, 24 Jun 2024 13:15:46 +0200] rev 51651
branching: merge stable into default
Raphaël Gomès <rgomes@octobus.net> [Mon, 24 Jun 2024 13:14:05 +0200] rev 51650
Added signature for changeset
6454c117c6a4
Raphaël Gomès <rgomes@octobus.net> [Mon, 24 Jun 2024 13:14:04 +0200] rev 51649
Added tag 6.8rc0 for changeset
6454c117c6a4
Raphaël Gomès <rgomes@octobus.net> [Mon, 24 Jun 2024 12:05:31 +0200] rev 51648
branching: merge default into stable for 6.8rc0
Raphaël Gomès <rgomes@octobus.net> [Mon, 24 Jun 2024 12:04:14 +0200] rev 51647
relnotes: add 6.8rc0
Raphaël Gomès <rgomes@octobus.net> [Mon, 24 Jun 2024 10:52:46 +0200] rev 51646
branch3: use an explicitely experimental name for files
Since this format is still experimental, we don't want to have to side-step
the `branch3` name in case people do start using it before it's stable.
Joerg Sonnenberger <joerg@bec.de> [Mon, 24 Jun 2024 03:16:52 +0200] rev 51645
obsolete: simplify relevantmarker
Drop duplicate assignment from a merge failure. Save
one loop iteration by exploiting that pendingnodes will
be seennodes after the first round anyway, so just
pre-initialize the set accordingly. From Anton Shestakov's
review on !867. Performance difference for my test case is
in the noise.
Joerg Sonnenberger <joerg@bec.de> [Tue, 11 Jun 2024 18:47:50 +0200] rev 51644
exchange: improve computation of relevant markers for large repos
Find the candidates for nodes with relevant markers by going over
all markers instead of iterating over all nodes. Most nodes will
not have markers anyway.
Further optimize the code by allowing revsets as well, which reduces the
materialization cost.
Pierre-Yves David <pierre-yves.david@octobus.net> [Thu, 13 Jun 2024 09:52:39 +0200] rev 51643
test: better glob some timing related line to avoid flakiness
If we go over 10 seconds, the number of white space changes.
Raphaël Gomès <rgomes@octobus.net> [Wed, 12 Jun 2024 11:29:11 +0200] rev 51642
branching: merge stable into default
Raphaël Gomès <rgomes@octobus.net> [Wed, 12 Jun 2024 11:27:01 +0200] rev 51641
Added signature for changeset
a1a011d4b148
Raphaël Gomès <rgomes@octobus.net> [Wed, 12 Jun 2024 11:26:57 +0200] rev 51640
Added tag 6.7.4 for changeset
a1a011d4b148
Raphaël Gomès <rgomes@octobus.net> [Wed, 12 Jun 2024 11:25:49 +0200] rev 51639
relnotes: add 6.7.4 and warn about 6.7.{1,2,3}
Pierre-Yves David <pierre-yves.david@octobus.net> [Wed, 12 Jun 2024 02:16:14 +0200] rev 51638
inline-changelog: fix pending transaction visibility when splitting
We move the name back to the expected name of `changelog.i.a`.
Pierre-Yves David <pierre-yves.david@octobus.net> [Wed, 12 Jun 2024 02:15:20 +0200] rev 51637
inline-changelog: fix a critical bug in write_pending that delete data
Since
a93e52f0b6ff we no longer use inline-revlog for the changelog. The goal there was to
solve the lack of testing for the two variants (inline vs split) and reduce the
complexity of the interaction with "diverted-write" on the changelog level.
However many existing repository still have inline-changelog and we
automatically move them to normal revlog as soon as we have the chances.
Unfortunately This conversion is buggy and can result in the destruction of the
changelog.i if hook triggers the "write pending" mechanism.
The bugs comes from the "revlog splitting" logic and the "write_pending" logic
stepping over each other. Ironically the change in
a93e52f0b6ff aims at no
longer having this kind of problem.
This changesets fix this issue and add associated tests.
Fixing this reveal that the transaction hooks end up not seeing the pending
transaction content, because the name is not right ("changelog.i.s.a" instead of
"changelog.i.s") we fix this in the next changeset.
Pierre-Yves David <pierre-yves.david@octobus.net> [Tue, 11 Jun 2024 03:05:20 +0200] rev 51636
bookmark: fix remote bookmark deletion when the push is raced
Before this patch, running `hg push -B book` to push the `book` bookmark
sideway at the same time as a commit making it moving forward might result in
the removal of the bookmark remotely.
After this changeset, the push can still be raced, but to remove deletion
happens. This is progress.
Pierre-Yves David <pierre-yves.david@octobus.net> [Tue, 11 Jun 2024 03:03:47 +0200] rev 51635
hooks: add a prewlock and a prelock hooks
This is useful for testing.
Pierre-Yves David <pierre-yves.david@octobus.net> [Tue, 11 Jun 2024 11:14:13 +0200] rev 51634
exchange: fix locking to actually be scoped
The previous code was taking locks before entering with statements, so
exception before the with statement would not release the lock (except for
garbage collection).
We need to move to a try except here because the logic is more complicated.
Pierre-Yves David <pierre-yves.david@octobus.net> [Tue, 11 Jun 2024 11:13:36 +0200] rev 51633
exchange: fix locking to actually be scoped
The previous code was taking locks before entering with statements, so
exception before the with statement would not release the lock (except for
garbage collection).
Pierre-Yves David <pierre-yves.david@octobus.net> [Wed, 06 Sep 2023 18:23:32 +0200] rev 51632
narrow: add a test for linkrev computation done during widen
This new tests show that the linkrev computed and sent by the server might end
up being wrong during a widen operation.
Joerg Sonnenberger <joerg@bec.de> [Mon, 10 Jun 2024 13:45:57 +0200] rev 51631
obsolete: quote the feature name
This makes it at least somewhat clearer that hg is talking about some
specific feature and not just outdated code.
Pierre-Yves David <pierre-yves.david@octobus.net> [Mon, 10 Jun 2024 12:12:56 +0200] rev 51630
branching: merge stable into default
Raphaël Gomès <rgomes@octobus.net> [Mon, 10 Jun 2024 10:59:44 +0200] rev 51629
rust-status: sort the failed matches when printing them
This was making the tests flaky after the recent patch¹ that opened up
more of the code to the Rust-augmented status.
[1]
865efc020c3355dca1cbaa35db80600009c01dd5
Julien Cristau <jcristau@mozilla.com> [Thu, 23 May 2024 11:05:11 +0200] rev 51628
clonebundles: add missing newline to legacy response
This seems to have been removed in 6.5 (likely by
60f9602b413e).
Anton Shestakov <av6@dwimlabs.net> [Tue, 07 May 2024 15:15:41 +0400] rev 51627
chistedit: change action for the correct item
We have an experimental config histedit.later-commits-first from
c820866c52f9,
and when it's true, the order of commits in histedit UI is reversed, both in
text mode and in curses mode.
But before this patch key presses in curses mode would change histedit actions
in the same old order, i.e. trying to edit the latest commit (which would be
first now) would put "edit" action on the last commit in the list. This wasn't
a cosmetic issue, histedit would actually proceed to edit the first commit in
the list.
Let's map rules to display items (hopefully now correctly).
Arseniy Alekseyev <aalekseyev@janestreet.com> [Fri, 26 Apr 2024 19:10:35 +0100] rev 51626
dirstate: remove the python-side whitelist of allowed matchers
This whitelist is too permissive because it allows matchers that contain
disallowed ones deep inside, for example through `intersectionmatcher`.
It is also too restrictive because it doesn't pass through
some of the matchers we support, such as `patternmatcher`.
It's also unnecessary because unsupported matchers raise
`FallbackError` and we fall back anyway.
Making this change makes more of the tests use rust code path,
and therefore subtly change behavior. For example, rust status
in largefiles repos seems to have strange behavior.
Arseniy Alekseyev <aalekseyev@janestreet.com> [Fri, 26 Apr 2024 18:53:02 +0100] rev 51625
match: make `was_tampered_with` work recursively
This is useful if we are to use it outside of Rust, when
deciding whether or not to do some fast-path operation with
a given matcher.
Arseniy Alekseyev <aalekseyev@janestreet.com> [Fri, 26 Apr 2024 19:43:42 +0100] rev 51624
largefiles: mark more matchers as having been tampered with
These happened to slip through the cracks earlier because they
weren't caught by tests. Now that we're enabling rust fast path
more widely these start breaking.
Raphaël Gomès <rgomes@octobus.net> [Mon, 06 May 2024 18:50:21 +0200] rev 51623
branching: merge stable into default
Raphaël Gomès <rgomes@octobus.net> [Mon, 06 May 2024 18:48:37 +0200] rev 51622
Added signature for changeset
028dc3f92dbd
Raphaël Gomès <rgomes@octobus.net> [Mon, 06 May 2024 18:48:34 +0200] rev 51621
Added tag 6.7.3 for changeset
028dc3f92dbd
Raphaël Gomès <rgomes@octobus.net> [Mon, 06 May 2024 17:51:21 +0200] rev 51620
relnotes: add 6.7.3
Georges Racinet <georges.racinet@octobus.net> [Mon, 22 Apr 2024 19:47:08 +0200] rev 51619
rust: blanket implementation of Graph for Graph references
The need comes from the fact that `AncestorsIterator` and many
Graph-related algorithms take ownership of the `Graph` they work with.
This, in turn is due to them needing to accept the `Index` instances
that are provided by the Python layers (that neither rhg nor `RHGitaly`
use, of course): the fact that nowadays the Python layer holds an object
that is itself implemented in Rust does not change the core problem that
they cannot be tracked by the borrow checker.
Even though it looks like cloning `Changelog` would be cheap, it seems
hard to guarantee that on the long run. The object is already too rich
for us to be comfortable with it, when using references is the most
natural and guaranteed way of proceeding.
The added test seems a bit superfleous, but it will act as a reminder
that this feature is really useful until something in the Mercurial code
base actually uses it.
Raphaël Gomès <rgomes@octobus.net> [Mon, 06 May 2024 15:30:21 +0200] rev 51618
rust-cpython: don't swallow the dirstate error message
In case we do get a dirstate error, we want to get the full error message and
not just an opaque `Dirstate error`.
Raphaël Gomès <rgomes@octobus.net> [Mon, 06 May 2024 13:07:02 +0200] rev 51617
dirstate-v2: check that root nodes are at the root before writing
More explanations in the previous changeset.
Raphaël Gomès <rgomes@octobus.net> [Mon, 06 May 2024 13:02:52 +0200] rev 51616
dirstate-v2: add check of parent/child nodes being related when writing
This stems from a corruption seen in a private repository. We're not sure
of the source of the corruption, and it's very possible that we're seeing
compounded effects of multiple writes on a corrupted dirstate.
Adding this check is not expensive in itself and large writes of the dirstate
are not common.
This change does not catch this problem at the root node, the next one will.
Raphaël Gomès <rgomes@octobus.net> [Mon, 06 May 2024 16:29:00 +0200] rev 51615
admin-verify: expect a number of errors to be returned
It's the responsibility of the check to handle errors, we only care about
the total count to sum up the check's work.
We use `admin::verify -c dirstate` to test this path at least somewhat.
Raphaël Gomès <rgomes@octobus.net> [Mon, 06 May 2024 16:16:15 +0200] rev 51614
admin-verify: fix error message handling
`dirstate.verify` used to return tuples but does not anymore, it returns
the pre-formatted error message, which is a nicer interface anyway.
Raphaël Gomès <rgomes@octobus.net> [Mon, 06 May 2024 12:31:29 +0200] rev 51613
admin-verify: pass p1 down to the dirstate function
This was forgotten and can break with certain kinds of corruption.
Raphaël Gomès <rgomes@octobus.net> [Mon, 06 May 2024 11:27:29 +0200] rev 51612
Backed out changeset
3e0f86f09f26
Raphaël Gomès <rgomes@octobus.net> [Mon, 06 May 2024 11:26:52 +0200] rev 51611
Backed out changeset
fc317bd5b637
Pierre-Yves David <pierre-yves.david@octobus.net> [Thu, 02 May 2024 02:20:42 +0200] rev 51610
re2: make errors quiet
By default, the re2 library will output error on its own instead of keeping the
error in an exception. This make re2 printing spurious error before fallback to
the stdlib remodule that may accept the pattern or also fails to parse it and
raise a proper error that will be handled by Mercurial.
So we also pass an Option object that changes this default.
Pierre-Yves David <pierre-yves.david@octobus.net> [Thu, 02 May 2024 08:46:58 +0200] rev 51609
fold-or-prune-me: update proposal
This does the same things but with a narrower wrapping.
Felipe Resende <felipe@fcresende.dev.br> [Sun, 31 Mar 2024 17:57:46 -0300] rev 51608
subrepo: propagate non-default path on outgoing
There was already a fix made in
5dbff89cf107 for pull and push commands. I did
the same for the outgoing command.
The problem I identified is that when the parent repository has multiple paths,
the outgoing command was not respecting the parent path used and was always
using the default path for subrepositories.
Hraban Luyat <hraban@0brg.net> [Tue, 26 Mar 2024 01:27:27 -0400] rev 51607
hgrc: search XDG_CONFIG_HOME on mac
Searching for hgrc was special cased not to look through ~/.config/hg on Mac,
but that’s unnecessary: Macs support it as do other unix based systems. There
are plenty tools that use it there, e.g. git, and people expect it to work, e.g.
"https://stackoverflow.com/questions/
72499837/mercurial-on-macos-doesnt-read-config-hg-hgrc".
Initial code introduced in
354020079723.
Raphaël Gomès <rgomes@octobus.net> [Tue, 16 Apr 2024 09:51:11 +0200] rev 51606
base-revsets: use an author that actually exercises a lot of changesets
This was caught in my big find-and-replace:
d4ba4d51f85f.
The point of `base-revsets` is to give revsets that will give a good coverage
of the repository. Using Pierre-Yves as the second largest committer
(in terms of number of changesets) seems like a good idea.
Arseniy Alekseyev <aalekseyev@janestreet.com> [Tue, 16 Apr 2024 17:21:37 +0100] rev 51605
match: simplify the rust-side file pattern kind parsing
There's no need to add the ':' characters if
we're simply pattern matching against constants next.
Arseniy Alekseyev <aalekseyev@janestreet.com> [Tue, 16 Apr 2024 13:51:45 +0100] rev 51604
match: share code between includematcher and patternmatcher
No need to have this duplication.
Arseniy Alekseyev <aalekseyev@janestreet.com> [Fri, 05 Apr 2024 17:57:26 +0100] rev 51603
matchers: support patternmatcher in rust
Arseniy Alekseyev <aalekseyev@janestreet.com> [Tue, 09 Apr 2024 11:12:24 +0100] rev 51602
match: avoid rust fast path if the matcher was tampered with
Otherwise the fast path does not respect the modifications made
by the extension (concretely largefiles, but other extensions can
start using that too)
Arseniy Alekseyev <aalekseyev@janestreet.com> [Tue, 09 Apr 2024 11:00:52 +0100] rev 51601
largefiles: track if a matcher was tampered with
This is used to make sure rust fast path is not taken for the
modified matchers.
Raphaël Gomès <rgomes@octobus.net> [Wed, 17 Apr 2024 12:28:48 +0200] rev 51600
branching: merge stable into default
Pierre-Yves David <pierre-yves.david@octobus.net> [Wed, 13 Mar 2024 12:02:06 +0100] rev 51599
tags-cache: directly perform a monimal walk for hgtagsfnodescache warming
We do something narrower than the path retrieving data. So lets use dedicated
code instead.
This provides further useful speedup:
### data-env-vars.name = mozilla-try-2023-03-22-zstd-sparse-revlog
# benchmark.name = hg.debug.debug-update-cache
# bin-env-vars.hg.flavor = default
# bin-env-vars.hg.py-re2-module = default
# benchmark.variants.pre-state = warm
before-this-series: 19.947581
skip-fnode-filter: 18.916804 (-5.17%, -1.03)
use-rev-num: 17.493725 (-12.30%, -2.45)
this-changesets: 15.919466 (-20.19%, -4.03)
Pierre-Yves David <pierre-yves.david@octobus.net> [Wed, 13 Mar 2024 11:51:11 +0100] rev 51598
tags-cache: directly operate on rev-num warming hgtagsfnodescache
Not having to goes through nodeid speed up things notably.
### data-env-vars.name = mozilla-try-2023-03-22-zstd-sparse-revlog
# benchmark.name = hg.debug.debug-update-cache
# bin-env-vars.hg.flavor = default
# bin-env-vars.hg.py-re2-module = default
# benchmark.variants.pre-state = warm
before-this-series: 19.947581
before-this-changes: 18.916804 (-5.17%, -1.03)
this-changesets: 17.493725 (-12.30%, -2.45)
Pierre-Yves David <pierre-yves.david@octobus.net> [Wed, 13 Mar 2024 11:38:28 +0100] rev 51597
tags-cache: skip the filternode step if we are not going to use it
When warming the hgtagsfnodescache, we don't need the actual result, so we can
simply skip the part that "filter" fnode we read from the cache. So provide a
quite visible speed up to the top level `hg debugupdatecache` function.
### data-env-vars.name = mozilla-try-2023-03-22-zstd-sparse-revlog
# benchmark.name = hg.debug.debug-update-cache
# bin-env-vars.hg.flavor = default
# bin-env-vars.hg.py-re2-module = default
# benchmark.variants.pre-state = warm
before: 19.947581
after: 18.916804 (-5.17%, -1.03)
Pierre-Yves David <pierre-yves.david@octobus.net> [Wed, 13 Mar 2024 11:34:21 +0100] rev 51596
tags-cache: add a dedicated warm cache function to hgtagsfnodescache
Having a dedicated API point will help to optimize that specific usage. Right
doing a full phases weam takes a long time, even when the cache is already
filled.
Pierre-Yves David <pierre-yves.david@octobus.net> [Tue, 09 Apr 2024 22:37:15 +0200] rev 51595
outgoing: add a simple fastpath when there is no common
This further speed up case like `hg bundle --all` for larger repository.
### data-env-vars.name = mozilla-try-2023-03-22-zstd-sparse-revlog
# benchmark.name = hg.command.bundle
# bin-env-vars.hg.flavor = default
# bin-env-vars.hg.py-re2-module = default
# benchmark.variants.revs = all
# benchmark.variants.type = none-streamv2
before: 316.749699
after: 311.165461 (-1.76%, -5.58)
There is further work to be done in this area like not doing any outgoing
computation in the stream case for example. however the recent changes already
gives use a large win for a small amount of local work.
### benchmark.name = hg.command.bundle
# bin-env-vars.hg.flavor = default
# bin-env-vars.hg.py-re2-module = default
# benchmark.variants.revs = all
# benchmark.variants.type = none-streamv2
## data-env-vars.name = mercurial-public-2024-03-22-zstd-sparse-revlog
pre-%ln-change: 1.263859
the-%ln-change: 0.700229 (-44.60%, -0.56)
prev-changeset: 0.496050 (-60.75%, -0.77)
this-changeset: 0.495243 (-60.81%, -0.77)
## data-env-vars.name = tryton-public-2024-03-22-zstd-sparse-revlog
pre-%ln-change: 2.975765
the-%ln-change: 1.870798 (-37.13%, -1.10)
prev-changeset: 1.461583 (-50.88%, -1.51)
this-changeset: 1.469185 (-50.63%, -1.51)
## data-env-vars.name = pypy-2024-03-22-zstd-sparse-revlog
pre-%ln-change: 4.540080
the-%ln-change: 3.401700 (-25.07%, -1.14)
prev-changeset: 2.915810 (-35.78%, -1.62)
this-changeset: 2.911643 (-35.87%, -1.63)
## data-env-vars.name = heptapod-public-2024-03-25-zstd-sparse-revlog
pre-%ln-change: 10.138396
the-%ln-change: 7.750458 (-23.55%, -2.39)
prev-changeset: 6.665565 (-34.25%, -3.47)
this-changeset: 6.672078 (-34.19%, -3.47)
## data-env-vars.name = mozilla-try-2023-03-22-zstd-sparse-revlog
pre-%ln-change: 399.484481
the-%ln-change: 346.508952 (-13.26%, -52.98)
prev-changeset: 316.749699 (-20.71%, -82.73)
this-changeset: 311.165461 (-22.11%, -88.32)
Pierre-Yves David <pierre-yves.david@octobus.net> [Tue, 09 Apr 2024 22:36:35 +0200] rev 51594
outgoing: rework the handling of the `missingroots` case to be faster
The previous implementation was slow, to the point it was taking a significant
amount of `hg bundle --type none-streamv2` call. We rework the code to compute
the same value much faster, making the operation disappear from the `hg bundle
--type none-streamv2` profile. Someone would remark that producing a streamclone
does not requires an `outgoing` object. However that is a matter for another
day. There is other user of `missingroots` (non stream `hg bundle` call for
example), and they will also benefit from this rework.
We implement an old TODO in the process, directly computing the missing and
common attribute as we have most element at hand already.
### benchmark.name = hg.command.bundle
# bin-env-vars.hg.flavor = default
# bin-env-vars.hg.py-re2-module = default
# benchmark.variants.revs = all
# benchmark.variants.type = none-streamv2
## data-env-vars.name = heptapod-public-2024-03-25-zstd-sparse-revlog
before: 7.750458
after: 6.665565 (-14.00%, -1.08)
## data-env-vars.name = mercurial-public-2024-03-22-zstd-sparse-revlog
before: 0.700229
after: 0.496050 (-29.16%, -0.20)
## data-env-vars.name = mozilla-try-2023-03-22-zstd-sparse-revlog
before: 346.508952
after: 316.749699 (-8.59%, -29.76)
## data-env-vars.name = pypy-2024-03-22-zstd-sparse-revlog
before: 3.401700
after: 2.915810 (-14.28%, -0.49)
## data-env-vars.name = tryton-public-2024-03-22-zstd-sparse-revlog
before: 1.870798
after: 1.461583 (-21.87%, -0.41)
note: this whole `missingroots` of outgoing has a limited number of callers and
could likely be replace by something simpler (like taking an explicit
"missing_revs" set for example). However this is a wider change and we focus on
a small impact, quick rework that does not change the API for now.
Pierre-Yves David <pierre-yves.david@octobus.net> [Sun, 14 Apr 2024 02:27:10 +0200] rev 51593
proxy-vfs: also proxy the `audit` attribute
In the previous changeset, we had to do a little dance to access the useful
`audit` attribute. We now provide a proper accessors to it.
We don't update the code in `perf.py` because it has to remain compatible with
older version of Mercurial. This will just be nicer in the future.
Pierre-Yves David <pierre-yves.david@octobus.net> [Sat, 13 Apr 2024 23:40:28 +0200] rev 51592
perf: clear vfs audit_cache before each run
When generating a stream clone, we spend a large amount of time auditing path.
Before this changes, the first run was warming the vfs cache for the other
runs, leading to a large runtime difference and a "faulty" reported timing for
the operation.
We now clear this important cache between run to get a more realistic timing.
Below are some example of median time change when clearing these cases. The
maximum time for a run did not changed significantly.
### data-env-vars.name = mozilla-central-2018-08-01-zstd-sparse-revlog
# benchmark.name = hg.perf.exchange.stream.generate
# bin-env-vars.hg.flavor = default
# bin-env-vars.hg.py-re2-module = default
# benchmark.variants.version = latest
no-clearing: 17.289905
cache-clearing: 21.587965 (+24.86%, +4.30)
## data-env-vars.name = mozilla-central-2024-03-22-zstd-sparse-revlog
no-clearing: 32.670748
cache-clearing: 40.467095 (+23.86%, +7.80)
## data-env-vars.name = mozilla-try-2019-02-18-zstd-sparse-revlog
no-clearing: 37.838858
cache-clearing: 46.072749 (+21.76%, +8.23)
## data-env-vars.name = mozilla-unified-2024-03-22-zstd-sparse-revlog
no-clearing: 32.969395
cache-clearing: 39.646209 (+20.25%, +6.68)
In addition, this significantly reduce the timing difference between the
performance command, from the perf extensions and a `real `hg bundle` call
producing a stream bundle. Some significant differences remain especially on
the "mozilla-try" repositories, but they are now smaller.
Note that some of that difference will actually not be
attributable to the stream generation (like maybe phases or branch map
computation).
Below are some benchmarks done on a currently draft changeset fixing some
unrelated slowness in `hg bundle` (
34a78972af409d1ff37c29e60f6ca811ad1a457d)
### data-env-vars.name = mozilla-central-2018-08-01-zstd-sparse-revlog
# bin-env-vars.hg.flavor = default
# bin-env-vars.hg.py-re2-module = default
hg.perf.exchange.stream.generate: 21.587965
hg.command.bundle: 24.301799 (+12.57%, +2.71)
## data-env-vars.name = mozilla-central-2024-03-22-zstd-sparse-revlog
hg.perf.exchange.stream.generate: 40.467095
hg.command.bundle: 44.831317 (+10.78%, +4.36)
## data-env-vars.name = mozilla-unified-2024-03-22-zstd-sparse-revlog
hg.perf.exchange.stream.generate: 39.646209
hg.command.bundle: 45.395258 (+14.50%, +5.75)
## data-env-vars.name = mozilla-try-2019-02-18-zstd-sparse-revlog
hg.perf.exchange.stream.generate: 46.072749
hg.command.bundle: 55.882608 (+21.29%, +9.81)
## data-env-vars.name = mozilla-try-2023-03-22-zlib-general-delta
hg.perf.exchange.stream.generate: 334.716708
hg.command.bundle: 377.856767 (+12.89%, +43.14)
## data-env-vars.name = mozilla-try-2023-03-22-zstd-sparse-revlog
hg.perf.exchange.stream.generate: 302.972301
hg.command.bundle: 326.098755 (+7.63%, +23.13)
Pierre-Yves David <pierre-yves.david@octobus.net> [Sun, 14 Apr 2024 02:41:36 +0200] rev 51591
perf: start recording total time after warming
The warming might be costly and this should not affect the "time profile" of the
actual collection.
Pierre-Yves David <pierre-yves.david@octobus.net> [Sun, 14 Apr 2024 02:40:15 +0200] rev 51590
perf: run the gc before each run
The python garbage collector is a large source of performance troubles, we run
it right before the timed section to reduce the change for the gc to add noise
to the benchmark.
Pierre-Yves David <pierre-yves.david@octobus.net> [Sun, 14 Apr 2024 02:38:41 +0200] rev 51589
perf: allow profiling of more than one run
By default, we still profile the first run only. However profiling more run help
to understand side effect from one run to the other. So we add an option to be
able to do so.
Pierre-Yves David <pierre-yves.david@octobus.net> [Sun, 14 Apr 2024 02:36:55 +0200] rev 51588
profiler: flush after writing the profiler output
Otherwise, the profiler output might only partially appears until the next flush
of the buffer. Since profiling often happens for long operation, the next flush
can be a long time away.
Pierre-Yves David <pierre-yves.david@octobus.net> [Sun, 14 Apr 2024 02:33:36 +0200] rev 51587
stream-clone: disable gc for the entry listing section for the v2 format
This is similar to the change we did for the v3 format in
6e4c8366c5ce.
The benchmark bellow show this gives us a notable gains, especially on larger
repositories.
### benchmark.name = hg.perf.stream-locked-section
# benchmark.name = hg.perf.stream-locked-section
# bin-env-vars.hg.flavor = default
# bin-env-vars.hg.py-re2-module = default
# benchmark.variants.version = v2
## data-env-vars.name = pypy-2018-08-01-zstd-sparse-revlog
5e931bf8707c: 0.503820 ~~~~~
1106d1bf695e: 0.470078 (-6.70%, -0.03)
## data-env-vars.name = pypy-2024-03-22-zstd-sparse-revlog
5e931bf8707c: 0.535756 ~~~~~
1106d1bf695e: 0.490249 (-8.49%, -0.05)
## data-env-vars.name = heptapod-public-2024-03-25-zstd-sparse-revlog
5e931bf8707c: 1.327041 ~~~~~
1106d1bf695e: 1.174636 (-11.48%, -0.15)
## data-env-vars.name = netbeans-2018-08-01-zstd-sparse-revlog
5e931bf8707c: 2.439158 ~~~~~
1106d1bf695e: 2.220515 (-8.96%, -0.22)
## data-env-vars.name = netbeans-2019-11-07-zstd-sparse-revlog
5e931bf8707c: 2.630794 ~~~~~
1106d1bf695e: 2.261473 (-14.04%, -0.37)
## data-env-vars.name = mozilla-central-2018-08-01-zstd-sparse-revlog
5e931bf8707c: 5.769002 ~~~~~
1106d1bf695e: 5.062000 (-12.26%, -0.71)
## data-env-vars.name = mozilla-try-2019-02-18-zstd-sparse-revlog
5e931bf8707c: 13.351750 ~~~~~
1106d1bf695e: 12.346655 (-7.53%, -1.01)
## data-env-vars.name = mozilla-central-2024-03-22-zstd-sparse-revlog
5e931bf8707c: 10.772939 ~~~~~
1106d1bf695e: 9.495407 (-11.86%, -1.28)
## data-env-vars.name = mozilla-unified-2024-03-22-zstd-sparse-revlog
5e931bf8707c: 10.864297 ~~~~~
1106d1bf695e: 9.475597 (-12.78%, -1.39)
## data-env-vars.name = mozilla-try-2023-03-22-zstd-sparse-revlog
5e931bf8707c: 17.448335 ~~~~~
1106d1bf695e: 16.027474 (-8.14%, -1.42)
Pierre-Yves David <pierre-yves.david@octobus.net> [Tue, 09 Apr 2024 02:54:19 +0200] rev 51586
phases: rework the logic of _pushdiscoveryphase to bound complexity
This rework the various graph traversal in _pushdiscoveryphase to keep the
complexity in check.
This is done though a couple of things:
- first, limiting the space we have to explore, for example, if we are not in
publishing push, we don't need to consider remote draft roots that are also
draft locally, as there is nothing to be moved there.
- avoid unbounded descendant computation, and use the faster "rev between"
computation.
This provide a massive boost to performance when exchanging with repository with
a massive amount of draft, like mozilla-try:
### data-env-vars.name = mozilla-try-2023-03-22-zstd-sparse-revlog
# benchmark.name = hg.command.push
# bin-env-vars.hg.flavor = default
# bin-env-vars.hg.py-re2-module = default
# benchmark.variants.explicit-rev = all-out-heads
# benchmark.variants.
issue6528 = disabled
# benchmark.variants.protocol = ssh
# benchmark.variants.reuse-external-delta-parent = default
## benchmark.variants.revs = any-1-extra-rev
before: 20.346590 seconds
after: 11.232059 seconds (-38.15%, -7.48 seconds)
## benchmark.variants.revs = any-100-extra-rev
before: 24.752051 seconds
after: 15.367412 seconds (-37.91%, -9.38 seconds)
After this changes, the push operation is still quite too slow. Some of this
can be attributed to general phases slowness (reading all the roots from disk
for example) and other know slowness (not using persistent-nodemap, branchmap,
tags, etc. We are also working on them, but with this series, phase discovery
during push no longer showing up in profile and this is a pretty nice and bit
low-hanging fruit out of the way.
### (same case as the above)
# benchmark.variants.revs = any-1-extra-rev
pre-%ln-change: 44.235070
this-changeset: 11.232059 seconds (-74.61%, -33.00 seconds)
# benchmark.variants.revs = any-100-extra-rev
pre-%ln-change: 49.234697
this-changeset: 15.367412 seconds (-68.79%, -33.87 seconds)
Note that with this change, the `hg push` performance is now much closer to the
`hg pull` performance, even it still lagging behind a bit. (and the overall
performance are still too slow).
### data-env-vars.name = mozilla-try-2023-03-22-ds2-pnm
# benchmark.variants.explicit-rev = all-out-heads
# benchmark.variants.
issue6528 = disabled
# benchmark.variants.protocol = ssh
# benchmark.variants.pulled-delta-reuse-policy = default
# bin-env-vars.hg.flavor = rust
## benchmark.variants.revs = any-1-extra-rev
hg.command.pull: 6.517450
hg.command.push: 11.219888
## benchmark.variants.revs = any-100-extra-rev
hg.command.pull: 10.160991
hg.command.push: 14.251107
### data-env-vars.name = mozilla-try-2023-03-22-zstd-sparse-revlog
# bin-env-vars.hg.py-re2-module = default
# benchmark.variants.explicit-rev = all-out-heads
# benchmark.variants.
issue6528 = disabled
# benchmark.variants.protocol = ssh
# benchmark.variants.pulled-delta-reuse-policy = default
## bin-env-vars.hg.flavor = default
## benchmark.variants.revs = any-1-extra-rev
hg.command.pull: 8.577772
hg.command.push: 11.232059
## bin-env-vars.hg.flavor = default
## benchmark.variants.revs = any-100-extra-rev
hg.command.pull: 13.152976
hg.command.push: 15.367412
## bin-env-vars.hg.flavor = rust
## benchmark.variants.revs = any-1-extra-rev
hg.command.pull: 8.731982
hg.command.push: 11.178751
## bin-env-vars.hg.flavor = rust
## benchmark.variants.revs = any-100-extra-rev
hg.command.pull: 13.184236
hg.command.push: 15.620843
Pierre-Yves David <pierre-yves.david@octobus.net> [Fri, 05 Apr 2024 22:47:44 +0200] rev 51585
phases: introduce a performant efficient way to access revision in a set
This will be useful in the next changesets.
Pierre-Yves David <pierre-yves.david@octobus.net> [Fri, 05 Apr 2024 14:13:47 +0200] rev 51584
phases: use revision number in `_pushdiscoveryphase`
We now reach our target checkpoint in terms of rev-num conversion. The
`_pushdiscoveryphase` function is now performing graph computation based on
revision number only. Avoiding repeated conversion from node-id to rev-num.
See previous changeset updated `new_heads` for rationnal.
Again, time saved in the 100 milliseconds order of magnitude for the mozilla-try
benchmark I have been using.
However, wow that the logic is done using revision number, we can look into having
better logic in the next changesets, which will provide a much bigger speedup.
Pierre-Yves David <pierre-yves.david@octobus.net> [Fri, 05 Apr 2024 14:11:02 +0200] rev 51583
phases: move RemotePhasesSummary to revision number
This continue our quest to align more logic on revision number instead of
node-ids. The motivation is similar to the change to `new_heads` and
`analyze_remote_phases` a few changeset earlier.
Again, we take this as an opportunity to rename the class, and the attribute to
the new naming scheme. This will highlight the need for code update for any
code using it an expecting node-ids.
Many of the rev-num → node-id conversion we had to introduce in the previous
changesets can now be removed. More will be removed in the future as we continue
to align code toward rev-num usage.
time saved in the 100 milliseconds order of magnitude for the mozilla-try
benchmark I have been using.
Pierre-Yves David <pierre-yves.david@octobus.net> [Fri, 05 Apr 2024 12:24:47 +0200] rev 51582
phases: stop using `repo.set` in `remotephasessummary`
The `repository.set` create changectx on the fly, an expensive operation. Using
`repo.revs` and a direct rev-num → node-id translation will be significantly
faster.
This is especially true as we prepare ourself to no longer do the rev-num →
node-id transalation there.
The speedup is a bit lost in the overall noisyness of the slow phase discovery algorithm, but it save a small amount of time in my benchmark.
Pierre-Yves David <pierre-yves.david@octobus.net> [Fri, 05 Apr 2024 12:02:43 +0200] rev 51581
phases: use revision number in analyze_remote_phases
Same logic as the previous change to `new_heads`, see rationnal there.
This avoids a small number of `nodes -> revs` conversion speeding thing up in
the 100 milliseconds order of magnitude for the worses cases. However, the rest
of the logic is noisy enough that it hardly matters for now.
Pierre-Yves David <pierre-yves.david@octobus.net> [Fri, 05 Apr 2024 11:33:47 +0200] rev 51580
phases: use revision number in new_heads
All graph operations will be done using revision numbers, so passing nodes only
means they will eventually get converted to revision numbers internally.
As part of an effort to align the code on using revision number we make the
`phases.newheads` function operated on revision number, taking them as input
and using them in returns, instead of the node-id it used to consume and
produce.
This is part of multiple changesets effort to translate more part of the logic,
but is done step by step to facilitate the identification of issue that might
arise in mercurial core and extensions.
To make the change simpler to handle for third party extensions, we also rename
the function, using a more modern form. This will help detecting the different
between the node-id version and the rev-num version.
I also take this as an opportunity to add some comment about possible
performance improvement for the future. They don't matter too much now, but they
are worse exploring in a while.
Pierre-Yves David <pierre-yves.david@octobus.net> [Mon, 08 Apr 2024 15:11:49 +0200] rev 51579
phases: convert remote phase root to node while reading them
This is currently a bit silly as we will convert them back to node right after,
but that is an intermediate step before doing more disruptive changes.
Pierre-Yves David <pierre-yves.david@octobus.net> [Fri, 05 Apr 2024 11:17:25 +0200] rev 51578
phases: more compact error handling in analyzeremotephases
using an intermediate variable result in more readable code, so let us use it.
Pierre-Yves David <pierre-yves.david@octobus.net> [Tue, 09 Apr 2024 02:54:12 +0200] rev 51577
push: rework the computation of fallbackheads to be correct
The previous computation tried to be smart but ended up being wrong. This was
caught by phase movement test while reworking the phase discovery logic to be
faster.
The previous logic was failing to catch case where the pushed set was not based
on a common heads (i.e. when the discovery seemed to have "over discovered"
content, outside the pushed set)
In the following graph, `e` is a common head and we `hg push -r f`. We need to
detect `c` as a fallback heads and we previous failed to do so::
e
|
d f
|/
c
|
b
|
a
The performance impact of the change seems minimal. On the most impacted
repository at hand (mozilla-try), the slowdown seems mostly mixed in the
overall noise `hg push` but seems to be in the hundred of milliseconds order of
magnitude. When using rust, we seems to be a bit faster, probably because we
leverage more accelaratd internals.
I added a couple of performance related common for further investigation later
on.
Pierre-Yves David <pierre-yves.david@octobus.net> [Fri, 05 Apr 2024 11:05:54 +0200] rev 51576
revset: stop serializing node when using "%ln"
Turning hundred of thousand of node from node to hex and back can be slow… what
about we stop doing it?
In many case were we are using node id we should be using revision id. However
this is not a good reason to have a stupidly slow implementation of "%ln".
This caught my attention again because the phase discovery during push make an
extensive use of "%ln" or huge set. In absolute, that phase discovery probably
should use "%ld" and need to improves its algorithmic complexity, but improving
"%ln" seems simple and long overdue. This greatly speeds up `hg push` on
repository with many drafts.
Here are some relevant poulpe benchmarks:
### data-env-vars.name = mozilla-try-2023-03-22-zstd-sparse-revlog
# benchmark.name = hg.command.push
# bin-env-vars.hg.flavor = default
# bin-env-vars.hg.py-re2-module = default
# benchmark.variants.explicit-rev = all-out-heads
# benchmark.variants.
issue6528 = disabled
# benchmark.variants.protocol = ssh
# benchmark.variants.reuse-external-delta-parent = default
## benchmark.variants.revs = any-1-extra-rev
before: 44.235070
after: 20.416329 (-53.85%, -23.82)
## benchmark.variants.revs = any-100-extra-rev
before: 49.234697
after: 26.519829 (-46.14%, -22.71)
### benchmark.name = hg.command.bundle
# bin-env-vars.hg.flavor = default
# bin-env-vars.hg.py-re2-module = default
# benchmark.variants.revs = all
# benchmark.variants.type = none-streamv2
## data-env-vars.name = heptapod-public-2024-03-25-zstd-sparse-revlog
before: 10.138396
after: 7.750458 (-23.55%, -2.39)
## data-env-vars.name = mercurial-public-2024-03-22-zstd-sparse-revlog
before: 1.263859
after: 0.700229 (-44.60%, -0.56)
## data-env-vars.name = mozilla-try-2023-03-22-zstd-sparse-revlog
before: 399.484481
after: 346.5089 (-13.26%, -52.98)
## data-env-vars.name = pypy-2024-03-22-zstd-sparse-revlog
before: 4.540080
after: 3.401700 (-25.07%, -1.14)
## data-env-vars.name = tryton-public-2024-03-22-zstd-sparse-revlog
before: 2.975765
after: 1.870798 (-37.13%, -1.10)
Pierre-Yves David <pierre-yves.david@octobus.net> [Tue, 09 Apr 2024 14:41:48 +0200] rev 51575
bundlespec: drop unused _bundlespecvariants dictionary
Why do we have a `_bundlespecvariants`?
Pierre-Yves David <pierre-yves.david@octobus.net> [Tue, 09 Apr 2024 14:37:24 +0200] rev 51574
bundlespec: type the _bundlespeccontentopts dictionary
If only we had a tool to detect the kind of stupid error we just fixed… ho wait.
Pierre-Yves David <pierre-yves.david@octobus.net> [Tue, 09 Apr 2024 14:36:01 +0200] rev 51573
bundlespec: fix the "streamv2" and "streamv3-exp" variant
In
c4aab3661f25, we broken this feature by adding unicode instead of bytes to
the dictionary.
On the other hand, this feature was never tested, so augment the tests to tests
this.
Arseniy Alekseyev <aalekseyev@janestreet.com> [Thu, 04 Apr 2024 14:15:32 +0100] rev 51572
wireprotoserver: ensure that output stream gets flushed on exception
Previously flush was happening due to Python finalizer being run on
`BufferedWriter`. With upgrade to Python 3.11 this started randomly
failing.
My guess is that the finalizer on the raw `FileIO` object may
be running before the finalizer of `BufferedWriter` has a chance to run.
At any rate, since we're not relying on finalizers in the happy case
we should also not rely on them in case of exception.
Arseniy Alekseyev <aalekseyev@janestreet.com> [Mon, 15 Apr 2024 16:33:37 +0100] rev 51571
match: strengthen visit_children_set invariant, Recursive means "all files"
My previous interpretation of "Recursive" was too relaxed: I thought it
instructed the caller to do something like this:
> you can stop calling `visit_children_set` because you'll need to descend into
> every directory recursively, but you should still check every file if it
> matches or not
Whereas the real instruction seems to be:
> I guarantee that everything in this subtree matches, you can stop
> querying the matcher for all files and dirs altogether.
The evidence to support this:
- the test actually passes with the stronger invariant, revealing no
exceptions from this rule
- the implementation of `visit_children_set` for `DifferenceMatcher`
clearly relies on this requirement, so it must hold for that not to
lead to bugs.