IGNITE-10415: MVCC TX: Exception handling fixed. This closes #6030.
authorAndrey V. Mashenkov <andrey.mashenkov@gmail.com>
Thu, 14 Feb 2019 13:12:19 +0000 (16:12 +0300)
committerIgor Seliverstov <gvvinblade@gmail.com>
Thu, 14 Feb 2019 13:12:19 +0000 (16:12 +0300)
modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/MvccUtils.java
modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java
modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcRequestHandler.java
modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java
modules/core/src/main/java/org/apache/ignite/internal/transactions/IgniteTxAlreadyCompletedCheckedException.java [new file with mode: 0644]
modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
modules/core/src/main/java/org/apache/ignite/transactions/TransactionAlreadyCompletedException.java [new file with mode: 0644]
modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnIncorrectParamsTest.java
modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java
modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/GridReduceQueryExecutor.java

index 9d688c5..f904966 100644 (file)
@@ -31,7 +31,7 @@ import org.apache.ignite.internal.processors.cache.persistence.tree.io.DataPageI
 import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx;
 import org.apache.ignite.internal.processors.cache.transactions.IgniteTxManager;
 import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
-import org.apache.ignite.internal.processors.query.IgniteSQLException;
+import org.apache.ignite.internal.transactions.IgniteTxAlreadyCompletedCheckedException;
 import org.apache.ignite.internal.transactions.IgniteTxUnexpectedStateCheckedException;
 import org.apache.ignite.internal.util.typedef.internal.CU;
 import org.apache.ignite.transactions.TransactionException;
@@ -43,7 +43,6 @@ import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
 import static org.apache.ignite.internal.pagemem.PageIdUtils.itemId;
 import static org.apache.ignite.internal.pagemem.PageIdUtils.pageId;
 import static org.apache.ignite.internal.processors.cache.persistence.tree.io.DataPageIO.MVCC_INFO_SIZE;
-import static org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode.TRANSACTION_COMPLETED;
 import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
 import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
 
@@ -678,9 +677,9 @@ public class MvccUtils {
      * @param tx Transaction.
      * @return Checked transaction.
      */
-    public static GridNearTxLocal checkActive(GridNearTxLocal tx) {
+    public static GridNearTxLocal checkActive(GridNearTxLocal tx) throws IgniteTxAlreadyCompletedCheckedException {
         if (tx != null && tx.state() != TransactionState.ACTIVE)
-            throw new IgniteSQLException("Transaction is already completed.", TRANSACTION_COMPLETED);
+            throw new IgniteTxAlreadyCompletedCheckedException("Transaction is already completed.");
 
         return tx;
     }
index 35bb2a9..7a28a19 100644 (file)
@@ -64,6 +64,7 @@ import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.internal.util.worker.GridWorker;
 import org.apache.ignite.lang.IgniteBiTuple;
+import org.apache.ignite.transactions.TransactionAlreadyCompletedException;
 import org.apache.ignite.transactions.TransactionDuplicateKeyException;
 import org.apache.ignite.transactions.TransactionSerializationException;
 
@@ -1116,6 +1117,8 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler {
             return new JdbcResponse(IgniteQueryErrorCode.QUERY_CANCELED, e.getMessage());
         if (e instanceof TransactionSerializationException)
             return new JdbcResponse(IgniteQueryErrorCode.TRANSACTION_SERIALIZATION_ERROR, e.getMessage());
+        if (e instanceof TransactionAlreadyCompletedException)
+            return new JdbcResponse(IgniteQueryErrorCode.TRANSACTION_COMPLETED, e.getMessage());
         if (e instanceof TransactionDuplicateKeyException)
             return new JdbcResponse(IgniteQueryErrorCode.DUPLICATE_KEY, e.getMessage());
         if (e instanceof MvccUtils.NonMvccTransactionException)
index 01ceb59..43fedae 100644 (file)
@@ -62,6 +62,7 @@ import org.apache.ignite.internal.util.typedef.X;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.internal.util.worker.GridWorker;
 import org.apache.ignite.lang.IgniteBiTuple;
+import org.apache.ignite.transactions.TransactionAlreadyCompletedException;
 import org.apache.ignite.transactions.TransactionDuplicateKeyException;
 import org.apache.ignite.transactions.TransactionSerializationException;
 
@@ -974,6 +975,8 @@ public class OdbcRequestHandler implements ClientListenerRequestHandler {
 
         if (e instanceof TransactionSerializationException)
             return new OdbcResponse(IgniteQueryErrorCode.TRANSACTION_SERIALIZATION_ERROR, msg);
+        if (e instanceof TransactionAlreadyCompletedException)
+            return new OdbcResponse(IgniteQueryErrorCode.TRANSACTION_COMPLETED, msg);
         if (e instanceof MvccUtils.NonMvccTransactionException)
             return new OdbcResponse(IgniteQueryErrorCode.TRANSACTION_TYPE_MISMATCH, msg);
         if (e instanceof MvccUtils.UnsupportedTxModeException)
index e15687e..da9279d 100644 (file)
@@ -67,6 +67,7 @@ import org.apache.ignite.internal.processors.query.schema.SchemaOperationExcepti
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.A;
 import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.transactions.TransactionAlreadyCompletedException;
 import org.apache.ignite.transactions.TransactionDuplicateKeyException;
 import org.apache.ignite.transactions.TransactionSerializationException;
 import org.jetbrains.annotations.NotNull;
@@ -1501,6 +1502,11 @@ public class QueryUtils {
 
             sqlState = IgniteQueryErrorCode.codeToSqlState(code);
         }
+        else if (e instanceof TransactionAlreadyCompletedException){
+            code = IgniteQueryErrorCode.TRANSACTION_COMPLETED;
+
+            sqlState = IgniteQueryErrorCode.codeToSqlState(code);
+        }
         else {
             sqlState = SqlStateCode.INTERNAL_ERROR;
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/transactions/IgniteTxAlreadyCompletedCheckedException.java b/modules/core/src/main/java/org/apache/ignite/internal/transactions/IgniteTxAlreadyCompletedCheckedException.java
new file mode 100644 (file)
index 0000000..47b47bc
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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.transactions;
+
+/**
+ * Exception thrown whenever Mvcc transaction has been finished before operation finished.
+ * E.g. rollback due to some reason.
+ */
+public class IgniteTxAlreadyCompletedCheckedException extends TransactionCheckedException {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /**
+     * Creates new exception with given error message.
+     *
+     * @param msg Error message.
+     */
+    public IgniteTxAlreadyCompletedCheckedException(String msg) {
+        super(msg);
+    }
+}
index 51feab6..8fb0a70 100755 (executable)
@@ -211,6 +211,7 @@ import org.apache.ignite.internal.processors.cache.GridCacheAttributes;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
 import org.apache.ignite.internal.processors.cluster.BaselineTopology;
+import org.apache.ignite.internal.transactions.IgniteTxAlreadyCompletedCheckedException;
 import org.apache.ignite.internal.transactions.IgniteTxDuplicateKeyCheckedException;
 import org.apache.ignite.internal.transactions.IgniteTxHeuristicCheckedException;
 import org.apache.ignite.internal.transactions.IgniteTxOptimisticCheckedException;
@@ -252,6 +253,7 @@ import org.apache.ignite.spi.IgniteSpi;
 import org.apache.ignite.spi.IgniteSpiException;
 import org.apache.ignite.spi.discovery.DiscoverySpi;
 import org.apache.ignite.spi.discovery.DiscoverySpiOrderSupport;
+import org.apache.ignite.transactions.TransactionAlreadyCompletedException;
 import org.apache.ignite.transactions.TransactionDeadlockException;
 import org.apache.ignite.transactions.TransactionDuplicateKeyException;
 import org.apache.ignite.transactions.TransactionHeuristicException;
@@ -974,6 +976,12 @@ public abstract class IgniteUtils {
             }
         });
 
+        m.put(IgniteTxAlreadyCompletedCheckedException.class, new C1<IgniteCheckedException, IgniteException>() {
+            @Override public IgniteException apply(IgniteCheckedException e) {
+                return new TransactionAlreadyCompletedException(e.getMessage(), e);
+            }
+        });
+
         return m;
     }
 
diff --git a/modules/core/src/main/java/org/apache/ignite/transactions/TransactionAlreadyCompletedException.java b/modules/core/src/main/java/org/apache/ignite/transactions/TransactionAlreadyCompletedException.java
new file mode 100644 (file)
index 0000000..e30cb27
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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.transactions;
+
+/**
+ * Exception thrown whenever Mvcc transaction has been finished before operation finished.
+ * E.g. rollback due to some reason.
+ */
+public class TransactionAlreadyCompletedException extends TransactionException {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /**
+     * Creates new exception with given error message and optional nested exception.
+     *
+     * @param msg Error message.
+     * @param cause Optional nested exception (can be {@code null}).
+     */
+    public TransactionAlreadyCompletedException(String msg, Throwable cause) {
+        super(cause);
+    }
+}
index b69a70e..c421f26 100644 (file)
@@ -28,8 +28,10 @@ import org.apache.ignite.events.TransactionStateChangedEvent;
 import org.apache.ignite.lang.IgniteBiPredicate;
 import org.apache.ignite.lang.IgnitePredicate;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.MvccFeatureChecker;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
 import org.apache.ignite.transactions.Transaction;
+import org.apache.ignite.transactions.TransactionAlreadyCompletedException;
 import org.apache.ignite.transactions.TransactionConcurrency;
 import org.apache.ignite.transactions.TransactionIsolation;
 import org.apache.ignite.transactions.TransactionRollbackException;
@@ -79,7 +81,10 @@ public class TxRollbackOnIncorrectParamsTest extends GridCommonAbstractTest {
             fail("Should fail prior this line.");
         }
         catch (CacheException ex) {
-            assertTrue(ex.getCause() instanceof TransactionRollbackException);
+            if (MvccFeatureChecker.forcedMvcc())
+                assertTrue(ex.toString(), ex.getCause() instanceof TransactionAlreadyCompletedException);
+            else
+                assertTrue(ex.toString(), ex.getCause() instanceof TransactionRollbackException);
         }
 
         try (Transaction tx = ignite.transactions().txStart()) {
@@ -90,7 +95,10 @@ public class TxRollbackOnIncorrectParamsTest extends GridCommonAbstractTest {
             fail("Should fail prior this line.");
         }
         catch (CacheException ex) {
-            assertTrue(ex.getCause() instanceof TransactionRollbackException);
+            if (MvccFeatureChecker.forcedMvcc())
+                assertTrue(ex.toString(), ex.getCause() instanceof TransactionAlreadyCompletedException);
+            else
+                assertTrue(ex.toString(), ex.getCause() instanceof TransactionRollbackException);
         }
     }
 
@@ -129,8 +137,11 @@ public class TxRollbackOnIncorrectParamsTest extends GridCommonAbstractTest {
 
             fail("Should fail prior this line.");
         }
-        catch (CacheException ignored) {
-            // No-op.
+        catch (CacheException ex) {
+            if (MvccFeatureChecker.forcedMvcc())
+                assertTrue(ex.toString(), ex.getCause() instanceof TransactionAlreadyCompletedException);
+            else
+                assertTrue(ex.toString(), ex.getCause() instanceof TransactionRollbackException);
         }
     }
 
@@ -179,8 +190,11 @@ public class TxRollbackOnIncorrectParamsTest extends GridCommonAbstractTest {
 
             fail("Should fail prior this line.");
         }
-        catch (CacheException ignored) {
-            // No-op.
+        catch (CacheException ex) {
+            if (MvccFeatureChecker.forcedMvcc())
+                assertTrue(ex.toString(), ex.getCause() instanceof TransactionAlreadyCompletedException);
+            else
+                assertTrue(ex.toString(), ex.getCause() instanceof TransactionRollbackException);
         }
 
         try (Transaction tx = remote.transactions().txStart()) {
@@ -190,8 +204,11 @@ public class TxRollbackOnIncorrectParamsTest extends GridCommonAbstractTest {
 
             fail("Should fail prior this line.");
         }
-        catch (CacheException ignored) {
-            // No-op.
+        catch (CacheException ex) {
+            if (MvccFeatureChecker.forcedMvcc())
+                assertTrue(ex.toString(), ex.getCause() instanceof TransactionAlreadyCompletedException);
+            else
+                assertTrue(ex.toString(), ex.getCause() instanceof TransactionRollbackException);
         }
     }
 
@@ -242,8 +259,11 @@ public class TxRollbackOnIncorrectParamsTest extends GridCommonAbstractTest {
 
             fail("Should fail prior this line.");
         }
-        catch (CacheException ignored) {
-            // No-op.
+        catch (CacheException ex) {
+            if (MvccFeatureChecker.forcedMvcc())
+                assertTrue(ex.toString(), ex.getCause() instanceof TransactionAlreadyCompletedException);
+            else
+                assertTrue(ex.toString(), ex.getCause() instanceof TransactionRollbackException);
         }
 
         try (Transaction tx = remote.transactions().txStart()) {
@@ -253,8 +273,11 @@ public class TxRollbackOnIncorrectParamsTest extends GridCommonAbstractTest {
 
             fail("Should fail prior this line.");
         }
-        catch (CacheException ignored) {
-            // No-op.
+        catch (CacheException ex) {
+            if (MvccFeatureChecker.forcedMvcc())
+                assertTrue(ex.toString(), ex.getCause() instanceof TransactionAlreadyCompletedException);
+            else
+                assertTrue(ex.toString(), ex.getCause() instanceof TransactionRollbackException);
         }
     }
 
@@ -306,8 +329,11 @@ public class TxRollbackOnIncorrectParamsTest extends GridCommonAbstractTest {
 
             fail("Should fail prior this line.");
         }
-        catch (CacheException ignored) {
-            // No-op.
+        catch (CacheException ex) {
+            if (MvccFeatureChecker.forcedMvcc())
+                assertTrue(ex.toString(), ex.getCause() instanceof TransactionAlreadyCompletedException);
+            else
+                assertTrue(ex.toString(), ex.getCause() instanceof TransactionRollbackException);
         }
 
         assertFalse(rollbackFailed.get());
index 88a72e8..621d6e8 100644 (file)
@@ -96,15 +96,6 @@ import org.apache.ignite.internal.processors.query.RunningQueryManager;
 import org.apache.ignite.internal.processors.query.SqlClientContext;
 import org.apache.ignite.internal.processors.query.UpdateSourceIterator;
 import org.apache.ignite.internal.processors.query.h2.affinity.H2PartitionResolver;
-import org.apache.ignite.internal.processors.query.h2.dml.DmlDistributedPlanInfo;
-import org.apache.ignite.internal.processors.query.h2.dml.DmlUpdateResultsIterator;
-import org.apache.ignite.internal.processors.query.h2.dml.DmlUpdateSingleEntryIterator;
-import org.apache.ignite.internal.processors.query.h2.dml.UpdateMode;
-import org.apache.ignite.internal.processors.query.h2.dml.UpdatePlanBuilder;
-import org.apache.ignite.internal.processors.query.h2.opt.QueryContext;
-import org.apache.ignite.internal.processors.query.h2.opt.QueryContextRegistry;
-import org.apache.ignite.internal.processors.query.h2.twostep.PartitionReservationManager;
-import org.apache.ignite.internal.sql.optimizer.affinity.PartitionResult;
 import org.apache.ignite.internal.processors.query.h2.affinity.PartitionExtractor;
 import org.apache.ignite.internal.processors.query.h2.database.H2TreeClientIndex;
 import org.apache.ignite.internal.processors.query.h2.database.H2TreeIndex;
@@ -114,10 +105,17 @@ import org.apache.ignite.internal.processors.query.h2.database.io.H2InnerIO;
 import org.apache.ignite.internal.processors.query.h2.database.io.H2LeafIO;
 import org.apache.ignite.internal.processors.query.h2.database.io.H2MvccInnerIO;
 import org.apache.ignite.internal.processors.query.h2.database.io.H2MvccLeafIO;
+import org.apache.ignite.internal.processors.query.h2.dml.DmlDistributedPlanInfo;
+import org.apache.ignite.internal.processors.query.h2.dml.DmlUpdateResultsIterator;
+import org.apache.ignite.internal.processors.query.h2.dml.DmlUpdateSingleEntryIterator;
 import org.apache.ignite.internal.processors.query.h2.dml.DmlUtils;
+import org.apache.ignite.internal.processors.query.h2.dml.UpdateMode;
 import org.apache.ignite.internal.processors.query.h2.dml.UpdatePlan;
+import org.apache.ignite.internal.processors.query.h2.dml.UpdatePlanBuilder;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2IndexBase;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table;
+import org.apache.ignite.internal.processors.query.h2.opt.QueryContext;
+import org.apache.ignite.internal.processors.query.h2.opt.QueryContextRegistry;
 import org.apache.ignite.internal.processors.query.h2.sql.GridSqlAlias;
 import org.apache.ignite.internal.processors.query.h2.sql.GridSqlAst;
 import org.apache.ignite.internal.processors.query.h2.sql.GridSqlQueryParser;
@@ -126,6 +124,7 @@ import org.apache.ignite.internal.processors.query.h2.sql.GridSqlTable;
 import org.apache.ignite.internal.processors.query.h2.twostep.GridMapQueryExecutor;
 import org.apache.ignite.internal.processors.query.h2.twostep.GridReduceQueryExecutor;
 import org.apache.ignite.internal.processors.query.h2.twostep.MapQueryLazyWorker;
+import org.apache.ignite.internal.processors.query.h2.twostep.PartitionReservationManager;
 import org.apache.ignite.internal.processors.query.h2.twostep.msg.GridH2QueryRequest;
 import org.apache.ignite.internal.processors.query.schema.SchemaIndexCacheVisitor;
 import org.apache.ignite.internal.processors.query.schema.SchemaIndexCacheVisitorClosure;
@@ -133,6 +132,7 @@ import org.apache.ignite.internal.processors.query.schema.SchemaIndexCacheVisito
 import org.apache.ignite.internal.sql.command.SqlCommand;
 import org.apache.ignite.internal.sql.command.SqlCommitTransactionCommand;
 import org.apache.ignite.internal.sql.command.SqlRollbackTransactionCommand;
+import org.apache.ignite.internal.sql.optimizer.affinity.PartitionResult;
 import org.apache.ignite.internal.util.GridBoundedConcurrentLinkedHashMap;
 import org.apache.ignite.internal.util.GridEmptyCloseableIterator;
 import org.apache.ignite.internal.util.GridSpinBusyLock;
@@ -1269,7 +1269,7 @@ public class IgniteH2Indexing implements GridQueryIndexing {
             };
         }
         catch (IgniteCheckedException e) {
-            throw new CacheException(e);
+            throw U.convertException(e);
         }
     }
 
index 046840e..24e93cd 100644 (file)
@@ -82,6 +82,7 @@ import org.apache.ignite.internal.processors.query.h2.twostep.msg.GridH2DmlReque
 import org.apache.ignite.internal.processors.query.h2.twostep.msg.GridH2DmlResponse;
 import org.apache.ignite.internal.processors.query.h2.twostep.msg.GridH2QueryRequest;
 import org.apache.ignite.internal.processors.query.h2.twostep.msg.GridH2SelectForUpdateTxDetails;
+import org.apache.ignite.internal.transactions.IgniteTxAlreadyCompletedCheckedException;
 import org.apache.ignite.internal.util.GridSpinBusyLock;
 import org.apache.ignite.internal.util.typedef.C2;
 import org.apache.ignite.internal.util.typedef.CIX2;
@@ -92,6 +93,7 @@ import org.apache.ignite.lang.IgniteBiClosure;
 import org.apache.ignite.lang.IgniteFuture;
 import org.apache.ignite.lang.IgniteUuid;
 import org.apache.ignite.plugin.extensions.communication.Message;
+import org.apache.ignite.transactions.TransactionAlreadyCompletedException;
 import org.apache.ignite.transactions.TransactionException;
 import org.h2.command.ddl.CreateTableData;
 import org.h2.engine.Session;
@@ -462,7 +464,14 @@ public class GridReduceQueryExecutor {
 
             boolean mvccEnabled = mvccEnabled(ctx);
 
-            final GridNearTxLocal curTx = mvccEnabled ? checkActive(tx(ctx)) : null;
+            final GridNearTxLocal curTx;
+
+            try {
+                curTx = mvccEnabled ? checkActive(tx(ctx)) : null;
+            }
+            catch (IgniteTxAlreadyCompletedCheckedException e) {
+                throw new TransactionAlreadyCompletedException(e.getMessage(), e);
+            }
 
             final GridNearTxSelectForUpdateFuture sfuFut;