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

Synchronize (hosted, clustered, Git) repositories over Conduit + HTTP

Summary:
Ref T4292. We currently synchronize hosted, clustered, Git repositories when we receive an SSH pull or push.

Additionally:

- Synchronize before HTTP reads and writes.
- Synchronize reads before Conduit requests.

We could relax Conduit eventually and allow Diffusion to say "it's OK to give me stale data".

We could also redirect some set of these actions to just go to the up-to-date host instead of connecting to a random host and synchronizing it. However, this potentially won't work as well at scale: if you have a larger number of servers, it sends all of the traffic to the leader immediately following a write. That can cause "thundering herd" issues, and isn't efficient if replicas are in different geographical regions and the write just went to the east coast but most clients are on the west coast. In large-scale cases, it's better to go to the local replica, wait for an update, then serve traffic from it -- particularly given that writes are relatively rare. But we can finesse this later once things are solid.

Test Plan:
- Pushed and pulled a Git repository over HTTP.
- Browsed a Git repository from the web UI.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T4292

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

+68 -9
+6
src/applications/diffusion/conduit/DiffusionQueryConduitAPIMethod.php
··· 145 145 146 146 $this->setDiffusionRequest($drequest); 147 147 148 + // TODO: Allow web UI queries opt out of this if they don't care about 149 + // fetching the most up-to-date data? Synchronization can be slow, and a 150 + // lot of web reads are probably fine if they're a few seconds out of 151 + // date. 152 + $repository->synchronizeWorkingCopyBeforeRead(); 153 + 148 154 return $this->getResult($request); 149 155 } 150 156 }
+29 -4
src/applications/diffusion/controller/DiffusionServeController.php
··· 538 538 $command = csprintf('%s', $bin); 539 539 $command = PhabricatorDaemon::sudoCommandAsDaemonUser($command); 540 540 541 - list($err, $stdout, $stderr) = id(new ExecFuture('%C', $command)) 542 - ->setEnv($env, true) 543 - ->write($input) 544 - ->resolve(); 541 + $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); 542 + 543 + $did_write_lock = false; 544 + if ($this->isReadOnlyRequest($repository)) { 545 + $repository->synchronizeWorkingCopyBeforeRead(); 546 + } else { 547 + $did_write_lock = true; 548 + $repository->synchronizeWorkingCopyBeforeWrite($viewer); 549 + } 550 + 551 + $caught = null; 552 + try { 553 + list($err, $stdout, $stderr) = id(new ExecFuture('%C', $command)) 554 + ->setEnv($env, true) 555 + ->write($input) 556 + ->resolve(); 557 + } catch (Exception $ex) { 558 + $caught = $ex; 559 + } 560 + 561 + if ($did_write_lock) { 562 + $repository->synchronizeWorkingCopyAfterWrite(); 563 + } 564 + 565 + unset($unguarded); 566 + 567 + if ($caught) { 568 + throw $caught; 569 + } 545 570 546 571 if ($err) { 547 572 if ($this->isValidGitShallowCloneResponse($stdout, $stderr)) {
+16
src/applications/diffusion/protocol/DiffusionCommandEngine.php
··· 8 8 private $argv; 9 9 private $passthru; 10 10 private $connectAsDevice; 11 + private $sudoAsDaemon; 11 12 12 13 public static function newCommandEngine(PhabricatorRepository $repository) { 13 14 $engines = self::newCommandEngines(); ··· 92 93 return $this->connectAsDevice; 93 94 } 94 95 96 + public function setSudoAsDaemon($sudo_as_daemon) { 97 + $this->sudoAsDaemon = $sudo_as_daemon; 98 + return $this; 99 + } 100 + 101 + public function getSudoAsDaemon() { 102 + return $this->sudoAsDaemon; 103 + } 104 + 95 105 public function newFuture() { 96 106 $argv = $this->newCommandArgv(); 97 107 $env = $this->newCommandEnvironment(); 108 + 109 + if ($this->getSudoAsDaemon()) { 110 + $command = call_user_func_array('csprintf', $argv); 111 + $command = PhabricatorDaemon::sudoCommandAsDaemonUser($command); 112 + $argv = array('%C', $command); 113 + } 98 114 99 115 if ($this->getPassthru()) { 100 116 $future = newv('PhutilExecPassthru', $argv);
+17 -5
src/applications/repository/storage/PhabricatorRepository.php
··· 1954 1954 1955 1955 $uris = array(); 1956 1956 foreach ($bindings as $binding) { 1957 + if ($binding->getIsDisabled()) { 1958 + continue; 1959 + } 1960 + 1957 1961 $iface = $binding->getInterface(); 1958 1962 1959 1963 // If we're never proxying this and it's locally satisfiable, return ··· 2197 2201 2198 2202 2199 2203 private function shouldEnableSynchronization() { 2200 - $device = AlmanacKeys::getLiveDevice(); 2201 - if (!$device) { 2202 - return false; 2203 - } 2204 - 2205 2204 $service_phid = $this->getAlmanacServicePHID(); 2206 2205 if (!$service_phid) { 2207 2206 return false; ··· 2212 2211 return false; 2213 2212 } 2214 2213 2214 + // TODO: It may eventually make sense to try to version and synchronize 2215 + // observed repositories (so that daemons don't do reads against out-of 2216 + // date hosts), but don't bother for now. 2217 + if (!$this->isHosted()) { 2218 + return false; 2219 + } 2220 + 2221 + $device = AlmanacKeys::getLiveDevice(); 2222 + if (!$device) { 2223 + return false; 2224 + } 2225 + 2215 2226 return true; 2216 2227 } 2217 2228 ··· 2451 2462 $future = DiffusionCommandEngine::newCommandEngine($this) 2452 2463 ->setArgv($argv) 2453 2464 ->setConnectAsDevice(true) 2465 + ->setSudoAsDaemon(true) 2454 2466 ->setProtocol($fetch_uri->getProtocol()) 2455 2467 ->newFuture(); 2456 2468