@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+89 -14
+30 -12
src/applications/diffusion/controller/DiffusionRefTableController.php
··· 66 66 $type = idx($cache, 'type'); 67 67 } 68 68 69 - $identifier = idx($vcs, 'identifier'); 70 - if ($identifier !== null) { 71 - $identifier = DiffusionView::linkCommit( 69 + $hash = idx($vcs, 'identifier'); 70 + if ($hash !== null) { 71 + $hash = DiffusionView::linkCommit( 72 72 $repository, 73 - $identifier); 73 + $hash); 74 74 } 75 75 76 - $cache_identifier = idx($cache, 'identifier'); 77 - if ($cache_identifier !== null) { 78 - $cache_identifier = DiffusionView::linkCommit( 76 + $cached_hash = idx($cache, 'identifier'); 77 + if ($cached_hash !== null) { 78 + $cache_hash = DiffusionView::linkCommit( 79 79 $repository, 80 - $cache_identifier); 80 + $cached_hash); 81 + } 82 + 83 + $closed = idx($vcs, 'closed', false); 84 + if (!$vcs) { 85 + $state = null; 86 + } else { 87 + $state = $closed ? pht('Closed') : pht('Open'); 88 + } 89 + 90 + $cached_closed = idx($cache, 'closed', false); 91 + if (!$cache) { 92 + $cached_state = null; 93 + } else { 94 + $cached_state = $cached_closed ? pht('Closed') : pht('Open'); 81 95 } 82 96 83 97 $alternate = idx($vcs, 'alternate'); ··· 90 104 $rows[] = array( 91 105 $ref, 92 106 $type, 93 - $identifier, 94 - $cache_identifier, 107 + $hash, 108 + $cached_hash, 109 + $state, 110 + $cached_state, 95 111 $alternate, 96 112 ); 97 113 } ··· 102 118 array( 103 119 pht('Ref'), 104 120 pht('Type'), 105 - pht('Identifier'), 106 - pht('Cached'), 121 + pht('Hash'), 122 + pht('Cached Hash'), 123 + pht('State'), 124 + pht('Cached State'), 107 125 pht('Alternate'), 108 126 )); 109 127
+59 -2
src/applications/diffusion/query/lowlevel/DiffusionLowLevelResolveRefsQuery.php
··· 140 140 private function resolveMercurialRefs() { 141 141 $repository = $this->getRepository(); 142 142 143 + // First, pull all of the branch heads in the repository. Doing this in 144 + // bulk is much faster than querying each individual head if we're 145 + // checking even a small number of refs. 143 146 $futures = array(); 144 - foreach ($this->refs as $ref) { 147 + $futures['all'] = $repository->getLocalCommandFuture( 148 + 'log --template=%s --rev %s', 149 + '{node} {branch}\\n', 150 + hgsprintf('head()')); 151 + $futures['open'] = $repository->getLocalCommandFuture( 152 + 'log --template=%s --rev %s', 153 + '{node} {branch}\\n', 154 + hgsprintf('head() and not closed()')); 155 + 156 + 157 + $map = array(); 158 + foreach (new FutureIterator($futures) as $key => $future) { 159 + list($stdout) = $future->resolvex(); 160 + $lines = phutil_split_lines($stdout, $retain_endings = false); 161 + foreach ($lines as $idx => $line) { 162 + list($node, $branch) = explode(' ', $line, 2); 163 + $map[$branch]['nodes'][] = $node; 164 + if ($key == 'open') { 165 + $map[$branch]['open'] = true; 166 + } 167 + } 168 + } 169 + 170 + $results = array(); 171 + $unresolved = $this->refs; 172 + foreach ($unresolved as $key => $ref) { 173 + if (!isset($map[$ref])) { 174 + continue; 175 + } 176 + 177 + $is_closed = !idx($map[$ref], 'open', false); 178 + foreach ($map[$ref]['nodes'] as $node) { 179 + $results[$ref][$node] = array( 180 + 'type' => 'branch', 181 + 'identifier' => $node, 182 + 'closed' => $is_closed, 183 + ); 184 + } 185 + 186 + unset($unresolved[$key]); 187 + } 188 + 189 + // Strip the node keys off the result list. 190 + foreach ($results as $ref => $result_list) { 191 + $results[$ref] = array_values($result_list); 192 + } 193 + 194 + if (!$unresolved) { 195 + return $results; 196 + } 197 + 198 + // If we still have unresolved refs (which might be things like "tip"), 199 + // try to resolve them individually. 200 + 201 + $futures = array(); 202 + foreach ($unresolved as $ref) { 145 203 $futures[$ref] = $repository->getLocalCommandFuture( 146 204 'log --template=%s --rev %s', 147 205 '{node}', 148 206 hgsprintf('%s', $ref)); 149 207 } 150 208 151 - $results = array(); 152 209 foreach (new FutureIterator($futures) as $ref => $future) { 153 210 try { 154 211 list($stdout) = $future->resolvex();