Skip to content

Commit 91fcbea

Browse files
Simperfitfabpot
authored andcommitted
[Lock] Split \"StoreInterface\" into multiple interfaces with less responsability
1 parent b79a1bf commit 91fcbea

16 files changed

+291
-78
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 <fabien@symfony.com>
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 <hamza.simperfit@gmail.com>
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+
* Checks 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: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ 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` and `Symfony\Component\Lock\PersistStoreInterface`
9+
910
4.2.0
1011
-----
1112

src/Symfony/Component/Lock/Lock.php

Lines changed: 9 additions & 5 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 support blocking locks.', \get_class($this->store)));
76+
}
7377
$this->store->waitAndSave($this->key);
7478
} else {
7579
$this->store->save($this->key);
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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é <jeremy@derusse.com>
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+
45+
/**
46+
* Extends the TTL of a resource.
47+
*
48+
* @param float $ttl amount of seconds to keep the lock in the store
49+
*
50+
* @throws LockConflictedException
51+
*/
52+
public function putOffExpiration(Key $key, $ttl);
53+
}

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

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Symfony\Component\Lock\Exception\LockConflictedException;
1919
use Symfony\Component\Lock\Exception\NotSupportedException;
2020
use Symfony\Component\Lock\Key;
21+
use Symfony\Component\Lock\PersistStoreInterface;
2122
use Symfony\Component\Lock\StoreInterface;
2223
use Symfony\Component\Lock\Strategy\StrategyInterface;
2324

@@ -26,27 +27,27 @@
2627
*
2728
* @author Jérémy Derussé <jeremy@derusse.com>
2829
*/
29-
class CombinedStore implements StoreInterface, LoggerAwareInterface
30+
class CombinedStore implements StoreInterface, PersistStoreInterface, LoggerAwareInterface
3031
{
3132
use LoggerAwareTrait;
3233
use ExpiringStoreTrait;
3334

34-
/** @var StoreInterface[] */
35+
/** @var PersistStoreInterface[] */
3536
private $stores;
3637
/** @var StrategyInterface */
3738
private $strategy;
3839

3940
/**
40-
* @param StoreInterface[] $stores The list of synchronized stores
41-
* @param StrategyInterface $strategy
41+
* @param PersistStoreInterface[] $stores The list of synchronized stores
42+
* @param StrategyInterface $strategy
4243
*
4344
* @throws InvalidArgumentException
4445
*/
4546
public function __construct(array $stores, StrategyInterface $strategy)
4647
{
4748
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)));
49+
if (!$store instanceof PersistStoreInterface) {
50+
throw new InvalidArgumentException(sprintf('The store must implement "%s". Got "%s".', PersistStoreInterface::class, \get_class($store)));
5051
}
5152
}
5253

@@ -92,8 +93,12 @@ public function save(Key $key)
9293
throw new LockConflictedException();
9394
}
9495

96+
/**
97+
* {@inheritdoc}
98+
*/
9599
public function waitAndSave(Key $key)
96100
{
101+
@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);
97102
throw new NotSupportedException(sprintf('The store "%s" does not supports blocking locks.', \get_class($this)));
98103
}
99104

@@ -181,4 +186,12 @@ public function exists(Key $key)
181186

182187
return false;
183188
}
189+
190+
/**
191+
* {@inheritdoc}
192+
*/
193+
public function supportsWaitAndSave(): bool
194+
{
195+
return false;
196+
}
184197
}

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
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;
1718
use Symfony\Component\Lock\Key;
19+
use Symfony\Component\Lock\PersistStoreInterface;
1820
use Symfony\Component\Lock\StoreInterface;
1921

2022
/**
@@ -27,7 +29,7 @@
2729
* @author Romain Neutron <imprec@gmail.com>
2830
* @author Nicolas Grekas <p@tchwork.com>
2931
*/
30-
class FlockStore implements StoreInterface
32+
class FlockStore implements StoreInterface, BlockingStoreInterface, PersistStoreInterface
3133
{
3234
private $lockPath;
3335

@@ -64,6 +66,14 @@ public function waitAndSave(Key $key)
6466
$this->lock($key, true);
6567
}
6668

69+
/**
70+
* {@inheritdoc}
71+
*/
72+
public function supportsWaitAndSave(): bool
73+
{
74+
return true;
75+
}
76+
6777
private function lock(Key $key, $blocking)
6878
{
6979
// The lock is maybe already acquired.

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,15 @@
1515
use Symfony\Component\Lock\Exception\InvalidTtlException;
1616
use Symfony\Component\Lock\Exception\LockConflictedException;
1717
use Symfony\Component\Lock\Key;
18+
use Symfony\Component\Lock\PersistStoreInterface;
1819
use Symfony\Component\Lock\StoreInterface;
1920

2021
/**
2122
* MemcachedStore is a StoreInterface implementation using Memcached as store engine.
2223
*
2324
* @author Jérémy Derussé <jeremy@derusse.com>
2425
*/
25-
class MemcachedStore implements StoreInterface
26+
class MemcachedStore implements StoreInterface, PersistStoreInterface
2627
{
2728
use ExpiringStoreTrait;
2829

@@ -69,8 +70,12 @@ public function save(Key $key)
6970
$this->checkNotExpired($key);
7071
}
7172

73+
/**
74+
* {@inheritdoc}
75+
*/
7276
public function waitAndSave(Key $key)
7377
{
78+
@trigger_error(sprintf('%s has been deprecated since Symfony 4.4 and will be removed in Symfony 5.0.', __METHOD__));
7479
throw new InvalidArgumentException(sprintf('The store "%s" does not supports blocking locks.', \get_class($this)));
7580
}
7681

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

Lines changed: 3 additions & 1 deletion
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\NotSupportedException;
2121
use Symfony\Component\Lock\Key;
22+
use Symfony\Component\Lock\PersistStoreInterface;
2223
use Symfony\Component\Lock\StoreInterface;
2324

2425
/**
@@ -34,7 +35,7 @@
3435
*
3536
* @author Jérémy Derussé <jeremy@derusse.com>
3637
*/
37-
class PdoStore implements StoreInterface
38+
class PdoStore implements StoreInterface, PersistStoreInterface
3839
{
3940
use ExpiringStoreTrait;
4041

@@ -145,6 +146,7 @@ public function save(Key $key)
145146
*/
146147
public function waitAndSave(Key $key)
147148
{
149+
@trigger_error(sprintf('%s has been deprecated since Symfony 4.4 and will be removed in Symfony 5.0.', __METHOD__));
148150
throw new NotSupportedException(sprintf('The store "%s" does not supports blocking locks.', __METHOD__));
149151
}
150152

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@
1717
use Symfony\Component\Lock\Exception\InvalidTtlException;
1818
use Symfony\Component\Lock\Exception\LockConflictedException;
1919
use Symfony\Component\Lock\Key;
20+
use Symfony\Component\Lock\PersistStoreInterface;
2021
use Symfony\Component\Lock\StoreInterface;
2122

2223
/**
2324
* RedisStore is a StoreInterface implementation using Redis as store engine.
2425
*
2526
* @author Jérémy Derussé <jeremy@derusse.com>
2627
*/
27-
class RedisStore implements StoreInterface
28+
class RedisStore implements StoreInterface, PersistStoreInterface
2829
{
2930
use ExpiringStoreTrait;
3031

@@ -77,6 +78,7 @@ public function save(Key $key)
7778
*/
7879
public function waitAndSave(Key $key)
7980
{
81+
@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);
8082
throw new InvalidArgumentException(sprintf('The store "%s" does not supports blocking locks.', \get_class($this)));
8183
}
8284

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

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
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\LockConflictedException;
1819
use Symfony\Component\Lock\Key;
20+
use Symfony\Component\Lock\PersistStoreInterface;
1921
use Symfony\Component\Lock\StoreInterface;
2022

2123
/**
@@ -24,7 +26,7 @@
2426
*
2527
* @author Jérémy Derussé <jeremy@derusse.com>
2628
*/
27-
class RetryTillSaveStore implements StoreInterface, LoggerAwareInterface
29+
class RetryTillSaveStore implements PersistStoreInterface, BlockingStoreInterface, StoreInterface, LoggerAwareInterface
2830
{
2931
use LoggerAwareTrait;
3032

@@ -33,11 +35,11 @@ class RetryTillSaveStore implements StoreInterface, LoggerAwareInterface
3335
private $retryCount;
3436

3537
/**
36-
* @param StoreInterface $decorated The decorated StoreInterface
37-
* @param int $retrySleep Duration in ms between 2 retry
38-
* @param int $retryCount Maximum amount of retry
38+
* @param PersistStoreInterface $decorated The decorated StoreInterface
39+
* @param int $retrySleep Duration in ms between 2 retry
40+
* @param int $retryCount Maximum amount of retry
3941
*/
40-
public function __construct(StoreInterface $decorated, int $retrySleep = 100, int $retryCount = PHP_INT_MAX)
42+
public function __construct(PersistStoreInterface $decorated, int $retrySleep = 100, int $retryCount = PHP_INT_MAX)
4143
{
4244
$this->decorated = $decorated;
4345
$this->retrySleep = $retrySleep;
@@ -99,4 +101,12 @@ public function exists(Key $key)
99101
{
100102
return $this->decorated->exists($key);
101103
}
104+
105+
/**
106+
* {@inheritdoc}
107+
*/
108+
public function supportsWaitAndSave(): bool
109+
{
110+
return true;
111+
}
102112
}

0 commit comments

Comments
 (0)