diff --git a/src/applications/diffusion/protocol/DiffusionCommandEngine.php b/src/applications/diffusion/protocol/DiffusionCommandEngine.php --- a/src/applications/diffusion/protocol/DiffusionCommandEngine.php +++ b/src/applications/diffusion/protocol/DiffusionCommandEngine.php @@ -138,7 +138,8 @@ // See T13108. By default, don't let any cluster command run indefinitely // to try to avoid cases where `git fetch` hangs for some reason and we're // left sitting with a held lock forever. - $future->setTimeout(phutil_units('15 minutes in seconds')); + $repository = $this->getRepository(); + $future->setTimeout($repository->getCopyTimeLimit()); return $future; } diff --git a/src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php b/src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php --- a/src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php +++ b/src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php @@ -173,6 +173,7 @@ $map = $resource->getAttribute('repositories.map'); + $futures = array(); $repositories = $this->loadRepositories(ipull($map, 'phid')); foreach ($map as $directory => $spec) { // TODO: Validate directory isn't goofy like "/etc" or "../../lol" @@ -181,11 +182,18 @@ $repository = $repositories[$spec['phid']]; $path = "{$root}/repo/{$directory}/"; - // TODO: Run these in parallel? - $interface->execx( + $future = $interface->getExecFuture( 'git clone -- %s %s', (string)$repository->getCloneURIObject(), $path); + + $future->setTimeout($repository->getCopyTimeLimit()); + + $futures[$directory] = $future; + } + + foreach (new FutureIterator($futures) as $key => $future) { + $future->resolvex(); } $resource @@ -240,8 +248,12 @@ $map = $lease->getAttribute('repositories.map'); $root = $resource->getAttribute('workingcopy.root'); + $repositories = $this->loadRepositories(ipull($map, 'phid')); + $default = null; foreach ($map as $directory => $spec) { + $repository = $repositories[$spec['phid']]; + $interface->pushWorkingDirectory("{$root}/repo/{$directory}/"); $cmd = array(); @@ -271,7 +283,9 @@ $arg[] = $branch; } - $this->execxv($interface, $cmd, $arg); + $this->newExecvFuture($interface, $cmd, $arg) + ->setTimeout($repository->getCopyTimeLimit()) + ->resolvex(); if (idx($spec, 'default')) { $default = $directory; @@ -295,7 +309,9 @@ $arg[] = $ref_ref; try { - $this->execxv($interface, $cmd, $arg); + $this->newExecvFuture($interface, $cmd, $arg) + ->setTimeout($repository->getCopyTimeLimit()) + ->resolvex(); } catch (CommandException $ex) { $display_command = csprintf( 'git fetch %R %R', @@ -509,12 +525,18 @@ DrydockCommandInterface $interface, array $commands, array $arguments) { + return $this->newExecvFuture($interface, $commands, $arguments)->resolvex(); + } + + private function newExecvFuture( + DrydockCommandInterface $interface, + array $commands, + array $arguments) { $commands = implode(' && ', $commands); $argv = array_merge(array($commands), $arguments); - return call_user_func_array(array($interface, 'execx'), $argv); + return call_user_func_array(array($interface, 'getExecFuture'), $argv); } - } diff --git a/src/applications/drydock/storage/DrydockSlotLock.php b/src/applications/drydock/storage/DrydockSlotLock.php --- a/src/applications/drydock/storage/DrydockSlotLock.php +++ b/src/applications/drydock/storage/DrydockSlotLock.php @@ -140,9 +140,9 @@ try { queryfx( $conn_w, - 'INSERT INTO %T (ownerPHID, lockIndex, lockKey) VALUES %Q', + 'INSERT INTO %T (ownerPHID, lockIndex, lockKey) VALUES %LQ', $table->getTableName(), - implode(', ', $sql)); + $sql); } catch (AphrontDuplicateKeyQueryException $ex) { // Try to improve the readability of the exception. We might miss on // this query if the lock has already been released, but most of the diff --git a/src/applications/repository/storage/PhabricatorRepository.php b/src/applications/repository/storage/PhabricatorRepository.php --- a/src/applications/repository/storage/PhabricatorRepository.php +++ b/src/applications/repository/storage/PhabricatorRepository.php @@ -1889,6 +1889,19 @@ } + /** + * Time limit for cloning or copying this repository. + * + * This limit is used to timeout operations like `git clone` or `git fetch` + * when doing intracluster synchronization, building working copies, etc. + * + * @return int Maximum number of seconds to spend copying this repository. + */ + public function getCopyTimeLimit() { + return phutil_units('15 minutes in seconds'); + } + + /** * Retrieve the service URI for the device hosting this repository. * diff --git a/src/applications/repository/storage/PhabricatorRepositoryURIIndex.php b/src/applications/repository/storage/PhabricatorRepositoryURIIndex.php --- a/src/applications/repository/storage/PhabricatorRepositoryURIIndex.php +++ b/src/applications/repository/storage/PhabricatorRepositoryURIIndex.php @@ -48,16 +48,16 @@ queryfx( $conn_w, - 'DELETE FROM %T WHERE repositoryPHID = %s', - $table->getTableName(), + 'DELETE FROM %R WHERE repositoryPHID = %s', + $table, $repository_phid); if ($sql) { queryfx( $conn_w, - 'INSERT INTO %T (repositoryPHID, repositoryURI) VALUES %Q', - $table->getTableName(), - implode(', ', $sql)); + 'INSERT INTO %R (repositoryPHID, repositoryURI) VALUES %LQ', + $table, + $sql); } $table->saveTransaction();