3 final class DiffusionGitReceivePackSSHWorkflow
extends DiffusionGitSSHWorkflow
{
5 protected function didConstruct() {
6 $this->setName('git-receive-pack');
16 protected function executeRepositoryOperations() {
17 // This is a write, and must have write access.
18 $this->requireWriteAccess();
20 $is_proxy = $this->shouldProxy();
22 return $this->executeRepositoryProxyOperations($for_write = true);
25 $host_wait_start = microtime(true);
27 $repository = $this->getRepository();
28 $viewer = $this->getSSHUser();
29 $device = AlmanacKeys
::getLiveDevice();
31 $cluster_engine = id(new DiffusionRepositoryClusterEngine())
33 ->setRepository($repository)
36 $command = csprintf('git-receive-pack %s', $repository->getLocalPath());
37 $cluster_engine->synchronizeWorkingCopyBeforeWrite();
40 $this->writeClusterEngineLogMessage(
42 "# Ready to receive on cluster host \"%s\".\n",
46 $log = $this->newProtocolLog($is_proxy);
48 $this->setProtocolLog($log);
49 $log->didStartSession($command);
54 $err = $this->executeRepositoryCommand($command);
55 } catch (Exception
$ex) {
60 $log->didEndSession();
63 // We've committed the write (or rejected it), so we can release the lock
64 // without waiting for the client to receive the acknowledgement.
65 $cluster_engine->synchronizeWorkingCopyAfterWrite();
72 $this->waitForGitClient();
74 // When a repository is clustered, we reach this cleanup code on both
75 // the proxy and the actual final endpoint node. Don't do more cleanup
76 // or logging than we need to.
77 $repository->writeStatusMessage(
78 PhabricatorRepositoryStatusMessage
::TYPE_NEEDS_UPDATE
,
79 PhabricatorRepositoryStatusMessage
::CODE_OKAY
);
81 $host_wait_end = microtime(true);
83 $this->updatePushLogWithTimingInformation(
84 $this->getClusterEngineLogProperty('writeWait'),
85 $this->getClusterEngineLogProperty('readWait'),
86 ($host_wait_end - $host_wait_start));
92 private function executeRepositoryCommand($command) {
93 $repository = $this->getRepository();
94 $command = PhabricatorDaemon
::sudoCommandAsDaemonUser($command);
96 $future = id(new ExecFuture('%C', $command))
97 ->setEnv($this->getEnvironment());
99 return $this->newPassthruCommand()
100 ->setIOChannel($this->getIOChannel())
101 ->setCommandChannelFromExecFuture($future)
105 private function updatePushLogWithTimingInformation(
110 if ($write_wait !== null) {
111 $write_wait = (int)(1000000 * $write_wait);
114 if ($read_wait !== null) {
115 $read_wait = (int)(1000000 * $read_wait);
118 if ($host_wait !== null) {
119 $host_wait = (int)(1000000 * $host_wait);
122 $identifier = $this->getRequestIdentifier();
124 $event = new PhabricatorRepositoryPushEvent();
125 $conn = $event->establishConnection('w');
129 'UPDATE %T SET writeWait = %nd, readWait = %nd, hostWait = %nd
130 WHERE requestIdentifier = %s',
131 $event->getTableName(),