Changeset View
Changeset View
Standalone View
Standalone View
src/infrastructure/util/PhabricatorGlobalLock.php
Show First 20 Lines • Show All 143 Lines • ▼ Show 20 Lines | if (!$conn) { | ||||
// application. | // application. | ||||
$dao = new PhabricatorRepository(); | $dao = new PhabricatorRepository(); | ||||
// NOTE: Using "force_new" to make sure each lock is on its own | // NOTE: Using "force_new" to make sure each lock is on its own | ||||
// connection. | // connection. | ||||
$conn = $dao->establishConnection('w', $force_new = true); | $conn = $dao->establishConnection('w', $force_new = true); | ||||
} | } | ||||
// See T13627. We must never hold more than one lock per connection, so | |||||
// make sure this connection has no existing locks. (Normally, we should | |||||
// only be able to get here if callers explicitly provide the same external | |||||
// connection to multiple locks.) | |||||
if ($conn->isHoldingAnyLock()) { | |||||
throw new Exception( | |||||
pht( | |||||
'Unable to establish lock on connection: this connection is '. | |||||
'already holding a lock. Acquiring a second lock on the same '. | |||||
'connection would release the first lock in MySQL versions '. | |||||
'older than 5.7.')); | |||||
} | |||||
// 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(); | $lock_name = $this->getName(); | ||||
$result = queryfx_one( | $result = queryfx_one( | ||||
$conn, | $conn, | ||||
'SELECT GET_LOCK(%s, %f)', | 'SELECT GET_LOCK(%s, %f)', | ||||
$lock_name, | $lock_name, | ||||
$wait); | $wait); | ||||
$ok = head($result); | $ok = head($result); | ||||
if (!$ok) { | if (!$ok) { | ||||
// See PHI1794. We failed to acquire the lock, but the connection itself | // See PHI1794. We failed to acquire the lock, but the connection itself | ||||
// is still good. We're done with it, so add it to the pool, just as we | // is still good. We're done with it, so add it to the pool, just as we | ||||
// would if we were releasing the lock. | // would if we were releasing the lock. | ||||
// If we don't do this, we may establish a huge number of connections | // If we don't do this, we may establish a huge number of connections | ||||
// very rapidly if many workers try to acquire a lock at once. For | // very rapidly if many workers try to acquire a lock at once. For | ||||
// example, this can happen if there are a large number of webhook tasks | // example, this can happen if there are a large number of webhook tasks | ||||
// in the queue. | // in the queue. | ||||
self::$pool[] = $conn; | self::$pool[] = $conn; | ||||
throw id(new PhutilLockException($lock_name)) | throw id(new PhutilLockException($lock_name)) | ||||
->setHint($this->newHint($lock_name, $wait)); | ->setHint($this->newHint($lock_name, $wait)); | ||||
▲ Show 20 Lines • Show All 226 Lines • Show Last 20 Lines |