This is an automated email from the ASF dual-hosted git repository.
rpuch pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new 0b803ee01b IGNITE-20415 Internal IncompatibleSchemaException is thrown
from public API (#4068)
0b803ee01b is described below
commit 0b803ee01b7ef84ecbdac145ce24f5530218888b
Author: Roman Puchkovskiy <[email protected]>
AuthorDate: Mon Jul 22 19:06:13 2024 +0400
IGNITE-20415 Internal IncompatibleSchemaException is thrown from public API
(#4068)
---
.../org/apache/ignite/lang/IgniteException.java | 4 +-
.../ignite/tx/IncompatibleSchemaException.java} | 26 ++++++-----
.../tx/MismatchingTransactionOutcomeException.java | 37 ++++++---------
.../org/apache/ignite/tx/TransactionException.java | 11 +++--
.../ItSchemaForwardCompatibilityTest.java | 50 +++++++++++++++-----
.../schemasync/ItSchemaSyncSingleNodeTest.java | 24 +++-------
.../ignite/internal/table/ItDurableFinishTest.java | 7 +--
.../internal/table/ItTransactionRecoveryTest.java | 8 ++--
.../ignite/internal/table/AbstractTableView.java | 4 +-
.../table/TableExceptionMapperProvider.java} | 17 +++----
...ava => IncompatibleSchemaVersionException.java} | 19 ++++----
.../replicator/PartitionReplicaListener.java | 13 +++---
.../replicator/SchemaCompatibilityValidator.java | 6 +--
.../StaleTransactionOperationException.java | 2 +-
.../table/TableExceptionMapperProviderTest.java | 54 ++++++++++++++++++++++
.../replication/PartitionReplicaListenerTest.java | 19 ++++----
.../tx/IncompatibleSchemaAbortException.java} | 25 ++++------
...tchingTransactionOutcomeInternalException.java} | 14 ++++--
.../tx/TransactionExceptionMapperProvider.java | 6 +++
.../internal/tx/impl/TransactionInflights.java | 4 +-
.../ignite/internal/tx/impl/TxManagerImpl.java | 11 +++--
.../apache/ignite/internal/tx/TxManagerTest.java | 13 +++---
22 files changed, 220 insertions(+), 154 deletions(-)
diff --git
a/modules/api/src/main/java/org/apache/ignite/lang/IgniteException.java
b/modules/api/src/main/java/org/apache/ignite/lang/IgniteException.java
index 218941be99..3c3fcd9eb5 100644
--- a/modules/api/src/main/java/org/apache/ignite/lang/IgniteException.java
+++ b/modules/api/src/main/java/org/apache/ignite/lang/IgniteException.java
@@ -143,7 +143,7 @@ public class IgniteException extends RuntimeException
implements TraceableExcept
* @param code Full error code.
* @param cause Optional nested exception (can be {@code null}).
*/
- public IgniteException(int code, Throwable cause) {
+ public IgniteException(int code, @Nullable Throwable cause) {
this(getOrCreateTraceId(cause), code, cause);
}
@@ -154,7 +154,7 @@ public class IgniteException extends RuntimeException
implements TraceableExcept
* @param code Full error code.
* @param cause Optional nested exception (can be {@code null}).
*/
- public IgniteException(UUID traceId, int code, Throwable cause) {
+ public IgniteException(UUID traceId, int code, @Nullable Throwable cause) {
super((cause != null) ? cause.getLocalizedMessage() : null, cause);
this.traceId = traceId;
diff --git
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replicator/StaleTransactionOperationException.java
b/modules/api/src/main/java/org/apache/ignite/tx/IncompatibleSchemaException.java
similarity index 52%
copy from
modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replicator/StaleTransactionOperationException.java
copy to
modules/api/src/main/java/org/apache/ignite/tx/IncompatibleSchemaException.java
index 1dab412af1..8625b0e56c 100644
---
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replicator/StaleTransactionOperationException.java
+++
b/modules/api/src/main/java/org/apache/ignite/tx/IncompatibleSchemaException.java
@@ -15,23 +15,25 @@
* limitations under the License.
*/
-package org.apache.ignite.internal.table.distributed.replicator;
-
-import static org.apache.ignite.internal.lang.IgniteStringFormatter.format;
-import static
org.apache.ignite.lang.ErrorGroups.Transactions.TX_STALE_OPERATION_ERR;
+package org.apache.ignite.tx;
import java.util.UUID;
-import org.apache.ignite.internal.tx.TransactionInternalException;
+import org.jetbrains.annotations.Nullable;
-/** Error that occurs when a stale operation of a completed transaction is
detected. */
-// TODO: IGNITE-20415 - make this exception public.
-public class StaleTransactionOperationException extends
TransactionInternalException {
+/**
+ * Thrown when, during an attempt to execute a transactional operation, it
turns out that the operation cannot be executed
+ * because an incompatible schema change has happened. The transaction in
question is aborted.
+ */
+public class IncompatibleSchemaException extends TransactionException {
/**
- * Constructor.
+ * Constructs a new instance of IncompatibleSchemaException.
*
- * @param txId Transaction ID.
+ * @param traceId Trace ID.
+ * @param code Error code.
+ * @param message Error message.
+ * @param cause The Throwable that is the cause of this exception (can be
{@code null}).
*/
- public StaleTransactionOperationException(UUID txId) {
- super(TX_STALE_OPERATION_ERR, format("Stale operation of a completed
transaction was detected: [txId={}]", txId));
+ public IncompatibleSchemaException(UUID traceId, int code, String message,
@Nullable Throwable cause) {
+ super(traceId, code, message, cause);
}
}
diff --git
a/modules/transactions/src/main/java/org/apache/ignite/internal/tx/MismatchingTransactionOutcomeException.java
b/modules/api/src/main/java/org/apache/ignite/tx/MismatchingTransactionOutcomeException.java
similarity index 50%
copy from
modules/transactions/src/main/java/org/apache/ignite/internal/tx/MismatchingTransactionOutcomeException.java
copy to
modules/api/src/main/java/org/apache/ignite/tx/MismatchingTransactionOutcomeException.java
index 6fc15f87c7..88a942f1d9 100644
---
a/modules/transactions/src/main/java/org/apache/ignite/internal/tx/MismatchingTransactionOutcomeException.java
+++
b/modules/api/src/main/java/org/apache/ignite/tx/MismatchingTransactionOutcomeException.java
@@ -15,38 +15,27 @@
* limitations under the License.
*/
-package org.apache.ignite.internal.tx;
+package org.apache.ignite.tx;
-import static
org.apache.ignite.lang.ErrorGroups.Transactions.TX_UNEXPECTED_STATE_ERR;
+import java.util.UUID;
+import org.jetbrains.annotations.Nullable;
/**
* The exception is thrown when the transaction result differs from the
intended one.
*
* <p>For example, {@code tx.commit()} is called for a transaction, but the
verification logic decided to abort it instead. The transaction
- * will be finished with {@link TxState#ABORTED} and the call to {@code
tx.commit()} will throw this exception.
+ * will be aborted and the call to {@code tx.commit()} will throw this
exception.</p>
*/
-// TODO: IGNITE-20415 - split this into public exception (in a public package)
and internal exception (carrying internal state).
-public class MismatchingTransactionOutcomeException extends
TransactionInternalException {
-
- private static final long serialVersionUID = -7953057695915339651L;
-
- /** Stored transaction result. */
- private final TransactionResult transactionResult;
-
+public class MismatchingTransactionOutcomeException extends
TransactionException {
/**
- * Constructor.
+ * Constructs a new instance.
+ *
+ * @param traceId Trace ID.
+ * @param code Full error code.
+ * @param message Error message.
+ * @param cause The Throwable that is the cause of this exception (can be
{@code null}).
*/
- public MismatchingTransactionOutcomeException(int errorCode, String
message, TransactionResult transactionResult, Throwable cause) {
- super(errorCode, message, cause);
-
- this.transactionResult = transactionResult;
- }
-
- public MismatchingTransactionOutcomeException(String message,
TransactionResult transactionResult) {
- this(TX_UNEXPECTED_STATE_ERR, message, transactionResult, null);
- }
-
- public TransactionResult transactionResult() {
- return transactionResult;
+ public MismatchingTransactionOutcomeException(UUID traceId, int code,
String message, @Nullable Throwable cause) {
+ super(traceId, code, message, cause);
}
}
diff --git
a/modules/api/src/main/java/org/apache/ignite/tx/TransactionException.java
b/modules/api/src/main/java/org/apache/ignite/tx/TransactionException.java
index 49895f2737..d1f2581b88 100644
--- a/modules/api/src/main/java/org/apache/ignite/tx/TransactionException.java
+++ b/modules/api/src/main/java/org/apache/ignite/tx/TransactionException.java
@@ -19,8 +19,9 @@ package org.apache.ignite.tx;
import java.util.UUID;
import org.apache.ignite.lang.IgniteException;
+import org.jetbrains.annotations.Nullable;
-/** This exception is thrown if a transaction can't be finished by some
reasons. */
+/** This exception is thrown if a transaction can't be finished for some
reason. */
public class TransactionException extends IgniteException {
/**
* Creates a new transaction exception with a message.
@@ -48,7 +49,7 @@ public class TransactionException extends IgniteException {
* @param code Full error code.
* @param cause Optional nested exception (can be {@code null}).
*/
- public TransactionException(int code, Throwable cause) {
+ public TransactionException(int code, @Nullable Throwable cause) {
super(code, cause);
}
@@ -70,7 +71,7 @@ public class TransactionException extends IgniteException {
* @param code Full error code.
* @param cause Optional nested exception (can be {@code null}).
*/
- public TransactionException(UUID traceId, int code, Throwable cause) {
+ public TransactionException(UUID traceId, int code, @Nullable Throwable
cause) {
super(traceId, code, cause);
}
@@ -81,7 +82,7 @@ public class TransactionException extends IgniteException {
* @param message Detail message.
* @param cause Optional nested exception (can be {@code null}).
*/
- public TransactionException(int code, String message, Throwable cause) {
+ public TransactionException(int code, String message, @Nullable Throwable
cause) {
super(code, message, cause);
}
@@ -93,7 +94,7 @@ public class TransactionException extends IgniteException {
* @param message Detail message.
* @param cause Optional nested exception (can be {@code null}).
*/
- public TransactionException(UUID traceId, int code, String message,
Throwable cause) {
+ public TransactionException(UUID traceId, int code, String message,
@Nullable Throwable cause) {
super(traceId, code, message, cause);
}
}
diff --git
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/schemasync/ItSchemaForwardCompatibilityTest.java
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/schemasync/ItSchemaForwardCompatibilityTest.java
index 4b130b40d9..3cfdd08f2c 100644
---
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/schemasync/ItSchemaForwardCompatibilityTest.java
+++
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/schemasync/ItSchemaForwardCompatibilityTest.java
@@ -17,8 +17,9 @@
package org.apache.ignite.internal.schemasync;
+import static java.util.concurrent.TimeUnit.SECONDS;
import static org.apache.ignite.internal.SessionUtils.executeUpdate;
-import static org.apache.ignite.internal.TestWrappers.unwrapTableViewInternal;
+import static
org.apache.ignite.internal.testframework.asserts.CompletableFutureAssert.assertWillThrow;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
@@ -33,9 +34,10 @@ import org.apache.ignite.internal.tx.TxState;
import org.apache.ignite.lang.ErrorGroups.Transactions;
import org.apache.ignite.table.Table;
import org.apache.ignite.table.Tuple;
+import org.apache.ignite.tx.IncompatibleSchemaException;
import org.apache.ignite.tx.Transaction;
-import org.apache.ignite.tx.TransactionException;
import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
@@ -62,7 +64,7 @@ class ItSchemaForwardCompatibilityTest extends
ClusterPerTestIntegrationTest {
}
/**
- * Makes sure forward-compatible schema changes happenning between
transaction operations and
+ * Makes sure forward-compatible schema changes happening between
transaction operations and
* commit do not prevent a commit from happening.
*/
@ParameterizedTest
@@ -79,18 +81,17 @@ class ItSchemaForwardCompatibilityTest extends
ClusterPerTestIntegrationTest {
assertDoesNotThrow(tx::commit);
}
- @SuppressWarnings("resource")
private void writeIn(Transaction tx) {
putInTx(cluster.node(0).tables().table(TABLE_NAME), tx);
}
/**
- * Makes sure forward-incompatible schema changes happenning between
transaction operations and
+ * Makes sure forward-incompatible schema changes happening between
transaction operations and
* commit prevent a commit from happening: instead, the transaction is
aborted.
*/
@ParameterizedTest
@EnumSource(ForwardIncompatibleDdl.class)
- void
forwardIncompatibleSchemaChangesDoNotAllowCommitting(ForwardIncompatibleDdl
ddl) {
+ void
forwardIncompatibleSchemaChangesDoNotAllowSyncCommit(ForwardIncompatibleDdl
ddl) {
createTable();
Table table = node.tables().table(TABLE_NAME);
@@ -101,9 +102,7 @@ class ItSchemaForwardCompatibilityTest extends
ClusterPerTestIntegrationTest {
ddl.executeOn(cluster);
- int tableId = unwrapTableViewInternal(table).tableId();
-
- TransactionException ex = assertThrows(TransactionException.class,
tx::commit);
+ IncompatibleSchemaException ex =
assertThrows(IncompatibleSchemaException.class, tx::commit);
assertThat(
ex.getMessage(),
containsString(String.format(
@@ -114,8 +113,35 @@ class ItSchemaForwardCompatibilityTest extends
ClusterPerTestIntegrationTest {
))
);
- // TODO: IGNITE-20415 - assert that the failure is because of a
changed schema.
- assertThat(ex.code(), is(Transactions.TX_COMMIT_ERR));
+ assertThat(ex.code(), is(Transactions.TX_INCOMPATIBLE_SCHEMA_ERR));
+
+ assertThat(tx.state(), is(TxState.ABORTED));
+ }
+
+ /**
+ * Makes sure forward-incompatible schema changes happening between
transaction operations and
+ * commit prevent a commit from happening (for async API): instead, the
transaction is aborted.
+ */
+ @Test
+ void forwardIncompatibleSchemaChangesDoNotAllowAsyncCommitting() {
+ createTable();
+
+ InternalTransaction tx = (InternalTransaction)
node.transactions().begin();
+
+ writeIn(tx);
+
+ ForwardIncompatibleDdl.CHANGE_DEFAULT.executeOn(cluster);
+
+ IncompatibleSchemaException ex = assertWillThrow(tx.commitAsync(),
IncompatibleSchemaException.class, 10, SECONDS);
+ assertThat(
+ ex.getMessage(),
+ containsString(
+ "Commit failed because schema is not
forward-compatible [fromSchemaVersion=1, toSchemaVersion=2, table=TEST, "
+ + "details=Column default value changed]"
+ )
+ );
+
+ assertThat(ex.code(), is(Transactions.TX_INCOMPATIBLE_SCHEMA_ERR));
assertThat(tx.state(), is(TxState.ABORTED));
}
@@ -136,7 +162,7 @@ class ItSchemaForwardCompatibilityTest extends
ClusterPerTestIntegrationTest {
private enum ForwardCompatibleDdl {
ADD_NULLABLE_COLUMN("ALTER TABLE " + TABLE_NAME + " ADD COLUMN new_col
INT"),
ADD_COLUMN_WITH_DEFAULT("ALTER TABLE " + TABLE_NAME + " ADD COLUMN
new_col INT NOT NULL DEFAULT 42"),
- // TODO: IGNITE-19485, IGNITE-20315 - Uncomment this after column
rename support gets aded.
+ // TODO: IGNITE-19485, IGNITE-20315 - Uncomment this after column
rename support gets added.
// RENAME_COLUMN("ALTER TABLE " + TABLE_NAME + " RENAME COLUMN
not_null_int to new_col"),
DROP_NOT_NULL("ALTER TABLE " + TABLE_NAME + " ALTER COLUMN
not_null_int DROP NOT NULL"),
WIDEN_COLUMN_TYPE("ALTER TABLE " + TABLE_NAME + " ALTER COLUMN
not_null_int SET DATA TYPE BIGINT");
diff --git
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/schemasync/ItSchemaSyncSingleNodeTest.java
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/schemasync/ItSchemaSyncSingleNodeTest.java
index 093693fe06..90e4b701ea 100644
---
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/schemasync/ItSchemaSyncSingleNodeTest.java
+++
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/schemasync/ItSchemaSyncSingleNodeTest.java
@@ -30,7 +30,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import org.apache.ignite.internal.Cluster;
import org.apache.ignite.internal.ClusterPerTestIntegrationTest;
import org.apache.ignite.internal.app.IgniteImpl;
-import
org.apache.ignite.internal.table.distributed.replicator.IncompatibleSchemaException;
import org.apache.ignite.internal.tx.InternalTransaction;
import org.apache.ignite.internal.tx.TxState;
import org.apache.ignite.internal.util.ExceptionUtils;
@@ -40,8 +39,8 @@ import org.apache.ignite.lang.IgniteException;
import org.apache.ignite.table.KeyValueView;
import org.apache.ignite.table.Table;
import org.apache.ignite.table.Tuple;
+import org.apache.ignite.tx.IncompatibleSchemaException;
import org.apache.ignite.tx.Transaction;
-import org.apache.ignite.tx.TransactionException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;
@@ -100,13 +99,10 @@ class ItSchemaSyncSingleNodeTest extends
ClusterPerTestIntegrationTest {
alterTable(TABLE_NAME);
- int errorCode;
-
- int tableId = unwrapTableViewInternal(table).tableId();
+ IgniteException ex;
if (operation.sql()) {
- IgniteException ex = assertThrows(IgniteException.class, () ->
operation.execute(table, tx, cluster));
- errorCode = ex.code();
+ ex = assertThrows(IgniteException.class, () ->
operation.execute(table, tx, cluster));
assertThat(
ex.getMessage(),
@@ -116,8 +112,7 @@ class ItSchemaSyncSingleNodeTest extends
ClusterPerTestIntegrationTest {
))
);
} else {
- IncompatibleSchemaException ex =
assertThrows(IncompatibleSchemaException.class, () -> operation.execute(table,
tx, cluster));
- errorCode = ex.code();
+ ex = assertThrows(IncompatibleSchemaException.class, () ->
operation.execute(table, tx, cluster));
assertThat(
ex.getMessage(),
@@ -128,7 +123,7 @@ class ItSchemaSyncSingleNodeTest extends
ClusterPerTestIntegrationTest {
);
}
- assertThat(errorCode, is(Transactions.TX_INCOMPATIBLE_SCHEMA_ERR));
+ assertThat(ex.code(), is(Transactions.TX_INCOMPATIBLE_SCHEMA_ERR));
assertThat(tx.state(), is(TxState.ABORTED));
}
@@ -296,19 +291,16 @@ class ItSchemaSyncSingleNodeTest extends
ClusterPerTestIntegrationTest {
dropTable(TABLE_NAME);
- int tableId = unwrapTableViewInternal(table).tableId();
-
Throwable ex = assertThrows(Throwable.class, () ->
operation.executeOn(tx));
ex = ExceptionUtils.unwrapCause(ex);
- assertThat(ex, is(instanceOf(TransactionException.class)));
+ assertThat(ex, is(instanceOf(IncompatibleSchemaException.class)));
assertThat(
ex.getMessage(),
containsString(String.format("Commit failed because a table
was already dropped [table=%s]", table.name()))
);
- // TODO: IGNITE-20415 - assert that the failure is because of a
changed schema.
- assertThat(((TransactionException) ex).code(),
is(Transactions.TX_COMMIT_ERR));
+ assertThat(((IncompatibleSchemaException) ex).code(),
is(Transactions.TX_INCOMPATIBLE_SCHEMA_ERR));
assertThat(tx.state(), is(TxState.ABORTED));
}
@@ -356,8 +348,6 @@ class ItSchemaSyncSingleNodeTest extends
ClusterPerTestIntegrationTest {
Tuple keyTuple = Tuple.create().set("id", KEY);
kvView.put(null, keyTuple, Tuple.create().set("val", "put-in-tx2"));
- int tableId = unwrapTableViewInternal(table).tableId();
-
Executable task = scan ? () -> consumeCursor(kvView.query(tx1, null))
: () -> kvView.get(tx1, keyTuple);
IgniteException ex = assertThrows(IgniteException.class, task);
diff --git
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/table/ItDurableFinishTest.java
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/table/ItDurableFinishTest.java
index 227b28e14d..929e46a5fb 100644
---
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/table/ItDurableFinishTest.java
+++
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/table/ItDurableFinishTest.java
@@ -51,7 +51,6 @@ import org.apache.ignite.internal.replicator.TablePartitionId;
import
org.apache.ignite.internal.replicator.configuration.ReplicationConfiguration;
import org.apache.ignite.internal.testframework.IgniteTestUtils;
import org.apache.ignite.internal.tx.InternalTransaction;
-import org.apache.ignite.internal.tx.MismatchingTransactionOutcomeException;
import org.apache.ignite.internal.tx.TxMeta;
import org.apache.ignite.internal.tx.TxStateMeta;
import org.apache.ignite.internal.tx.message.CleanupReplicatedInfoMessage;
@@ -60,9 +59,9 @@ import
org.apache.ignite.internal.tx.message.TxCleanupMessageErrorResponse;
import org.apache.ignite.internal.tx.message.TxCleanupMessageResponse;
import org.apache.ignite.internal.tx.message.TxFinishReplicaRequest;
import org.apache.ignite.internal.tx.storage.state.TxStateStorage;
-import org.apache.ignite.internal.util.ExceptionUtils;
import org.apache.ignite.table.Table;
import org.apache.ignite.table.Tuple;
+import org.apache.ignite.tx.MismatchingTransactionOutcomeException;
import org.apache.ignite.tx.TransactionException;
import org.jetbrains.annotations.Nullable;
import org.junit.jupiter.api.Test;
@@ -308,9 +307,7 @@ public class ItDurableFinishTest extends
ClusterPerTestIntegrationTest {
// Tx.commit should throw MismatchingTransactionOutcomeException.
TransactionException transactionException =
assertThrows(TransactionException.class, context.tx::commit);
- Throwable cause =
ExceptionUtils.unwrapCause(transactionException.getCause());
-
- assertInstanceOf(MismatchingTransactionOutcomeException.class,
cause.getCause());
+ assertInstanceOf(MismatchingTransactionOutcomeException.class,
transactionException);
}
private void markTxAbortedInTxStateStorage(IgniteImpl primaryNode,
InternalTransaction tx, Table publicTable) {
diff --git
a/modules/table/src/integrationTest/java/org/apache/ignite/internal/table/ItTransactionRecoveryTest.java
b/modules/table/src/integrationTest/java/org/apache/ignite/internal/table/ItTransactionRecoveryTest.java
index 76cad253f5..8d43943ccc 100644
---
a/modules/table/src/integrationTest/java/org/apache/ignite/internal/table/ItTransactionRecoveryTest.java
+++
b/modules/table/src/integrationTest/java/org/apache/ignite/internal/table/ItTransactionRecoveryTest.java
@@ -74,7 +74,7 @@ import
org.apache.ignite.internal.testframework.WithSystemProperty;
import org.apache.ignite.internal.testframework.flow.TestFlowUtils;
import org.apache.ignite.internal.tx.HybridTimestampTracker;
import org.apache.ignite.internal.tx.InternalTransaction;
-import org.apache.ignite.internal.tx.MismatchingTransactionOutcomeException;
+import
org.apache.ignite.internal.tx.MismatchingTransactionOutcomeInternalException;
import org.apache.ignite.internal.tx.TxMeta;
import org.apache.ignite.internal.tx.TxState;
import org.apache.ignite.internal.tx.TxStateMeta;
@@ -531,7 +531,7 @@ public class ItTransactionRecoveryTest extends
ClusterPerTestIntegrationTest {
ErrorTimestampAwareReplicaResponse errorResponse =
(ErrorTimestampAwareReplicaResponse) response;
- assertInstanceOf(MismatchingTransactionOutcomeException.class,
ExceptionUtils.unwrapCause(errorResponse.throwable()));
+ assertInstanceOf(MismatchingTransactionOutcomeInternalException.class,
ExceptionUtils.unwrapCause(errorResponse.throwable()));
assertEquals(TxState.ABORTED, txStoredState(commitPartNode,
orphanTx.id()));
}
@@ -647,7 +647,7 @@ public class ItTransactionRecoveryTest extends
ClusterPerTestIntegrationTest {
rwTx1Id
);
- assertThat(finish2,
willThrow(MismatchingTransactionOutcomeException.class));
+ assertThat(finish2,
willThrow(MismatchingTransactionOutcomeInternalException.class));
}
@Test
@@ -792,7 +792,7 @@ public class ItTransactionRecoveryTest extends
ClusterPerTestIntegrationTest {
cancelLease(commitPartNode, tblReplicationGrp);
TransactionException txEx = assertWillThrow(commitFut,
TransactionException.class, 30, SECONDS);
- assertThat(txEx.getCause(),
instanceOf(MismatchingTransactionOutcomeException.class));
+ assertThat(txEx.getCause(),
instanceOf(MismatchingTransactionOutcomeInternalException.class));
RecordView<Tuple> view =
txCrdNode.tables().table(TABLE_NAME).recordView();
diff --git
a/modules/table/src/main/java/org/apache/ignite/internal/table/AbstractTableView.java
b/modules/table/src/main/java/org/apache/ignite/internal/table/AbstractTableView.java
index 70ff46fb76..2778dbf84b 100644
---
a/modules/table/src/main/java/org/apache/ignite/internal/table/AbstractTableView.java
+++
b/modules/table/src/main/java/org/apache/ignite/internal/table/AbstractTableView.java
@@ -40,7 +40,7 @@ import
org.apache.ignite.internal.table.criteria.CursorAdapter;
import org.apache.ignite.internal.table.criteria.QueryCriteriaAsyncCursor;
import org.apache.ignite.internal.table.criteria.SqlSerializer;
import org.apache.ignite.internal.table.criteria.SqlSerializer.Builder;
-import
org.apache.ignite.internal.table.distributed.replicator.IncompatibleSchemaException;
+import
org.apache.ignite.internal.table.distributed.replicator.IncompatibleSchemaVersionException;
import
org.apache.ignite.internal.table.distributed.replicator.InternalSchemaVersionMismatchException;
import org.apache.ignite.internal.table.distributed.schema.SchemaVersions;
import org.apache.ignite.internal.tx.InternalTransaction;
@@ -157,7 +157,7 @@ abstract class AbstractTableView<R> implements
CriteriaQuerySource<R> {
// Repeat.
return withSchemaSync(tx, schemaVersion,
action);
- } else if (tx == null &&
isOrCausedBy(IncompatibleSchemaException.class, ex)) {
+ } else if (tx == null &&
isOrCausedBy(IncompatibleSchemaVersionException.class, ex)) {
// Table version was changed while we were
executing an implicit transaction (between it had been created
// and the moment when the operation actually
touched the partition), let's retry.
assertSchemaVersionIncreased(previousSchemaVersion, schemaVersion);
diff --git
a/modules/transactions/src/main/java/org/apache/ignite/internal/tx/TransactionExceptionMapperProvider.java
b/modules/table/src/main/java/org/apache/ignite/internal/table/TableExceptionMapperProvider.java
similarity index 69%
copy from
modules/transactions/src/main/java/org/apache/ignite/internal/tx/TransactionExceptionMapperProvider.java
copy to
modules/table/src/main/java/org/apache/ignite/internal/table/TableExceptionMapperProvider.java
index 7c0dc5c40c..f558d1d812 100644
---
a/modules/transactions/src/main/java/org/apache/ignite/internal/tx/TransactionExceptionMapperProvider.java
+++
b/modules/table/src/main/java/org/apache/ignite/internal/table/TableExceptionMapperProvider.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.apache.ignite.internal.tx;
+package org.apache.ignite.internal.table;
import static org.apache.ignite.internal.lang.IgniteExceptionMapper.unchecked;
@@ -25,21 +25,22 @@ import java.util.Collection;
import java.util.List;
import org.apache.ignite.internal.lang.IgniteExceptionMapper;
import org.apache.ignite.internal.lang.IgniteExceptionMappersProvider;
-import org.apache.ignite.internal.replicator.exception.ReplicationException;
-import org.apache.ignite.tx.TransactionException;
+import
org.apache.ignite.internal.table.distributed.replicator.IncompatibleSchemaVersionException;
+import org.apache.ignite.tx.IncompatibleSchemaException;
/**
- * Transaction module exception mapper.
+ * Table module exception mapper.
*/
@AutoService(IgniteExceptionMappersProvider.class)
-public class TransactionExceptionMapperProvider implements
IgniteExceptionMappersProvider {
+public class TableExceptionMapperProvider implements
IgniteExceptionMappersProvider {
@Override
public Collection<IgniteExceptionMapper<?, ?>> mappers() {
List<IgniteExceptionMapper<?, ?>> mappers = new ArrayList<>();
- mappers.add(unchecked(LockException.class, err -> new
TransactionException(err.traceId(), err.code(), err.getMessage(), err)));
- mappers.add(unchecked(ReplicationException.class,
- err -> new TransactionException(err.traceId(), err.code(),
err.getMessage(), err)));
+ mappers.add(unchecked(
+ IncompatibleSchemaVersionException.class,
+ err -> new IncompatibleSchemaException(err.traceId(),
err.code(), err.getMessage(), err)
+ ));
return mappers;
}
diff --git
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replicator/IncompatibleSchemaException.java
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replicator/IncompatibleSchemaVersionException.java
similarity index 76%
rename from
modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replicator/IncompatibleSchemaException.java
rename to
modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replicator/IncompatibleSchemaVersionException.java
index 99f20b5fda..a184b81820 100644
---
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replicator/IncompatibleSchemaException.java
+++
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replicator/IncompatibleSchemaVersionException.java
@@ -18,15 +18,14 @@
package org.apache.ignite.internal.table.distributed.replicator;
import
org.apache.ignite.internal.replicator.exception.ExpectedReplicationException;
+import org.apache.ignite.internal.tx.TransactionInternalException;
import org.apache.ignite.lang.ErrorGroups.Transactions;
-import org.apache.ignite.tx.TransactionException;
/**
* Thrown when, during an attempt to execute a transactional operation, it
turns out that the operation cannot be executed
* because an incompatible schema change has happened.
*/
-// TODO: IGNITE-20415 - make this extend TransactionInternalException.
-public class IncompatibleSchemaException extends TransactionException
implements ExpectedReplicationException {
+public class IncompatibleSchemaVersionException extends
TransactionInternalException implements ExpectedReplicationException {
private static final String SCHEMA_CHANGED_MESSAGE = "Table schema was
updated after the transaction was started "
+ "[table=%s, startSchema=%d, operationSchema=%d]";
@@ -34,7 +33,7 @@ public class IncompatibleSchemaException extends
TransactionException implements
private static final String TABLE_DROPPED_ID_MESSAGE = "Table was dropped
[tableId=%d]";
- public IncompatibleSchemaException(String message) {
+ public IncompatibleSchemaVersionException(String message) {
super(Transactions.TX_INCOMPATIBLE_SCHEMA_ERR, message);
}
@@ -46,8 +45,8 @@ public class IncompatibleSchemaException extends
TransactionException implements
* @param operationSchemaVersion Schema version at the moment of the
operation.
* @return Exception with formatted message.
*/
- public static IncompatibleSchemaException schemaChanged(String tableName,
int startSchemaVersion, int operationSchemaVersion) {
- return new IncompatibleSchemaException(String.format(
+ public static IncompatibleSchemaVersionException schemaChanged(String
tableName, int startSchemaVersion, int operationSchemaVersion) {
+ return new IncompatibleSchemaVersionException(String.format(
SCHEMA_CHANGED_MESSAGE,
tableName, startSchemaVersion, operationSchemaVersion
));
@@ -59,8 +58,8 @@ public class IncompatibleSchemaException extends
TransactionException implements
* @param tableName Name of the table.
* @return Exception with formatted message.
*/
- public static IncompatibleSchemaException tableDropped(String tableName) {
- return new
IncompatibleSchemaException(String.format(TABLE_DROPPED_NAME_MESSAGE,
tableName));
+ public static IncompatibleSchemaVersionException tableDropped(String
tableName) {
+ return new
IncompatibleSchemaVersionException(String.format(TABLE_DROPPED_NAME_MESSAGE,
tableName));
}
/**
@@ -70,7 +69,7 @@ public class IncompatibleSchemaException extends
TransactionException implements
* @return Exception with formatted message.
*/
// TODO https://issues.apache.org/jira/browse/IGNITE-22309 use tableName
instead
- public static IncompatibleSchemaException tableDropped(int tableId) {
- return new
IncompatibleSchemaException(String.format(TABLE_DROPPED_ID_MESSAGE, tableId));
+ public static IncompatibleSchemaVersionException tableDropped(int tableId)
{
+ return new
IncompatibleSchemaVersionException(String.format(TABLE_DROPPED_ID_MESSAGE,
tableId));
}
}
diff --git
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replicator/PartitionReplicaListener.java
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replicator/PartitionReplicaListener.java
index 3e5c67b2f3..3cb1abfbfc 100644
---
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replicator/PartitionReplicaListener.java
+++
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replicator/PartitionReplicaListener.java
@@ -174,11 +174,12 @@ import
org.apache.ignite.internal.table.distributed.raft.UnexpectedTransactionSt
import org.apache.ignite.internal.table.distributed.schema.SchemaSyncService;
import
org.apache.ignite.internal.table.distributed.schema.ValidationSchemasSource;
import org.apache.ignite.internal.tx.HybridTimestampTracker;
+import org.apache.ignite.internal.tx.IncompatibleSchemaAbortException;
import org.apache.ignite.internal.tx.Lock;
import org.apache.ignite.internal.tx.LockKey;
import org.apache.ignite.internal.tx.LockManager;
import org.apache.ignite.internal.tx.LockMode;
-import org.apache.ignite.internal.tx.MismatchingTransactionOutcomeException;
+import
org.apache.ignite.internal.tx.MismatchingTransactionOutcomeInternalException;
import org.apache.ignite.internal.tx.TransactionMeta;
import org.apache.ignite.internal.tx.TransactionResult;
import org.apache.ignite.internal.tx.TxManager;
@@ -1065,7 +1066,7 @@ public class PartitionReplicaListener implements
ReplicaListener {
return schemaCompatValidator.validateBackwards(row.schemaVersion(),
tableId(), txId)
.thenAccept(validationResult -> {
if (!validationResult.isSuccessful()) {
- throw new IncompatibleSchemaException(String.format(
+ throw new
IncompatibleSchemaVersionException(String.format(
"Operation failed because it tried to access a
row with newer schema version than transaction's [table=%s, "
+ "txSchemaVersion=%d,
rowSchemaVersion=%d]",
validationResult.failedTableName(),
validationResult.fromSchemaVersion(), validationResult.toSchemaVersion()
@@ -1660,12 +1661,12 @@ public class PartitionReplicaListener implements
ReplicaListener {
private static void
throwIfSchemaValidationOnCommitFailed(CompatValidationResult validationResult,
TransactionResult txResult) {
if (!validationResult.isSuccessful()) {
if (validationResult.isTableDropped()) {
- throw new MismatchingTransactionOutcomeException(
+ throw new IncompatibleSchemaAbortException(
format("Commit failed because a table was already
dropped [table={}]", validationResult.failedTableName()),
txResult
);
} else {
- throw new MismatchingTransactionOutcomeException(
+ throw new IncompatibleSchemaAbortException(
format(
"Commit failed because schema is not
forward-compatible "
+ "[fromSchemaVersion={},
toSchemaVersion={}, table={}, details={}]",
@@ -1723,7 +1724,7 @@ public class PartitionReplicaListener implements
ReplicaListener {
txMeta.txState()
);
- throw new MismatchingTransactionOutcomeException(
+ throw new MismatchingTransactionOutcomeInternalException(
"Failed to change the outcome of a finished
transaction [txId=" + txId + ", txState=" + txMeta.txState() + "].",
new TransactionResult(txMeta.txState(),
txMeta.commitTimestamp())
);
@@ -1777,7 +1778,7 @@ public class PartitionReplicaListener implements
ReplicaListener {
markFinished(txId, result.transactionState(),
result.commitTimestamp());
- throw new
MismatchingTransactionOutcomeException(utse.getMessage(),
utse.transactionResult());
+ throw new
MismatchingTransactionOutcomeInternalException(utse.getMessage(),
utse.transactionResult());
}
// Otherwise we convert from the internal exception to
the client one.
throw new TransactionException(commit ? TX_COMMIT_ERR
: TX_ROLLBACK_ERR, ex);
diff --git
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replicator/SchemaCompatibilityValidator.java
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replicator/SchemaCompatibilityValidator.java
index 303a2b8d2a..1e31b33c86 100644
---
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replicator/SchemaCompatibilityValidator.java
+++
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replicator/SchemaCompatibilityValidator.java
@@ -246,11 +246,11 @@ class SchemaCompatibilityValidator {
assert tableAtBeginTs != null;
if (tableAtOpTs == null) {
- throw
IncompatibleSchemaException.tableDropped(tableAtBeginTs.name());
+ throw
IncompatibleSchemaVersionException.tableDropped(tableAtBeginTs.name());
}
if (tableAtOpTs.tableVersion() != tableAtBeginTs.tableVersion()) {
- throw IncompatibleSchemaException.schemaChanged(
+ throw IncompatibleSchemaVersionException.schemaChanged(
tableAtBeginTs.name(),
tableAtBeginTs.tableVersion(),
tableAtOpTs.tableVersion()
@@ -262,7 +262,7 @@ class SchemaCompatibilityValidator {
CatalogTableDescriptor tableAtOpTs = catalogService.table(tableId,
operationTimestamp.longValue());
if (tableAtOpTs == null) {
- throw IncompatibleSchemaException.tableDropped(tableId);
+ throw IncompatibleSchemaVersionException.tableDropped(tableId);
}
}
diff --git
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replicator/StaleTransactionOperationException.java
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replicator/StaleTransactionOperationException.java
index 1dab412af1..76983328e0 100644
---
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replicator/StaleTransactionOperationException.java
+++
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replicator/StaleTransactionOperationException.java
@@ -24,7 +24,7 @@ import java.util.UUID;
import org.apache.ignite.internal.tx.TransactionInternalException;
/** Error that occurs when a stale operation of a completed transaction is
detected. */
-// TODO: IGNITE-20415 - make this exception public.
+// TODO: IGNITE-22748 - make this exception public?
public class StaleTransactionOperationException extends
TransactionInternalException {
/**
* Constructor.
diff --git
a/modules/table/src/test/java/org/apache/ignite/internal/table/TableExceptionMapperProviderTest.java
b/modules/table/src/test/java/org/apache/ignite/internal/table/TableExceptionMapperProviderTest.java
new file mode 100644
index 0000000000..5dd462995b
--- /dev/null
+++
b/modules/table/src/test/java/org/apache/ignite/internal/table/TableExceptionMapperProviderTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.table;
+
+import static java.util.stream.Collectors.toList;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+
+import java.util.Collection;
+import java.util.List;
+import org.apache.ignite.internal.lang.IgniteExceptionMapper;
+import
org.apache.ignite.internal.table.distributed.replicator.IncompatibleSchemaVersionException;
+import org.apache.ignite.tx.IncompatibleSchemaException;
+import org.junit.jupiter.api.Test;
+
+class TableExceptionMapperProviderTest {
+ private final TableExceptionMapperProvider provider = new
TableExceptionMapperProvider();
+
+ @Test
+ void translatesIncompatibleSchemaVersionException() {
+ Collection<IgniteExceptionMapper<?, ?>> mappers = provider.mappers();
+
+ List<IgniteExceptionMapper<?, ?>> matchingMappers = mappers.stream()
+ .filter(mapper ->
IncompatibleSchemaVersionException.class.equals(mapper.mappingFrom()))
+ .collect(toList());
+
+ assertThat(matchingMappers, hasSize(1));
+
+ var mapper =
(IgniteExceptionMapper<IncompatibleSchemaVersionException,
IncompatibleSchemaException>) matchingMappers.get(0);
+
+ IncompatibleSchemaVersionException originalException = new
IncompatibleSchemaVersionException("Oops");
+ IncompatibleSchemaException translationResult =
mapper.map(originalException);
+
+ assertThat(translationResult.traceId(),
is(originalException.traceId()));
+ assertThat(translationResult.code(), is(originalException.code()));
+ assertThat(translationResult.getMessage(),
is(originalException.getMessage()));
+ }
+}
diff --git
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/PartitionReplicaListenerTest.java
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/PartitionReplicaListenerTest.java
index 2d1cd8018c..89ea604cd5 100644
---
a/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/PartitionReplicaListenerTest.java
+++
b/modules/table/src/test/java/org/apache/ignite/internal/table/distributed/replication/PartitionReplicaListenerTest.java
@@ -191,7 +191,7 @@ import
org.apache.ignite.internal.table.distributed.index.IndexUpdateHandler;
import org.apache.ignite.internal.table.distributed.index.MetaIndexStatus;
import
org.apache.ignite.internal.table.distributed.index.MetaIndexStatusChange;
import org.apache.ignite.internal.table.distributed.raft.PartitionDataStorage;
-import
org.apache.ignite.internal.table.distributed.replicator.IncompatibleSchemaException;
+import
org.apache.ignite.internal.table.distributed.replicator.IncompatibleSchemaVersionException;
import
org.apache.ignite.internal.table.distributed.replicator.InternalSchemaVersionMismatchException;
import
org.apache.ignite.internal.table.distributed.replicator.PartitionReplicaListener;
import
org.apache.ignite.internal.table.distributed.replicator.StaleTransactionOperationException;
@@ -205,8 +205,8 @@ import
org.apache.ignite.internal.table.impl.DummySchemaManagerImpl;
import org.apache.ignite.internal.testframework.IgniteAbstractTest;
import org.apache.ignite.internal.tostring.IgniteToStringInclude;
import org.apache.ignite.internal.tostring.S;
+import org.apache.ignite.internal.tx.IncompatibleSchemaAbortException;
import org.apache.ignite.internal.tx.LockManager;
-import org.apache.ignite.internal.tx.MismatchingTransactionOutcomeException;
import org.apache.ignite.internal.tx.TransactionMeta;
import org.apache.ignite.internal.tx.TransactionResult;
import org.apache.ignite.internal.tx.TxManager;
@@ -1809,8 +1809,7 @@ public class PartitionReplicaListenerTest extends
IgniteAbstractTest {
CompletableFuture<?> future = beginAndCommitTx();
- MismatchingTransactionOutcomeException ex = assertWillThrowFast(future,
- MismatchingTransactionOutcomeException.class);
+ IncompatibleSchemaAbortException ex = assertWillThrowFast(future,
IncompatibleSchemaAbortException.class);
assertThat(ex.getMessage(), containsString("Commit failed because
schema is not forward-compatible [fromSchemaVersion=1, "
+ "toSchemaVersion=2, table=test, details=Column default value
changed]"));
@@ -1902,8 +1901,8 @@ public class PartitionReplicaListenerTest extends
IgniteAbstractTest {
CompletableFuture<?> future,
AtomicReference<Boolean> committed
) {
- IncompatibleSchemaException ex = assertWillThrowFast(future,
- IncompatibleSchemaException.class);
+ IncompatibleSchemaVersionException ex = assertWillThrowFast(future,
+ IncompatibleSchemaVersionException.class);
assertThat(ex.code(), is(Transactions.TX_INCOMPATIBLE_SCHEMA_ERR));
assertThat(ex.getMessage(), containsString(
"Operation failed because it tried to access a row with newer
schema version than transaction's [table=test, "
@@ -2240,7 +2239,7 @@ public class PartitionReplicaListenerTest extends
IgniteAbstractTest {
}
if (expectValidationFailure) {
- IncompatibleSchemaException ex = assertWillThrowFast(future,
IncompatibleSchemaException.class);
+ IncompatibleSchemaVersionException ex =
assertWillThrowFast(future, IncompatibleSchemaVersionException.class);
assertThat(ex.code(), is(Transactions.TX_INCOMPATIBLE_SCHEMA_ERR));
assertThat(
ex.getMessage(),
@@ -2360,7 +2359,7 @@ public class PartitionReplicaListenerTest extends
IgniteAbstractTest {
CompletableFuture<?> future = listenerInvocation.invoke(txId, key);
- IncompatibleSchemaException ex = assertWillThrowFast(future,
IncompatibleSchemaException.class);
+ IncompatibleSchemaVersionException ex = assertWillThrowFast(future,
IncompatibleSchemaVersionException.class);
assertThat(ex.code(), is(Transactions.TX_INCOMPATIBLE_SCHEMA_ERR));
assertThat(ex.getMessage(), is("Table was dropped [tableId=1]"));
}
@@ -2458,7 +2457,7 @@ public class PartitionReplicaListenerTest extends
IgniteAbstractTest {
CompletableFuture<?> future = listenerInvocation.invoke(txId, readTs,
key);
- IncompatibleSchemaException ex = assertWillThrowFast(future,
IncompatibleSchemaException.class);
+ IncompatibleSchemaVersionException ex = assertWillThrowFast(future,
IncompatibleSchemaVersionException.class);
assertThat(ex.code(), is(Transactions.TX_INCOMPATIBLE_SCHEMA_ERR));
assertThat(ex.getMessage(), is("Table was dropped [tableId=1]"));
}
@@ -2529,7 +2528,7 @@ public class PartitionReplicaListenerTest extends
IgniteAbstractTest {
localNode.id()
);
- MismatchingTransactionOutcomeException ex =
assertWillThrowFast(future, MismatchingTransactionOutcomeException.class);
+ IncompatibleSchemaAbortException ex = assertWillThrowFast(future,
IncompatibleSchemaAbortException.class);
assertThat(ex.getMessage(), is("Commit failed because a table was
already dropped [table=" + tableNameToBeDropped + "]"));
diff --git
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replicator/StaleTransactionOperationException.java
b/modules/transactions/src/main/java/org/apache/ignite/internal/tx/IncompatibleSchemaAbortException.java
similarity index 50%
copy from
modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replicator/StaleTransactionOperationException.java
copy to
modules/transactions/src/main/java/org/apache/ignite/internal/tx/IncompatibleSchemaAbortException.java
index 1dab412af1..e63d0409c1 100644
---
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replicator/StaleTransactionOperationException.java
+++
b/modules/transactions/src/main/java/org/apache/ignite/internal/tx/IncompatibleSchemaAbortException.java
@@ -15,23 +15,16 @@
* limitations under the License.
*/
-package org.apache.ignite.internal.table.distributed.replicator;
+package org.apache.ignite.internal.tx;
-import static org.apache.ignite.internal.lang.IgniteStringFormatter.format;
-import static
org.apache.ignite.lang.ErrorGroups.Transactions.TX_STALE_OPERATION_ERR;
+import org.apache.ignite.lang.ErrorGroups.Transactions;
-import java.util.UUID;
-import org.apache.ignite.internal.tx.TransactionInternalException;
-
-/** Error that occurs when a stale operation of a completed transaction is
detected. */
-// TODO: IGNITE-20415 - make this exception public.
-public class StaleTransactionOperationException extends
TransactionInternalException {
- /**
- * Constructor.
- *
- * @param txId Transaction ID.
- */
- public StaleTransactionOperationException(UUID txId) {
- super(TX_STALE_OPERATION_ERR, format("Stale operation of a completed
transaction was detected: [txId={}]", txId));
+/**
+ * Thrown when a commit attempt fails due to incompatible schema change (that
is, the transaction was started on some schema
+ * V1, but at the commit timestamp another schema V2 is effective, and it's
not forward-compatible with V1).
+ */
+public class IncompatibleSchemaAbortException extends
MismatchingTransactionOutcomeInternalException {
+ public IncompatibleSchemaAbortException(String message, TransactionResult
transactionResult) {
+ super(Transactions.TX_INCOMPATIBLE_SCHEMA_ERR, message,
transactionResult, null);
}
}
diff --git
a/modules/transactions/src/main/java/org/apache/ignite/internal/tx/MismatchingTransactionOutcomeException.java
b/modules/transactions/src/main/java/org/apache/ignite/internal/tx/MismatchingTransactionOutcomeInternalException.java
similarity index 79%
rename from
modules/transactions/src/main/java/org/apache/ignite/internal/tx/MismatchingTransactionOutcomeException.java
rename to
modules/transactions/src/main/java/org/apache/ignite/internal/tx/MismatchingTransactionOutcomeInternalException.java
index 6fc15f87c7..6fd3c73a39 100644
---
a/modules/transactions/src/main/java/org/apache/ignite/internal/tx/MismatchingTransactionOutcomeException.java
+++
b/modules/transactions/src/main/java/org/apache/ignite/internal/tx/MismatchingTransactionOutcomeInternalException.java
@@ -19,14 +19,15 @@ package org.apache.ignite.internal.tx;
import static
org.apache.ignite.lang.ErrorGroups.Transactions.TX_UNEXPECTED_STATE_ERR;
+import org.jetbrains.annotations.Nullable;
+
/**
* The exception is thrown when the transaction result differs from the
intended one.
*
* <p>For example, {@code tx.commit()} is called for a transaction, but the
verification logic decided to abort it instead. The transaction
* will be finished with {@link TxState#ABORTED} and the call to {@code
tx.commit()} will throw this exception.
*/
-// TODO: IGNITE-20415 - split this into public exception (in a public package)
and internal exception (carrying internal state).
-public class MismatchingTransactionOutcomeException extends
TransactionInternalException {
+public class MismatchingTransactionOutcomeInternalException extends
TransactionInternalException {
private static final long serialVersionUID = -7953057695915339651L;
@@ -36,13 +37,18 @@ public class MismatchingTransactionOutcomeException extends
TransactionInternalE
/**
* Constructor.
*/
- public MismatchingTransactionOutcomeException(int errorCode, String
message, TransactionResult transactionResult, Throwable cause) {
+ public MismatchingTransactionOutcomeInternalException(
+ int errorCode,
+ String message,
+ TransactionResult transactionResult,
+ @Nullable Throwable cause
+ ) {
super(errorCode, message, cause);
this.transactionResult = transactionResult;
}
- public MismatchingTransactionOutcomeException(String message,
TransactionResult transactionResult) {
+ public MismatchingTransactionOutcomeInternalException(String message,
TransactionResult transactionResult) {
this(TX_UNEXPECTED_STATE_ERR, message, transactionResult, null);
}
diff --git
a/modules/transactions/src/main/java/org/apache/ignite/internal/tx/TransactionExceptionMapperProvider.java
b/modules/transactions/src/main/java/org/apache/ignite/internal/tx/TransactionExceptionMapperProvider.java
index 7c0dc5c40c..35af89caa0 100644
---
a/modules/transactions/src/main/java/org/apache/ignite/internal/tx/TransactionExceptionMapperProvider.java
+++
b/modules/transactions/src/main/java/org/apache/ignite/internal/tx/TransactionExceptionMapperProvider.java
@@ -26,6 +26,8 @@ import java.util.List;
import org.apache.ignite.internal.lang.IgniteExceptionMapper;
import org.apache.ignite.internal.lang.IgniteExceptionMappersProvider;
import org.apache.ignite.internal.replicator.exception.ReplicationException;
+import org.apache.ignite.tx.IncompatibleSchemaException;
+import org.apache.ignite.tx.MismatchingTransactionOutcomeException;
import org.apache.ignite.tx.TransactionException;
/**
@@ -40,6 +42,10 @@ public class TransactionExceptionMapperProvider implements
IgniteExceptionMapper
mappers.add(unchecked(LockException.class, err -> new
TransactionException(err.traceId(), err.code(), err.getMessage(), err)));
mappers.add(unchecked(ReplicationException.class,
err -> new TransactionException(err.traceId(), err.code(),
err.getMessage(), err)));
+
mappers.add(unchecked(MismatchingTransactionOutcomeInternalException.class,
+ err -> new
MismatchingTransactionOutcomeException(err.traceId(), err.code(),
err.getMessage(), err)));
+ mappers.add(unchecked(IncompatibleSchemaAbortException.class,
+ err -> new IncompatibleSchemaException(err.traceId(),
err.code(), err.getMessage(), err)));
return mappers;
}
diff --git
a/modules/transactions/src/main/java/org/apache/ignite/internal/tx/impl/TransactionInflights.java
b/modules/transactions/src/main/java/org/apache/ignite/internal/tx/impl/TransactionInflights.java
index 58fa141a32..cd6f09c75e 100644
---
a/modules/transactions/src/main/java/org/apache/ignite/internal/tx/impl/TransactionInflights.java
+++
b/modules/transactions/src/main/java/org/apache/ignite/internal/tx/impl/TransactionInflights.java
@@ -38,7 +38,7 @@ import org.apache.ignite.internal.hlc.HybridTimestamp;
import org.apache.ignite.internal.lang.IgniteBiTuple;
import org.apache.ignite.internal.placementdriver.PlacementDriver;
import org.apache.ignite.internal.replicator.TablePartitionId;
-import org.apache.ignite.internal.tx.MismatchingTransactionOutcomeException;
+import
org.apache.ignite.internal.tx.MismatchingTransactionOutcomeInternalException;
import org.apache.ignite.internal.tx.TransactionResult;
import org.apache.ignite.internal.tx.message.FinishedTransactionsBatchMessage;
import org.apache.ignite.network.ClusterNode;
@@ -266,7 +266,7 @@ public class TransactionInflights {
Throwable unwrappedReadyToFinishException =
unwrapCause(readyToFinishException);
if (commit && unwrappedReadyToFinishException instanceof
PrimaryReplicaExpiredException) {
- finishInProgressFuture.completeExceptionally(new
MismatchingTransactionOutcomeException(
+ finishInProgressFuture.completeExceptionally(new
MismatchingTransactionOutcomeInternalException(
TX_PRIMARY_REPLICA_EXPIRED_ERR,
"Failed to commit the transaction.",
new TransactionResult(ABORTED, null),
diff --git
a/modules/transactions/src/main/java/org/apache/ignite/internal/tx/impl/TxManagerImpl.java
b/modules/transactions/src/main/java/org/apache/ignite/internal/tx/impl/TxManagerImpl.java
index fa416eeb62..542952d0a6 100644
---
a/modules/transactions/src/main/java/org/apache/ignite/internal/tx/impl/TxManagerImpl.java
+++
b/modules/transactions/src/main/java/org/apache/ignite/internal/tx/impl/TxManagerImpl.java
@@ -94,7 +94,7 @@ import org.apache.ignite.internal.tx.HybridTimestampTracker;
import org.apache.ignite.internal.tx.InternalTransaction;
import org.apache.ignite.internal.tx.LocalRwTxCounter;
import org.apache.ignite.internal.tx.LockManager;
-import org.apache.ignite.internal.tx.MismatchingTransactionOutcomeException;
+import
org.apache.ignite.internal.tx.MismatchingTransactionOutcomeInternalException;
import org.apache.ignite.internal.tx.TransactionMeta;
import org.apache.ignite.internal.tx.TransactionResult;
import org.apache.ignite.internal.tx.TxManager;
@@ -566,7 +566,7 @@ public class TxManagerImpl implements TxManager,
NetworkMessageHandler {
return nullCompletedFuture();
}
- return failedFuture(new MismatchingTransactionOutcomeException(
+ return failedFuture(new MismatchingTransactionOutcomeInternalException(
"Failed to change the outcome of a finished transaction
[txId=" + txId + ", txState=" + stateMeta.txState() + "].",
new TransactionResult(stateMeta.txState(),
stateMeta.commitTimestamp()))
);
@@ -640,8 +640,9 @@ public class TxManagerImpl implements TxManager,
NetworkMessageHandler {
if (ex != null) {
Throwable cause = ExceptionUtils.unwrapCause(ex);
- if (cause instanceof
MismatchingTransactionOutcomeException) {
- MismatchingTransactionOutcomeException
transactionException = (MismatchingTransactionOutcomeException) cause;
+ if (cause instanceof
MismatchingTransactionOutcomeInternalException) {
+ MismatchingTransactionOutcomeInternalException
transactionException =
+
(MismatchingTransactionOutcomeInternalException) cause;
TransactionResult result =
transactionException.transactionResult();
@@ -740,7 +741,7 @@ public class TxManagerImpl implements TxManager,
NetworkMessageHandler {
txResult.transactionState()
);
- throw new MismatchingTransactionOutcomeException(
+ throw new MismatchingTransactionOutcomeInternalException(
"Failed to change the outcome of a finished transaction
[txId=" + txId + ", txState=" + txResult.transactionState()
+ "].",
txResult
diff --git
a/modules/transactions/src/test/java/org/apache/ignite/internal/tx/TxManagerTest.java
b/modules/transactions/src/test/java/org/apache/ignite/internal/tx/TxManagerTest.java
index 11d25032e7..4a164e3eb9 100644
---
a/modules/transactions/src/test/java/org/apache/ignite/internal/tx/TxManagerTest.java
+++
b/modules/transactions/src/test/java/org/apache/ignite/internal/tx/TxManagerTest.java
@@ -31,6 +31,7 @@ import static
org.apache.ignite.lang.ErrorGroups.Transactions.TX_PRIMARY_REPLICA
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -76,7 +77,6 @@ import org.apache.ignite.internal.replicator.ReplicaService;
import org.apache.ignite.internal.replicator.TablePartitionId;
import
org.apache.ignite.internal.replicator.exception.PrimaryReplicaMissException;
import org.apache.ignite.internal.testframework.IgniteAbstractTest;
-import org.apache.ignite.internal.testframework.IgniteTestUtils;
import org.apache.ignite.internal.tx.configuration.TransactionConfiguration;
import org.apache.ignite.internal.tx.impl.HeapLockManager;
import org.apache.ignite.internal.tx.impl.PrimaryReplicaExpiredException;
@@ -90,6 +90,7 @@ import org.apache.ignite.internal.tx.test.TestTransactionIds;
import org.apache.ignite.lang.ErrorGroups.Transactions;
import org.apache.ignite.network.ClusterNode;
import org.apache.ignite.network.NetworkAddress;
+import org.apache.ignite.tx.MismatchingTransactionOutcomeException;
import org.apache.ignite.tx.TransactionException;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.AfterEach;
@@ -327,7 +328,7 @@ public class TxManagerTest extends IgniteAbstractTest {
when(replicaService.invoke(anyString(),
any(TxFinishReplicaRequest.class)))
.thenReturn(failedFuture(
- new MismatchingTransactionOutcomeException(
+ new MismatchingTransactionOutcomeInternalException(
"Test exception",
new TransactionResult(TxState.ABORTED, null
)
@@ -342,7 +343,7 @@ public class TxManagerTest extends IgniteAbstractTest {
TransactionException transactionException =
assertThrows(TransactionException.class, tx::commit);
- assertTrue(IgniteTestUtils.hasCause(transactionException,
MismatchingTransactionOutcomeException.class, null));
+ assertInstanceOf(MismatchingTransactionOutcomeException.class,
transactionException);
tx.commitAsync().get(3, TimeUnit.SECONDS);
tx.rollbackAsync().get(3, TimeUnit.SECONDS);
@@ -355,7 +356,7 @@ public class TxManagerTest extends IgniteAbstractTest {
when(replicaService.invoke(anyString(),
any(TxFinishReplicaRequest.class)))
.thenReturn(failedFuture(
- new MismatchingTransactionOutcomeException(
+ new MismatchingTransactionOutcomeInternalException(
"Test exception",
new TransactionResult(TxState.ABORTED, null
)
@@ -370,7 +371,7 @@ public class TxManagerTest extends IgniteAbstractTest {
TransactionException transactionException =
assertThrows(TransactionException.class, tx::rollback);
- assertTrue(IgniteTestUtils.hasCause(transactionException,
MismatchingTransactionOutcomeException.class, null));
+ assertInstanceOf(MismatchingTransactionOutcomeException.class,
transactionException);
tx.commitAsync().get(3, TimeUnit.SECONDS);
tx.rollbackAsync().get(3, TimeUnit.SECONDS);
@@ -582,7 +583,7 @@ public class TxManagerTest extends IgniteAbstractTest {
when(placementDriver.awaitPrimaryReplica(any(), any(), anyLong(),
any())).thenReturn(completedFuture(
new TestReplicaMetaImpl(LOCAL_NODE, hybridTimestamp(1),
hybridTimestamp(10))));
when(replicaService.invoke(anyString(),
any(TxFinishReplicaRequest.class)))
- .thenReturn(failedFuture(new
MismatchingTransactionOutcomeException(
+ .thenReturn(failedFuture(new
MismatchingTransactionOutcomeInternalException(
"TX already finished.",
new TransactionResult(TxState.ABORTED, null)
)));