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} */