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 7bdfba086a IGNITE-18925 Avoid BinaryTuple conversion from client to 
storage (#2004)
7bdfba086a is described below

commit 7bdfba086af5f8071c4244d8840003645c222a44
Author: Pavel Tupitsyn <[email protected]>
AuthorDate: Wed May 3 14:28:10 2023 +0300

    IGNITE-18925 Avoid BinaryTuple conversion from client to storage (#2004)
    
    Copy client-provided `BinaryTuple` from the client as is to storage when 
the conditions are met:
    * Schema version matches current schema.
    * There are no unset values (which require values from 
`DefaultValueProvider`).
      * Default value behavior is checked by 
`testColumnWithDefaultValueNotSetReturnsDefault` and many other tests.
    * There are no temporal types in the schema (which require precision-based 
normalization).
      * Normalization is checked by the following tests: 
`testAllColumnsBinaryPutPojoGet`, `testAllColumnsPojoPutBinaryGet`, 
`testAllColumnsBinaryPutPojoGet`, `testAllColumnsPojoPutBinaryGet`
---
 .../table/MutableTupleBinaryTupleAdapter.java      | 10 ++++++++
 .../client/handler/requests/table/ClientTuple.java |  7 +++---
 .../ignite/internal/schema/SchemaDescriptor.java   | 24 ++++++++++++++++++-
 .../ignite/internal/schema/row/RowAssembler.java   | 18 ++++++++++++---
 .../schema/marshaller/TupleMarshallerImpl.java     | 27 +++++++++++++++++++++-
 5 files changed, 78 insertions(+), 8 deletions(-)

diff --git 
a/modules/client-common/src/main/java/org/apache/ignite/internal/client/table/MutableTupleBinaryTupleAdapter.java
 
b/modules/client-common/src/main/java/org/apache/ignite/internal/client/table/MutableTupleBinaryTupleAdapter.java
index 4c1cfea432..8cc2fb4f33 100644
--- 
a/modules/client-common/src/main/java/org/apache/ignite/internal/client/table/MutableTupleBinaryTupleAdapter.java
+++ 
b/modules/client-common/src/main/java/org/apache/ignite/internal/client/table/MutableTupleBinaryTupleAdapter.java
@@ -408,6 +408,16 @@ public abstract class MutableTupleBinaryTupleAdapter 
implements Tuple, BinaryTup
     /** {@inheritDoc} */
     @Override
     public @Nullable BinaryTupleReader binaryTuple() {
+        if (tuple != null) {
+            return null;
+        }
+
+        if (noValueSet != null && !noValueSet.isEmpty()) {
+            // Can't expose binary tuple if there are unset values.
+            // On the server side, DefaultValueProvider is used to replace 
unset values with proper defaults.
+            return null;
+        }
+
         return binaryTuple;
     }
 
diff --git 
a/modules/client-handler/src/main/java/org/apache/ignite/client/handler/requests/table/ClientTuple.java
 
b/modules/client-handler/src/main/java/org/apache/ignite/client/handler/requests/table/ClientTuple.java
index 6531e8200d..edfca53be7 100644
--- 
a/modules/client-handler/src/main/java/org/apache/ignite/client/handler/requests/table/ClientTuple.java
+++ 
b/modules/client-handler/src/main/java/org/apache/ignite/client/handler/requests/table/ClientTuple.java
@@ -22,6 +22,7 @@ import 
org.apache.ignite.internal.binarytuple.BinaryTupleReader;
 import org.apache.ignite.internal.client.table.MutableTupleBinaryTupleAdapter;
 import org.apache.ignite.internal.schema.Column;
 import org.apache.ignite.internal.schema.NativeTypeSpec;
+import org.apache.ignite.internal.schema.SchemaAware;
 import org.apache.ignite.internal.schema.SchemaDescriptor;
 import org.apache.ignite.sql.ColumnType;
 import org.apache.ignite.table.Tuple;
@@ -31,7 +32,7 @@ import org.jetbrains.annotations.Nullable;
 /**
  * Server-side client Tuple.
  */
-class ClientTuple extends MutableTupleBinaryTupleAdapter {
+class ClientTuple extends MutableTupleBinaryTupleAdapter implements 
SchemaAware {
     /** Schema. */
     private final SchemaDescriptor schema;
 
@@ -52,8 +53,8 @@ class ClientTuple extends MutableTupleBinaryTupleAdapter {
 
     /** {@inheritDoc} */
     @Override
-    public @Nullable BinaryTupleReader binaryTuple() {
-        return super.binaryTuple();
+    public @Nullable SchemaDescriptor schema() {
+        return binaryTuple() != null ? schema : null;
     }
 
     /** {@inheritDoc} */
diff --git 
a/modules/schema/src/main/java/org/apache/ignite/internal/schema/SchemaDescriptor.java
 
b/modules/schema/src/main/java/org/apache/ignite/internal/schema/SchemaDescriptor.java
index 048753bbb1..95518c5e62 100644
--- 
a/modules/schema/src/main/java/org/apache/ignite/internal/schema/SchemaDescriptor.java
+++ 
b/modules/schema/src/main/java/org/apache/ignite/internal/schema/SchemaDescriptor.java
@@ -23,6 +23,7 @@ import java.util.Comparator;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.stream.Stream;
 import org.apache.ignite.internal.schema.mapping.ColumnMapper;
 import org.apache.ignite.internal.schema.mapping.ColumnMapping;
@@ -50,6 +51,9 @@ public class SchemaDescriptor {
     /** Mapping 'Column name' -&gt; Column. */
     private final Map<String, Column> colMap;
 
+    /** Whether schema contains time or timestamp columns. */
+    private final boolean hasTemporalColumns;
+
     /** Column mapper. */
     private ColumnMapper colMapper = ColumnMapping.identityMapping();
 
@@ -82,10 +86,19 @@ public class SchemaDescriptor {
         assert this.keyCols.nullMapSize() == 0 : "Primary key cannot contain 
nullable column [cols=" + this.keyCols + ']';
 
         colMap = new LinkedHashMap<>(keyCols.length + valCols.length);
+        var hasTemporalColumns = new AtomicBoolean(false);
 
         Stream.concat(Arrays.stream(this.keyCols.columns()), 
Arrays.stream(this.valCols.columns()))
                 .sorted(Comparator.comparingInt(Column::columnOrder))
-                .forEach(c -> colMap.put(c.name(), c));
+                .forEach(c -> {
+                    if (c.type() instanceof TemporalNativeType) {
+                        hasTemporalColumns.set(true);
+                    }
+
+                    colMap.put(c.name(), c);
+                });
+
+        this.hasTemporalColumns = hasTemporalColumns.get();
 
         // Preserving key chunk column order is not actually required.
         // It is sufficient to has same column order for all nodes.
@@ -208,6 +221,15 @@ public class SchemaDescriptor {
         return colMapper;
     }
 
+    /**
+     * Get a value indicating whether schema contains temporal columns.
+     *
+     * @return {@code true} if schema contains temporal columns (time, 
datetime, timestamp), {@code false} otherwise.
+     */
+    public boolean hasTemporalColumns() {
+        return hasTemporalColumns;
+    }
+
     /** {@inheritDoc} */
     @Override
     public String toString() {
diff --git 
a/modules/schema/src/main/java/org/apache/ignite/internal/schema/row/RowAssembler.java
 
b/modules/schema/src/main/java/org/apache/ignite/internal/schema/row/RowAssembler.java
index 6d3f1f350d..e65eec9673 100644
--- 
a/modules/schema/src/main/java/org/apache/ignite/internal/schema/row/RowAssembler.java
+++ 
b/modules/schema/src/main/java/org/apache/ignite/internal/schema/row/RowAssembler.java
@@ -665,13 +665,25 @@ public class RowAssembler {
      */
     public BinaryRow build() {
         boolean hasValue = flush();
-
         ByteBuffer tupleBuffer = builder.build();
-        ByteBuffer buffer = ByteBuffer.allocate(SCHEMA_VERSION_FLD_LEN + 
HAS_VALUE_FLD_LEN + tupleBuffer.limit()).order(ORDER);
+
+        return build(tupleBuffer, schemaVersion, hasValue);
+    }
+
+    /**
+     * Builds serialized row from a BinaryTuple.
+     *
+     * @param binTupleBuffer Binary tuple buffer.
+     * @param schemaVersion Schema version.
+     * @return Created {@link BinaryRow}.
+     */
+    public static BinaryRow build(ByteBuffer binTupleBuffer, int 
schemaVersion, boolean hasValue) {
+        ByteBuffer buffer = ByteBuffer.allocate(SCHEMA_VERSION_FLD_LEN + 
HAS_VALUE_FLD_LEN + binTupleBuffer.limit()).order(ORDER);
         buffer.putShort((short) schemaVersion);
         buffer.put(hasValue ? (byte) 1 : 0);
-        buffer.put(tupleBuffer);
+        buffer.put(binTupleBuffer);
         buffer.position(0);
+
         return new ByteBufferRow(buffer);
     }
 
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 c549a6246b..d6d438cc30 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
@@ -24,6 +24,8 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import org.apache.ignite.internal.binarytuple.BinaryTupleContainer;
+import org.apache.ignite.internal.binarytuple.BinaryTupleReader;
 import org.apache.ignite.internal.schema.Column;
 import org.apache.ignite.internal.schema.Columns;
 import org.apache.ignite.internal.schema.NativeType;
@@ -64,6 +66,18 @@ public class TupleMarshallerImpl implements TupleMarshaller {
         try {
             SchemaDescriptor schema = schemaReg.schema();
 
+            if (tuple instanceof SchemaAware && tuple instanceof 
BinaryTupleContainer) {
+                SchemaDescriptor tupleSchema = ((SchemaAware) tuple).schema();
+                BinaryTupleReader tupleReader = ((BinaryTupleContainer) 
tuple).binaryTuple();
+
+                if (tupleSchema != null
+                        && tupleReader != null
+                        && tupleSchema.version() == schema.version()
+                        && !binaryTupleRebuildRequired(schema)) {
+                    return new Row(schema, 
RowAssembler.build(tupleReader.byteBuffer(), schema.version(), true));
+                }
+            }
+
             InternalTuple keyTuple0 = toInternalTuple(schema, tuple, true);
             InternalTuple valTuple0 = toInternalTuple(schema, tuple, false);
 
@@ -317,10 +331,21 @@ public class TupleMarshallerImpl implements 
TupleMarshaller {
      * @param tup    Internal tuple.
      * @throws SchemaMismatchException If a tuple column value doesn't match 
the current column type.
      */
-    private void writeColumn(RowAssembler rowAsm, Column col, InternalTuple 
tup) throws SchemaMismatchException {
+    private static void writeColumn(RowAssembler rowAsm, Column col, 
InternalTuple tup) throws SchemaMismatchException {
         RowAssembler.writeValue(rowAsm, col, tup.value(col.name()));
     }
 
+    /**
+     * Determines whether binary tuple rebuild is required.
+     *
+     * @param schema Schema.
+     * @return True if binary tuple rebuild is required; false if the tuple 
can be written to storage as is.
+     */
+    private static boolean binaryTupleRebuildRequired(SchemaDescriptor schema) 
{
+        // Temporal columns require normalization according to the specified 
precision.
+        return schema.hasTemporalColumns();
+    }
+
     /**
      * Internal tuple enriched original tuple with additional info.
      */

Reply via email to