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)"));
}