Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 09fadd2

Browse files
committed
[Lock] Split "StoreInterface" into multiple interfaces with less responsability
1 parent b79a1bf commit 09fadd2

17 files changed

+487
-71
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Lock;
13+
14+
use Symfony\Component\Lock\Exception\LockConflictedException;
15+
use Symfony\Component\Lock\Exception\NotSupportedException;
16+
17+
/**
18+
* @author Hamza Amrouche <[email protected]>
19+
*/
20+
interface BlockingStoreInterface
21+
{
22+
/**
23+
* Waits until a key becomes free, then stores the resource.
24+
*
25+
* If the store does not support this feature it should throw a NotSupportedException.
26+
*
27+
* @throws LockConflictedException
28+
* @throws NotSupportedException
29+
*/
30+
public function waitAndSave(Key $key);
31+
32+
/**
33+
* Check if the store can wait until a key becomes free before storing the resource.
34+
*/
35+
public function supportsWaitAndSave(): bool;
36+
}

src/Symfony/Component/Lock/CHANGELOG.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ CHANGELOG
44
4.4.0
55
-----
66

7-
* added InvalidTtlException
8-
7+
* added InvalidTtlException
8+
* deprecated `Symfony\Component\Lock\StoreInterface` in favor of `Symfony\Component\Lock\BlockingStoreInterface`, `Symfony\Component\Lock\PersistStoreInterface`
9+
and `Symfony\Component\Lock\ExpiringStoreInterface`
10+
911
4.2.0
1012
-----
1113

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Lock;
13+
14+
use Symfony\Component\Lock\Exception\LockConflictedException;
15+
use Symfony\Component\Lock\Exception\NotSupportedException;
16+
17+
/**
18+
* @author Hamza Amrouche <[email protected]>
19+
*/
20+
interface ExpiringStoreInterface
21+
{
22+
/**
23+
* Extends the ttl of a resource.
24+
*
25+
* If the store does not support this feature it should throw a NotSupportedException.
26+
*
27+
* @param float $ttl amount of seconds to keep the lock in the store
28+
*
29+
* @throws LockConflictedException
30+
* @throws NotSupportedException
31+
*/
32+
public function putOffExpiration(Key $key, $ttl);
33+
34+
/**
35+
* Check if the store supports extending the ttl of a resource.
36+
*
37+
* @throws LockConflictedException
38+
* @throws NotSupportedException
39+
*/
40+
public function supportsPutOffExpiration(): bool;
41+
}

src/Symfony/Component/Lock/Lock.php

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\Component\Lock\Exception\LockConflictedException;
2020
use Symfony\Component\Lock\Exception\LockExpiredException;
2121
use Symfony\Component\Lock\Exception\LockReleasingException;
22+
use Symfony\Component\Lock\Exception\NotSupportedException;
2223

2324
/**
2425
* Lock is the default implementation of the LockInterface.
@@ -36,12 +37,12 @@ final class Lock implements LockInterface, LoggerAwareInterface
3637
private $dirty = false;
3738

3839
/**
39-
* @param Key $key Resource to lock
40-
* @param StoreInterface $store Store used to handle lock persistence
41-
* @param float|null $ttl Maximum expected lock duration in seconds
42-
* @param bool $autoRelease Whether to automatically release the lock or not when the lock instance is destroyed
40+
* @param Key $key Resource to lock
41+
* @param PersistStoreInterface $store Store used to handle lock persistence
42+
* @param float|null $ttl Maximum expected lock duration in seconds
43+
* @param bool $autoRelease Whether to automatically release the lock or not when the lock instance is destroyed
4344
*/
44-
public function __construct(Key $key, StoreInterface $store, float $ttl = null, bool $autoRelease = true)
45+
public function __construct(Key $key, PersistStoreInterface $store, float $ttl = null, bool $autoRelease = true)
4546
{
4647
$this->store = $store;
4748
$this->key = $key;
@@ -70,6 +71,9 @@ public function acquire($blocking = false)
7071
{
7172
try {
7273
if ($blocking) {
74+
if (!($this->store instanceof StoreInterface) && !($this->store instanceof BlockingStoreInterface && $this->store->supportsWaitAndSave())) {
75+
throw new NotSupportedException(sprintf('The store "%s" does not supports blocking locks.', \get_class($this->store)));
76+
}
7377
$this->store->waitAndSave($this->key);
7478
} else {
7579
$this->store->save($this->key);
@@ -121,7 +125,9 @@ public function refresh($ttl = null)
121125

122126
try {
123127
$this->key->resetLifetime();
124-
$this->store->putOffExpiration($this->key, $ttl);
128+
if ($this->store instanceof StoreInterface || ($this->store instanceof ExpiringStoreInterface && $this->store->supportsPutOffExpiration())) {
129+
$this->store->putOffExpiration($this->key, $ttl);
130+
}
125131
$this->dirty = true;
126132

127133
if ($this->key->isExpired()) {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Lock;
13+
14+
use Symfony\Component\Lock\Exception\LockAcquiringException;
15+
use Symfony\Component\Lock\Exception\LockConflictedException;
16+
use Symfony\Component\Lock\Exception\LockReleasingException;
17+
18+
/**
19+
* @author Jérémy Derussé <[email protected]>
20+
*/
21+
interface PersistStoreInterface
22+
{
23+
/**
24+
* Stores the resource if it's not locked by someone else.
25+
*
26+
* @throws LockAcquiringException
27+
* @throws LockConflictedException
28+
*/
29+
public function save(Key $key);
30+
31+
/**
32+
* Removes a resource from the storage.
33+
*
34+
* @throws LockReleasingException
35+
*/
36+
public function delete(Key $key);
37+
38+
/**
39+
* Returns whether or not the resource exists in the storage.
40+
*
41+
* @return bool
42+
*/
43+
public function exists(Key $key);
44+
}

src/Symfony/Component/Lock/Store/CombinedStore.php

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@
1414
use Psr\Log\LoggerAwareInterface;
1515
use Psr\Log\LoggerAwareTrait;
1616
use Psr\Log\NullLogger;
17+
use Symfony\Component\Lock\BlockingStoreInterface;
1718
use Symfony\Component\Lock\Exception\InvalidArgumentException;
1819
use Symfony\Component\Lock\Exception\LockConflictedException;
1920
use Symfony\Component\Lock\Exception\NotSupportedException;
21+
use Symfony\Component\Lock\ExpiringStoreInterface;
2022
use Symfony\Component\Lock\Key;
23+
use Symfony\Component\Lock\PersistStoreInterface;
2124
use Symfony\Component\Lock\StoreInterface;
2225
use Symfony\Component\Lock\Strategy\StrategyInterface;
2326

@@ -26,27 +29,27 @@
2629
*
2730
* @author Jérémy Derussé <[email protected]>
2831
*/
29-
class CombinedStore implements StoreInterface, LoggerAwareInterface
32+
class CombinedStore implements PersistStoreInterface, BlockingStoreInterface, LoggerAwareInterface, StoreInterface
3033
{
3134
use LoggerAwareTrait;
3235
use ExpiringStoreTrait;
3336

34-
/** @var StoreInterface[] */
37+
/** @var PersistStoreInterface[] */
3538
private $stores;
3639
/** @var StrategyInterface */
3740
private $strategy;
3841

3942
/**
40-
* @param StoreInterface[] $stores The list of synchronized stores
41-
* @param StrategyInterface $strategy
43+
* @param PersistStoreInterface[] $stores The list of synchronized stores
44+
* @param StrategyInterface $strategy
4245
*
4346
* @throws InvalidArgumentException
4447
*/
4548
public function __construct(array $stores, StrategyInterface $strategy)
4649
{
4750
foreach ($stores as $store) {
48-
if (!$store instanceof StoreInterface) {
49-
throw new InvalidArgumentException(sprintf('The store must implement "%s". Got "%s".', StoreInterface::class, \get_class($store)));
51+
if (!$store instanceof PersistStoreInterface) {
52+
throw new InvalidArgumentException(sprintf('The store must implement "%s". Got "%s".', PersistStoreInterface::class, \get_class($store)));
5053
}
5154
}
5255

@@ -92,8 +95,12 @@ public function save(Key $key)
9295
throw new LockConflictedException();
9396
}
9497

98+
/**
99+
* {@inheritdoc}
100+
*/
95101
public function waitAndSave(Key $key)
96102
{
103+
@trigger_error(sprintf('%s::%s has been deprecated since Symfony 4.4 and will be removed in Symfony 5.0.', \get_class($this), __METHOD__), E_USER_DEPRECATED);
97104
throw new NotSupportedException(sprintf('The store "%s" does not supports blocking locks.', \get_class($this)));
98105
}
99106

@@ -104,9 +111,14 @@ public function putOffExpiration(Key $key, $ttl)
104111
{
105112
$successCount = 0;
106113
$failureCount = 0;
114+
107115
$storesCount = \count($this->stores);
108116
$expireAt = microtime(true) + $ttl;
109117

118+
if (false === $this->supportsPutOffExpiration()) {
119+
throw new NotSupportedException();
120+
}
121+
110122
foreach ($this->stores as $store) {
111123
try {
112124
if (0.0 >= $adjustedTtl = $expireAt - microtime(true)) {
@@ -115,7 +127,10 @@ public function putOffExpiration(Key $key, $ttl)
115127
break;
116128
}
117129

118-
$store->putOffExpiration($key, $adjustedTtl);
130+
if ($store instanceof ExpiringStoreInterface && $store->supportsPutOffExpiration()) {
131+
$store->putOffExpiration($key, $adjustedTtl);
132+
}
133+
119134
++$successCount;
120135
} catch (\Exception $e) {
121136
$this->logger->warning('One store failed to put off the expiration of the "{resource}" lock.', ['resource' => $key, 'store' => $store, 'exception' => $e]);
@@ -181,4 +196,26 @@ public function exists(Key $key)
181196

182197
return false;
183198
}
199+
200+
/**
201+
* {@inheritdoc}
202+
*/
203+
public function supportsPutOffExpiration(): bool
204+
{
205+
foreach ($this->stores as $store) {
206+
if ($store instanceof ExpiringStoreInterface && $store->supportsPutOffExpiration()) {
207+
return true;
208+
}
209+
}
210+
211+
return false;
212+
}
213+
214+
/**
215+
* {@inheritdoc}
216+
*/
217+
public function supportsWaitAndSave(): bool
218+
{
219+
return false;
220+
}
184221
}

src/Symfony/Component/Lock/Store/FlockStore.php

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,14 @@
1111

1212
namespace Symfony\Component\Lock\Store;
1313

14+
use Symfony\Component\Lock\BlockingStoreInterface;
1415
use Symfony\Component\Lock\Exception\InvalidArgumentException;
1516
use Symfony\Component\Lock\Exception\LockConflictedException;
1617
use Symfony\Component\Lock\Exception\LockStorageException;
18+
use Symfony\Component\Lock\Exception\NotSupportedException;
19+
use Symfony\Component\Lock\ExpiringStoreInterface;
1720
use Symfony\Component\Lock\Key;
21+
use Symfony\Component\Lock\PersistStoreInterface;
1822
use Symfony\Component\Lock\StoreInterface;
1923

2024
/**
@@ -27,7 +31,7 @@
2731
* @author Romain Neutron <[email protected]>
2832
* @author Nicolas Grekas <[email protected]>
2933
*/
30-
class FlockStore implements StoreInterface
34+
class FlockStore implements BlockingStoreInterface, ExpiringStoreInterface, PersistStoreInterface, StoreInterface
3135
{
3236
private $lockPath;
3337

@@ -64,6 +68,14 @@ public function waitAndSave(Key $key)
6468
$this->lock($key, true);
6569
}
6670

71+
/**
72+
* {@inheritdoc}
73+
*/
74+
public function supportsWaitAndSave(): bool
75+
{
76+
return true;
77+
}
78+
6779
private function lock(Key $key, $blocking)
6880
{
6981
// The lock is maybe already acquired.
@@ -104,7 +116,14 @@ private function lock(Key $key, $blocking)
104116
}
105117

106118
/**
107-
* {@inheritdoc}
119+
* Extends the ttl of a resource.
120+
*
121+
* If the store does not support this feature it should throw a NotSupportedException.
122+
*
123+
* @param float $ttl amount of seconds to keep the lock in the store
124+
*
125+
* @throws LockConflictedException
126+
* @throws NotSupportedException
108127
*/
109128
public function putOffExpiration(Key $key, $ttl)
110129
{
@@ -136,4 +155,9 @@ public function exists(Key $key)
136155
{
137156
return $key->hasState(__CLASS__);
138157
}
158+
159+
public function supportsPutOffExpiration(): bool
160+
{
161+
return true;
162+
}
139163
}

0 commit comments

Comments
 (0)