diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/datastructures/GridCacheLockImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/datastructures/GridCacheLockImpl.java index 3881820381b0b..22999476c38f9 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/datastructures/GridCacheLockImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/datastructures/GridCacheLockImpl.java @@ -607,6 +607,9 @@ boolean synchronizeQueue(final boolean cancelled, final Thread thread) { LinkedList nodes = val.getNodes(); if (!cancelled) { + if (sync.waitingThreads.contains(thread.getId()) && nodes.contains(thisNode)) + return true; + nodes.add(thisNode); val.setChanged(false); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/datastructures/IgniteLockAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/datastructures/IgniteLockAbstractSelfTest.java index 1d31bacedb3a2..2d9a069f9e66d 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/datastructures/IgniteLockAbstractSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/datastructures/IgniteLockAbstractSelfTest.java @@ -28,11 +28,14 @@ import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; +import java.util.stream.IntStream; import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCache; import org.apache.ignite.IgniteCheckedException; @@ -113,6 +116,55 @@ public void testFailover() throws Exception { checkFailover(false, true); } + /** + * Tests that {@link IgniteLock} can be acquired after release, especially while running on JDK 17. + * + * @throws Exception If failed. + */ + @Test + public void testFairLockIsAbleToBeAcquiredAfterRelease() throws Exception { + List locks = IntStream.range(0, NODES_CNT) + .mapToObj(i -> grid(i).reentrantLock("test", true, true, true)) + .collect(Collectors.toList()); + + CountDownLatch lockEnterLatch = new CountDownLatch(NODES_CNT - 1); + locks.get(0).lock(); + try { + acquireLockInSeparateThreads(locks.subList(1, NODES_CNT), lockEnterLatch); + } + finally { + locks.get(0).unlock(); + } + + assertTrue(lockEnterLatch.await(GridTestUtils.DFLT_TEST_TIMEOUT, TimeUnit.SECONDS)); + + // Try to acquire the first lock in separate thread. + lockEnterLatch = new CountDownLatch(1); + acquireLockInSeparateThreads(locks.subList(0, 1), lockEnterLatch); + assertTrue(lockEnterLatch.await(GridTestUtils.DFLT_TEST_TIMEOUT, TimeUnit.SECONDS)); + } + + /** */ + private void acquireLockInSeparateThreads(List locks, CountDownLatch lockEnterLatch) throws Exception { + CountDownLatch startLatch = new CountDownLatch(locks.size()); + + for (IgniteLock lock: locks) { + GridTestUtils.runAsync(() -> { + startLatch.countDown(); + + lock.lock(); + try { + lockEnterLatch.countDown(); + } + finally { + lock.unlock(); + } + }); + } + + assertTrue(startLatch.await(GridTestUtils.DFLT_TEST_TIMEOUT, TimeUnit.SECONDS)); + } + /** * Implementation of ignite data structures internally uses special system caches, need make sure * that transaction on these system caches do not intersect with transactions started by user.