Skip to content

Commit 9b9ecbc

Browse files
committed
GH-3444: Add Custom TTL support for RedisLock, and JdbcLock
Fixes: #3444 * Modify DistributedLock` interfaces. * Modify implementation of `JdbcLockRegistry`, `RedisLockRegistry`. * Modify JavaDoc. Signed-off-by: Eddie Cho <[email protected]>
1 parent cd2225c commit 9b9ecbc

File tree

7 files changed

+32
-24
lines changed

7 files changed

+32
-24
lines changed

spring-integration-core/src/main/java/org/springframework/integration/support/locks/DistributedLock.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package org.springframework.integration.support.locks;
1818

1919
import java.time.Duration;
20-
import java.util.concurrent.TimeUnit;
2120
import java.util.concurrent.locks.Lock;
2221

2322
/**
@@ -36,17 +35,14 @@ public interface DistributedLock extends Lock {
3635
void lock(Duration ttl);
3736

3837
/**
39-
* Acquires the lock with a specific time-to-live if it is free within the
40-
* given waiting time and the current thread has not been {@linkplain Thread#interrupt interrupted}.
41-
* @param time the maximum time to wait for the lock
42-
* @param unit the time unit of the {@code time} argument
38+
* Attempt to acquire a lock with a specific time-to-live
39+
* @param waitTime the maximum time to wait for the lock
4340
* @param ttl the specific time-to-live for the lock status data
4441
* @return {@code true} if the lock was acquired and {@code false}
4542
* if the waiting time elapsed before the lock was acquired
46-
*
4743
* @throws InterruptedException if the current thread is interrupted
4844
* while acquiring the lock (and interruption of lock
4945
* acquisition is supported)
5046
*/
51-
boolean tryLock(long time, TimeUnit unit, Duration ttl) throws InterruptedException;
47+
boolean tryLock(Duration waitTime, Duration ttl) throws InterruptedException;
5248
}

spring-integration-core/src/main/java/org/springframework/integration/support/locks/RenewableLockRegistry.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
* @author Alexandre Strubel
3030
* @author Artem Bilan
3131
* @author Youbin Wu
32+
* @author Eddie Cho
3233
*
3334
* @since 5.4
3435
*/
@@ -46,7 +47,7 @@ public interface RenewableLockRegistry<L extends Lock> extends LockRegistry<L> {
4647
* The lock must be held by the current thread
4748
* @param lockKey The object with which the lock is associated.
4849
* @param ttl the specific time-to-live for the lock status data
49-
*
50+
* @since 7.0
5051
*/
5152
void renewLock(Object lockKey, Duration ttl);
5253

spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/lock/JdbcLockRegistry.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ protected boolean removeEldestEntry(Entry<String, JdbcLock> eldest) {
8888

8989
/**
9090
* Default value for the time-to-live property.
91+
* @since 7.0
9192
*/
9293
public static final Duration DEFAULT_TTL = Duration.ofSeconds(10);
9394

@@ -102,6 +103,12 @@ public JdbcLockRegistry(LockRepository client) {
102103
this.ttl = DEFAULT_TTL;
103104
}
104105

106+
/**
107+
* Create a lock registry with the supplied lock expiration.
108+
* @param client the {@link LockRepository} to rely on.
109+
* @param expireAfter The expiration in {@link Duration}.
110+
* @since 7.0
111+
*/
105112
public JdbcLockRegistry(LockRepository client, Duration expireAfter) {
106113
this.client = client;
107114
this.ttl = expireAfter;
@@ -290,16 +297,16 @@ public boolean tryLock() {
290297

291298
@Override
292299
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
293-
return tryLock(time, unit, JdbcLockRegistry.this.ttl);
300+
return tryLock(Duration.of(time, unit.toChronoUnit()), JdbcLockRegistry.this.ttl);
294301
}
295302

296303
@Override
297-
public boolean tryLock(long time, TimeUnit unit, Duration ttl) throws InterruptedException {
304+
public boolean tryLock(Duration waitTime, Duration ttl) throws InterruptedException {
298305
long now = System.currentTimeMillis();
299-
if (!this.delegate.tryLock(time, unit)) {
306+
if (!this.delegate.tryLock(waitTime.toMillis(), TimeUnit.MILLISECONDS)) {
300307
return false;
301308
}
302-
long expire = now + TimeUnit.MILLISECONDS.convert(time, unit);
309+
long expire = now + waitTime.toMillis();
303310
boolean acquired;
304311
while (true) {
305312
try {
@@ -388,6 +395,7 @@ public boolean renew() {
388395
* @param ttl the new time-to-live value for the lock status data
389396
* @return {@code true} if the lock's time-to-live was successfully renewed;
390397
* {@code false} if the time-to-live could not be renewed
398+
* @since 7.0
391399
*/
392400
public boolean renew(Duration ttl) {
393401
if (!this.delegate.isHeldByCurrentThread()) {

spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/lock/JdbcLockRegistryTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ void testTryLockWithCustomTtl() throws Exception {
146146
long sleepTimeLongerThanDefaultTTL = 110;
147147
for (int i = 0; i < 10; i++) {
148148
DistributedLock lock = lockRegistry.obtain("foo");
149-
lock.tryLock(100, TimeUnit.MILLISECONDS, Duration.ofMillis(200));
149+
lock.tryLock(Duration.ofMillis(100), Duration.ofMillis(200));
150150
try {
151151
assertThat(TestUtils.getPropertyValue(lockRegistry, "locks", Map.class)).hasSize(1);
152152
Thread.sleep(sleepTimeLongerThanDefaultTTL);
@@ -388,7 +388,7 @@ void testLockRenewWithCustomTtl() throws InterruptedException {
388388
final DistributedLock lock = this.registry.obtain("foo");
389389
final Lock lockOfAnotherProcess = registryOfAnotherProcess.obtain("foo");
390390

391-
assertThat(lock.tryLock(100, TimeUnit.MILLISECONDS, Duration.ofMillis(100))).isTrue();
391+
assertThat(lock.tryLock(Duration.ofMillis(100), Duration.ofMillis(100))).isTrue();
392392
try {
393393
registry.renewLock("foo", Duration.ofSeconds(2));
394394
Thread.sleep(110);

spring-integration-redis/src/main/java/org/springframework/integration/redis/util/RedisLockRegistry.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ protected boolean removeEldestEntry(Entry<String, RedisLock> eldest) {
170170
private volatile RedisMessageListenerContainer redisMessageListenerContainer;
171171

172172
/**
173-
* Constructs a lock registry with the default (60 second) lock expiration.
173+
* Create a lock registry with the default (60 second) lock expiration.
174174
* @param connectionFactory The connection factory.
175175
* @param registryKey The key prefix for locks.
176176
*/
@@ -179,7 +179,7 @@ public RedisLockRegistry(RedisConnectionFactory connectionFactory, String regist
179179
}
180180

181181
/**
182-
* Constructs a lock registry with the supplied lock expiration.
182+
* Create a lock registry with the supplied lock expiration.
183183
* @param connectionFactory The connection factory.
184184
* @param registryKey The key prefix for locks.
185185
* @param expireAfter The expiration in milliseconds.
@@ -189,10 +189,11 @@ public RedisLockRegistry(RedisConnectionFactory connectionFactory, String regist
189189
}
190190

191191
/**
192-
* Constructs a lock registry with the supplied lock expiration.
192+
* Create a lock registry with the supplied lock expiration.
193193
* @param connectionFactory The connection factory.
194194
* @param registryKey The key prefix for locks.
195195
* @param expireAfter The expiration in {@link Duration}.
196+
* @since 7.0
196197
*/
197198
public RedisLockRegistry(RedisConnectionFactory connectionFactory, String registryKey, Duration expireAfter) {
198199
Assert.notNull(connectionFactory, "'connectionFactory' cannot be null");
@@ -500,17 +501,16 @@ public final boolean tryLock() {
500501

501502
@Override
502503
public final boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
503-
return this.tryLock(time, unit, RedisLockRegistry.this.expireAfter);
504+
return this.tryLock(Duration.of(time, unit.toChronoUnit()), RedisLockRegistry.this.expireAfter);
504505
}
505506

506507
@Override
507-
public boolean tryLock(long time, TimeUnit unit, Duration ttl) throws InterruptedException {
508-
if (!this.localLock.tryLock(time, unit)) {
508+
public boolean tryLock(Duration waitTime, Duration ttl) throws InterruptedException {
509+
if (!this.localLock.tryLock(waitTime.toMillis(), TimeUnit.MILLISECONDS)) {
509510
return false;
510511
}
511512
try {
512-
long waitTime = TimeUnit.MILLISECONDS.convert(time, unit);
513-
boolean acquired = tryRedisLock(waitTime, ttl.toMillis());
513+
boolean acquired = tryRedisLock(waitTime.toMillis(), ttl.toMillis());
514514
if (!acquired) {
515515
this.localLock.unlock();
516516
}

spring-integration-redis/src/test/java/org/springframework/integration/redis/util/RedisLockRegistryTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ void testTryLockWithCustomTtl(RedisLockType testRedisLockType) throws Interrupte
151151
registry.setRedisLockType(testRedisLockType);
152152
for (int i = 0; i < 3; i++) {
153153
DistributedLock lock = registry.obtain("foo");
154-
lock.tryLock(100, TimeUnit.MILLISECONDS, Duration.ofMillis(500));
154+
lock.tryLock(Duration.ofMillis(100), Duration.ofMillis(500));
155155
try {
156156
assertThat(getRedisLockRegistryLocks(registry)).hasSize(1);
157157
Thread.sleep(sleepTimeLongerThanDefaultTTL);
@@ -999,7 +999,7 @@ void testLockRenewWithCustomTtl(RedisLockType redisLockType) throws InterruptedE
999999
final Lock lockOfAnotherProcess = registryOfAnotherProcess.obtain("foo");
10001000
long ttl = 100;
10011001
long sleepTimeLongerThanTtl = 110;
1002-
assertThat(lock.tryLock(100, TimeUnit.MILLISECONDS, Duration.ofMillis(ttl))).isTrue();
1002+
assertThat(lock.tryLock(Duration.ofMillis(100), Duration.ofMillis(ttl))).isTrue();
10031003
try {
10041004
registry.renewLock("foo", Duration.ofSeconds(2));
10051005
Thread.sleep(sleepTimeLongerThanTtl);

src/reference/antora/modules/ROOT/pages/whats-new.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ Junit 4 Based Support Components are deprecated.
2525
The JDBC module now provides a Java DSL API via its dedicated `org.springframework.integration.jdbc.dsl.Jdbc` factory.
2626
The xref:jdbc/dsl.adoc[] chapter provides more details.
2727

28+
A new `DistributedLock` interface has been introduced, providing new methods, `lock(Duration ttl`) and `tryLock(long time, TimeUnit unit, Duration ttl)`, to acquire a lock with a custom time-to-live (TTL).
29+
See xref:distributed-locks.adoc[] for more information.
30+
2831
[[x7.0-jdbc-changes]]
2932
=== JDBC Changes
3033

0 commit comments

Comments
 (0)