Skip to content

Commit 3a6025d

Browse files
authored
Fix float to int casting and improve timeout names (#71)
1 parent 1e59e9c commit 3a6025d

15 files changed

+123
-102
lines changed

src/Exception/LockReleaseException.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
*
1010
* Take this exception very serious.
1111
*
12-
* Failing to release a lock might have the potential to introduce deadlocks. Also the
13-
* critical code was executed i.e. side effects may have happened.
12+
* This exception implies that the critical code was executed, i.e. side effects may have happened.
13+
*
14+
* Failing to release a lock might have the potential to introduce deadlocks.
1415
*/
1516
class LockReleaseException extends MutexException
1617
{
@@ -20,9 +21,9 @@ class LockReleaseException extends MutexException
2021
private ?\Throwable $codeException = null;
2122

2223
/**
23-
* Gets the result that has been returned during the critical code execution.
24+
* The return value of the executed critical code.
2425
*
25-
* @return mixed The return value of the executed code block
26+
* @return mixed
2627
*/
2728
public function getCodeResult()
2829
{
@@ -42,7 +43,7 @@ public function setCodeResult($codeResult): self
4243
}
4344

4445
/**
45-
* Gets the exception that has happened during the synchronized code execution.
46+
* The exception that has happened during the critical code execution.
4647
*/
4748
public function getCodeException(): ?\Throwable
4849
{

src/Mutex/AbstractLockMutex.php

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,48 +15,46 @@
1515
abstract class AbstractLockMutex extends AbstractMutex
1616
{
1717
/**
18-
* Acquires the lock.
18+
* Acquire a lock.
1919
*
2020
* This method blocks until the lock was acquired.
2121
*
22-
* @throws LockAcquireException The lock could not be acquired
22+
* @throws LockAcquireException
2323
*/
2424
abstract protected function lock(): void;
2525

2626
/**
27-
* Releases the lock.
27+
* Release the lock.
2828
*
29-
* @throws LockReleaseException The lock could not be released
29+
* @throws LockReleaseException
3030
*/
3131
abstract protected function unlock(): void;
3232

3333
#[\Override]
34-
public function synchronized(callable $code)
34+
public function synchronized(callable $fx)
3535
{
3636
$this->lock();
3737

38-
$codeResult = null;
39-
$codeException = null;
38+
$fxResult = null;
39+
$fxException = null;
4040
try {
41-
$codeResult = $code();
42-
} catch (\Throwable $exception) {
43-
$codeException = $exception;
44-
45-
throw $exception;
41+
$fxResult = $fx();
42+
} catch (\Throwable $fxException) {
43+
throw $fxException;
4644
} finally {
4745
try {
4846
$this->unlock();
4947
} catch (LockReleaseException $lockReleaseException) {
50-
$lockReleaseException->setCodeResult($codeResult);
48+
$lockReleaseException->setCodeResult($fxResult);
5149

52-
if ($codeException !== null) {
53-
$lockReleaseException->setCodeException($codeException);
50+
if ($fxException !== null) {
51+
$lockReleaseException->setCodeException($fxException);
5452
}
5553

5654
throw $lockReleaseException;
5755
}
5856
}
5957

60-
return $codeResult;
58+
return $fxResult;
6159
}
6260
}

src/Mutex/AbstractRedlockMutex.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ abstract class AbstractRedlockMutex extends AbstractSpinlockMutex implements Log
3232
* called already.
3333
*
3434
* @param array<int, TClient> $clients
35-
* @param float $timeout The timeout in seconds a lock expires
35+
* @param float $acquireTimeout In seconds
3636
*/
37-
public function __construct(array $clients, string $name, float $timeout = 3)
37+
public function __construct(array $clients, string $name, float $acquireTimeout = 3)
3838
{
39-
parent::__construct($name, $timeout);
39+
parent::__construct($name, $acquireTimeout);
4040

4141
$this->clients = $clients;
4242
$this->logger = new NullLogger();

src/Mutex/AbstractSpinlockMutex.php

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,18 @@ abstract class AbstractSpinlockMutex extends AbstractLockMutex
2020
private string $key;
2121

2222
/** In seconds */
23-
private float $timeout;
23+
private float $acquireTimeout;
2424

2525
/** The timestamp when the lock was acquired */
2626
private ?float $acquiredTs = null;
2727

2828
/**
29-
* @param float $timeout The timeout in seconds a lock expires
29+
* @param float $acquireTimeout In seconds
3030
*/
31-
public function __construct(string $name, float $timeout = 3)
31+
public function __construct(string $name, float $acquireTimeout = 3)
3232
{
3333
$this->key = LockUtil::getInstance()->getKeyPrefix() . ':' . $name;
34-
$this->timeout = $timeout;
34+
$this->acquireTimeout = $acquireTimeout;
3535
}
3636

3737
#[\Override]
@@ -49,18 +49,18 @@ protected function lock(): void
4949
* acquires successfully the same key which would then be deleted
5050
* by this process.
5151
*/
52-
if ($this->acquire($this->key, $this->timeout + 1)) {
52+
if ($this->acquire($this->key, $this->acquireTimeout + 1)) {
5353
$loop->end();
5454
}
55-
}, $this->timeout);
55+
}, $this->acquireTimeout);
5656
}
5757

5858
#[\Override]
5959
protected function unlock(): void
6060
{
6161
$elapsedTime = microtime(true) - $this->acquiredTs;
62-
if ($elapsedTime > $this->timeout) {
63-
throw ExecutionOutsideLockException::create($elapsedTime, $this->timeout);
62+
if ($elapsedTime > $this->acquireTimeout) {
63+
throw ExecutionOutsideLockException::create($elapsedTime, $this->acquireTimeout);
6464
}
6565

6666
/*
@@ -75,11 +75,11 @@ protected function unlock(): void
7575
/**
7676
* Try to acquire a lock.
7777
*
78-
* @param float $expire The timeout in seconds when a lock expires
78+
* @param float $expire In seconds
7979
*
8080
* @return bool True if the lock was acquired
8181
*
82-
* @throws LockAcquireException an unexpected error happened
82+
* @throws LockAcquireException An unexpected error happened
8383
*/
8484
abstract protected function acquire(string $key, float $expire): bool;
8585

src/Mutex/FlockMutex.php

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Malkusch\Lock\Exception\LockAcquireException;
99
use Malkusch\Lock\Exception\LockAcquireTimeoutException;
1010
use Malkusch\Lock\Exception\LockReleaseException;
11+
use Malkusch\Lock\Util\LockUtil;
1112
use Malkusch\Lock\Util\Loop;
1213
use Malkusch\Lock\Util\PcntlTimeout;
1314

@@ -16,33 +17,30 @@
1617
*/
1718
class FlockMutex extends AbstractLockMutex
1819
{
19-
public const INFINITE_TIMEOUT = -1.0;
20-
2120
private const STRATEGY_BLOCK = 'block';
22-
2321
private const STRATEGY_PCNTL = 'pcntl';
24-
2522
private const STRATEGY_LOOP = 'loop';
2623

2724
/** @var resource */
2825
private $fileHandle;
2926

30-
private float $timeout;
27+
private float $acquireTimeout;
3128

3229
/** @var self::STRATEGY_* */
3330
private $strategy;
3431

3532
/**
3633
* @param resource $fileHandle
34+
* @param float $acquireTimeout In seconds
3735
*/
38-
public function __construct($fileHandle, float $timeout = self::INFINITE_TIMEOUT)
36+
public function __construct($fileHandle, float $acquireTimeout = \INF)
3937
{
4038
if (!is_resource($fileHandle)) {
4139
throw new \InvalidArgumentException('The file handle is not a valid resource');
4240
}
4341

4442
$this->fileHandle = $fileHandle;
45-
$this->timeout = $timeout;
43+
$this->acquireTimeout = $acquireTimeout;
4644
$this->strategy = $this->determineLockingStrategy();
4745
}
4846

@@ -51,7 +49,7 @@ public function __construct($fileHandle, float $timeout = self::INFINITE_TIMEOUT
5149
*/
5250
private function determineLockingStrategy(): string
5351
{
54-
if ($this->timeout === self::INFINITE_TIMEOUT) {
52+
if ($this->acquireTimeout > 100 * 365.25 * 24 * 60 * 60) { // 100 years
5553
return self::STRATEGY_BLOCK;
5654
}
5755

@@ -62,25 +60,18 @@ private function determineLockingStrategy(): string
6260
return self::STRATEGY_LOOP;
6361
}
6462

65-
/**
66-
* @throws LockAcquireException
67-
*/
6863
private function lockBlocking(): void
6964
{
7065
if (!flock($this->fileHandle, \LOCK_EX)) {
7166
throw new LockAcquireException('Failed to lock the file');
7267
}
7368
}
7469

75-
/**
76-
* @throws LockAcquireException
77-
* @throws LockAcquireTimeoutException
78-
*/
7970
private function lockPcntl(): void
8071
{
81-
$timeoutInt = (int) ceil($this->timeout);
72+
$acquireTimeoutInt = LockUtil::getInstance()->castFloatToInt(ceil($this->acquireTimeout));
8273

83-
$timebox = new PcntlTimeout($timeoutInt);
74+
$timebox = new PcntlTimeout($acquireTimeoutInt);
8475

8576
try {
8677
$timebox->timeBoxed(
@@ -89,14 +80,10 @@ function (): void {
8980
}
9081
);
9182
} catch (DeadlineException $e) {
92-
throw LockAcquireTimeoutException::create($timeoutInt);
83+
throw LockAcquireTimeoutException::create($acquireTimeoutInt);
9384
}
9485
}
9586

96-
/**
97-
* @throws LockAcquireTimeoutException
98-
* @throws LockAcquireException
99-
*/
10087
private function lockBusy(): void
10188
{
10289
$loop = new Loop();
@@ -105,12 +92,9 @@ private function lockBusy(): void
10592
if ($this->acquireNonBlockingLock()) {
10693
$loop->end();
10794
}
108-
}, $this->timeout);
95+
}, $this->acquireTimeout);
10996
}
11097

111-
/**
112-
* @throws LockAcquireException
113-
*/
11498
private function acquireNonBlockingLock(): bool
11599
{
116100
if (!flock($this->fileHandle, \LOCK_EX | \LOCK_NB, $wouldBlock)) {
@@ -125,10 +109,6 @@ private function acquireNonBlockingLock(): bool
125109
return true;
126110
}
127111

128-
/**
129-
* @throws LockAcquireException
130-
* @throws LockAcquireTimeoutException
131-
*/
132112
#[\Override]
133113
protected function lock(): void
134114
{

src/Mutex/MemcachedMutex.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace Malkusch\Lock\Mutex;
66

7+
use Malkusch\Lock\Util\LockUtil;
8+
79
/**
810
* Memcached based spinlock implementation.
911
*/
@@ -15,12 +17,11 @@ class MemcachedMutex extends AbstractSpinlockMutex
1517
* The Memcached API needs to have at least one server in its pool. I.e.
1618
* it has to be added with Memcached::addServer().
1719
*
18-
* @param string $name The lock name
19-
* @param float $timeout The timeout in seconds a lock expires
20+
* @param float $acquireTimeout In seconds
2021
*/
21-
public function __construct(string $name, \Memcached $memcached, float $timeout = 3)
22+
public function __construct(string $name, \Memcached $memcached, float $acquireTimeout = 3)
2223
{
23-
parent::__construct($name, $timeout);
24+
parent::__construct($name, $acquireTimeout);
2425

2526
$this->memcached = $memcached;
2627
}
@@ -30,7 +31,7 @@ protected function acquire(string $key, float $expire): bool
3031
{
3132
// memcached supports only integer expire
3233
// https://github.com/memcached/memcached/wiki/Commands#standard-protocol
33-
$expireInt = (int) ceil($expire);
34+
$expireInt = LockUtil::getInstance()->castFloatToInt(ceil($expire));
3435

3536
return $this->memcached->add($key, true, $expireInt);
3637
}

src/Mutex/Mutex.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
namespace Malkusch\Lock\Mutex;
66

7-
use Malkusch\Lock\Exception\ExecutionOutsideLockException;
87
use Malkusch\Lock\Exception\LockAcquireException;
98
use Malkusch\Lock\Exception\LockReleaseException;
109
use Malkusch\Lock\Util\DoubleCheckedLocking;
@@ -30,10 +29,9 @@ interface Mutex
3029
*
3130
* @return T
3231
*
33-
* @throws \Exception The execution callback threw an exception
34-
* @throws LockAcquireException The mutex could not be acquired, no further side effects
35-
* @throws LockReleaseException The mutex could not be released, the code was already executed
36-
* @throws ExecutionOutsideLockException Some code has been executed outside of the lock
32+
* @throws \Throwable
33+
* @throws LockAcquireException
34+
* @throws LockReleaseException
3735
*/
3836
public function synchronized(callable $code);
3937

src/Mutex/MySQLMutex.php

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@ class MySQLMutex extends AbstractLockMutex
1414

1515
private string $name;
1616

17-
private float $timeout;
17+
/** In seconds */
18+
private float $acquireTimeout;
1819

1920
/**
20-
* @param float $timeout In seconds
21+
* @param float $acquireTimeout In seconds
2122
*/
22-
public function __construct(\PDO $PDO, string $name, float $timeout = 0)
23+
public function __construct(\PDO $PDO, string $name, float $acquireTimeout = 0)
2324
{
2425
$this->pdo = $PDO;
2526

@@ -30,7 +31,7 @@ public function __construct(\PDO $PDO, string $name, float $timeout = 0)
3031
}
3132

3233
$this->name = $namePrefix . $name;
33-
$this->timeout = $timeout;
34+
$this->acquireTimeout = $acquireTimeout;
3435
}
3536

3637
#[\Override]
@@ -42,11 +43,11 @@ protected function lock(): void
4243
// TODO MariaDB supports microseconds precision since 10.1.2 version,
4344
// but we need to detect the support reliably first
4445
// https://github.com/MariaDB/server/commit/3e792e6cbccb5d7bf5b84b38336f8a40ad232020
45-
$timeoutInt = (int) ceil($this->timeout);
46+
$acquireTimeoutInt = LockUtil::getInstance()->castFloatToInt(ceil($this->acquireTimeout));
4647

4748
$statement->execute([
4849
$this->name,
49-
$timeoutInt,
50+
$acquireTimeoutInt,
5051
]);
5152

5253
$statement->setFetchMode(\PDO::FETCH_NUM);
@@ -62,7 +63,7 @@ protected function lock(): void
6263
throw new LockAcquireException('An error occurred while acquiring the lock');
6364
}
6465

65-
throw LockAcquireTimeoutException::create($this->timeout);
66+
throw LockAcquireTimeoutException::create($this->acquireTimeout);
6667
}
6768

6869
#[\Override]

0 commit comments

Comments
 (0)