Changeset View
Changeset View
Standalone View
Standalone View
src/infrastructure/util/PhabricatorGlobalLock.php
| Show All 23 Lines | |||||
| * are isolated from one another. | * are isolated from one another. | ||||
| * | * | ||||
| * @task construct Constructing Locks | * @task construct Constructing Locks | ||||
| * @task impl Implementation | * @task impl Implementation | ||||
| */ | */ | ||||
| final class PhabricatorGlobalLock extends PhutilLock { | final class PhabricatorGlobalLock extends PhutilLock { | ||||
| private $conn; | private $conn; | ||||
| private $isExternalConnection = false; | |||||
| private static $pool = array(); | private static $pool = array(); | ||||
| /* -( Constructing Locks )------------------------------------------------- */ | /* -( Constructing Locks )------------------------------------------------- */ | ||||
| public static function newLock($name) { | public static function newLock($name) { | ||||
| Show All 29 Lines | /* -( Constructing Locks )------------------------------------------------- */ | ||||
| * (somewhat arbitrarily). In most cases this is fine, but this method can | * (somewhat arbitrarily). In most cases this is fine, but this method can | ||||
| * be used to lock on a specific connection. | * be used to lock on a specific connection. | ||||
| * | * | ||||
| * @param AphrontDatabaseConnection | * @param AphrontDatabaseConnection | ||||
| * @return this | * @return this | ||||
| */ | */ | ||||
| public function useSpecificConnection(AphrontDatabaseConnection $conn) { | public function useSpecificConnection(AphrontDatabaseConnection $conn) { | ||||
| $this->conn = $conn; | $this->conn = $conn; | ||||
| $this->isExternalConnection = true; | |||||
| return $this; | return $this; | ||||
| } | } | ||||
| /* -( Implementation )----------------------------------------------------- */ | /* -( Implementation )----------------------------------------------------- */ | ||||
| protected function doLock($wait) { | protected function doLock($wait) { | ||||
| $conn = $this->conn; | $conn = $this->conn; | ||||
| Show All 19 Lines | protected function doLock($wait) { | ||||
| } | } | ||||
| // NOTE: Since MySQL will disconnect us if we're idle for too long, we set | // NOTE: Since MySQL will disconnect us if we're idle for too long, we set | ||||
| // the wait_timeout to an enormous value, to allow us to hold the | // the wait_timeout to an enormous value, to allow us to hold the | ||||
| // connection open indefinitely (or, at least, for 24 days). | // connection open indefinitely (or, at least, for 24 days). | ||||
| $max_allowed_timeout = 2147483; | $max_allowed_timeout = 2147483; | ||||
| queryfx($conn, 'SET wait_timeout = %d', $max_allowed_timeout); | queryfx($conn, 'SET wait_timeout = %d', $max_allowed_timeout); | ||||
| $lock_name = $this->getName(); | |||||
| $result = queryfx_one( | $result = queryfx_one( | ||||
| $conn, | $conn, | ||||
| 'SELECT GET_LOCK(%s, %f)', | 'SELECT GET_LOCK(%s, %f)', | ||||
| $this->getName(), | $lock_name, | ||||
| $wait); | $wait); | ||||
| $ok = head($result); | $ok = head($result); | ||||
| if (!$ok) { | if (!$ok) { | ||||
| throw new PhutilLockException($this->getName()); | throw new PhutilLockException($lock_name); | ||||
| } | } | ||||
| $conn->rememberLock($lock_name); | |||||
| $this->conn = $conn; | $this->conn = $conn; | ||||
| } | } | ||||
| protected function doUnlock() { | protected function doUnlock() { | ||||
| queryfx( | $lock_name = $this->getName(); | ||||
| $this->conn, | |||||
| $conn = $this->conn; | |||||
| try { | |||||
| $result = queryfx_one( | |||||
| $conn, | |||||
| 'SELECT RELEASE_LOCK(%s)', | 'SELECT RELEASE_LOCK(%s)', | ||||
| $this->getName()); | $lock_name); | ||||
| $conn->forgetLock($lock_name); | |||||
| } catch (Exception $ex) { | |||||
| $result = array(null); | |||||
| } | |||||
| $ok = head($result); | |||||
| if (!$ok) { | |||||
| // TODO: We could throw here, but then this lock doesn't get marked | |||||
Lint: TODO Comment: This comment has a TODO. | |||||
| // unlocked and we throw again later when exiting. It also doesn't | |||||
| // particularly matter for any current applications. For now, just | |||||
| // swallow the error. | |||||
| } | |||||
| $this->conn->close(); | |||||
| self::$pool[] = $this->conn; | |||||
| $this->conn = null; | $this->conn = null; | ||||
| $this->isExternalConnection = false; | |||||
| if (!$this->isExternalConnection) { | |||||
| $conn->close(); | |||||
| self::$pool[] = $conn; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
This comment has a TODO.