From 67ecc713642f40e18917b609f41219b82057b5b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Mon, 31 Jul 2017 09:31:57 +0200 Subject: [PATCH] Deprecate Filesystem/LockHandler --- UPGRADE-3.4.md | 7 +++++ UPGRADE-4.0.md | 7 +++++ .../Console/Command/LockableTrait.php | 31 ++++++++++++------- .../Tests/Command/LockableTraitTest.php | 14 +++++++-- src/Symfony/Component/Console/composer.json | 4 +-- .../Component/Filesystem/LockHandler.php | 6 ++++ .../Filesystem/Tests/LockHandlerTest.php | 3 ++ .../Component/Lock/Store/SemaphoreStore.php | 19 ++++++++++-- .../Tests/Store/BlockingStoreTestTrait.php | 8 ++--- 9 files changed, 77 insertions(+), 22 deletions(-) diff --git a/UPGRADE-3.4.md b/UPGRADE-3.4.md index 503e74922ce41..1619ec95adf04 100644 --- a/UPGRADE-3.4.md +++ b/UPGRADE-3.4.md @@ -11,6 +11,13 @@ Debug * Support for stacked errors in the `ErrorHandler` is deprecated and will be removed in Symfony 4.0. +Filesystem +---------- + + * The `Symfony\Component\Filesystem\LockHandler` class has been deprecated, + use the `Symfony\Component\Lock\Store\FlockStore` class + or the `Symfony\Component\Lock\Store\FlockStore\SemaphoreStore` class directly instead. + Finder ------ diff --git a/UPGRADE-4.0.md b/UPGRADE-4.0.md index 5a8042835c2da..aabaed1c3c18c 100644 --- a/UPGRADE-4.0.md +++ b/UPGRADE-4.0.md @@ -147,6 +147,13 @@ ExpressionLanguage class has been removed. You should use the `CacheItemPoolInterface` interface instead. +Filesystem +---------- + + * The `Symfony\Component\Filesystem\LockHandler` has been removed, + use the `Symfony\Component\Lock\Store\FlockStore` class + or the `Symfony\Component\Lock\Store\FlockStore\SemaphoreStore` class directly instead. + Finder ------ diff --git a/src/Symfony/Component/Console/Command/LockableTrait.php b/src/Symfony/Component/Console/Command/LockableTrait.php index 95597705941ca..b521f3b7708b9 100644 --- a/src/Symfony/Component/Console/Command/LockableTrait.php +++ b/src/Symfony/Component/Console/Command/LockableTrait.php @@ -13,7 +13,10 @@ use Symfony\Component\Console\Exception\LogicException; use Symfony\Component\Console\Exception\RuntimeException; -use Symfony\Component\Filesystem\LockHandler; +use Symfony\Component\Lock\Factory; +use Symfony\Component\Lock\Lock; +use Symfony\Component\Lock\Store\FlockStore; +use Symfony\Component\Lock\Store\SemaphoreStore; /** * Basic lock feature for commands. @@ -22,7 +25,8 @@ */ trait LockableTrait { - private $lockHandler; + /** @var Lock */ + private $lock; /** * Locks a command. @@ -31,18 +35,23 @@ trait LockableTrait */ private function lock($name = null, $blocking = false) { - if (!class_exists(LockHandler::class)) { - throw new RuntimeException('To enable the locking feature you must install the symfony/filesystem component.'); + if (!class_exists(SemaphoreStore::class)) { + throw new RuntimeException('To enable the locking feature you must install the symfony/lock component.'); } - if (null !== $this->lockHandler) { + if (null !== $this->lock) { throw new LogicException('A lock is already in place.'); } - $this->lockHandler = new LockHandler($name ?: $this->getName()); + if (SemaphoreStore::isSupported($blocking)) { + $store = new SemaphoreStore(); + } else { + $store = new FlockStore(sys_get_temp_dir()); + } - if (!$this->lockHandler->lock($blocking)) { - $this->lockHandler = null; + $this->lock = (new Factory($store))->createLock($name ?: $this->getName()); + if (!$this->lock->acquire($blocking)) { + $this->lock = null; return false; } @@ -55,9 +64,9 @@ private function lock($name = null, $blocking = false) */ private function release() { - if ($this->lockHandler) { - $this->lockHandler->release(); - $this->lockHandler = null; + if ($this->lock) { + $this->lock->release(); + $this->lock = null; } } } diff --git a/src/Symfony/Component/Console/Tests/Command/LockableTraitTest.php b/src/Symfony/Component/Console/Tests/Command/LockableTraitTest.php index d45da73bf329c..401ff823a7761 100644 --- a/src/Symfony/Component/Console/Tests/Command/LockableTraitTest.php +++ b/src/Symfony/Component/Console/Tests/Command/LockableTraitTest.php @@ -13,7 +13,9 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Tester\CommandTester; -use Symfony\Component\Filesystem\LockHandler; +use Symfony\Component\Lock\Factory; +use Symfony\Component\Lock\Store\FlockStore; +use Symfony\Component\Lock\Store\SemaphoreStore; class LockableTraitTest extends TestCase { @@ -39,8 +41,14 @@ public function testLockReturnsFalseIfAlreadyLockedByAnotherCommand() { $command = new \FooLockCommand(); - $lock = new LockHandler($command->getName()); - $lock->lock(); + if (SemaphoreStore::isSupported(false)) { + $store = new SemaphoreStore(); + } else { + $store = new FlockStore(sys_get_temp_dir()); + } + + $lock = (new Factory($store))->createLock($command->getName()); + $lock->acquire(); $tester = new CommandTester($command); $this->assertSame(1, $tester->execute(array())); diff --git a/src/Symfony/Component/Console/composer.json b/src/Symfony/Component/Console/composer.json index 5f7fe6ec1aa3b..472136c87ea10 100644 --- a/src/Symfony/Component/Console/composer.json +++ b/src/Symfony/Component/Console/composer.json @@ -25,13 +25,13 @@ "symfony/http-kernel": "~2.8|~3.0|~4.0", "symfony/event-dispatcher": "~2.8|~3.0|~4.0", "symfony/dependency-injection": "~3.3|~4.0", - "symfony/filesystem": "~2.8|~3.0|~4.0", + "symfony/lock": "~3.4|~4.0", "symfony/process": "~3.3|~4.0", "psr/log": "~1.0" }, "suggest": { "symfony/event-dispatcher": "", - "symfony/filesystem": "", + "symfony/lock": "", "symfony/process": "", "psr/log": "For using the console logger" }, diff --git a/src/Symfony/Component/Filesystem/LockHandler.php b/src/Symfony/Component/Filesystem/LockHandler.php index 3496faae21336..a05529f13c3ec 100644 --- a/src/Symfony/Component/Filesystem/LockHandler.php +++ b/src/Symfony/Component/Filesystem/LockHandler.php @@ -11,7 +11,11 @@ namespace Symfony\Component\Filesystem; +@trigger_error(sprintf('The %s class is deprecated since version 3.4 and will be removed in 4.0. Use %s or %s instead.', LockHandler::class, SemaphoreStore::class, FlockStore::class), E_USER_DEPRECATED); + use Symfony\Component\Filesystem\Exception\IOException; +use Symfony\Component\Lock\Store\FlockStore; +use Symfony\Component\Lock\Store\SemaphoreStore; /** * LockHandler class provides a simple abstraction to lock anything by means of @@ -25,6 +29,8 @@ * @author Grégoire Pineau * @author Romain Neutron * @author Nicolas Grekas + * + * @deprecated since version 3.4, to be removed in 4.0. Use Symfony\Component\Lock\Store\SemaphoreStore or Symfony\Component\Lock\Store\FlockStore instead. */ class LockHandler { diff --git a/src/Symfony/Component/Filesystem/Tests/LockHandlerTest.php b/src/Symfony/Component/Filesystem/Tests/LockHandlerTest.php index 9ed871ea5a2a3..e0b2281e0552a 100644 --- a/src/Symfony/Component/Filesystem/Tests/LockHandlerTest.php +++ b/src/Symfony/Component/Filesystem/Tests/LockHandlerTest.php @@ -16,6 +16,9 @@ use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Filesystem\LockHandler; +/** + * @group legacy + */ class LockHandlerTest extends TestCase { /** diff --git a/src/Symfony/Component/Lock/Store/SemaphoreStore.php b/src/Symfony/Component/Lock/Store/SemaphoreStore.php index 9b375fe8d9746..006f6f3f14f80 100644 --- a/src/Symfony/Component/Lock/Store/SemaphoreStore.php +++ b/src/Symfony/Component/Lock/Store/SemaphoreStore.php @@ -24,9 +24,24 @@ */ class SemaphoreStore implements StoreInterface { - public static function isSupported() + /** + * Returns whether or not the store is supported. + * + * @param bool|null $blocking When not null, checked again the blocking mode. + * + * @return bool + */ + public static function isSupported($blocking = null) { - return extension_loaded('sysvsem'); + if (!extension_loaded('sysvsem')) { + return false; + } + + if ($blocking === false && \PHP_VERSION_ID < 50601) { + return false; + } + + return true; } public function __construct() diff --git a/src/Symfony/Component/Lock/Tests/Store/BlockingStoreTestTrait.php b/src/Symfony/Component/Lock/Tests/Store/BlockingStoreTestTrait.php index 566f7eb562daf..d95837ff7456d 100644 --- a/src/Symfony/Component/Lock/Tests/Store/BlockingStoreTestTrait.php +++ b/src/Symfony/Component/Lock/Tests/Store/BlockingStoreTestTrait.php @@ -35,7 +35,7 @@ abstract protected function getStore(); public function testBlockingLocks() { // Amount a microsecond used to order async actions - $clockDelay = 50000; + $clockDelay = 200000; if (\PHP_VERSION_ID < 50600 || defined('HHVM_VERSION_ID')) { $this->markTestSkipped('The PHP engine does not keep resource in child forks'); @@ -49,7 +49,7 @@ public function testBlockingLocks() if ($childPID1 = pcntl_fork()) { // give time to fork to start - usleep(2 * $clockDelay); + usleep(1 * $clockDelay); try { // This call should failed given the lock should already by acquired by the child #1 @@ -69,8 +69,8 @@ public function testBlockingLocks() } else { try { $store->save($key); - // Wait 3 ClockDelay to let parent process to finish - usleep(3 * $clockDelay); + // Wait 2 ClockDelay to let parent process to finish + usleep(2 * $clockDelay); $store->delete($key); exit(0); } catch (\Exception $e) {