@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.

Use futures to improve clustered repository main page performance

Summary:
Ref T11954. In cluster configurations, we get repository information by making HTTP calls over Conduit.

These are slower than local calls, so clustering imposes a performance penalty. However, we can use futures and parallelize them so that clustering actually improves overall performance.

When not running in clustered mode, this just makes us run stuff inline.

Test Plan:
- Browsed Git, Mercurial and Subversion repositories.
- Locally, saw a 700ms wall time page drop to 200ms.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T11954

Differential Revision: https://secure.phabricator.com/D17009

+158 -52
+17 -8
src/applications/conduit/storage/PhabricatorConduitToken.php
··· 42 42 return null; 43 43 } 44 44 45 + if ($user->hasConduitClusterToken()) { 46 + return $user->getConduitClusterToken(); 47 + } 48 + 45 49 $tokens = id(new PhabricatorConduitTokenQuery()) 46 50 ->setViewer($user) 47 51 ->withObjectPHIDs(array($user->getPHID())) ··· 55 59 $now = PhabricatorTime::getNow(); 56 60 $must_expire_after = $now + phutil_units('5 minutes in seconds'); 57 61 62 + $valid_token = null; 58 63 foreach ($tokens as $token) { 59 64 if ($token->getExpires() > $must_expire_after) { 60 - return $token; 65 + $valid_token = $token; 66 + break; 61 67 } 62 68 } 63 69 64 70 // We didn't find any existing tokens (or the existing tokens are all about 65 71 // to expire) so generate a new token. 72 + if (!$valid_token) { 73 + $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); 74 + $valid_token = self::initializeNewToken( 75 + $user->getPHID(), 76 + self::TYPE_CLUSTER); 77 + $valid_token->save(); 78 + unset($unguarded); 79 + } 66 80 67 - $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); 68 - $token = self::initializeNewToken( 69 - $user->getPHID(), 70 - self::TYPE_CLUSTER); 71 - $token->save(); 72 - unset($unguarded); 81 + $user->attachConduitClusterToken($valid_token); 73 82 74 - return $token; 83 + return $valid_token; 75 84 } 76 85 77 86 public static function initializeNewToken($object_phid, $token_type) {
+12
src/applications/diffusion/controller/DiffusionController.php
··· 239 239 $params); 240 240 } 241 241 242 + protected function callConduitMethod($method, array $params = array()) { 243 + $user = $this->getViewer(); 244 + $drequest = $this->getDiffusionRequest(); 245 + 246 + return DiffusionQuery::callConduitWithDiffusionRequest( 247 + $user, 248 + $drequest, 249 + $method, 250 + $params, 251 + true); 252 + } 253 + 242 254 protected function getRepositoryControllerURI( 243 255 PhabricatorRepository $repository, 244 256 $path) {
+104 -41
src/applications/diffusion/controller/DiffusionRepositoryController.php
··· 2 2 3 3 final class DiffusionRepositoryController extends DiffusionController { 4 4 5 + private $historyFuture; 6 + private $browseFuture; 7 + private $tagFuture; 8 + private $branchFuture; 9 + 5 10 public function shouldAllowPublic() { 6 11 return true; 7 12 } ··· 106 111 $request = $this->getRequest(); 107 112 $repository = $drequest->getRepository(); 108 113 114 + $commit = $drequest->getCommit(); 115 + $path = $drequest->getPath(); 116 + 117 + $this->historyFuture = $this->callConduitMethod( 118 + 'diffusion.historyquery', 119 + array( 120 + 'commit' => $commit, 121 + 'path' => $path, 122 + 'offset' => 0, 123 + 'limit' => 15, 124 + )); 125 + 126 + $browse_pager = id(new PHUIPagerView()) 127 + ->readFromRequest($request); 128 + 129 + $this->browseFuture = $this->callConduitMethod( 130 + 'diffusion.browsequery', 131 + array( 132 + 'commit' => $commit, 133 + 'path' => $path, 134 + 'limit' => $browse_pager->getPageSize() + 1, 135 + )); 136 + 137 + if ($this->needTagFuture()) { 138 + $tag_limit = $this->getTagLimit(); 139 + $this->tagFuture = $this->callConduitMethod( 140 + 'diffusion.tagsquery', 141 + array( 142 + // On the home page, we want to find tags on any branch. 143 + 'commit' => null, 144 + 'limit' => $tag_limit + 1, 145 + )); 146 + } 147 + 148 + if ($this->needBranchFuture()) { 149 + $branch_limit = $this->getBranchLimit(); 150 + $this->branchFuture = $this->callConduitMethod( 151 + 'diffusion.branchquery', 152 + array( 153 + 'closed' => false, 154 + 'limit' => $branch_limit + 1, 155 + )); 156 + } 157 + 158 + $futures = array( 159 + $this->historyFuture, 160 + $this->browseFuture, 161 + $this->tagFuture, 162 + $this->branchFuture, 163 + ); 164 + $futures = array_filter($futures); 165 + $futures = new FutureIterator($futures); 166 + foreach ($futures as $future) { 167 + // Just resolve all the futures before continuing. 168 + } 169 + 109 170 $phids = array(); 110 171 $content = array(); 111 172 112 173 try { 113 - $history_results = $this->callConduitWithDiffusionRequest( 114 - 'diffusion.historyquery', 115 - array( 116 - 'commit' => $drequest->getCommit(), 117 - 'path' => $drequest->getPath(), 118 - 'offset' => 0, 119 - 'limit' => 15, 120 - )); 174 + $history_results = $this->historyFuture->resolve(); 121 175 $history = DiffusionPathChange::newFromConduit( 122 176 $history_results['pathChanges']); 123 177 ··· 138 192 $history = null; 139 193 $history_exception = $ex; 140 194 } 141 - 142 - $browse_pager = id(new PHUIPagerView()) 143 - ->readFromRequest($request); 144 195 145 196 try { 197 + $browse_results = $this->browseFuture->resolve(); 146 198 $browse_results = DiffusionBrowseResultSet::newFromConduit( 147 - $this->callConduitWithDiffusionRequest( 148 - 'diffusion.browsequery', 149 - array( 150 - 'path' => $drequest->getPath(), 151 - 'commit' => $drequest->getCommit(), 152 - 'limit' => $browse_pager->getPageSize() + 1, 153 - ))); 199 + $browse_results); 200 + 154 201 $browse_paths = $browse_results->getPaths(); 155 202 $browse_paths = $browse_pager->sliceResults($browse_paths); 156 203 ··· 366 413 private function buildBranchListTable(DiffusionRequest $drequest) { 367 414 $viewer = $this->getViewer(); 368 415 369 - if ($drequest->getBranch() === null) { 416 + if (!$this->needBranchFuture()) { 370 417 return null; 371 418 } 372 419 373 - $limit = 15; 374 - 375 - $branches = $this->callConduitWithDiffusionRequest( 376 - 'diffusion.branchquery', 377 - array( 378 - 'closed' => false, 379 - 'limit' => $limit + 1, 380 - )); 420 + $branches = $this->branchFuture->resolve(); 381 421 if (!$branches) { 382 422 return null; 383 423 } 384 424 425 + $limit = $this->getBranchLimit(); 385 426 $more_branches = (count($branches) > $limit); 386 427 $branches = array_slice($branches, 0, $limit); 387 428 ··· 428 469 $viewer = $this->getViewer(); 429 470 $repository = $drequest->getRepository(); 430 471 431 - switch ($repository->getVersionControlSystem()) { 432 - case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: 433 - // no tags in SVN 434 - return null; 472 + if (!$this->needTagFuture()) { 473 + return null; 435 474 } 436 - $tag_limit = 15; 437 - $tags = array(); 438 - $tags = DiffusionRepositoryTag::newFromConduit( 439 - $this->callConduitWithDiffusionRequest( 440 - 'diffusion.tagsquery', 441 - array( 442 - // On the home page, we want to find tags on any branch. 443 - 'commit' => null, 444 - 'limit' => $tag_limit + 1, 445 - ))); 446 475 476 + $tags = $this->tagFuture->resolve(); 477 + $tags = DiffusionRepositoryTag::newFromConduit($tags); 447 478 if (!$tags) { 448 479 return null; 449 480 } 450 481 482 + $tag_limit = $this->getTagLimit(); 451 483 $more_tags = (count($tags) > $tag_limit); 452 484 $tags = array_slice($tags, 0, $tag_limit); 453 485 ··· 686 718 ->setRepository($repository) 687 719 ->setRepositoryURI($uri) 688 720 ->setDisplayURI($display); 721 + } 722 + 723 + private function needTagFuture() { 724 + $drequest = $this->getDiffusionRequest(); 725 + $repository = $drequest->getRepository(); 726 + 727 + switch ($repository->getVersionControlSystem()) { 728 + case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: 729 + // No tags in SVN. 730 + return false; 731 + } 732 + 733 + return true; 734 + } 735 + 736 + private function getTagLimit() { 737 + return 15; 738 + } 739 + 740 + private function needBranchFuture() { 741 + $drequest = $this->getDiffusionRequest(); 742 + 743 + if ($drequest->getBranch() === null) { 744 + return false; 745 + } 746 + 747 + return true; 748 + } 749 + 750 + private function getBranchLimit() { 751 + return 15; 689 752 } 690 753 691 754 }
+11 -3
src/applications/diffusion/query/DiffusionQuery.php
··· 48 48 PhabricatorUser $user, 49 49 DiffusionRequest $drequest, 50 50 $method, 51 - array $params = array()) { 51 + array $params = array(), 52 + $return_future = false) { 52 53 53 54 $repository = $drequest->getRepository(); 54 55 ··· 76 77 $user, 77 78 $drequest->getIsClusterRequest()); 78 79 if (!$client) { 79 - return id(new ConduitCall($method, $params)) 80 + $result = id(new ConduitCall($method, $params)) 80 81 ->setUser($user) 81 82 ->execute(); 83 + $future = new ImmediateFuture($result); 82 84 } else { 83 - return $client->callMethodSynchronous($method, $params); 85 + $future = $client->callMethod($method, $params); 86 + } 87 + 88 + if (!$return_future) { 89 + return $future->resolve(); 84 90 } 91 + 92 + return $future; 85 93 } 86 94 87 95 public function execute() {
+14
src/applications/people/storage/PhabricatorUser.php
··· 64 64 private $settingCacheKeys = array(); 65 65 private $settingCache = array(); 66 66 private $allowInlineCacheGeneration; 67 + private $conduitClusterToken = self::ATTACHABLE; 67 68 68 69 protected function readField($field) { 69 70 switch ($field) { ··· 935 936 */ 936 937 public function getAuthorities() { 937 938 return $this->authorities; 939 + } 940 + 941 + public function hasConduitClusterToken() { 942 + return ($this->conduitClusterToken !== self::ATTACHABLE); 943 + } 944 + 945 + public function attachConduitClusterToken(PhabricatorConduitToken $token) { 946 + $this->conduitClusterToken = $token; 947 + return $this; 948 + } 949 + 950 + public function getConduitClusterToken() { 951 + return $this->assertAttached($this->conduitClusterToken); 938 952 } 939 953 940 954