This is an automated email from the ASF dual-hosted git repository.

zstan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new d3770324b20 IGNITE-28675 Fix flaky TxDeadlockCauseTest #testCause, 
#testCauseSeveralNodes (#13136)
d3770324b20 is described below

commit d3770324b20881580de2d78794a305c1995e5103
Author: Evgeniy Stanilovskiy <[email protected]>
AuthorDate: Tue Jun 2 10:37:37 2026 +0300

    IGNITE-28675 Fix flaky TxDeadlockCauseTest #testCause, 
#testCauseSeveralNodes (#13136)
---
 .../cache/transactions/TxDeadlockDetection.java    | 56 +++++++---------------
 .../cache/transactions/TxDeadlockCauseTest.java    | 12 +++--
 .../TxDeadlockDetectionNoHangsTest.java            | 34 +++++++------
 3 files changed, 46 insertions(+), 56 deletions(-)

diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TxDeadlockDetection.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TxDeadlockDetection.java
index a5cae1194cf..9003f5625d9 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TxDeadlockDetection.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TxDeadlockDetection.java
@@ -39,6 +39,7 @@ import 
org.apache.ignite.internal.processors.timeout.GridTimeoutObjectAdapter;
 import org.apache.ignite.internal.util.future.GridFutureAdapter;
 import org.apache.ignite.internal.util.tostring.GridToStringExclude;
 import org.apache.ignite.internal.util.tostring.GridToStringInclude;
+import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.T2;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.util.typedef.internal.U;
@@ -55,7 +56,7 @@ public class TxDeadlockDetection {
     public static final int DFLT_TX_DEADLOCK_DETECTION_TIMEOUT = 60000;
 
     /** Deadlock detection maximum iterations. */
-    private static int deadLockTimeout =
+    private static final int DEAD_LOCK_TIMEOUT =
         getInteger(IGNITE_TX_DEADLOCK_DETECTION_TIMEOUT, 
DFLT_TX_DEADLOCK_DETECTION_TIMEOUT);
 
     /** Sequence. */
@@ -80,7 +81,7 @@ public class TxDeadlockDetection {
      *
      * @param tx Target tx.
      * @param keys Keys.
-     * @return {@link TxDeadlock} if found, otherwise - {@code null}.
+     * @return {@link TxDeadlockFuture} future.
      */
     TxDeadlockFuture detectDeadlock(IgniteInternalTx tx, Set<IgniteTxKey> 
keys) {
         GridCacheVersion txId = tx.nearXidVersion();
@@ -101,7 +102,7 @@ public class TxDeadlockDetection {
      * @param wfg Wait-for-graph.
      * @param txId Tx ID - start vertex for cycle search in graph.
      */
-    static List<GridCacheVersion> findCycle(Map<GridCacheVersion, 
Set<GridCacheVersion>> wfg, GridCacheVersion txId) {
+    static @Nullable List<GridCacheVersion> findCycle(Map<GridCacheVersion, 
Set<GridCacheVersion>> wfg, GridCacheVersion txId) {
         if (wfg == null || wfg.isEmpty())
             return null;
 
@@ -181,7 +182,7 @@ public class TxDeadlockDetection {
 
         /** Pending keys. */
         @GridToStringInclude
-        private Map<UUID, Set<IgniteTxKey>> pendingKeys = new HashMap<>();
+        private final Map<UUID, Set<IgniteTxKey>> pendingKeys = new 
HashMap<>();
 
         /** Nodes queue. */
         @GridToStringInclude
@@ -233,7 +234,7 @@ public class TxDeadlockDetection {
             this.topVer = topVer;
             this.keys = keys;
 
-            if (deadLockTimeout > 0) {
+            if (DEAD_LOCK_TIMEOUT > 0) {
                 timeoutObj = new DeadlockTimeoutObject();
 
                 cctx.time().addTimeoutObject(timeoutObj);
@@ -322,7 +323,7 @@ public class TxDeadlockDetection {
          * Maps tx keys on nodes. Key can be mapped on some node if this node 
is primary for given key or
          * node is near for transaction that holds or requests lock for key.
          *
-         * Key will not be be mapped to node if both key and node are already 
handled.
+         * Key will not be mapped to node if both key and node are already 
handled.
          *
          * @param txKeys Tx keys.
          * @param txLocks Tx locks.
@@ -348,10 +349,7 @@ public class TxDeadlockDetection {
                         // Process this node earlier than other in order to 
optimize amount of requests.
                         preferredNodes.add(nodeId);
 
-                        Set<IgniteTxKey> mappedKeys = pendingKeys.get(nodeId);
-
-                        if (mappedKeys == null)
-                            pendingKeys.put(nodeId, mappedKeys = new 
HashSet<>());
+                        Set<IgniteTxKey> mappedKeys = 
pendingKeys.computeIfAbsent(nodeId, k -> new HashSet<>());
 
                         mappedKeys.add(txKey);
                     }
@@ -363,10 +361,7 @@ public class TxDeadlockDetection {
                         else
                             nodesQueue.addLast(nearNodeId);
 
-                        Set<IgniteTxKey> mappedKeys = 
pendingKeys.get(nearNodeId);
-
-                        if (mappedKeys == null)
-                            pendingKeys.put(nearNodeId, mappedKeys = new 
HashSet<>());
+                        Set<IgniteTxKey> mappedKeys = 
pendingKeys.computeIfAbsent(nearNodeId, k -> new HashSet<>());
 
                         mappedKeys.add(txKey);
                     }
@@ -387,10 +382,7 @@ public class TxDeadlockDetection {
 
                     nodesQueue.addLast(nodeId);
 
-                    Set<IgniteTxKey> mappedKeys = pendingKeys.get(nodeId);
-
-                    if (mappedKeys == null)
-                        pendingKeys.put(nodeId, mappedKeys = new HashSet<>());
+                    Set<IgniteTxKey> mappedKeys = 
pendingKeys.computeIfAbsent(nodeId, k -> new HashSet<>());
 
                     mappedKeys.add(txKey);
                 }
@@ -417,7 +409,7 @@ public class TxDeadlockDetection {
         private void merge(TxLocksResponse res) {
             Map<IgniteTxKey, List<TxLock>> txLocks = res.txLocks();
 
-            if (txLocks == null || txLocks.isEmpty())
+            if (F.isEmpty(txLocks))
                 return;
 
             for (Map.Entry<IgniteTxKey, List<TxLock>> e : txLocks.entrySet()) {
@@ -425,7 +417,7 @@ public class TxDeadlockDetection {
 
                 List<TxLock> lockList = e.getValue();
 
-                if (lockList != null && !lockList.isEmpty()) {
+                if (!F.isEmpty(lockList)) {
                     for (TxLock lock : lockList) {
                         if (lock.owner() || lock.candiate()) {
                             if (txs.get(lock.txId()) == null)
@@ -435,18 +427,12 @@ public class TxDeadlockDetection {
                         if (lock.owner()) {
                             GridCacheVersion txId = lock.txId();
 
-                            Set<IgniteTxKey> keys = txLockedKeys.get(txId);
-
-                            if (keys == null)
-                                txLockedKeys.put(txId, keys = new HashSet<>());
+                            Set<IgniteTxKey> keys = 
txLockedKeys.computeIfAbsent(txId, k -> new HashSet<>());
 
                             keys.add(txKey);
                         }
                         else if (lock.candiate()) {
-                            Set<GridCacheVersion> txs = 
txRequestedKeys.get(txKey);
-
-                            if (txs == null)
-                                txRequestedKeys.put(txKey, txs = new 
HashSet<>());
+                            Set<GridCacheVersion> txs = 
txRequestedKeys.computeIfAbsent(txKey, k -> new HashSet<>());
 
                             txs.add(lock.txId());
                         }
@@ -473,10 +459,7 @@ public class TxDeadlockDetection {
                         txOwner = lock.txId();
 
                         if (keys.contains(e.getKey()) && 
!txId.equals(lock.txId())) {
-                            Set<GridCacheVersion> waitingTxs = wfg.get(txId);
-
-                            if (waitingTxs == null)
-                                wfg.put(txId, waitingTxs = new HashSet<>());
+                            Set<GridCacheVersion> waitingTxs = 
wfg.computeIfAbsent(txId, k -> new HashSet<>());
 
                             waitingTxs.add(lock.txId());
                         }
@@ -487,10 +470,7 @@ public class TxDeadlockDetection {
                     if (lock.candiate() || lock.owner()) {
                         GridCacheVersion txId0 = lock.txId();
 
-                        Set<GridCacheVersion> waitForTxs = wfg.get(txId0);
-
-                        if (waitForTxs == null)
-                            wfg.put(txId0, waitForTxs = new HashSet<>());
+                        Set<GridCacheVersion> waitForTxs = 
wfg.computeIfAbsent(txId0, k -> new HashSet<>());
 
                         waitForTxs.add(txOwner);
                     }
@@ -562,7 +542,7 @@ public class TxDeadlockDetection {
              * Default constructor.
              */
             DeadlockTimeoutObject() {
-                super(deadLockTimeout);
+                super(DEAD_LOCK_TIMEOUT);
             }
 
             /** {@inheritDoc} */
@@ -571,7 +551,7 @@ public class TxDeadlockDetection {
 
                 IgniteLogger log = cctx.kernalContext().log(this.getClass());
 
-                U.warn(log, "Deadlock detection was timed out [timeout=" + 
deadLockTimeout + ", fut=" + this + ']');
+                U.warn(log, "Deadlock detection was timed out [timeout=" + 
DEAD_LOCK_TIMEOUT + ", fut=" + this + ']');
 
                 onDone();
             }
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxDeadlockCauseTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxDeadlockCauseTest.java
index a68543abfb5..8d57871626a 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxDeadlockCauseTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxDeadlockCauseTest.java
@@ -28,7 +28,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
-import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.DataRegionConfiguration;
@@ -165,6 +164,9 @@ public class TxDeadlockCauseTest extends 
GridCommonAbstractTest {
         final TransactionIsolation isolation,
         final boolean oneOp
     ) throws Exception {
+        if (nodes > 1)
+            awaitPartitionMapExchange();
+
         final Ignite ignite = grid(new Random().nextInt(nodes));
 
         final IgniteCache<Integer, Account> cache = 
ignite.cache(DEFAULT_CACHE_NAME);
@@ -183,7 +185,7 @@ public class TxDeadlockCauseTest extends 
GridCommonAbstractTest {
         final CyclicBarrier barrier = new CyclicBarrier(2);
 
         IgniteInternalFuture<Long> fut = 
GridTestUtils.runMultiThreadedAsync(new CAX() {
-            @Override public void applyx() throws IgniteCheckedException {
+            @Override public void applyx() {
                 try (Transaction tx = 
ignite.transactions().txStart(TransactionConcurrency.PESSIMISTIC, isolation,
                     timeout, keys.size())) {
 
@@ -204,7 +206,9 @@ public class TxDeadlockCauseTest extends 
GridCommonAbstractTest {
                     tx.commit();
                 }
                 catch (Exception e) {
-                    ex.compareAndSet(null, e);
+                    // TransactionDeadlockException raised at least for one 
transaction involved in the deadlock
+                    if (X.hasCause(e, TransactionDeadlockException.class))
+                        ex.compareAndSet(null, e);
                 }
             }
         }, 2, "tx");
@@ -268,7 +272,7 @@ public class TxDeadlockCauseTest extends 
GridCommonAbstractTest {
         /**
          * Change balance by specified amount.
          *
-         * @param amount Amount to add to balance (may be negative).
+         * @param amount Amount to add to balance (maybe negative).
          */
         void update(double amount) {
             balance += amount;
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxDeadlockDetectionNoHangsTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxDeadlockDetectionNoHangsTest.java
index 5898f0a3701..2328a2db413 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxDeadlockDetectionNoHangsTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxDeadlockDetectionNoHangsTest.java
@@ -21,6 +21,7 @@ import java.util.Collection;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.IgniteCheckedException;
@@ -32,14 +33,13 @@ import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteKernal;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.ListeningTestLogger;
 import org.apache.ignite.testframework.junits.WithSystemProperty;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.transactions.Transaction;
 import org.apache.ignite.transactions.TransactionConcurrency;
 import org.junit.Test;
 
-import static 
org.apache.ignite.IgniteSystemProperties.IGNITE_TX_DEADLOCK_DETECTION_TIMEOUT;
-import static org.apache.ignite.IgniteSystemProperties.getInteger;
 import static org.apache.ignite.transactions.TransactionConcurrency.OPTIMISTIC;
 import static 
org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
 import static 
org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
@@ -54,6 +54,18 @@ public class TxDeadlockDetectionNoHangsTest extends 
GridCommonAbstractTest {
     /** Cache. */
     private static final String CACHE = "cache";
 
+    /** Log listener. */
+    private final ListeningTestLogger listeningLog = new 
ListeningTestLogger(log);
+
+    /** Deadlock timeout, it`s unexpected during these tests. */
+    private static final AtomicBoolean DEAD_LOCK_FLAG = new AtomicBoolean();
+
+    /** */
+    private static final Consumer<String> DEAD_LOCK_LSNR = s -> {
+        if (s.contains("Deadlock detection was timed out"))
+            DEAD_LOCK_FLAG.set(true);
+    };
+
     /** {@inheritDoc} */
     @SuppressWarnings("unchecked")
     @Override protected IgniteConfiguration getConfiguration(String 
igniteInstanceName) throws Exception {
@@ -68,6 +80,11 @@ public class TxDeadlockDetectionNoHangsTest extends 
GridCommonAbstractTest {
 
         cfg.setCacheConfiguration(ccfg);
 
+        assertFalse(DEAD_LOCK_FLAG.get());
+
+        listeningLog.registerListener(DEAD_LOCK_LSNR);
+        cfg.setGridLogger(listeningLog);
+
         return cfg;
     }
 
@@ -83,19 +100,8 @@ public class TxDeadlockDetectionNoHangsTest extends 
GridCommonAbstractTest {
         super.afterTest();
 
         stopAllGrids();
-    }
 
-    /** {@inheritDoc} */
-    @Override protected void beforeTestsStarted() throws Exception {
-        super.beforeTestsStarted();
-
-        GridTestUtils.setFieldValue(TxDeadlockDetection.class, 
"deadLockTimeout", (int)(getTestTimeout() * 2));
-    }
-
-    /** {@inheritDoc} */
-    @Override protected void afterTestsStopped() throws Exception {
-        GridTestUtils.setFieldValue(TxDeadlockDetection.class, 
"deadLockTimeout",
-            getInteger(IGNITE_TX_DEADLOCK_DETECTION_TIMEOUT, 60000));
+        assertFalse(DEAD_LOCK_FLAG.get());
     }
 
     /** {@inheritDoc} */

Reply via email to