This is an automated email from the ASF dual-hosted git repository. alexpl 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 42439684cb8 IGNITE-25541 Fix NPE on timeout during transaction initialization - Fixes #12125. 42439684cb8 is described below commit 42439684cb8b944bb47cd555af6f78449349c616 Author: Aleksey Plekhanov <plehanov.a...@gmail.com> AuthorDate: Tue Jun 10 11:22:54 2025 +0300 IGNITE-25541 Fix NPE on timeout during transaction initialization - Fixes #12125. Signed-off-by: Aleksey Plekhanov <plehanov.a...@gmail.com> --- .../cache/distributed/near/GridNearTxLocal.java | 19 ++++- .../cache/transactions/IgniteTxManager.java | 6 +- .../TxTimeoutOnInitializationTest.java | 80 ++++++++++++++++++++++ .../ignite/testsuites/IgniteCacheTestSuite6.java | 2 + 4 files changed, 104 insertions(+), 3 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java index e414eedd071..4ed59193af5 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java @@ -101,6 +101,7 @@ import org.apache.ignite.plugin.security.SecurityPermission; import org.apache.ignite.transactions.TransactionConcurrency; import org.apache.ignite.transactions.TransactionIsolation; import org.apache.ignite.transactions.TransactionState; +import org.apache.ignite.transactions.TransactionTimeoutException; import org.jetbrains.annotations.Nullable; import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC; @@ -270,8 +271,6 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou this.txDumpsThrottling = txDumpsThrottling; initResult(); - - trackTimeout = timeout() > 0 && !implicit() && cctx.time().addTimeoutObject(this); } /** {@inheritDoc} */ @@ -4313,6 +4312,22 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou this.threadId = threadId; } + /** + * Starts tracking tx as timeout object. + */ + public void initTimeoutHandler() throws TransactionTimeoutException { + if (timeout() > 0 && !implicit()) { + if (remainingTime() == -1L) { + onTimeout(); + + throw new TransactionTimeoutException( + "Failed to start transaction. Transaction is timed out during initialization."); + } + else + trackTimeout = cctx.time().addTimeoutObject(this); + } + } + /** * Removes timeout handler. * diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java index e9cd1228322..5fb6fb51365 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java @@ -722,7 +722,11 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter { tx.applicationAttributes(appAttrs); - return onCreated(sysCacheCtx, tx); + onCreated(sysCacheCtx, tx); + + tx.initTimeoutHandler(); + + return tx; } /** diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxTimeoutOnInitializationTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxTimeoutOnInitializationTest.java new file mode 100644 index 00000000000..569ddf43449 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxTimeoutOnInitializationTest.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.processors.cache.transactions; + +import org.apache.ignite.Ignition; +import org.apache.ignite.client.ClientTransaction; +import org.apache.ignite.client.Config; +import org.apache.ignite.client.IgniteClient; +import org.apache.ignite.configuration.ClientConfiguration; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; +import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.apache.ignite.transactions.Transaction; +import org.junit.Test; +import org.mockito.Mockito; + +import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC; +import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ; + +/** + * Tests transaction timeout during initialization. + */ +public class TxTimeoutOnInitializationTest extends GridCommonAbstractTest { + /** + * @throws Exception If failed. + */ + @Test + public void testTxTimeoutOnInitialization() throws Exception { + long txTimeout = 500L; + + IgniteEx ignite0 = startGrid(0); + + GridCacheSharedContext<?, ?> sharedCtx = ignite0.context().cache().context(); + + IgniteTxManager tm = Mockito.spy(sharedCtx.tm()); + sharedCtx.setTxManager(tm); + + Mockito.doAnswer(m -> { + doSleep(txTimeout * 2); + + return m.callRealMethod(); + }).when(tm).onCreated(Mockito.any(), Mockito.any()); + + try (Transaction tx = ignite0.transactions().txStart(PESSIMISTIC, REPEATABLE_READ, txTimeout, 1)) { + // No-op. + } + catch (Exception e) { + assertTrue(e.getMessage().contains("timed out")); + } + + assertTrue(GridTestUtils.waitForCondition(() -> tm.activeTransactions().isEmpty(), 1_000L)); + + try (IgniteClient client = Ignition.startClient(new ClientConfiguration().setAddresses(Config.SERVER))) { + try (ClientTransaction tx = client.transactions().txStart(PESSIMISTIC, REPEATABLE_READ, txTimeout)) { + // No-op. + } + catch (Exception e) { + assertTrue(e.getMessage().contains("timed out")); + } + } + + assertTrue(GridTestUtils.waitForCondition(() -> tm.activeTransactions().isEmpty(), 1_000L)); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite6.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite6.java index 1da50af28ac..eecf72df48c 100644 --- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite6.java +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite6.java @@ -70,6 +70,7 @@ import org.apache.ignite.internal.processors.cache.transactions.TxRollbackOnTime import org.apache.ignite.internal.processors.cache.transactions.TxRollbackOnTimeoutTest; import org.apache.ignite.internal.processors.cache.transactions.TxRollbackOnTopologyChangeTest; import org.apache.ignite.internal.processors.cache.transactions.TxStateChangeEventTest; +import org.apache.ignite.internal.processors.cache.transactions.TxTimeoutOnInitializationTest; import org.apache.ignite.testframework.GridTestUtils; import org.apache.ignite.testframework.junits.DynamicSuite; import org.junit.runner.RunWith; @@ -111,6 +112,7 @@ public class IgniteCacheTestSuite6 { GridTestUtils.addTestIfNeeded(suite, TxRollbackAsyncNearCacheTest.class, ignoredTests); GridTestUtils.addTestIfNeeded(suite, TxRollbackOnTopologyChangeTest.class, ignoredTests); GridTestUtils.addTestIfNeeded(suite, TxRollbackOnTimeoutOnePhaseCommitTest.class, ignoredTests); + GridTestUtils.addTestIfNeeded(suite, TxTimeoutOnInitializationTest.class, ignoredTests); GridTestUtils.addTestIfNeeded(suite, TxOptimisticPrepareOnUnstableTopologyTest.class, ignoredTests);