diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3548,6 +3548,7 @@ 'PhabricatorGitGraphStream' => 'applications/repository/daemon/PhabricatorGitGraphStream.php', 'PhabricatorGitHubAuthProvider' => 'applications/auth/provider/PhabricatorGitHubAuthProvider.php', 'PhabricatorGlobalLock' => 'infrastructure/util/PhabricatorGlobalLock.php', + 'PhabricatorGlobalLockTestCase' => 'infrastructure/util/__tests__/PhabricatorGlobalLockTestCase.php', 'PhabricatorGlobalUploadTargetView' => 'applications/files/view/PhabricatorGlobalUploadTargetView.php', 'PhabricatorGoogleAuthProvider' => 'applications/auth/provider/PhabricatorGoogleAuthProvider.php', 'PhabricatorGuidanceContext' => 'applications/guides/guidance/PhabricatorGuidanceContext.php', @@ -10093,6 +10094,7 @@ 'PhabricatorGitGraphStream' => 'PhabricatorRepositoryGraphStream', 'PhabricatorGitHubAuthProvider' => 'PhabricatorOAuth2AuthProvider', 'PhabricatorGlobalLock' => 'PhutilLock', + 'PhabricatorGlobalLockTestCase' => 'PhabricatorTestCase', 'PhabricatorGlobalUploadTargetView' => 'AphrontView', 'PhabricatorGoogleAuthProvider' => 'PhabricatorOAuth2AuthProvider', 'PhabricatorGuidanceContext' => 'Phobject', diff --git a/src/infrastructure/util/PhabricatorGlobalLock.php b/src/infrastructure/util/PhabricatorGlobalLock.php --- a/src/infrastructure/util/PhabricatorGlobalLock.php +++ b/src/infrastructure/util/PhabricatorGlobalLock.php @@ -30,7 +30,7 @@ private $parameters; private $conn; - private $isExternalConnection = false; + private $externalConnection; private $log; private $disableLogging; @@ -93,7 +93,7 @@ */ public function useSpecificConnection(AphrontDatabaseConnection $conn) { $this->conn = $conn; - $this->isExternalConnection = true; + $this->externalConnection = $conn; return $this; } @@ -103,6 +103,16 @@ } +/* -( Connection Pool )---------------------------------------------------- */ + + public static function getConnectionPoolSize() { + return count(self::$pool); + } + + public static function clearConnectionPool() { + self::$pool = array(); + } + /* -( Implementation )----------------------------------------------------- */ protected function doLock($wait) { @@ -201,9 +211,8 @@ } $this->conn = null; - $this->isExternalConnection = false; - if (!$this->isExternalConnection) { + if (!$this->externalConnection) { $conn->close(); self::$pool[] = $conn; } diff --git a/src/infrastructure/util/__tests__/PhabricatorGlobalLockTestCase.php b/src/infrastructure/util/__tests__/PhabricatorGlobalLockTestCase.php new file mode 100644 --- /dev/null +++ b/src/infrastructure/util/__tests__/PhabricatorGlobalLockTestCase.php @@ -0,0 +1,92 @@ + true, + ); + } + + public function testConnectionPoolWithDefaultConnection() { + PhabricatorGlobalLock::clearConnectionPool(); + + $this->assertEqual( + 0, + PhabricatorGlobalLock::getConnectionPoolSize(), + pht('Clear Connection Pool')); + + $lock_name = $this->newLockName(); + $lock = PhabricatorGlobalLock::newLock($lock_name); + $lock->lock(); + + $this->assertEqual( + 0, + PhabricatorGlobalLock::getConnectionPoolSize(), + pht('Connection Pool With Lock')); + + $lock->unlock(); + + $this->assertEqual( + 1, + PhabricatorGlobalLock::getConnectionPoolSize(), + pht('Connection Pool With Lock Released')); + + PhabricatorGlobalLock::clearConnectionPool(); + } + + public function testConnectionPoolWithSpecificConnection() { + $conn = id(new HarbormasterScratchTable()) + ->establishConnection('w'); + + PhabricatorGlobalLock::clearConnectionPool(); + + $this->assertEqual( + 0, + PhabricatorGlobalLock::getConnectionPoolSize(), + pht('Clear Connection Pool')); + + $this->assertEqual( + false, + $conn->isHoldingAnyLock(), + pht('Specific Connection, No Lock')); + + $lock_name = $this->newLockName(); + $lock = PhabricatorGlobalLock::newLock($lock_name); + $lock->useSpecificConnection($conn); + $lock->lock(); + + $this->assertEqual( + 0, + PhabricatorGlobalLock::getConnectionPoolSize(), + pht('Connection Pool + Specific, With Lock')); + + $this->assertEqual( + true, + $conn->isHoldingAnyLock(), + pht('Specific Connection, Holding Lock')); + + $lock->unlock(); + + // The specific connection provided should NOT be returned to the + // connection pool. + + $this->assertEqual( + 0, + PhabricatorGlobalLock::getConnectionPoolSize(), + pht('Connection Pool + Specific, With Lock Released')); + + $this->assertEqual( + false, + $conn->isHoldingAnyLock(), + pht('Specific Connection, No Lock')); + + PhabricatorGlobalLock::clearConnectionPool(); + } + + private function newLockName() { + return 'testlock-'.Filesystem::readRandomCharacters(16); + } + +}