From 365d6b916ef189fc3a8d08113050e6ecbdb77603 Mon Sep 17 00:00:00 2001 From: Nikita Koksharov Date: Sat, 7 Oct 2023 13:27:26 +0300 Subject: [PATCH] Fixed - RReadWriteLock.readLock().isLocked() method returns incorrect result if acquired by writeLock owner thread. #4400 --- .../java/org/redisson/RedissonReadLock.java | 12 +++-- .../redisson/RedissonReadWriteLockTest.java | 45 ++++++++++--------- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/redisson/src/main/java/org/redisson/RedissonReadLock.java b/redisson/src/main/java/org/redisson/RedissonReadLock.java index b0ee38171..7e5260e37 100644 --- a/redisson/src/main/java/org/redisson/RedissonReadLock.java +++ b/redisson/src/main/java/org/redisson/RedissonReadLock.java @@ -195,9 +195,15 @@ public class RedissonReadLock extends RedissonLock implements RLock { @Override public boolean isLocked() { - RFuture future = commandExecutor.writeAsync(getRawName(), StringCodec.INSTANCE, RedisCommands.HGET, getRawName(), "mode"); - String res = get(future); - return "read".equals(res); + RFuture future = commandExecutor.evalWriteAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN, + "local mode = redis.call('hget', KEYS[1], 'mode'); " + + "if (mode == 'read') or (mode == 'write' and redis.call('hlen', KEYS[1]) > 2) then " + + "return 1; " + + "end; " + + "return 0; ", + Arrays.asList(getRawName())); + + return get(future); } } diff --git a/redisson/src/test/java/org/redisson/RedissonReadWriteLockTest.java b/redisson/src/test/java/org/redisson/RedissonReadWriteLockTest.java index cf4d73e96..5ff6e46aa 100644 --- a/redisson/src/test/java/org/redisson/RedissonReadWriteLockTest.java +++ b/redisson/src/test/java/org/redisson/RedissonReadWriteLockTest.java @@ -1,36 +1,27 @@ package org.redisson; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.awaitility.Awaitility.await; +import org.awaitility.Awaitility; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.redisson.ClusterRunner.ClusterProcesses; +import org.redisson.api.RLock; +import org.redisson.api.RReadWriteLock; +import org.redisson.api.RedissonClient; +import org.redisson.config.Config; import java.security.SecureRandom; import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.Random; -import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; +import java.util.concurrent.*; 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; -import org.junit.jupiter.api.Test; -import org.redisson.ClusterRunner.ClusterProcesses; -import org.redisson.api.RLock; -import org.redisson.api.RReadWriteLock; -import org.redisson.api.RedissonClient; -import org.redisson.config.Config; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.awaitility.Awaitility.await; public class RedissonReadWriteLockTest extends BaseConcurrentTest { @@ -76,6 +67,18 @@ public class RedissonReadWriteLockTest extends BaseConcurrentTest { Awaitility.await().between(8, TimeUnit.SECONDS, 10, TimeUnit.SECONDS).untilTrue(flag); } + @Test + public void testReadLockIsLocked() throws InterruptedException { + RReadWriteLock readWriteLock = redisson.getReadWriteLock("TEST"); + RLock writeLock = readWriteLock.writeLock(); + RLock readLock = readWriteLock.readLock(); + + writeLock.lock(); + assertThat(readLock.isLocked()).isFalse(); + assertThat(readLock.tryLock(10, TimeUnit.SECONDS)).isTrue(); + assertThat(readLock.isLocked()).isTrue(); + } + @Test public void testReadLockExpirationRenewal() throws InterruptedException { int threadCount = 50;