statichttprepo: use a context manager to handle a file descriptor
I'm not sure if this should be reduced to `vfs.exists()`. That would seem to be
equivalent code (since the result of the read is ignored, so we can't tell if
the file actually has content, which has been the state of things going back to
98b6c3dde237), but this is at least safer file descriptor handling.
profiling: pass bytes to `_()` and `error.Abort()`
And of course `other_tool_name` is str too, so that needs to be converted. The
type hints from PyCharm say `sys.monitoring.get_tool()` can return None, so
handle that case explicitly before it trips up pytype.
exchange: improve computation of relevant markers for large repos
Compute the candidate nodes with relevant markers directly
from keys of the predecessors/successors/children dictionaries of
obsstore. This is faster than iterating over all nodes directly.
This test could be further improved for repositories with relative
few markers compared to the repository size, but this is no longer
hot already. With the current loop structure, the obshashrange use
works as well as before as it passes lists with a single node.
Adjust the interface by allowing revision lists as well as node lists.
This helps cases that computes ancestors as it reduces the
materialisation cost. Use this in _pushdiscoveryobsmarker and
_getbundleobsmarkerpart. Improve the latter further by directly using
ancestors().
Performance benchmarks show notable and welcome improvement to no-op push and
pull (that would also apply to other push/pull). This apply to push and pull
done without evolve.
### push/pull Benchmark parameter
# bin-env-vars.hg.flavor = default
# benchmark.variants.explicit-rev = none
# benchmark.variants.protocol = ssh
# benchmark.variants.revs = none
## benchmark.name = hg.command.pull
# data-env-vars.name = mercurial-devel-2024-03-22-zstd-sparse-revlog
before: 5.968537 seconds
after: 5.668507 seconds (-5.03%, -0.30)
# data-env-vars.name = tryton-devel-2024-03-22-zstd-sparse-revlog
before: 1.446232 seconds
after: 0.835553 seconds (-42.23%, -0.61)
# data-env-vars.name = netbsd-src-draft-2024-09-19-zstd-sparse-revlog
before: 5.777412 seconds
after: 2.523454 seconds (-56.32%, -3.25)
## benchmark.name = hg.command.push
# data-env-vars.name = mercurial-devel-2024-03-22-zstd-sparse-revlog
before: 6.155501 seconds
after: 5.885072 seconds (-4.39%, -0.27)
# data-env-vars.name = tryton-devel-2024-03-22-zstd-sparse-revlog
before: 1.491054 seconds
after: 0.934882 seconds (-37.30%, -0.56)
# data-env-vars.name = netbsd-src-draft-2024-09-19-zstd-sparse-revlog
before: 5.902494 seconds
after: 2.957644 seconds (-49.89%, -2.94)
There is not notable different in these result using the "rust" flavor instead
of the "default". The performance impact on the same operation when using
evolve were also tested and no impact was noted.
typing: make the localrepo classes known to pytype
9d4ad05bc91c and
1b17309cdaab both mentioned making `bundlerepository` and
`unionrepository` subclass `localrepository` during the type checking phase, but
that didn't apply to pytype in practice. See
bcaa5d408657 and friends for how
the zope interfaces confuse pytype, and end up converting the classes they
decorate into `Any`.
This commit is slightly more complex though, because `localrepository` has mixin
classes applied to it when it is instantiated. Specifically, `RevlogFileStorage`
is added, which adds `def file(f)` (which isn't defined on `localrepository`).
Therefore a list of `localrepository` superclasses is provided during type
checking to account for the mixins. Without this, the `bundlerepository` class
gets flagged when it attempts to call its superclass implementation of `file()`.
Note that pytype doesn't understand these mixin superclasses (it marks the
superclass of `localrepository` as `Any`, because they are zope interfaces it
doesn't understand), but that's enough to get it to not flag `bundlerepository`.
PyCharm also stops flagging it as a missing function, though it seems like it is
able to handle the zope interfaces.