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