From 1fe3d61a3bac1fb8e59b9d026d9f37b5c5eadd4a Mon Sep 17 00:00:00 2001 From: Robert Korulczyk Date: Sun, 4 Nov 2018 22:23:24 +0100 Subject: [PATCH] Fixes #16838: `yii\mutex\Mutex::acquire()` no longer returns `true` if lock is already acquired by the same component in the same process --- framework/CHANGELOG.md | 1 + framework/UPGRADE.md | 11 +++++++++++ framework/mutex/Mutex.php | 2 +- tests/framework/mutex/MutexTestTrait.php | 25 ++++++++++++++++++++---- 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 3f70aaa007..bbc07e478e 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -78,6 +78,7 @@ Yii Framework 2 Change Log - Bug #15204: `yii\helpers\BaseInflector::slug()` is not removing substrings matching provided replacement from given string anymore (bizley) - Bug #16101: Fixed Error Handler to clear registered meta tags, link tags, css/js scripts and files in error view (bizley) - Bug #16836: Fix `yii\mutex\MysqlMutex` to handle locks with names longer than 64 characters (rob006) +- Bug #16838: `yii\mutex\Mutex::acquire()` no longer returns `true` if lock is already acquired by the same component in the same process (rob006) - Enh #16839: Increase frequency of lock tries for `yii\mutex\FileMutex::acquireLock()` when $timeout is provided (rob006) - Enh #16839: Add support for `$timeout` in `yii\mutex\PgsqlMutex::acquire()` (rob006) - Bug #16828: `yii\console\controllers\MessageController::translator` recognized object' methods and functions calls as identical sets of tokens (erickskrauch) diff --git a/framework/UPGRADE.md b/framework/UPGRADE.md index e89e542af1..1ecf7457eb 100644 --- a/framework/UPGRADE.md +++ b/framework/UPGRADE.md @@ -62,6 +62,17 @@ Upgrade from Yii 2.0.15 ```json "cebe/markdown": "~1.1.0", ``` + +* `yii\mutex\Mutex::acquire()` no longer returns `true` if lock is already acquired by the same component in the same process. + Make sure that you're not trying to acquire the same lock multiple times in a way that may create infinite loops, for example: + + ```php + if (Yii::$app->mutex->acquire('test')) { + while (!Yii::$app->mutex->acquire('test')) { + // `Yii::$app->mutex->acquire('test')` will always return `false` here, since lock is already acquired + } + } + ``` Upgrade from Yii 2.0.14 diff --git a/framework/mutex/Mutex.php b/framework/mutex/Mutex.php index 794c8fd87f..9bbd11495b 100644 --- a/framework/mutex/Mutex.php +++ b/framework/mutex/Mutex.php @@ -69,7 +69,7 @@ abstract class Mutex extends Component */ public function acquire($name, $timeout = 0) { - if ($this->acquireLock($name, $timeout)) { + if (!in_array($name, $this->_locks, true) && $this->acquireLock($name, $timeout)) { $this->_locks[] = $name; return true; diff --git a/tests/framework/mutex/MutexTestTrait.php b/tests/framework/mutex/MutexTestTrait.php index 3fa77d360a..fce50ec9d5 100644 --- a/tests/framework/mutex/MutexTestTrait.php +++ b/tests/framework/mutex/MutexTestTrait.php @@ -41,15 +41,32 @@ trait MutexTestTrait */ public function testThatMutexLockIsWorking($mutexName) { - $mutexOne = $this->createMutex($mutexName); - $mutexTwo = $this->createMutex($mutexName); + $mutexOne = $this->createMutex(); + $mutexTwo = $this->createMutex(); $this->assertTrue($mutexOne->acquire($mutexName)); $this->assertFalse($mutexTwo->acquire($mutexName)); - - $mutexOne->release($mutexName); + $this->assertTrue($mutexOne->release($mutexName)); + $this->assertFalse($mutexTwo->release($mutexName)); $this->assertTrue($mutexTwo->acquire($mutexName)); + $this->assertTrue($mutexTwo->release($mutexName)); + } + + /** + * @dataProvider mutexDataProvider() + * + * @param string $mutexName + */ + public function testThatMutexLockIsWorkingOnTheSameComponent($mutexName) + { + $mutex = $this->createMutex(); + + $this->assertTrue($mutex->acquire($mutexName)); + $this->assertFalse($mutex->acquire($mutexName)); + + $this->assertTrue($mutex->release($mutexName)); + $this->assertFalse($mutex->release($mutexName)); } public function testTimeout()