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 2794308

Browse filesBrowse files
jderussefabpot
authored andcommitted
[Lock] Expose an expiringDate and isExpired method in Lock
1 parent c36262e commit 2794308
Copy full SHA for 2794308

File tree

7 files changed

+97
-6
lines changed
Filter options

7 files changed

+97
-6
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Lock/Key.php
+26Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
final class Key
2020
{
2121
private $resource;
22+
private $expiringDate;
2223
private $state = array();
2324

2425
/**
@@ -70,4 +71,29 @@ public function getState($stateKey)
7071
{
7172
return $this->state[$stateKey];
7273
}
74+
75+
/**
76+
* @param float $ttl The expiration delay of locks in seconds.
77+
*/
78+
public function reduceLifetime($ttl)
79+
{
80+
$newExpiringDate = \DateTimeImmutable::createFromFormat('U.u', (string) (microtime(true) + $ttl));
81+
82+
if (null === $this->expiringDate || $newExpiringDate < $this->expiringDate) {
83+
$this->expiringDate = $newExpiringDate;
84+
}
85+
}
86+
87+
public function resetExpiringDate()
88+
{
89+
$this->expiringDate = null;
90+
}
91+
92+
/**
93+
* @return \DateTimeImmutable
94+
*/
95+
public function getExpiringDate()
96+
{
97+
return $this->expiringDate;
98+
}
7399
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Lock/Lock.php
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ public function refresh()
8989
}
9090

9191
try {
92+
$this->key->resetExpiringDate();
9293
$this->store->putOffExpiration($this->key, $this->ttl);
9394
$this->logger->info('Expiration defined for "{resource}" lock for "{ttl}" seconds.', array('resource' => $this->key, 'ttl' => $this->ttl));
9495
} catch (LockConflictedException $e) {
@@ -120,4 +121,21 @@ public function release()
120121
throw new LockReleasingException(sprintf('Failed to release the "%s" lock.', $this->key));
121122
}
122123
}
124+
125+
/**
126+
* @return bool
127+
*/
128+
public function isExpired()
129+
{
130+
if (null === $expireDate = $this->key->getExpiringDate()) {
131+
return false;
132+
}
133+
134+
return $expireDate <= new \DateTime();
135+
}
136+
137+
public function getExpiringDate()
138+
{
139+
return $this->key->getExpiringDate();
140+
}
123141
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Lock/Store/MemcachedStore.php
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ public function save(Key $key)
5858
{
5959
$token = $this->getToken($key);
6060

61+
$key->reduceLifetime($this->initialTtl);
6162
if ($this->memcached->add((string) $key, $token, (int) ceil($this->initialTtl))) {
6263
return;
6364
}
@@ -87,6 +88,7 @@ public function putOffExpiration(Key $key, $ttl)
8788

8889
list($value, $cas) = $this->getValueAndCas($key);
8990

91+
$key->reduceLifetime($ttl);
9092
// Could happens when we ask a putOff after a timeout but in luck nobody steal the lock
9193
if (\Memcached::RES_NOTFOUND === $this->memcached->getResultCode()) {
9294
if ($this->memcached->add((string) $key, $token, $ttl)) {

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Lock/Store/RedisStore.php
+4-4Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ public function save(Key $key)
5757
end
5858
';
5959

60-
$expire = (int) ceil($this->initialTtl * 1000);
61-
if (!$this->evaluate($script, (string) $key, array($this->getToken($key), $expire))) {
60+
$key->reduceLifetime($this->initialTtl);
61+
if (!$this->evaluate($script, (string) $key, array($this->getToken($key), (int) ceil($this->initialTtl * 1000)))) {
6262
throw new LockConflictedException();
6363
}
6464
}
@@ -81,8 +81,8 @@ public function putOffExpiration(Key $key, $ttl)
8181
end
8282
';
8383

84-
$expire = (int) ceil($ttl * 1000);
85-
if (!$this->evaluate($script, (string) $key, array($this->getToken($key), $expire))) {
84+
$key->reduceLifetime($ttl);
85+
if (!$this->evaluate($script, (string) $key, array($this->getToken($key), (int) ceil($ttl * 1000)))) {
8686
throw new LockConflictedException();
8787
}
8888
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Lock/Tests/LockTest.php
+30Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,4 +153,34 @@ public function testReleaseThrowsExceptionIfNotWellDeleted()
153153

154154
$lock->release();
155155
}
156+
157+
/**
158+
* @dataProvider provideExpiredDates
159+
*/
160+
public function testExpiration($ttls, $expected)
161+
{
162+
$key = new Key(uniqid(__METHOD__, true));
163+
$store = $this->getMockBuilder(StoreInterface::class)->getMock();
164+
$lock = new Lock($key, $store, 10);
165+
166+
foreach ($ttls as $ttl) {
167+
if (null === $ttl) {
168+
$key->resetExpiringDate();
169+
} else {
170+
$key->reduceLifetime($ttl);
171+
}
172+
}
173+
$this->assertSame($expected, $lock->isExpired());
174+
}
175+
176+
public function provideExpiredDates()
177+
{
178+
yield array(array(-1.0), true);
179+
yield array(array(1, -1.0), true);
180+
yield array(array(-1.0, 1), true);
181+
182+
yield array(array(), false);
183+
yield array(array(1), false);
184+
yield array(array(-1.0, null), false);
185+
}
156186
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Lock/Tests/Store/AbstractStoreTest.php
+5-2Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,17 @@ public function testSaveWithDifferentResources()
4949
$store->save($key1);
5050
$this->assertTrue($store->exists($key1));
5151
$this->assertFalse($store->exists($key2));
52-
$store->save($key2);
5352

53+
$store->save($key2);
5454
$this->assertTrue($store->exists($key1));
5555
$this->assertTrue($store->exists($key2));
5656

5757
$store->delete($key1);
5858
$this->assertFalse($store->exists($key1));
59+
$this->assertTrue($store->exists($key2));
60+
5961
$store->delete($key2);
62+
$this->assertFalse($store->exists($key1));
6063
$this->assertFalse($store->exists($key2));
6164
}
6265

@@ -74,7 +77,7 @@ public function testSaveWithDifferentKeysOnSameResources()
7477

7578
try {
7679
$store->save($key2);
77-
throw new \Exception('The store shouldn\'t save the second key');
80+
$this->fail('The store shouldn\'t save the second key');
7881
} catch (LockConflictedException $e) {
7982
}
8083

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Lock/Tests/Store/ExpiringStoreTestTrait.php
+12Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,16 @@ public function testRefreshLock()
7575
usleep(2.1 * $clockDelay);
7676
$this->assertFalse($store->exists($key));
7777
}
78+
79+
public function testSetExpiration()
80+
{
81+
$key = new Key(uniqid(__METHOD__, true));
82+
83+
/** @var StoreInterface $store */
84+
$store = $this->getStore();
85+
86+
$store->save($key);
87+
$store->putOffExpiration($key, 1);
88+
$this->assertNotNull($key->getExpiringDate());
89+
}
7890
}

0 commit comments

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