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 7a1540365d IGNITE-20644 Java thin: Fix error detection in 
doSchemaOutInOpAsync (#2739)
7a1540365d is described below

commit 7a1540365d89d188da1f0d22c27c96ddc21485ac
Author: Pavel Tupitsyn <[email protected]>
AuthorDate: Tue Oct 24 11:35:51 2023 +0300

    IGNITE-20644 Java thin: Fix error detection in doSchemaOutInOpAsync (#2739)
    
    Fix well-known error detection in `ClientTable` when 
`sendServerExceptionStackTraceToClient` is enabled: `unwrapRootCause` did not 
work, the important exception can be on any level.
---
 .../ignite/internal/client/table/ClientTable.java  | 72 ++++++++++++----------
 .../ignite/internal/util/ExceptionUtils.java       | 16 -----
 .../Table/SchemaSynchronizationTest.cs             |  2 -
 .../ItThinClientSchemaSynchronizationTest.java     | 11 ++--
 .../schema/marshaller/KvMarshallerTest.java        |  9 ++-
 5 files changed, 52 insertions(+), 58 deletions(-)

diff --git 
a/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientTable.java
 
b/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientTable.java
index e0cf936128..3c31d1a3a5 100644
--- 
a/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientTable.java
+++ 
b/modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientTable.java
@@ -42,7 +42,6 @@ import org.apache.ignite.internal.lang.IgniteBiTuple;
 import org.apache.ignite.internal.logger.IgniteLogger;
 import org.apache.ignite.internal.marshaller.UnmappedColumnsException;
 import org.apache.ignite.internal.tostring.IgniteToStringBuilder;
-import org.apache.ignite.internal.util.ExceptionUtils;
 import org.apache.ignite.lang.IgniteException;
 import org.apache.ignite.table.KeyValueView;
 import org.apache.ignite.table.RecordView;
@@ -408,38 +407,47 @@ public class ClientTable implements Table {
                         return;
                     }
 
-                    // Retry schema errors.
-                    Throwable cause = ExceptionUtils.unwrapRootCause(err);
-                    if (cause instanceof ClientSchemaVersionMismatchException) 
{
-                        // Retry with specific schema version.
-                        int expectedVersion = 
((ClientSchemaVersionMismatchException) cause).expectedVersion();
-
-                        doSchemaOutInOpAsync(opCode, writer, reader, 
defaultValue, responseSchemaRequired, provider, retryPolicyOverride,
-                                expectedVersion)
-                                .whenComplete((res0, err0) -> {
-                                    if (err0 != null) {
-                                        fut.completeExceptionally(err0);
-                                    } else {
-                                        fut.complete(res0);
-                                    }
-                                });
-                    } else if (schemaVersionOverride == null && cause 
instanceof UnmappedColumnsException) {
-                        // Force load latest schema and revalidate user data 
against it.
-                        // When schemaVersionOverride is not null, we already 
tried to load the schema.
-                        schemas.remove(UNKNOWN_SCHEMA_VERSION);
-
-                        doSchemaOutInOpAsync(opCode, writer, reader, 
defaultValue, responseSchemaRequired, provider, retryPolicyOverride,
-                                UNKNOWN_SCHEMA_VERSION)
-                                .whenComplete((res0, err0) -> {
-                                    if (err0 != null) {
-                                        fut.completeExceptionally(err0);
-                                    } else {
-                                        fut.complete(res0);
-                                    }
-                                });
-                    } else {
-                        fut.completeExceptionally(err);
+                    // Retry schema errors, if any.
+                    Throwable cause = err;
+
+                    while (cause != null) {
+                        if (cause instanceof 
ClientSchemaVersionMismatchException) {
+                            // Retry with specific schema version.
+                            int expectedVersion = 
((ClientSchemaVersionMismatchException) cause).expectedVersion();
+
+                            doSchemaOutInOpAsync(opCode, writer, reader, 
defaultValue, responseSchemaRequired, provider,
+                                    retryPolicyOverride, expectedVersion)
+                                    .whenComplete((res0, err0) -> {
+                                        if (err0 != null) {
+                                            fut.completeExceptionally(err0);
+                                        } else {
+                                            fut.complete(res0);
+                                        }
+                                    });
+
+                            return;
+                        } else if (schemaVersionOverride == null && cause 
instanceof UnmappedColumnsException) {
+                            // Force load latest schema and revalidate user 
data against it.
+                            // When schemaVersionOverride is not null, we 
already tried to load the schema.
+                            schemas.remove(UNKNOWN_SCHEMA_VERSION);
+
+                            doSchemaOutInOpAsync(opCode, writer, reader, 
defaultValue, responseSchemaRequired, provider,
+                                    retryPolicyOverride, 
UNKNOWN_SCHEMA_VERSION)
+                                    .whenComplete((res0, err0) -> {
+                                        if (err0 != null) {
+                                            fut.completeExceptionally(err0);
+                                        } else {
+                                            fut.complete(res0);
+                                        }
+                                    });
+
+                            return;
+                        }
+
+                        cause = cause.getCause();
                     }
+
+                    fut.completeExceptionally(err);
                 });
 
         return fut;
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/util/ExceptionUtils.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/util/ExceptionUtils.java
index 4182f17f7f..acef8dc60c 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/util/ExceptionUtils.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/util/ExceptionUtils.java
@@ -346,22 +346,6 @@ public final class ExceptionUtils {
         return e;
     }
 
-    /**
-     * Unwraps the root cause of the provided {@code err}.
-     *
-     * @param e Throwable.
-     * @return Root cause.
-     */
-    public static <T extends Throwable> T unwrapRootCause(Throwable e) {
-        var cause = e;
-
-        while (cause.getCause() != null) {
-            cause = cause.getCause();
-        }
-
-        return (T) cause;
-    }
-
     /**
      * Creates a new exception, which type is defined by the provided {@code 
supplier}, with the specified {@code t} as a cause.
      * In the case when the provided cause {@code t} is an instance of {@link 
TraceableException},
diff --git 
a/modules/platforms/dotnet/Apache.Ignite.Tests/Table/SchemaSynchronizationTest.cs
 
b/modules/platforms/dotnet/Apache.Ignite.Tests/Table/SchemaSynchronizationTest.cs
index c7abd1a87d..ef1d664935 100644
--- 
a/modules/platforms/dotnet/Apache.Ignite.Tests/Table/SchemaSynchronizationTest.cs
+++ 
b/modules/platforms/dotnet/Apache.Ignite.Tests/Table/SchemaSynchronizationTest.cs
@@ -19,14 +19,12 @@ namespace Apache.Ignite.Tests.Table;
 
 using System;
 using System.Collections.Generic;
-using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
 using System.Linq;
 using System.Threading.Tasks;
 using Compute;
 using Ignite.Compute;
 using Ignite.Table;
-using Internal.Table;
 using NUnit.Framework;
 
 /// <summary>
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientSchemaSynchronizationTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientSchemaSynchronizationTest.java
index 5f78ee2497..60b4e4752f 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientSchemaSynchronizationTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/client/ItThinClientSchemaSynchronizationTest.java
@@ -38,25 +38,26 @@ import org.junit.jupiter.params.provider.ValueSource;
  */
 @SuppressWarnings("resource")
 public class ItThinClientSchemaSynchronizationTest extends 
ItAbstractThinClientTest {
-    @Test
-    void testClientUsesLatestSchemaOnWrite() {
+    @ParameterizedTest
+    @ValueSource(ints = {1, 2, 8, 9, 13}) // Test different nodes - 
sendServerExceptionStackTraceToClient affects exception propagation.
+    void testClientUsesLatestSchemaOnWrite(int id) {
         IgniteClient client = client();
         Session ses = client.sql().createSession();
 
         // Create table, insert data.
-        String tableName = "testClientUsesLatestSchemaOnWrite";
+        String tableName = "testClientUsesLatestSchemaOnWrite" + id;
         ses.execute(null, "CREATE TABLE " + tableName + "(ID INT NOT NULL 
PRIMARY KEY, NAME VARCHAR NOT NULL)");
 
         RecordView<Tuple> recordView = 
client.tables().table(tableName).recordView();
 
-        Tuple rec = Tuple.create().set("ID", 1).set("NAME", "name");
+        Tuple rec = Tuple.create().set("ID", -id).set("NAME", "name");
         recordView.insert(null, rec);
 
         // Modify table, insert data - client will use old schema, receive 
error, retry with new schema, fail due to an extra column.
         // The process is transparent for the user: updated schema is in 
effect immediately.
         ses.execute(null, "ALTER TABLE " + tableName + " DROP COLUMN NAME");
 
-        Tuple rec2 = Tuple.create().set("ID", 2).set("NAME", "name2");
+        Tuple rec2 = Tuple.create().set("ID", id).set("NAME", "name2");
         Throwable ex = assertThrowsWithCause(() -> recordView.upsert(null, 
rec2), IllegalArgumentException.class);
         assertEquals("Tuple doesn't match schema: schemaVersion=2, 
extraColumns=[NAME]", ex.getMessage());
     }
diff --git 
a/modules/schema/src/test/java/org/apache/ignite/internal/schema/marshaller/KvMarshallerTest.java
 
b/modules/schema/src/test/java/org/apache/ignite/internal/schema/marshaller/KvMarshallerTest.java
index ebd891af9e..56e2abe045 100644
--- 
a/modules/schema/src/test/java/org/apache/ignite/internal/schema/marshaller/KvMarshallerTest.java
+++ 
b/modules/schema/src/test/java/org/apache/ignite/internal/schema/marshaller/KvMarshallerTest.java
@@ -84,7 +84,6 @@ import 
org.apache.ignite.internal.testframework.IgniteTestUtils;
 import org.apache.ignite.internal.type.NativeType;
 import org.apache.ignite.internal.type.NativeTypeSpec;
 import org.apache.ignite.internal.type.NativeTypes;
-import org.apache.ignite.internal.util.ExceptionUtils;
 import org.apache.ignite.internal.util.ObjectFactory;
 import org.apache.ignite.table.mapper.Mapper;
 import org.junit.jupiter.api.Assumptions;
@@ -318,9 +317,13 @@ public class KvMarshallerTest {
         KvMarshaller<Integer, BitSet> marshaller =
                 factory.create(schema, Integer.class, BitSet.class);
 
-        Throwable ex = ExceptionUtils.unwrapRootCause(assertThrows(
+        Throwable ex = assertThrows(
                 MarshallerException.class,
-                () -> marshaller.marshal(1, IgniteTestUtils.randomBitSet(rnd, 
42))));
+                () -> marshaller.marshal(1, IgniteTestUtils.randomBitSet(rnd, 
42)));
+
+        while (ex.getCause() != null) {
+            ex = ex.getCause();
+        }
 
         assertThat(ex.getMessage(), startsWith("Failed to set bitmask for 
column 'BITMASKCOL' (mask size exceeds allocated size)"));
     }

Reply via email to