eden: make the EdenFS import helper use EdenAPI's /trees endpoint instead of /complete_trees

Summary:
The EdenFS import helper's `_fetch_tree_impl` method works by either calling `repo._prefetchtrees` or `repo.prefetchtrees`, both of which are methods from `treemanifest` extension's `treerepository` class. Unfortunately, these methods are lower-level than their names would suggest, and will always perform gettreepack style fetching (see [1]).

If HTTP fetching is enabled, this means that EdenFS will always query EdenAPI's `/complete_trees` endpoint instead of `/trees`, which is needlessly expensive given that EdenFS just wants the exact set of trees specified. As a somewhat hacky workaround, this diff just checks whether HTTP fetching is enabled, and if so, directly calls the appropriate HTTP fetch method.

This solution isn't ideal; it would be better for the import helper to request the trees from Mercurial's `remotetreestore` instead of via methods from `treerepository`. Unfortunately, with the current structure of Mercurial's storage layer, the `remotetreestore` isn't readily accessible because it gets passed into the Rust API's storage hierarchy upon construction.
 ---
[1]: The various `*prefetchtrees` methods  are usually called from Mercurial's `remotetreestore`, which is where the choice of tree fetching strategy is made (i.e., designated nodes vs gettreepack). The `remotetreestore` then calls `*prefetchtrees` for gettreepack-style fetching, or `*getdesignatednodes` for on-demand fetching. As such, a call to `*prefetchtrees` generally implies gettreepack-style fetching.

Reviewed By: quark-zju

Differential Revision: D26560451

fbshipit-source-id: 2eedf50a6e66fac78df77214b777544eb8049714
This commit is contained in:
Arun Kulshreshtha 2021-02-22 14:22:18 -08:00 committed by Facebook GitHub Bot
parent 2c0b490179
commit befabb81c0
2 changed files with 19 additions and 1 deletions

View File

@ -660,6 +660,22 @@ class HgServer(object):
def _fetch_tree_impl(self, path, manifest_node):
# type: (str, bytes) -> None
# The _prefetchtrees function called below will *always* perform
# gettreepack-style fetching (even if treemanifest.ondemandfetch is
# set to True) because the logic that determines the tree fetching
# strategy occurs in Mercurial's `remotetreestore` (which is not
# readily accessible here because it is passed into Mercurial's Rust
# storage API upon construction.
#
# As a workaround, let's just check if HTTP fetching is enabled, and
# if so, just directly call the appropriate treerepository method to
# send the request to EdenAPI's `/trees` endpoint (which only returns
# the exact set of trees requested, as desired here).
if self.repo._shouldusehttp():
self.repo._httpgetdesignatednodes([(path, manifest_node)])
return
mfnodes = set([manifest_node])
depth = str(self._treefetchdepth)
with self.repo.ui.configoverride(

View File

@ -8,6 +8,7 @@
import __future__
import __builtin__
import _weakref
import contextlib
from typing import (
Any,
@ -26,7 +27,6 @@ from typing import (
Union,
)
import _weakref
import edenscm.mercurial.connectionpool
import edenscm.mercurial.context
import edenscm.mercurial.filelog
@ -179,6 +179,7 @@ class localrepository(object):
def _filter(self, filterpats, filename, data) -> Any: ...
def _getsvfsward(self, origfunc) -> Callable: ...
def _getvfsward(self, origfunc) -> Callable: ...
def _httpgetdesignatednodes(self, keys: Iterable[(str, bytes)]): ...
def _journalfiles(
self,
) -> Tuple[
@ -215,6 +216,7 @@ class localrepository(object):
def _refreshfilecachestats(repo: localrepository, *args, **kwargs) -> None: ...
def _restrictcapabilities(self, caps: Set[str]) -> Set[str]: ...
def _rollback(repo: localrepository, *args, **kwargs) -> int: ...
def _shouldusehttp(self) -> bool: ...
def _syncrevlogtozstore(self) -> None: ...
def _wlockchecktransaction(self) -> None: ...
def _writejournal(repo: localrepository, *args, **kwargs) -> None: ...