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

korlov 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 c40daaf1f4 IGNITE-22958 Improve performance of TupleMarshaller part 2 
(#4205)
c40daaf1f4 is described below

commit c40daaf1f41cc0b134f51ae9141b7778f460f4fd
Author: korlov42 <[email protected]>
AuthorDate: Thu Aug 8 16:52:45 2024 +0300

    IGNITE-22958 Improve performance of TupleMarshaller part 2 (#4205)
---
 .../java/org/apache/ignite/table/TupleImpl.java    |  8 +++
 .../org/apache/ignite/table/TupleImplTest.java     | 25 +++++++++
 .../schema/marshaller/TupleMarshallerImpl.java     | 26 +++++-----
 .../java/org/apache/ignite/table/TupleHelper.java  | 47 +++++++++++++++++
 .../org/apache/ignite/table/TupleHelperTest.java   | 59 ++++++++++++++++++++++
 5 files changed, 153 insertions(+), 12 deletions(-)

diff --git a/modules/api/src/main/java/org/apache/ignite/table/TupleImpl.java 
b/modules/api/src/main/java/org/apache/ignite/table/TupleImpl.java
index abbe0e638b..4a8771b25b 100644
--- a/modules/api/src/main/java/org/apache/ignite/table/TupleImpl.java
+++ b/modules/api/src/main/java/org/apache/ignite/table/TupleImpl.java
@@ -358,6 +358,14 @@ class TupleImpl implements Tuple, Serializable {
         }
     }
 
+    <T> @Nullable T valueOrDefaultSkipNormalization(String columnName, 
@Nullable T def) {
+        Objects.requireNonNull(columnName);
+
+        Integer idx = colMapping.get(columnName);
+
+        return (idx == null) ? def : (T) colValues.get(idx);
+    }
+
     /** {@inheritDoc} */
     @Override
     public String toString() {
diff --git 
a/modules/api/src/test/java/org/apache/ignite/table/TupleImplTest.java 
b/modules/api/src/test/java/org/apache/ignite/table/TupleImplTest.java
index 7972c707bf..5d9a301ccc 100644
--- a/modules/api/src/test/java/org/apache/ignite/table/TupleImplTest.java
+++ b/modules/api/src/test/java/org/apache/ignite/table/TupleImplTest.java
@@ -55,4 +55,29 @@ public class TupleImplTest extends AbstractMutableTupleTest {
         assertEquals(Tuple.create().set("id", 42L).set("\"name\"", "universe"),
                 Tuple.copy(Tuple.create().set("\"ID\"", 42L).set("\"name\"", 
"universe")));
     }
+
+    @Test
+    void testValueOrDefaultSkipNormalization() {
+        TupleImpl tuple = new TupleImpl();
+
+        tuple.set("name", "normalized").set("\"Name\"", "non-normalized");
+
+        assertEquals("normalized", 
tuple.valueOrDefaultSkipNormalization("NAME", "default"));
+
+        // must not be found by non normalized name, this method doesn't do 
normalization
+        assertEquals("default", tuple.valueOrDefaultSkipNormalization("name", 
"default"));
+        assertEquals("default", 
tuple.valueOrDefaultSkipNormalization("\"NAME\"", "default"));
+
+        // must be found by non normalized name, regular method does 
normalization
+        assertEquals("normalized", tuple.valueOrDefault("name", "default"));
+        assertEquals("normalized", tuple.valueOrDefault("\"NAME\"", 
"default"));
+
+        assertEquals("non-normalized", 
tuple.valueOrDefaultSkipNormalization("Name", "default"));
+
+        // must not be found by non normalized name, this method doesn't do 
normalization
+        assertEquals("default", 
tuple.valueOrDefaultSkipNormalization("\"Name\"", "default"));
+
+        // must be found by non normalized name, regular method does 
normalization
+        assertEquals("non-normalized", tuple.valueOrDefault("\"Name\"", 
"default"));
+    }
 }
diff --git 
a/modules/table/src/main/java/org/apache/ignite/internal/schema/marshaller/TupleMarshallerImpl.java
 
b/modules/table/src/main/java/org/apache/ignite/internal/schema/marshaller/TupleMarshallerImpl.java
index 837b8aaf94..30bfe749d2 100644
--- 
a/modules/table/src/main/java/org/apache/ignite/internal/schema/marshaller/TupleMarshallerImpl.java
+++ 
b/modules/table/src/main/java/org/apache/ignite/internal/schema/marshaller/TupleMarshallerImpl.java
@@ -40,8 +40,8 @@ import org.apache.ignite.internal.type.DecimalNativeType;
 import org.apache.ignite.internal.type.NativeType;
 import org.apache.ignite.internal.type.NativeTypeSpec;
 import org.apache.ignite.lang.MarshallerException;
-import org.apache.ignite.lang.util.IgniteNameUtils;
 import org.apache.ignite.table.Tuple;
+import org.apache.ignite.table.TupleHelper;
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.annotations.TestOnly;
 
@@ -53,8 +53,8 @@ public class TupleMarshallerImpl implements TupleMarshaller {
 
     private final SchemaDescriptor schema;
 
-    private final int keyOnlyFixedLengthColumnSize; 
-    private final int valueOnlyFixedLengthColumnSize; 
+    private final int keyOnlyFixedLengthColumnSize;
+    private final int valueOnlyFixedLengthColumnSize;
 
     /**
      * Creates marshaller for given schema.
@@ -105,9 +105,10 @@ public class TupleMarshallerImpl implements 
TupleMarshaller {
                 }
             }
 
+            TuplePart part = TuplePart.KEY_VALUE;
             ValuesWithStatistics valuesWithStatistics = new 
ValuesWithStatistics();
 
-            gatherStatistics(TuplePart.KEY_VALUE, tuple, valuesWithStatistics);
+            gatherStatistics(part, tuple, valuesWithStatistics);
 
             if (valuesWithStatistics.knownColumns != tuple.columnCount()) {
                 throw new SchemaMismatchException(
@@ -115,7 +116,7 @@ public class TupleMarshallerImpl implements TupleMarshaller 
{
                                 schema.version(), extraColumnNames(tuple, 
schema)));
             }
 
-            return buildRow(false, valuesWithStatistics);
+            return buildRow(part, valuesWithStatistics);
         } catch (Exception ex) {
             throw new MarshallerException(ex.getMessage(), ex);
         }
@@ -146,7 +147,7 @@ public class TupleMarshallerImpl implements TupleMarshaller 
{
                 }
             }
 
-            return buildRow(keyOnly, valuesWithStatistics);
+            return buildRow(keyOnly ? TuplePart.KEY : TuplePart.KEY_VALUE, 
valuesWithStatistics);
         } catch (Exception ex) {
             throw new MarshallerException(ex.getMessage(), ex);
         }
@@ -157,31 +158,32 @@ public class TupleMarshallerImpl implements 
TupleMarshaller {
     public Row marshalKey(Tuple keyTuple) throws MarshallerException {
         try {
             ValuesWithStatistics valuesWithStatistics = new 
ValuesWithStatistics();
+            TuplePart part = TuplePart.KEY;
 
-            gatherStatistics(TuplePart.KEY, keyTuple, valuesWithStatistics);
+            gatherStatistics(part, keyTuple, valuesWithStatistics);
 
             if (valuesWithStatistics.knownColumns < keyTuple.columnCount()) {
                 throw new SchemaMismatchException("Key tuple contains extra 
columns: " + extraColumnNames(keyTuple, true, schema));
             }
 
-            return buildRow(true, valuesWithStatistics);
+            return buildRow(part, valuesWithStatistics);
         } catch (Exception ex) {
             throw new MarshallerException(ex.getMessage(), ex);
         }
     }
 
     private Row buildRow(
-            boolean keyOnly,
+            TuplePart part,
             ValuesWithStatistics values
     ) throws SchemaMismatchException {
-        List<Column> columns = keyOnly ? schema.keyColumns() : 
schema.columns();
+        List<Column> columns = part.deriveColumnList(schema);
         RowAssembler rowBuilder = new RowAssembler(schema.version(), columns, 
values.estimatedValueSize, false);
 
         for (Column col : columns) {
             rowBuilder.appendValue(values.value(col.name()));
         }
 
-        return keyOnly
+        return part == TuplePart.KEY
                 ? Row.wrapKeyOnlyBinaryRow(schema, rowBuilder.build())
                 : Row.wrapBinaryRow(schema, rowBuilder.build());
     }
@@ -196,7 +198,7 @@ public class TupleMarshallerImpl implements TupleMarshaller 
{
         for (Column col : part.deriveColumnList(schema)) {
             NativeType colType = col.type();
 
-            Object val = 
tuple.valueOrDefault(IgniteNameUtils.quote(col.name()), POISON_OBJECT);
+            Object val = TupleHelper.valueOrDefault(tuple, col.name(), 
POISON_OBJECT);
 
             if (val == POISON_OBJECT && col.positionInKey() != -1) {
                 throw new SchemaMismatchException("Missed key column: " + 
col.name());
diff --git 
a/modules/table/src/main/java/org/apache/ignite/table/TupleHelper.java 
b/modules/table/src/main/java/org/apache/ignite/table/TupleHelper.java
new file mode 100644
index 0000000000..73eece7749
--- /dev/null
+++ b/modules/table/src/main/java/org/apache/ignite/table/TupleHelper.java
@@ -0,0 +1,47 @@
+/*
+ * 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.table;
+
+import org.apache.ignite.lang.util.IgniteNameUtils;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Utility class to provide direct access to internals of {@link TupleImpl}.
+ */
+public class TupleHelper {
+    /**
+     * Returns value from a given tuple which corresponds to a specified 
column.
+     * 
+     * <p>Given name is expected to be normalized, thus it's up to caller to 
invoke 
+     * {@link IgniteNameUtils#parseSimpleName(String)} prior passing the name 
to this method.
+     *
+     * @param tuple A tuple to get value from.
+     * @param normalizedName A column name that is considered to be normalized 
+     *      (e.g result of {@link IgniteNameUtils#parseSimpleName(String)}).
+     * @param defaultValue A value to return in case tuple doesn't have column 
with given name.
+     * @param <T> A type of the returned value.
+     * @return A value from a tuple.
+     */
+    public static <T> @Nullable T valueOrDefault(Tuple tuple, String 
normalizedName, @Nullable T defaultValue) {
+        if (tuple instanceof TupleImpl) {
+            return ((TupleImpl) 
tuple).valueOrDefaultSkipNormalization(normalizedName, defaultValue);
+        }
+
+        return tuple.valueOrDefault(IgniteNameUtils.quote(normalizedName), 
defaultValue);
+    }
+}
diff --git 
a/modules/table/src/test/java/org/apache/ignite/table/TupleHelperTest.java 
b/modules/table/src/test/java/org/apache/ignite/table/TupleHelperTest.java
new file mode 100644
index 0000000000..f0e6a60cd7
--- /dev/null
+++ b/modules/table/src/test/java/org/apache/ignite/table/TupleHelperTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.table;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import org.apache.ignite.internal.testframework.IgniteAbstractTest;
+import org.apache.ignite.lang.util.IgniteNameUtils;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests to validate {@link TupleHelper}.
+ */
+class TupleHelperTest extends IgniteAbstractTest {
+
+    @Test
+    void valueOrDefault() {
+        String columnName = "col_1";
+        String defaultValue = "default";
+
+        {
+            TupleImpl tuple = mock(TupleImpl.class);
+
+            TupleHelper.valueOrDefault(tuple, columnName, defaultValue);
+
+            // in case of TupleImpl optimized method avoiding normalization 
must be invoked
+            verify(tuple).valueOrDefaultSkipNormalization(eq(columnName), 
eq(defaultValue));
+            verifyNoMoreInteractions(tuple);
+        }
+
+        {
+            Tuple tuple = mock(Tuple.class);
+
+            TupleHelper.valueOrDefault(tuple, columnName, defaultValue);
+
+            // in case of other implementations regular method must be 
invoked, but column name must be quoted
+            
verify(tuple).valueOrDefault(eq(IgniteNameUtils.quote(columnName)), 
eq(defaultValue));
+            verifyNoMoreInteractions(tuple);
+        }
+    }
+}

Reply via email to