Fixed - RReadWriteLock renewal doesn't work if writeLock released before readLock then both were acquired. #4217

pull/4272/head
Nikita Koksharov 3 years ago
parent 1d796c14ad
commit 86c49d5a89

@ -137,7 +137,7 @@ public abstract class RedissonBaseLock extends RedissonExpirable implements RLoc
return;
}
RFuture<Boolean> future = renewExpirationAsync(threadId);
CompletionStage<Boolean> future = renewExpirationAsync(threadId);
future.whenComplete((res, e) -> {
if (e != null) {
log.error("Can't update lock " + getRawName() + " expiration", e);
@ -175,7 +175,7 @@ public abstract class RedissonBaseLock extends RedissonExpirable implements RLoc
}
}
protected RFuture<Boolean> renewExpirationAsync(long threadId) {
protected CompletionStage<Boolean> renewExpirationAsync(long threadId) {
return evalWriteAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
"if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +

@ -16,6 +16,7 @@
package org.redisson;
import java.util.Arrays;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
@ -36,7 +37,7 @@ import org.redisson.pubsub.LockPubSub;
*/
public class RedissonReadLock extends RedissonLock implements RLock {
public RedissonReadLock(CommandAsyncExecutor commandExecutor, String name) {
protected RedissonReadLock(CommandAsyncExecutor commandExecutor, String name) {
super(commandExecutor, name);
}
@ -136,7 +137,7 @@ public class RedissonReadLock extends RedissonLock implements RLock {
}
@Override
protected RFuture<Boolean> renewExpirationAsync(long threadId) {
protected CompletionStage<Boolean> renewExpirationAsync(long threadId) {
String timeoutPrefix = getReadWriteTimeoutNamePrefix(threadId);
String keyPrefix = getKeyPrefix(threadId, timeoutPrefix);

@ -16,6 +16,8 @@
package org.redisson;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
@ -113,6 +115,18 @@ public class RedissonWriteLock extends RedissonLock implements RLock {
throw new UnsupportedOperationException();
}
@Override
protected CompletionStage<Boolean> renewExpirationAsync(long threadId) {
CompletionStage<Boolean> f = super.renewExpirationAsync(threadId);
return f.thenCompose(r -> {
if (!r) {
RedissonReadLock lock = new RedissonReadLock(commandExecutor, getRawName());
return lock.renewExpirationAsync(threadId);
}
return CompletableFuture.completedFuture(r);
});
}
@Override
public RFuture<Boolean> forceUnlockAsync() {
cancelExpirationRenewal(null);

@ -20,6 +20,8 @@ import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.awaitility.Awaitility;
import org.junit.jupiter.api.Assertions;
@ -445,6 +447,27 @@ public class RedissonReadWriteLockTest extends BaseConcurrentTest {
assertThat(lock.writeLock().isLocked()).isFalse();
}
@Test
public void testReadWriteTTL() throws InterruptedException {
RReadWriteLock rwlock = redisson.getReadWriteLock("rwlock");
rwlock.writeLock().lock();
rwlock.readLock().lock();
for (int i = 0; i < 5; i++) {
assertThat(rwlock.readLock().remainTimeToLive()).isGreaterThan(19000);
TimeUnit.SECONDS.sleep(5);
}
rwlock.writeLock().unlock();
for (int i = 0; i < 5; i++) {
assertThat(rwlock.readLock().remainTimeToLive()).isGreaterThan(19000);
TimeUnit.SECONDS.sleep(5);
}
rwlock.readLock().unlock();
}
@Test
public void testExpireRead() throws InterruptedException {
RReadWriteLock lock = redisson.getReadWriteLock("lock");

Loading…
Cancel
Save