Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 2c6fca7

Browse filesBrowse files
committed
Fix expired lock not cleaned
1 parent a8520ae commit 2c6fca7
Copy full SHA for 2c6fca7

File tree

Expand file treeCollapse file tree

6 files changed

+68
-16
lines changed
Filter options
Expand file treeCollapse file tree

6 files changed

+68
-16
lines changed

‎src/Symfony/Component/Lock/Lock.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Lock/Lock.php
+10Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ public function acquire($blocking = false)
8383
}
8484

8585
if ($this->key->isExpired()) {
86+
try {
87+
$this->release();
88+
} catch (\Exception $e) {
89+
// swallow exception to not hide the original issue
90+
}
8691
throw new LockExpiredException(sprintf('Failed to store the "%s" lock.', $this->key));
8792
}
8893

@@ -117,6 +122,11 @@ public function refresh()
117122
$this->dirty = true;
118123

119124
if ($this->key->isExpired()) {
125+
try {
126+
$this->release();
127+
} catch (\Exception $e) {
128+
// swallow exception to not hide the original issue
129+
}
120130
throw new LockExpiredException(sprintf('Failed to put off the expiration of the "%s" lock within the specified time.', $this->key));
121131
}
122132

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Lock/Store/CombinedStore.php
+4-3Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
class CombinedStore implements StoreInterface, LoggerAwareInterface
3131
{
3232
use LoggerAwareTrait;
33+
use ExpiringStoreTrait;
3334

3435
/** @var StoreInterface[] */
3536
private $stores;
@@ -78,6 +79,8 @@ public function save(Key $key)
7879
}
7980
}
8081

82+
$this->checkNotExpired($key);
83+
8184
if ($this->strategy->isMet($successCount, $storesCount)) {
8285
return;
8386
}
@@ -125,9 +128,7 @@ public function putOffExpiration(Key $key, $ttl)
125128
}
126129
}
127130

128-
if ($key->isExpired()) {
129-
throw new LockExpiredException(sprintf('Failed to put off the expiration of the "%s" lock within the specified time.', $key));
130-
}
131+
$this->checkNotExpired($key);
131132

132133
if ($this->strategy->isMet($successCount, $storesCount)) {
133134
return;
+21Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace Symfony\Component\Lock\Store;
4+
5+
use Symfony\Component\Lock\Exception\LockExpiredException;
6+
use Symfony\Component\Lock\Key;
7+
8+
trait ExpiringStoreTrait
9+
{
10+
private function checkNotExpired(Key $key)
11+
{
12+
if ($key->isExpired()) {
13+
try {
14+
$this->delete($key);
15+
} catch (\Exception $e) {
16+
// swallow exception to not hide the original issue
17+
}
18+
throw new LockExpiredException(sprintf('Failed to store the "%s" lock.', $key));
19+
}
20+
}
21+
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Lock/Store/MemcachedStore.php
+4-6Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
*/
2525
class MemcachedStore implements StoreInterface
2626
{
27+
use ExpiringStoreTrait;
28+
2729
private $memcached;
2830
private $initialTtl;
2931
/** @var bool */
@@ -64,9 +66,7 @@ public function save(Key $key)
6466
$this->putOffExpiration($key, $this->initialTtl);
6567
}
6668

67-
if ($key->isExpired()) {
68-
throw new LockExpiredException(sprintf('Failed to store the "%s" lock.', $key));
69-
}
69+
$this->checkNotExpired($key);
7070
}
7171

7272
public function waitAndSave(Key $key)
@@ -110,9 +110,7 @@ public function putOffExpiration(Key $key, $ttl)
110110
throw new LockConflictedException();
111111
}
112112

113-
if ($key->isExpired()) {
114-
throw new LockExpiredException(sprintf('Failed to put off the expiration of the "%s" lock within the specified time.', $key));
115-
}
113+
$this->checkNotExpired($key);
116114
}
117115

118116
/**

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Lock/Store/RedisStore.php
+4-7Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
use Symfony\Component\Cache\Traits\RedisProxy;
1515
use Symfony\Component\Lock\Exception\InvalidArgumentException;
1616
use Symfony\Component\Lock\Exception\LockConflictedException;
17-
use Symfony\Component\Lock\Exception\LockExpiredException;
1817
use Symfony\Component\Lock\Key;
1918
use Symfony\Component\Lock\StoreInterface;
2019

@@ -25,6 +24,8 @@
2524
*/
2625
class RedisStore implements StoreInterface
2726
{
27+
use ExpiringStoreTrait;
28+
2829
private $redis;
2930
private $initialTtl;
3031

@@ -66,9 +67,7 @@ public function save(Key $key)
6667
throw new LockConflictedException();
6768
}
6869

69-
if ($key->isExpired()) {
70-
throw new LockExpiredException(sprintf('Failed to store the "%s" lock.', $key));
71-
}
70+
$this->checkNotExpired($key);
7271
}
7372

7473
public function waitAndSave(Key $key)
@@ -94,9 +93,7 @@ public function putOffExpiration(Key $key, $ttl)
9493
throw new LockConflictedException();
9594
}
9695

97-
if ($key->isExpired()) {
98-
throw new LockExpiredException(sprintf('Failed to put off the expiration of the "%s" lock within the specified time.', $key));
99-
}
96+
$this->checkNotExpired($key);
10097
}
10198

10299
/**

‎src/Symfony/Component/Lock/Tests/Store/ExpiringStoreTestTrait.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Lock/Tests/Store/ExpiringStoreTestTrait.php
+25Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\Lock\Tests\Store;
1313

14+
use Symfony\Component\Lock\Exception\LockExpiredException;
1415
use Symfony\Component\Lock\Key;
1516
use Symfony\Component\Lock\StoreInterface;
1617

@@ -105,4 +106,28 @@ public function testSetExpiration()
105106
$this->assertGreaterThanOrEqual(0, $key->getRemainingLifetime());
106107
$this->assertLessThanOrEqual(1, $key->getRemainingLifetime());
107108
}
109+
110+
public function testExpiredLockCleaned()
111+
{
112+
$resource = uniqid(__METHOD__, true);
113+
114+
$key1 = new Key($resource);
115+
$key2 = new Key($resource);
116+
117+
/** @var StoreInterface $store */
118+
$store = $this->getStore();
119+
$key1->reduceLifetime(0);
120+
121+
$this->assertTrue($key1->isExpired());
122+
try {
123+
$store->save($key1);
124+
$this->fail('The store shouldn\'t have save an expired key');
125+
} catch (LockExpiredException $e) {
126+
}
127+
128+
$this->assertFalse($store->exists($key1));
129+
130+
$store->save($key2);
131+
$this->assertTrue($store->exists($key2));
132+
}
108133
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.