Skip to content

Rename NoMutex class to NullMutex #74

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ implementations or create/extend your own implementation.
#### FlockMutex

The **FlockMutex** is a lock implementation based on
[`flock()`](http://php.net/manual/en/function.flock.php).
[`flock()`](https://php.net/manual/en/function.flock.php).

Example:
```php
Expand All @@ -194,7 +194,7 @@ extension if possible or busy waiting if not.
#### MemcachedMutex

The **MemcachedMutex** is a spinlock implementation which uses the
[`Memcached` extension](http://php.net/manual/en/book.memcached.php).
[`Memcached` extension](https://php.net/manual/en/book.memcached.php).

Example:
```php
Expand All @@ -215,7 +215,7 @@ $mutex->synchronized(function () use ($bankAccount, $amount) {
#### RedisMutex

The **RedisMutex** is the distributed lock implementation of
[RedLock](http://redis.io/topics/distlock) which supports the
[RedLock](https://redis.io/topics/distlock#the-redlock-algorithm) which supports the
[`phpredis` extension](https://github.com/phpredis/phpredis)
or [`Predis` API](https://github.com/nrk/predis).

Expand Down Expand Up @@ -244,7 +244,7 @@ $mutex->synchronized(function () use ($bankAccount, $amount) {
#### SemaphoreMutex

The **SemaphoreMutex** is a lock implementation based on
[Semaphore](http://php.net/manual/en/ref.sem.php).
[Semaphore](https://php.net/manual/en/ref.sem.php).

Example:
```php
Expand Down Expand Up @@ -330,9 +330,9 @@ Commercial support is available.

This project is free and is licensed under the MIT.

[1]: http://semver.org/
[1]: https://semver.org/
[2]: https://github.com/nrk/predis
[3]: http://php.net/manual/en/book.pcntl.php
[3]: https://php.net/manual/en/book.pcntl.php
[4]: https://getcomposer.org/
[5]: https://github.com/php-lock/lock/blob/3ca295ccda/src/Mutex/Mutex.php#L15
[6]: https://github.com/php-lock/lock/blob/3ca295ccda/src/Mutex/Mutex.php#L38
Expand Down
5 changes: 3 additions & 2 deletions src/Exception/ExecutionOutsideLockException.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@

/**
* This exception should be thrown when for example the lock is released or the
* lock times out before the critical code has finished execution. This is a
* serious exception. Side effects might have happened while the critical code
* lock times out before the critical code has finished execution.
*
* This is a serious exception. Side effects might have happened while the critical code
* was executed outside of the lock which should not be trusted to be valid.
*
* Should only be used in contexts where the lock is being released.
Expand Down
4 changes: 3 additions & 1 deletion src/Mutex/AbstractRedlockMutex.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
*
* @template TClient of object
*
* @see http://redis.io/topics/distlock
* @internal
*
* @see https://redis.io/topics/distlock#the-redlock-algorithm
*/
abstract class AbstractRedlockMutex extends AbstractSpinlockWithTokenMutex implements LoggerAwareInterface
{
Expand Down
3 changes: 1 addition & 2 deletions src/Mutex/Mutex.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ public function synchronized(callable $code);
/**
* Performs a double-checked locking pattern.
*
* Call {@link \Malkusch\Lock\Util\DoubleCheckedLocking::then()} on the
* returned object.
* Call {@link DoubleCheckedLocking::then()} on the returned object.
*
* Example:
* <code>
Expand Down
2 changes: 1 addition & 1 deletion src/Mutex/MySQLMutex.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public function __construct(\PDO $PDO, string $name, float $acquireTimeout = 0)
$namePrefix = LockUtil::getInstance()->getKeyPrefix() . ':';

if (\strlen($name) > 64 - \strlen($namePrefix)) {
throw new \InvalidArgumentException('The maximum length of the lock name is ' . (64 - \strlen($namePrefix)) . ' characters');
throw new \InvalidArgumentException('The maximum length of the database lock name is ' . (64 - \strlen($namePrefix)) . ' characters');
}

$this->name = $namePrefix . $name;
Expand Down
7 changes: 2 additions & 5 deletions src/Mutex/NoMutex.php → src/Mutex/NullMutex.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,9 @@
namespace Malkusch\Lock\Mutex;

/**
* This mutex doesn't lock at all.
*
* Synchronization is not provided! This mutex is just implementing the
* interface without locking.
* This mutex does not lock at all.
*/
class NoMutex extends AbstractMutex
class NullMutex extends AbstractMutex
{
#[\Override]
public function synchronized(callable $code)
Expand Down
4 changes: 2 additions & 2 deletions src/Mutex/RedisMutex.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
*
* @extends AbstractRedlockMutex<TClient>
*
* @see http://redis.io/topics/distlock
* @see https://redis.io/topics/distlock#the-redlock-algorithm
*/
class RedisMutex extends AbstractRedlockMutex
{
Expand Down Expand Up @@ -122,7 +122,7 @@ protected function evalScript(object $client, string $luaScript, array $keys, ar
}
} else {
try {
return $client->eval($luaScript, count($keys), ...[...$keys, ...$arguments]);
return $client->eval($luaScript, count($keys), ...$keys, ...$arguments);
} catch (PredisException $e) {
throw new LockReleaseException('Failed to release lock', 0, $e);
}
Expand Down
6 changes: 3 additions & 3 deletions src/Mutex/SemaphoreMutex.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@
*/
class SemaphoreMutex extends AbstractLockMutex
{
/** @var \SysvSemaphore|resource The semaphore id */
/** @var \SysvSemaphore|resource */
private $semaphore;

/**
* Use {@link sem_get()} to create the semaphore id.
* Use {@link sem_get()} to create the semaphore.
*
* Example:
* <code>
* $semaphore = sem_get(ftok(__FILE__, 'a'));
* $mutex = new SemaphoreMutex($semaphore);
* </code>
*
* @param \SysvSemaphore|resource $semaphore The semaphore id
* @param \SysvSemaphore|resource $semaphore
*/
public function __construct($semaphore)
{
Expand Down
18 changes: 6 additions & 12 deletions src/Util/DoubleCheckedLocking.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
* The double-checked locking pattern.
*
* You should not instantiate this class directly. Use
* {@link \Malkusch\Lock\Mutex\Mutex::check()}.
* {@link Mutex::check()}.
*
* @internal
*/
Expand All @@ -24,9 +24,8 @@ class DoubleCheckedLocking
private $check;

/**
* @param Mutex $mutex Provides methods for exclusive code execution
* @param callable(): bool $check Callback that decides if the lock should be acquired and if the critical code
* callback should be executed after acquiring the lock
* @param callable(): bool $check Callback that decides if the lock should be acquired and is rechecked
* after a lock has been acquired
*/
public function __construct(Mutex $mutex, callable $check)
{
Expand All @@ -35,17 +34,12 @@ public function __construct(Mutex $mutex, callable $check)
}

/**
* Executes a synchronized callback only after the check callback passes
* before and after acquiring the lock.
*
* If then returns boolean boolean false, the check did not pass before or
* after acquiring the lock. A boolean false can also be returned from the
* critical code callback to indicate that processing did not occure or has
* failed. It is up to the user to decide the last point.
* Executes a block of code only after the check callback passes
* before and after acquiring a lock.
*
* @template T
*
* @param callable(): T $code The critical code callback
* @param callable(): T $code
*
* @return T|false False if check did not pass
*
Expand Down
4 changes: 2 additions & 2 deletions src/Util/Loop.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class Loop
private bool $looping = false;

/**
* Notifies that this was the last iteration.
* Notify that this was the last iteration.
*/
public function end(): void
{
Expand All @@ -35,7 +35,7 @@ public function end(): void
*
* The code has to be designed in a way that it can be repeated without any
* side effects. When execution was successful it should notify that event
* by calling {@link \Malkusch\Lock\Util\Loop::end()}. I.e. the only side
* by calling {@link Loop::end()}. I.e. the only side
* effects of the code may happen after a successful execution.
*
* If the code throws an exception it will stop repeating the execution.
Expand Down
13 changes: 10 additions & 3 deletions tests/Mutex/FlockMutexTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@
use Malkusch\Lock\Util\LockUtil;
use Malkusch\Lock\Util\PcntlTimeout;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\RequiresPhpExtension;
use PHPUnit\Framework\TestCase;

class FlockMutexTest extends TestCase
{
/** @var FlockMutex */
private $mutex;

/** @var string */
private $file;
private string $file;

#[\Override]
protected function setUp(): void
Expand Down Expand Up @@ -88,10 +88,17 @@ static function () {
*/
public static function provideTimeoutableStrategiesCases(): iterable
{
yield [\Closure::bind(static fn () => FlockMutex::STRATEGY_PCNTL, null, FlockMutex::class)()];
if (extension_loaded('pcntl')) {
yield [\Closure::bind(static fn () => FlockMutex::STRATEGY_PCNTL, null, FlockMutex::class)()];
}

yield [\Closure::bind(static fn () => FlockMutex::STRATEGY_LOOP, null, FlockMutex::class)()];
}

/**
* @requires extension pcntl
*/
#[RequiresPhpExtension('pcntl')]
public function testNoTimeoutWaitsForever(): void
{
$this->expectException(DeadlineException::class);
Expand Down
14 changes: 8 additions & 6 deletions tests/Mutex/MutexConcurrencyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -159,13 +159,15 @@ public static function provideExecutionIsSerializedWhenLockedCases(): iterable
return new FlockMutex($file, $timeout);
}];

yield 'flockWithTimoutPcntl' => [static function ($timeout) use ($filename): Mutex {
$file = fopen($filename, 'w');
$lock = Liberator::liberate(new FlockMutex($file, $timeout));
$lock->strategy = \Closure::bind(static fn () => FlockMutex::STRATEGY_PCNTL, null, FlockMutex::class)(); // @phpstan-ignore property.notFound
if (extension_loaded('pcntl')) {
yield 'flockWithTimoutPcntl' => [static function ($timeout) use ($filename): Mutex {
$file = fopen($filename, 'w');
$lock = Liberator::liberate(new FlockMutex($file, $timeout));
$lock->strategy = \Closure::bind(static fn () => FlockMutex::STRATEGY_PCNTL, null, FlockMutex::class)(); // @phpstan-ignore property.notFound

return $lock->popsValue();
}];
return $lock->popsValue();
}];
}

yield 'flockWithTimoutLoop' => [static function ($timeout) use ($filename): Mutex {
$file = fopen($filename, 'w');
Expand Down
20 changes: 11 additions & 9 deletions tests/Mutex/MutexTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use Malkusch\Lock\Mutex\MemcachedMutex;
use Malkusch\Lock\Mutex\Mutex;
use Malkusch\Lock\Mutex\MySQLMutex;
use Malkusch\Lock\Mutex\NoMutex;
use Malkusch\Lock\Mutex\NullMutex;
use Malkusch\Lock\Mutex\PostgreSQLMutex;
use Malkusch\Lock\Mutex\RedisMutex;
use Malkusch\Lock\Mutex\SemaphoreMutex;
Expand Down Expand Up @@ -46,8 +46,8 @@ public static function setUpBeforeClass(): void
*/
public static function provideMutexFactoriesCases(): iterable
{
yield 'NoMutex' => [static function (): Mutex {
return new NoMutex();
yield 'NullMutex' => [static function (): Mutex {
return new NullMutex();
}];

yield 'FlockMutex' => [static function (): Mutex {
Expand All @@ -56,13 +56,15 @@ public static function provideMutexFactoriesCases(): iterable
return new FlockMutex($file);
}];

yield 'flockWithTimoutPcntl' => [static function (): Mutex {
$file = fopen(vfsStream::url('test/lock'), 'w');
$lock = Liberator::liberate(new FlockMutex($file, 3));
$lock->strategy = \Closure::bind(static fn () => FlockMutex::STRATEGY_PCNTL, null, FlockMutex::class)(); // @phpstan-ignore property.notFound
if (extension_loaded('pcntl')) {
yield 'flockWithTimoutPcntl' => [static function (): Mutex {
$file = fopen(vfsStream::url('test/lock'), 'w');
$lock = Liberator::liberate(new FlockMutex($file, 3));
$lock->strategy = \Closure::bind(static fn () => FlockMutex::STRATEGY_PCNTL, null, FlockMutex::class)(); // @phpstan-ignore property.notFound

return $lock->popsValue();
}];
return $lock->popsValue();
}];
}

yield 'flockWithTimoutLoop' => [static function (): Mutex {
$file = fopen(vfsStream::url('test/lock'), 'w');
Expand Down
31 changes: 6 additions & 25 deletions tests/Util/LoopTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,10 @@ public static function provideInvalidAcquireTimeoutCases(): iterable
}

/**
* Tests execution within the timeout.
*
* @doesNotPerformAssertions
*/
#[DoesNotPerformAssertions]
public function testExecutionWithinTimeout(): void
public function testExecutionWithinAcquireTimeout(): void
{
$loop = new Loop();
$loop->execute(static function () use ($loop): void {
Expand All @@ -78,10 +76,7 @@ public function testExecutionWithinTimeout(): void
}, 0.5);
}

/**
* Tests execution within the timeout without calling end().
*/
public function testExecutionWithinAcquireTimeoutWithoutExplicitEnd(): void
public function testExecutionWithinAcquireTimeoutWithoutCallingEnd(): void
{
$this->expectException(LockAcquireTimeoutException::class);
$this->expectExceptionMessage('Lock acquire timeout of 0.5 seconds has been exceeded');
Expand All @@ -93,12 +88,10 @@ public function testExecutionWithinAcquireTimeoutWithoutExplicitEnd(): void
}

/**
* Tests exceeding the execution timeout.
*
* @doesNotPerformAssertions
*/
#[DoesNotPerformAssertions]
public function testExceedTimeoutIsAcceptableIfEndWasCalled(): void
public function testExceedAcquireTimeoutIsAcceptableIfEndWasCalled(): void
{
$loop = new Loop();
$loop->execute(static function () use ($loop): void {
Expand All @@ -107,10 +100,7 @@ public function testExceedTimeoutIsAcceptableIfEndWasCalled(): void
}, 0.5);
}

/**
* Tests exceeding the execution timeout without calling end().
*/
public function testExceedAcquireTimeoutWithoutExplicitEnd(): void
public function testExceedAcquireTimeoutWithoutCallingEnd(): void
{
$this->expectException(LockAcquireTimeoutException::class);
$this->expectExceptionMessage('Lock acquire timeout of 0.5 seconds has been exceeded');
Expand All @@ -121,9 +111,6 @@ public function testExceedAcquireTimeoutWithoutExplicitEnd(): void
}, 0.5);
}

/**
* Tests that an exception would stop any further iteration.
*/
public function testExceptionStopsIteration(): void
{
$this->expectException(\DomainException::class);
Expand All @@ -134,10 +121,7 @@ public function testExceptionStopsIteration(): void
}, 1);
}

/**
* Tests end() will stop the iteration and return the result.
*/
public function testEnd(): void
public function testEndCodeExecutedOnce(): void
{
$i = 0;
$loop = new Loop();
Expand All @@ -148,10 +132,7 @@ public function testEnd(): void
self::assertSame(1, $i);
}

/**
* Tests that the code is executed more times.
*/
public function testIteration(): void
public function testEndCodeExecutedTwice(): void
{
$i = 0;
$loop = new Loop();
Expand Down
Loading