1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-26 00:32:42 +01:00

Prevent external connections from being mutated on held locks

Summary: Ref T13627. This makes the API harder to misuse: setting an external connection on a held lock isn't a meaningful operation. Prevent it.

Test Plan: Added a failing test, made it pass.

Maniphest Tasks: T13627

Differential Revision: https://secure.phabricator.com/D21584
This commit is contained in:
epriestley 2021-03-02 12:53:52 -08:00
parent 15dbf6bdf0
commit 466013f11a
4 changed files with 40 additions and 5 deletions

View file

@ -311,7 +311,7 @@ final class DiffusionRepositoryClusterEngine extends Phobject {
$write_lock = PhabricatorRepositoryWorkingCopyVersion::getWriteLock(
$repository_phid);
$write_lock->useSpecificConnection($locked_connection);
$write_lock->setExternalConnection($locked_connection);
$this->logLine(
pht(

View file

@ -1229,7 +1229,7 @@ abstract class PhabricatorStorageManagementWorkflow
// log table yet, or may need to adjust it.
return PhabricatorGlobalLock::newLock('adjust', $parameters)
->useSpecificConnection($api->getConn(null))
->setExternalConnection($api->getConn(null))
->setDisableLogging(true)
->lock();
}

View file

@ -91,8 +91,13 @@ final class PhabricatorGlobalLock extends PhutilLock {
* @param AphrontDatabaseConnection
* @return this
*/
public function useSpecificConnection(AphrontDatabaseConnection $conn) {
$this->conn = $conn;
public function setExternalConnection(AphrontDatabaseConnection $conn) {
if ($this->conn) {
throw new Exception(
pht(
'Lock is already held, and must be released before the '.
'connection may be changed.'));
}
$this->externalConnection = $conn;
return $this;
}
@ -118,6 +123,12 @@ final class PhabricatorGlobalLock extends PhutilLock {
protected function doLock($wait) {
$conn = $this->conn;
if (!$conn) {
if ($this->externalConnection) {
$conn = $this->externalConnection;
}
}
if (!$conn) {
// Try to reuse a connection from the connection pool.
$conn = array_pop(self::$pool);

View file

@ -54,7 +54,7 @@ final class PhabricatorGlobalLockTestCase
$lock_name = $this->newLockName();
$lock = PhabricatorGlobalLock::newLock($lock_name);
$lock->useSpecificConnection($conn);
$lock->setExternalConnection($conn);
$lock->lock();
$this->assertEqual(
@ -85,6 +85,30 @@ final class PhabricatorGlobalLockTestCase
PhabricatorGlobalLock::clearConnectionPool();
}
public function testExternalConnectionMutationScope() {
$conn = id(new HarbormasterScratchTable())
->establishConnection('w');
$lock_name = $this->newLockName();
$lock = PhabricatorGlobalLock::newLock($lock_name);
$lock->lock();
$caught = null;
try {
$lock->setExternalConnection($conn);
} catch (Exception $ex) {
$caught = $ex;
} catch (Throwable $ex) {
$caught = $ex;
}
$lock->unlock();
$this->assertTrue(
($caught instanceof Exception),
pht('Changing connection while locked is forbidden.'));
}
private function newLockName() {
return 'testlock-'.Filesystem::readRandomCharacters(16);
}