You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by pt...@apache.org on 2023/12/19 09:23:04 UTC

(ignite-3) branch main updated: IGNITE-20598 Java client: Fix incorrect error for query on closed transaction (#2972)

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

ptupitsyn 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 c6d00df24f IGNITE-20598 Java client: Fix incorrect error for query on closed transaction (#2972)
c6d00df24f is described below

commit c6d00df24f0385590de7c0ffd149ac73c0d26028
Author: Pavel Tupitsyn <pt...@apache.org>
AuthorDate: Tue Dec 19 11:22:58 2023 +0200

    IGNITE-20598 Java client: Fix incorrect error for query on closed transaction (#2972)
    
    * Add local tx state check - disallow using finished tx
    * Wrap all `ClientSession` exceptions in `SqlException` (match embedded API behavior)
    
    Also fixes [IGNITE-20742 Thin client cannot find the resource when it is trying to execute an operation on the finalized transaction](https://issues.apache.org/jira/browse/IGNITE-20742)
---
 .../ignite/internal/client/sql/ClientSession.java  | 10 ++++--
 .../internal/client/tx/ClientTransaction.java      | 38 +++++++++++++++++++++-
 .../sql/api/ItSqlClientAsynchronousApiTest.java    | 12 -------
 .../sql/api/ItSqlClientSynchronousApiTest.java     | 12 -------
 4 files changed, 45 insertions(+), 27 deletions(-)

diff --git a/modules/client/src/main/java/org/apache/ignite/internal/client/sql/ClientSession.java b/modules/client/src/main/java/org/apache/ignite/internal/client/sql/ClientSession.java
index 59e242baac..5d6e739683 100644
--- a/modules/client/src/main/java/org/apache/ignite/internal/client/sql/ClientSession.java
+++ b/modules/client/src/main/java/org/apache/ignite/internal/client/sql/ClientSession.java
@@ -37,12 +37,14 @@ import org.apache.ignite.internal.client.proto.ClientOp;
 import org.apache.ignite.internal.client.tx.ClientTransaction;
 import org.apache.ignite.internal.sql.AbstractSession;
 import org.apache.ignite.sql.BatchedArguments;
+import org.apache.ignite.sql.SqlException;
 import org.apache.ignite.sql.SqlRow;
 import org.apache.ignite.sql.Statement;
 import org.apache.ignite.sql.async.AsyncResultSet;
 import org.apache.ignite.sql.reactive.ReactiveResultSet;
 import org.apache.ignite.table.mapper.Mapper;
 import org.apache.ignite.tx.Transaction;
+import org.apache.ignite.tx.TransactionException;
 import org.jetbrains.annotations.Nullable;
 
 /**
@@ -166,8 +168,12 @@ public class ClientSession implements AbstractSession {
         PayloadReader<AsyncResultSet<T>> payloadReader = r -> new ClientAsyncResultSet<>(r.clientChannel(), r.in(), mapper);
 
         if (transaction != null) {
-            //noinspection resource
-            return ClientTransaction.get(transaction).channel().serviceAsync(ClientOp.SQL_EXEC, payloadWriter, payloadReader);
+            try {
+                //noinspection resource
+                return ClientTransaction.get(transaction).channel().serviceAsync(ClientOp.SQL_EXEC, payloadWriter, payloadReader);
+            } catch (TransactionException e) {
+                return CompletableFuture.failedFuture(new SqlException(e.traceId(), e.code(), e.getMessage(), e));
+            }
         }
 
         return ch.serviceAsync(ClientOp.SQL_EXEC, payloadWriter, payloadReader);
diff --git a/modules/client/src/main/java/org/apache/ignite/internal/client/tx/ClientTransaction.java b/modules/client/src/main/java/org/apache/ignite/internal/client/tx/ClientTransaction.java
index 57bbcb2793..ecfe99694f 100644
--- a/modules/client/src/main/java/org/apache/ignite/internal/client/tx/ClientTransaction.java
+++ b/modules/client/src/main/java/org/apache/ignite/internal/client/tx/ClientTransaction.java
@@ -18,9 +18,12 @@
 package org.apache.ignite.internal.client.tx;
 
 import static org.apache.ignite.internal.client.ClientUtils.sync;
+import static org.apache.ignite.internal.lang.IgniteStringFormatter.format;
 import static org.apache.ignite.lang.ErrorGroups.Common.INTERNAL_ERR;
+import static org.apache.ignite.lang.ErrorGroups.Transactions.TX_FAILED_READ_WRITE_OPERATION_ERR;
 
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 import org.apache.ignite.internal.client.ClientChannel;
 import org.apache.ignite.internal.client.proto.ClientOp;
@@ -32,6 +35,15 @@ import org.apache.ignite.tx.TransactionException;
  * Client transaction.
  */
 public class ClientTransaction implements Transaction {
+    /** Open state. */
+    private static final int STATE_OPEN = 0;
+
+    /** Committed state. */
+    private static final int STATE_COMMITTED = 1;
+
+    /** Rolled back state. */
+    private static final int STATE_ROLLED_BACK = 2;
+
     /** Channel that the transaction belongs to. */
     private final ClientChannel ch;
 
@@ -41,6 +53,9 @@ public class ClientTransaction implements Transaction {
     /** The future used on repeated commit/rollback. */
     private final AtomicReference<CompletableFuture<Void>> finishFut = new AtomicReference<>();
 
+    /** State. */
+    private final AtomicInteger state = new AtomicInteger(STATE_OPEN);
+
     /** Read-only flag. */
     private final boolean isReadOnly;
 
@@ -87,6 +102,8 @@ public class ClientTransaction implements Transaction {
             return finishFut.get();
         }
 
+        setState(STATE_COMMITTED);
+
         CompletableFuture<Void> mainFinishFut = ch.serviceAsync(ClientOp.TX_COMMIT, w -> w.out().packLong(id), r -> null);
 
         mainFinishFut.handle((res, e) -> finishFut.get().complete(null));
@@ -107,6 +124,8 @@ public class ClientTransaction implements Transaction {
             return finishFut.get();
         }
 
+        setState(STATE_ROLLED_BACK);
+
         CompletableFuture<Void> mainFinishFut = ch.serviceAsync(ClientOp.TX_ROLLBACK, w -> w.out().packLong(id), r -> null);
 
         mainFinishFut.handle((res, e) -> finishFut.get().complete(null));
@@ -134,6 +153,23 @@ public class ClientTransaction implements Transaction {
                     + "'. Use IgniteClient.transactions() to start transactions.");
         }
 
-        return (ClientTransaction) tx;
+        ClientTransaction clientTx = (ClientTransaction) tx;
+
+        int state = clientTx.state.get();
+
+        if (state == STATE_OPEN) {
+            return clientTx;
+        }
+
+        // Match org.apache.ignite.internal.tx.TxState enum:
+        String stateStr = state == STATE_COMMITTED ? "COMMITTED" : "ABORTED";
+
+        throw new TransactionException(
+                TX_FAILED_READ_WRITE_OPERATION_ERR,
+                format("Transaction is already finished [id={}, state={}].", clientTx.id, stateStr));
+    }
+
+    private void setState(int state) {
+        this.state.compareAndExchange(STATE_OPEN, state);
     }
 }
diff --git a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlClientAsynchronousApiTest.java b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlClientAsynchronousApiTest.java
index 2b2e174fd3..601fd00d57 100644
--- a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlClientAsynchronousApiTest.java
+++ b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlClientAsynchronousApiTest.java
@@ -56,16 +56,4 @@ public class ItSqlClientAsynchronousApiTest extends ItSqlAsynchronousApiTest {
     public void closeSession() {
         super.closeSession();
     }
-
-    @Override
-    @Disabled("https://issues.apache.org/jira/browse/IGNITE-20598")
-    public void checkTransactionsWithDml() {
-        super.checkTransactionsWithDml();
-    }
-
-    @Override
-    @Disabled("https://issues.apache.org/jira/browse/IGNITE-20742")
-    public void testLockIsNotReleasedAfterTxRollback() {
-        super.testLockIsNotReleasedAfterTxRollback();
-    }
 }
diff --git a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlClientSynchronousApiTest.java b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlClientSynchronousApiTest.java
index fa48bff50f..b359975153 100644
--- a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlClientSynchronousApiTest.java
+++ b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/api/ItSqlClientSynchronousApiTest.java
@@ -56,16 +56,4 @@ public class ItSqlClientSynchronousApiTest extends ItSqlSynchronousApiTest {
     public void closeSession() {
         super.closeSession();
     }
-
-    @Override
-    @Disabled("https://issues.apache.org/jira/browse/IGNITE-20598")
-    public void checkTransactionsWithDml() {
-        super.checkTransactionsWithDml();
-    }
-
-    @Override
-    @Disabled("https://issues.apache.org/jira/browse/IGNITE-20742")
-    public void testLockIsNotReleasedAfterTxRollback() {
-        super.testLockIsNotReleasedAfterTxRollback();
-    }
 }