1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-19 12:00:55 +01:00

Improve low-level branch resolution in Mercurial

Summary:
Ref T7100. Ref T7108. Ref T6160. Several issues:

  - High load for mercurial repositories with huge numbers of branches (T7108).
    - In Mercurial, we resolve refs individually (one `hg` call per ref).
    - Each repository update also updates all refs, which requires resolving all of them.
    - For repositories with a huge number of branches,
  - We don't distinguish between closed branches (a Mercurial-only concept) and open branches (T6160).
    - In Git, when a branch is merged, it ceases to exist.
    - In Mercurial, when a branch is merged, it still exists, it's just "closed". Normally, no one cares about these branches.
    - In the low-level query, correctly identify which refs we resolve as branches.
    - In the low-level query, correctly mark closed branches as closed.
  - This marginally improves ref handling in general (see T7100).

Test Plan:
{F384366}

{F384367}

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T6160, T7108, T7100

Differential Revision: https://secure.phabricator.com/D12548
This commit is contained in:
epriestley 2015-04-27 03:50:20 -07:00
parent 7f43cde82d
commit 21c4aeb032
2 changed files with 89 additions and 14 deletions

View file

@ -66,18 +66,32 @@ final class DiffusionRefTableController extends DiffusionController {
$type = idx($cache, 'type'); $type = idx($cache, 'type');
} }
$identifier = idx($vcs, 'identifier'); $hash = idx($vcs, 'identifier');
if ($identifier !== null) { if ($hash !== null) {
$identifier = DiffusionView::linkCommit( $hash = DiffusionView::linkCommit(
$repository, $repository,
$identifier); $hash);
} }
$cache_identifier = idx($cache, 'identifier'); $cached_hash = idx($cache, 'identifier');
if ($cache_identifier !== null) { if ($cached_hash !== null) {
$cache_identifier = DiffusionView::linkCommit( $cache_hash = DiffusionView::linkCommit(
$repository, $repository,
$cache_identifier); $cached_hash);
}
$closed = idx($vcs, 'closed', false);
if (!$vcs) {
$state = null;
} else {
$state = $closed ? pht('Closed') : pht('Open');
}
$cached_closed = idx($cache, 'closed', false);
if (!$cache) {
$cached_state = null;
} else {
$cached_state = $cached_closed ? pht('Closed') : pht('Open');
} }
$alternate = idx($vcs, 'alternate'); $alternate = idx($vcs, 'alternate');
@ -90,8 +104,10 @@ final class DiffusionRefTableController extends DiffusionController {
$rows[] = array( $rows[] = array(
$ref, $ref,
$type, $type,
$identifier, $hash,
$cache_identifier, $cached_hash,
$state,
$cached_state,
$alternate, $alternate,
); );
} }
@ -102,8 +118,10 @@ final class DiffusionRefTableController extends DiffusionController {
array( array(
pht('Ref'), pht('Ref'),
pht('Type'), pht('Type'),
pht('Identifier'), pht('Hash'),
pht('Cached'), pht('Cached Hash'),
pht('State'),
pht('Cached State'),
pht('Alternate'), pht('Alternate'),
)); ));

View file

@ -140,15 +140,72 @@ final class DiffusionLowLevelResolveRefsQuery
private function resolveMercurialRefs() { private function resolveMercurialRefs() {
$repository = $this->getRepository(); $repository = $this->getRepository();
// First, pull all of the branch heads in the repository. Doing this in
// bulk is much faster than querying each individual head if we're
// checking even a small number of refs.
$futures = array(); $futures = array();
foreach ($this->refs as $ref) { $futures['all'] = $repository->getLocalCommandFuture(
'log --template=%s --rev %s',
'{node} {branch}\\n',
hgsprintf('head()'));
$futures['open'] = $repository->getLocalCommandFuture(
'log --template=%s --rev %s',
'{node} {branch}\\n',
hgsprintf('head() and not closed()'));
$map = array();
foreach (new FutureIterator($futures) as $key => $future) {
list($stdout) = $future->resolvex();
$lines = phutil_split_lines($stdout, $retain_endings = false);
foreach ($lines as $idx => $line) {
list($node, $branch) = explode(' ', $line, 2);
$map[$branch]['nodes'][] = $node;
if ($key == 'open') {
$map[$branch]['open'] = true;
}
}
}
$results = array();
$unresolved = $this->refs;
foreach ($unresolved as $key => $ref) {
if (!isset($map[$ref])) {
continue;
}
$is_closed = !idx($map[$ref], 'open', false);
foreach ($map[$ref]['nodes'] as $node) {
$results[$ref][$node] = array(
'type' => 'branch',
'identifier' => $node,
'closed' => $is_closed,
);
}
unset($unresolved[$key]);
}
// Strip the node keys off the result list.
foreach ($results as $ref => $result_list) {
$results[$ref] = array_values($result_list);
}
if (!$unresolved) {
return $results;
}
// If we still have unresolved refs (which might be things like "tip"),
// try to resolve them individually.
$futures = array();
foreach ($unresolved as $ref) {
$futures[$ref] = $repository->getLocalCommandFuture( $futures[$ref] = $repository->getLocalCommandFuture(
'log --template=%s --rev %s', 'log --template=%s --rev %s',
'{node}', '{node}',
hgsprintf('%s', $ref)); hgsprintf('%s', $ref));
} }
$results = array();
foreach (new FutureIterator($futures) as $ref => $future) { foreach (new FutureIterator($futures) as $ref => $future) {
try { try {
list($stdout) = $future->resolvex(); list($stdout) = $future->resolvex();