From 34cc8f6c0253260abec1069e1c37611756b78e17 Mon Sep 17 00:00:00 2001 From: Markus Klein <klein.t3@mfc-linz.at> Date: Fri, 7 Mar 2014 13:38:42 +0100 Subject: [PATCH] [TASK] Improve Locker Code cleanup for locker and fix of semaphore locking. It is now possible to reuse a semaphore. Resolves: #40420 Releases: 6.2 Change-Id: I843aca1f9fa3d070ce0a508a27d3c433725991fa Reviewed-on: https://review.typo3.org/28159 Reviewed-by: Thomas Maroschik Tested-by: Thomas Maroschik --- typo3/sysext/core/Classes/Locking/Locker.php | 309 +++++++++++++----- .../core/Classes/Mail/MboxTransport.php | 11 +- .../core/Tests/Unit/Locking/LockerTest.php | 105 ++---- 3 files changed, 278 insertions(+), 147 deletions(-) diff --git a/typo3/sysext/core/Classes/Locking/Locker.php b/typo3/sysext/core/Classes/Locking/Locker.php index bb02a401821e..74f304af4170 100644 --- a/typo3/sysext/core/Classes/Locking/Locker.php +++ b/typo3/sysext/core/Classes/Locking/Locker.php @@ -5,6 +5,7 @@ namespace TYPO3\CMS\Core\Locking; * Copyright notice * * (c) 2008-2013 Michael Stucki (michael@typo3.org) + * (c) 2014 Markus Klein <klein.t3@mfc-linz.at> * All rights reserved * * This script is part of the TYPO3 project. The TYPO3 project is @@ -26,6 +27,7 @@ namespace TYPO3\CMS\Core\Locking; * * This copyright notice MUST APPEAR in all copies of the script! ***************************************************************/ +use TYPO3\CMS\Core\Utility\GeneralUtility; /** * TYPO3 locking class @@ -35,13 +37,21 @@ namespace TYPO3\CMS\Core\Locking; * This is especially useful if two clients are requesting the same website short after each other. While the request of client 1 triggers building and caching of the website, client 2 will be waiting at this lock. * * @author Michael Stucki <michael@typo3.org> + * @author Markus Klein <klein.t3@mfc-linz.at> */ class Locker { + const LOCKING_METHOD_SIMPLE = 'simple'; + const LOCKING_METHOD_FLOCK = 'flock'; + const LOCKING_METHOD_SEMAPHORE = 'semaphore'; + const LOCKING_METHOD_DISABLED = 'disable'; + + const FILE_LOCK_FOLDER = 'typo3temp/locks/'; + /** - * @var string Locking method: One of 'simple', 'flock', 'semaphore' or 'disable' + * @var string Locking method: One of the constants above */ - protected $method; + protected $method = ''; /** * @var mixed Identifier used for this lock @@ -56,7 +66,7 @@ class Locker { /** * @var resource File pointer if using flock method */ - protected $filepointer; + protected $filePointer; /** * @var boolean True if lock is acquired @@ -87,84 +97,120 @@ class Locker { * Constructor: * initializes locking, check input parameters and set variables accordingly. * + * Parameters $loops and $step only apply to the locking method LOCKING_METHOD_SIMPLE. + * * @param string $id ID to identify this lock in the system - * @param string $method Define which locking method to use. Defaults to "simple". - * @param integer $loops Number of times a locked resource is tried to be acquired. Only used in manual locks method "simple". - * @param integer step Milliseconds after lock acquire is retried. $loops * $step results in the maximum delay of a lock. Only used in manual lock method "simple". + * @param string $method Define which locking method to use. Use one of the LOCKING_METHOD_* constants. Defaults to LOCKING_METHOD_SIMPLE. Use '' to use setting from Install Tool. + * @param int $loops Number of times a locked resource is tried to be acquired. + * @param int $step Milliseconds after lock acquire is retried. $loops * $step results in the maximum delay of a lock. + * @throws \RuntimeException + * @throws \InvalidArgumentException */ - public function __construct($id, $method = 'simple', $loops = 0, $step = 0) { + public function __construct($id, $method = self::LOCKING_METHOD_SIMPLE, $loops = 0, $step = 0) { // Force ID to be string - $id = (string) $id; + $id = (string)$id; if ((int)$loops) { $this->loops = (int)$loops; } if ((int)$step) { $this->step = (int)$step; } - $this->method = $method; - switch ($this->method) { - case 'simple': + if ($method === '' && isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['lockingMode'])) { + $method = (string)$GLOBALS['TYPO3_CONF_VARS']['SYS']['lockingMode']; + } - case 'flock': - $path = PATH_site . 'typo3temp/locks/'; + switch ($method) { + case self::LOCKING_METHOD_SIMPLE: + // intended fall through + case self::LOCKING_METHOD_FLOCK: + $path = PATH_site . self::FILE_LOCK_FOLDER; if (!is_dir($path)) { - \TYPO3\CMS\Core\Utility\GeneralUtility::mkdir($path); + GeneralUtility::mkdir($path); } $this->id = md5($id); $this->resource = $path . $this->id; break; - case 'semaphore': + case self::LOCKING_METHOD_SEMAPHORE: $this->id = abs(crc32($id)); - if (($this->resource = sem_get($this->id, 1)) === FALSE) { - throw new \RuntimeException('Unable to get semaphore', 1313828196); - } break; - case 'disable': + case self::LOCKING_METHOD_DISABLED: break; default: - throw new \InvalidArgumentException('No such method "' . $method . '"', 1294586097); + throw new \InvalidArgumentException('No such locking method "' . $method . '"', 1294586097); } + $this->method = $method; } /** * Destructor: - * Releases lock automatically when instance is destroyed. - * - * @return void - * @todo Define visibility + * Releases lock automatically when instance is destroyed and release resources */ public function __destruct() { $this->release(); + switch ($this->method) { + case self::LOCKING_METHOD_FLOCK: + if ( + GeneralUtility::isAllowedAbsPath($this->resource) + && GeneralUtility::isFirstPartOfStr($this->resource, PATH_site . self::FILE_LOCK_FOLDER) + ) { + @unlink($this->resource); + } + break; + case self::LOCKING_METHOD_SEMAPHORE: + @sem_remove($this->resource); + break; + default: + // do nothing + } } /** - * Acquire a lock and return when successful. If the lock is already open, the client will be + * Tries to allocate the semaphore * - * It is important to know that the lock will be acquired in any case, even if the request was blocked first. Therefore, the lock needs to be released in every situation. + * @return void + * @throws \RuntimeException + */ + protected function getSemaphore() { + $this->resource = sem_get($this->id, 1); + if ($this->resource === FALSE) { + throw new \RuntimeException('Unable to get semaphore with id ' . $this->id, 1313828196); + } + } + + /** + * Acquire a lock and return when successful. + * + * It is important to know that the lock will be acquired in any case, even if the request was blocked first. + * Therefore, the lock needs to be released in every situation. * * @return boolean Returns TRUE if lock could be acquired without waiting, FALSE otherwise. * @throws \RuntimeException + * @deprecated since 6.2 - will be removed two versions later; use new API instead */ public function acquire() { - // Default is TRUE, which means continue without caring for other clients. In the case of TYPO3s cache management, this has no negative effect except some resource overhead. - $noWait = TRUE; - $isAcquired = TRUE; + // TODO refactor locking in TSFE to use the new API, then this call can be logged + // GeneralUtility::logDeprecatedFunction(); + + // Default is TRUE, which means continue without caring for other clients. + // In the case of TYPO3s cache management, this has no negative effect except some resource overhead. + $noWait = FALSE; + $isAcquired = FALSE; switch ($this->method) { - case 'simple': - if (is_file($this->resource)) { + case self::LOCKING_METHOD_SIMPLE: + if (file_exists($this->resource)) { $this->sysLog('Waiting for a different process to release the lock'); - $maxExecutionTime = ini_get('max_execution_time'); - $maxAge = time() - ($maxExecutionTime ? $maxExecutionTime : 120); + $maxExecutionTime = (int)ini_get('max_execution_time'); + $maxAge = time() - ($maxExecutionTime ?: 120); if (@filectime($this->resource) < $maxAge) { @unlink($this->resource); - $this->sysLog('Unlink stale lockfile'); + $this->sysLog('Unlinking stale lockfile'); } } - $isAcquired = FALSE; for ($i = 0; $i < $this->loops; $i++) { - $filepointer = @fopen($this->resource, 'x'); - if ($filepointer !== FALSE) { - fclose($filepointer); + $filePointer = @fopen($this->resource, 'x'); + if ($filePointer !== FALSE) { + fclose($filePointer); + GeneralUtility::fixPermissions($this->resource); $this->sysLog('Lock acquired'); $noWait = $i === 0; $isAcquired = TRUE; @@ -175,41 +221,125 @@ class Locker { if (!$isAcquired) { throw new \RuntimeException('Lock file could not be created', 1294586098); } - \TYPO3\CMS\Core\Utility\GeneralUtility::fixPermissions($this->resource); break; - case 'flock': - if (($this->filepointer = fopen($this->resource, 'w+')) == FALSE) { + case self::LOCKING_METHOD_FLOCK: + $this->filePointer = fopen($this->resource, 'c'); + if ($this->filePointer === FALSE) { throw new \RuntimeException('Lock file could not be opened', 1294586099); } // Lock without blocking - if (flock($this->filepointer, (LOCK_EX | LOCK_NB)) == TRUE) { + if (flock($this->filePointer, LOCK_EX | LOCK_NB)) { $noWait = TRUE; - } elseif (flock($this->filepointer, LOCK_EX) == TRUE) { + } elseif (flock($this->filePointer, LOCK_EX)) { // Lock with blocking (waiting for similar locks to become released) $noWait = FALSE; } else { throw new \RuntimeException('Could not lock file "' . $this->resource . '"', 1294586100); } + $isAcquired = TRUE; break; - case 'semaphore': - if (sem_acquire($this->resource)) { - // Unfortunately it is not possible to find out if the request has blocked, - // as sem_acquire will block until we get the resource. - // So we return FALSE in any case. - $noWait = FALSE; - } else { - throw new \RuntimeException('Could not get lock on semaphore "' . $this->resource . '"', 1379502242); + case self::LOCKING_METHOD_SEMAPHORE: + $this->getSemaphore(); + while (!$isAcquired) { + if (@sem_acquire($this->resource)) { + // Unfortunately it is not possible to find out if the request has blocked, + // as sem_acquire will block until we get the resource. + // So we do not set $noWait here at all + $isAcquired = TRUE; + } } break; - case 'disable': - $noWait = FALSE; - $isAcquired = FALSE; + case self::LOCKING_METHOD_DISABLED: break; + default: + // will never be reached } $this->isAcquired = $isAcquired; return $noWait; } + /** + * Try to acquire an exclusive lock + * + * @throws \RuntimeException + * @return bool Returns TRUE if the lock was acquired successfully + */ + public function acquireExclusiveLock() { + if ($this->isAcquired) { + return TRUE; + } + $this->isAcquired = FALSE; + switch ($this->method) { + case self::LOCKING_METHOD_SIMPLE: + if (file_exists($this->resource)) { + $this->sysLog('Waiting for a different process to release the lock'); + $maxExecutionTime = (int)ini_get('max_execution_time'); + $maxAge = time() - ($maxExecutionTime ?: 120); + if (@filectime($this->resource) < $maxAge) { + @unlink($this->resource); + $this->sysLog('Unlinking stale lockfile'); + } + } + for ($i = 0; $i < $this->loops; $i++) { + $filePointer = @fopen($this->resource, 'x'); + if ($filePointer !== FALSE) { + fclose($filePointer); + GeneralUtility::fixPermissions($this->resource); + $this->sysLog('Lock acquired'); + $this->isAcquired = TRUE; + break; + } + usleep($this->step * 1000); + } + break; + case self::LOCKING_METHOD_FLOCK: + $this->filePointer = fopen($this->resource, 'c'); + if ($this->filePointer === FALSE) { + throw new \RuntimeException('Lock file could not be opened', 1294586099); + } + if (flock($this->filePointer, LOCK_EX)) { + $this->isAcquired = TRUE; + } + break; + case self::LOCKING_METHOD_SEMAPHORE: + $this->getSemaphore(); + if (@sem_acquire($this->resource)) { + $this->isAcquired = TRUE; + } + break; + case self::LOCKING_METHOD_DISABLED: + break; + default: + // will never be reached + } + return $this->isAcquired; + } + + /** + * Try to acquire a shared lock + * + * (Only works for the flock() locking method currently) + * + * @return bool Returns TRUE if the lock was acquired successfully + * @throws \RuntimeException + */ + public function acquireSharedLock() { + if ($this->isAcquired) { + return TRUE; + } + $isAcquired = FALSE; + if ($this->method === self::LOCKING_METHOD_FLOCK) { + $this->filePointer = fopen($this->resource, 'c'); + if ($this->filePointer === FALSE) { + throw new \RuntimeException('Lock file could not be opened', 1294586099); + } + if (flock($this->filePointer, LOCK_SH)) { + $isAcquired = TRUE; + } + } + return $isAcquired; + } + /** * Release the lock * @@ -221,34 +351,33 @@ class Locker { } $success = TRUE; switch ($this->method) { - case 'simple': - if (\TYPO3\CMS\Core\Utility\GeneralUtility::isAllowedAbsPath($this->resource) && \TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($this->resource, PATH_site . 'typo3temp/locks/')) { - if (@unlink($this->resource) == FALSE) { + case self::LOCKING_METHOD_SIMPLE: + if ( + GeneralUtility::isAllowedAbsPath($this->resource) + && GeneralUtility::isFirstPartOfStr($this->resource, PATH_site . self::FILE_LOCK_FOLDER) + ) { + if (@unlink($this->resource) === FALSE) { $success = FALSE; } } break; - case 'flock': - if (is_resource($this->filepointer)) { - if (flock($this->filepointer, LOCK_UN) == FALSE) { + case self::LOCKING_METHOD_FLOCK: + if (is_resource($this->filePointer)) { + if (flock($this->filePointer, LOCK_UN) === FALSE) { $success = FALSE; } - fclose($this->filepointer); - } - if (\TYPO3\CMS\Core\Utility\GeneralUtility::isAllowedAbsPath($this->resource) && \TYPO3\CMS\Core\Utility\GeneralUtility::isFirstPartOfStr($this->resource, PATH_site . 'typo3temp/locks/')) { - @unlink($this->resource); + fclose($this->filePointer); } break; - case 'semaphore': - if (@sem_release($this->resource)) { - sem_remove($this->resource); - } else { + case self::LOCKING_METHOD_SEMAPHORE: + if (!@sem_release($this->resource)) { $success = FALSE; } break; - case 'disable': - $success = FALSE; + case self::LOCKING_METHOD_DISABLED: break; + default: + // will never be reached } $this->isAcquired = FALSE; return $success; @@ -283,14 +412,48 @@ class Locker { } /** - * Return the status of a lock + * Return the local status of a lock * - * @return string Returns TRUE if lock is acquired, FALSE otherwise + * @return bool Returns TRUE if lock is acquired by this process, FALSE otherwise */ public function getLockStatus() { return $this->isAcquired; } + /** + * Return the global status of the lock + * + * @return bool Returns TRUE if the lock is locked by either this or another process, FALSE otherwise + */ + public function isLocked() { + $result = FALSE; + switch ($this->method) { + case self::LOCKING_METHOD_SIMPLE: + if (file_exists($this->resource)) { + $maxExecutionTime = (int)ini_get('max_execution_time'); + $maxAge = time() - ($maxExecutionTime ?: 120); + if (@filectime($this->resource) < $maxAge) { + @unlink($this->resource); + $this->sysLog('Unlinking stale lockfile'); + } else { + $result = TRUE; + } + } + break; + case self::LOCKING_METHOD_FLOCK: + // we can't detect this reliably here, since the third parameter of flock() does not work on windows + break; + case self::LOCKING_METHOD_SEMAPHORE: + // no way to detect this at all, no PHP API for that + break; + case self::LOCKING_METHOD_DISABLED: + break; + default: + // will never be reached + } + return $result; + } + /** * Sets the facility (extension name) for the syslog entry. * @@ -319,7 +482,7 @@ class Locker { */ public function sysLog($message, $severity = 0) { if ($this->isLoggingEnabled) { - \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog('Locking [' . $this->method . '::' . $this->id . ']: ' . trim($message), $this->syslogFacility, $severity); + GeneralUtility::sysLog('Locking [' . $this->method . '::' . $this->id . ']: ' . trim($message), $this->syslogFacility, $severity); } } diff --git a/typo3/sysext/core/Classes/Mail/MboxTransport.php b/typo3/sysext/core/Classes/Mail/MboxTransport.php index 792945553274..8133d7a41444 100644 --- a/typo3/sysext/core/Classes/Mail/MboxTransport.php +++ b/typo3/sysext/core/Classes/Mail/MboxTransport.php @@ -74,7 +74,7 @@ class MboxTransport implements \Swift_Transport { /** * Outputs the mail to a text file according to RFC 4155. * - * @param Swift_Mime_Message $message The message to send + * @param \Swift_Mime_Message $message The message to send * @param string[] &$failedRecipients To collect failures by-reference, nothing will fail in our debugging case * @return int * @throws \RuntimeException @@ -88,9 +88,9 @@ class MboxTransport implements \Swift_Transport { // Add the complete mail inclusive headers $messageStr .= $message->toString(); $messageStr .= LF . LF; - $lockObject = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Locking\\Locker', $this->debugFile, $GLOBALS['TYPO3_CONF_VARS']['SYS']['lockingMode']); + $lockObject = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Locking\\Locker', $this->debugFile); /** @var \TYPO3\CMS\Core\Locking\Locker $lockObject */ - $lockObject->acquire(); + $lockObject->acquireExclusiveLock(); // Write the mbox file $file = @fopen($this->debugFile, 'a'); if (!$file) { @@ -109,7 +109,7 @@ class MboxTransport implements \Swift_Transport { /** * Determine the best-use reverse path for this message * - * @param Swift_Mime_Message $message + * @param \Swift_Mime_Message $message * @return mixed|NULL */ private function getReversePath(\Swift_Mime_Message $message) { @@ -132,7 +132,8 @@ class MboxTransport implements \Swift_Transport { /** * Register a plugin in the Transport. * - * @param Swift_Events_EventListener $plugin + * @param \Swift_Events_EventListener $plugin + * @return bool */ public function registerPlugin(\Swift_Events_EventListener $plugin) { return TRUE; diff --git a/typo3/sysext/core/Tests/Unit/Locking/LockerTest.php b/typo3/sysext/core/Tests/Unit/Locking/LockerTest.php index 87c63186d320..56faefac6830 100644 --- a/typo3/sysext/core/Tests/Unit/Locking/LockerTest.php +++ b/typo3/sysext/core/Tests/Unit/Locking/LockerTest.php @@ -23,6 +23,7 @@ namespace TYPO3\CMS\Core\Tests\Unit\Locking; * * This copyright notice MUST APPEAR in all copies of the script! ***************************************************************/ +use TYPO3\CMS\Core\Locking\Locker; /** * Testcase for \TYPO3\CMS\Core\Locking\Locker @@ -38,95 +39,81 @@ class LockerTest extends \TYPO3\CMS\Core\Tests\UnitTestCase { * @test */ public function constructorUsesDefaultLockingMethodSimple() { - $instance = new \TYPO3\CMS\Core\Locking\Locker('999999999'); - $this->assertSame('simple', $instance->getMethod()); + $instance = new Locker('999999999'); + $this->assertSame(Locker::LOCKING_METHOD_SIMPLE, $instance->getMethod()); } /** * @test */ public function constructorSetsMethodToGivenParameter() { - $instance = new \TYPO3\CMS\Core\Locking\Locker('999999999', 'flock'); - $this->assertSame('flock', $instance->getMethod()); + $instance = new Locker('999999999', Locker::LOCKING_METHOD_FLOCK); + $this->assertSame(Locker::LOCKING_METHOD_FLOCK, $instance->getMethod()); } /** * @test + * @expectedException \InvalidArgumentException */ - public function constructorDoesNotThrowExceptionIfUsingDisableMethod() { - $instance = new \TYPO3\CMS\Core\Locking\Locker('999999999', 'disable'); + public function constructorThrowsExceptionForNotExistingLockingMethod() { + new Locker('999999999', 'foo'); } /** * @test - * @expectedException \InvalidArgumentException */ - public function constructorThrowsExceptionForNotExistingLockingMethod() { - $instance = new \TYPO3\CMS\Core\Locking\Locker('999999999', 'foo'); + public function constructorFetchesInstallToolConfigurationIfEmptyMethod() { + $GLOBALS['TYPO3_CONF_VARS']['SYS']['lockingMode'] = Locker::LOCKING_METHOD_SIMPLE; + $instance = new Locker('999999999', ''); + $this->assertSame(Locker::LOCKING_METHOD_SIMPLE, $instance->getMethod()); } /** * @test */ public function constructorUsesDefaultValueForLoops() { - $instance = new \TYPO3\CMS\Core\Locking\Locker('999999999'); - $instance->setEnableLogging(FALSE); - $t3libLockReflection = new \ReflectionClass('TYPO3\\CMS\\Core\\Locking\\Locker'); - $t3libLockReflectionResourceProperty = $t3libLockReflection->getProperty('loops'); - $t3libLockReflectionResourceProperty->setAccessible(TRUE); - $this->assertSame(150, $t3libLockReflectionResourceProperty->getValue($instance)); + $instance = $this->getAccessibleMock('TYPO3\\CMS\\Core\\Locking\\Locker', array('dummy'), array('999999999', Locker::LOCKING_METHOD_DISABLED)); + $this->assertSame(150, $instance->_get('loops')); } /** * @test */ public function constructorSetsLoopsToGivenNumberOfLoops() { - $instance = new \TYPO3\CMS\Core\Locking\Locker('999999999', 'simple', 10); - $instance->setEnableLogging(FALSE); - $t3libLockReflection = new \ReflectionClass('TYPO3\\CMS\\Core\\Locking\\Locker'); - $t3libLockReflectionResourceProperty = $t3libLockReflection->getProperty('loops'); - $t3libLockReflectionResourceProperty->setAccessible(TRUE); - $this->assertSame(10, $t3libLockReflectionResourceProperty->getValue($instance)); + $instance = $this->getAccessibleMock('TYPO3\\CMS\\Core\\Locking\\Locker', array('dummy'), array('999999999', Locker::LOCKING_METHOD_DISABLED, 10)); + $this->assertSame(10, $instance->_get('loops')); } /** * @test */ public function constructorUsesDefaultValueForSteps() { - $instance = new \TYPO3\CMS\Core\Locking\Locker('999999999'); - $instance->setEnableLogging(FALSE); - $t3libLockReflection = new \ReflectionClass('TYPO3\\CMS\\Core\\Locking\\Locker'); - $t3libLockReflectionResourceProperty = $t3libLockReflection->getProperty('step'); - $t3libLockReflectionResourceProperty->setAccessible(TRUE); - $this->assertSame(200, $t3libLockReflectionResourceProperty->getValue($instance)); + $instance = $this->getAccessibleMock('TYPO3\\CMS\\Core\\Locking\\Locker', array('dummy'), array('999999999', Locker::LOCKING_METHOD_DISABLED)); + $this->assertSame(200, $instance->_get('step')); } /** * @test */ public function constructorSetsStepToGivenNumberOfStep() { - $instance = new \TYPO3\CMS\Core\Locking\Locker('999999999', 'simple', 0, 10); - $instance->setEnableLogging(FALSE); - $t3libLockReflection = new \ReflectionClass('TYPO3\\CMS\\Core\\Locking\\Locker'); - $t3libLockReflectionResourceProperty = $t3libLockReflection->getProperty('step'); - $t3libLockReflectionResourceProperty->setAccessible(TRUE); - $this->assertSame(10, $t3libLockReflectionResourceProperty->getValue($instance)); + $instance = $this->getAccessibleMock('TYPO3\\CMS\\Core\\Locking\\Locker', array('dummy'), array('999999999', Locker::LOCKING_METHOD_DISABLED, 0, 10)); + $this->assertSame(10, $instance->_get('step')); } /** * @test */ public function constructorCreatesLockDirectoryIfNotExisting() { - \TYPO3\CMS\Core\Utility\GeneralUtility::rmdir(PATH_site . 'typo3temp/locks/', TRUE); - $instance = new \TYPO3\CMS\Core\Locking\Locker('999999999', 'simple'); - $this->assertTrue(is_dir(PATH_site . 'typo3temp/locks/')); + \TYPO3\CMS\Core\Utility\GeneralUtility::rmdir(PATH_site . Locker::FILE_LOCK_FOLDER, TRUE); + new Locker('999999999', Locker::LOCKING_METHOD_SIMPLE); + $this->assertTrue(is_dir(PATH_site . Locker::FILE_LOCK_FOLDER)); } /** * @test */ - public function constructorSetsIdToMd5OfStringIfUsingSimleLocking() { - $instance = new \TYPO3\CMS\Core\Locking\Locker('999999999', 'simple'); + public function constructorSetsIdToMd5OfStringIfUsingSimpleLocking() { + $instance = new Locker('999999999', Locker::LOCKING_METHOD_SIMPLE); $this->assertSame(md5('999999999'), $instance->getId()); } @@ -134,8 +121,8 @@ class LockerTest extends \TYPO3\CMS\Core\Tests\UnitTestCase { * @test */ public function constructorSetsResourceToPathWithIdIfUsingSimpleLocking() { - $instance = new \TYPO3\CMS\Core\Locking\Locker('999999999', 'simple'); - $this->assertSame(PATH_site . 'typo3temp/locks/' . md5('999999999'), $instance->getResource()); + $instance = new Locker('999999999', Locker::LOCKING_METHOD_SIMPLE); + $this->assertSame(PATH_site . Locker::FILE_LOCK_FOLDER . md5('999999999'), $instance->getResource()); } /** @@ -145,21 +132,10 @@ class LockerTest extends \TYPO3\CMS\Core\Tests\UnitTestCase { if (!function_exists('sem_get')) { $this->markTestSkipped('The system does not support semaphore base locking.'); } - $instance = new \TYPO3\CMS\Core\Locking\Locker('999999999', 'semaphore'); + $instance = new Locker('999999999', Locker::LOCKING_METHOD_SEMAPHORE); $this->assertSame(abs(crc32('999999999')), $instance->getId()); } - /** - * @test - */ - public function constructorSetsResourceToSemaphoreResourceIfUsingSemaphoreLocking() { - if (!function_exists('sem_get')) { - $this->markTestSkipped('The system does not support semaphore base locking.'); - } - $instance = new \TYPO3\CMS\Core\Locking\Locker('999999999', 'semaphore'); - $this->assertTrue(is_resource($instance->getResource())); - } - /////////////////////////////// // tests concerning acquire /////////////////////////////// @@ -171,42 +147,33 @@ class LockerTest extends \TYPO3\CMS\Core\Tests\UnitTestCase { $this->markTestSkipped('acquireFixesPermissionsOnLockFileIfUsingSimpleLogging() test not available on Windows.'); } // Use a very high id to be unique - $instance = new \TYPO3\CMS\Core\Locking\Locker(999999999, 'simple'); + $instance = new Locker(999999999, Locker::LOCKING_METHOD_SIMPLE); + $instance->setEnableLogging(FALSE); $pathOfLockFile = $instance->getResource(); $GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'] = '0777'; // Acquire lock, get actual file permissions and clean up - $instance->acquire(); + $instance->acquireExclusiveLock(); clearstatcache(); $resultFilePermissions = substr(decoct(fileperms($pathOfLockFile)), 2); - $instance->__destruct(); + $instance->release(); $this->assertEquals($resultFilePermissions, '0777'); } /////////////////////////////// // tests concerning release /////////////////////////////// - /** - * Dataprovider for releaseRemovesLockfileInTypo3TempLocks - */ - public function fileBasedLockMethods() { - return array( - 'simple' => array('simple'), - 'flock' => array('flock') - ); - } /** * @test - * @dataProvider fileBasedLockMethods */ - public function releaseRemovesLockfileInTypo3TempLocks($lockMethod) { + public function releaseRemovesLockfileInTypo3TempLocks() { // Use a very high id to be unique - $instance = new \TYPO3\CMS\Core\Locking\Locker(999999999, $lockMethod); + $instance = new Locker(999999999, Locker::LOCKING_METHOD_SIMPLE); // Disable logging $instance->setEnableLogging(FALSE); // File pointer to current lock file $lockFile = $instance->getResource(); - $instance->acquire(); + $instance->acquireExclusiveLock(); $instance->release(); $this->assertFalse(is_file($lockFile)); } @@ -241,7 +208,7 @@ class LockerTest extends \TYPO3\CMS\Core\Tests\UnitTestCase { $this->markTestSkipped('releaseDoesNotRemoveFilesNotWithinTypo3TempLocksDirectory() skipped: Test file could not be created'); } // Create instance, set lockfile to invalid path - $instance = new \TYPO3\CMS\Core\Locking\Locker(999999999, $lockMethod); + $instance = new Locker(999999999, $lockMethod); $instance->setEnableLogging(FALSE); $t3libLockReflection = new \ReflectionClass('TYPO3\\CMS\\Core\\Locking\\Locker'); $t3libLockReflectionResourceProperty = $t3libLockReflection->getProperty('resource'); -- GitLab