You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by am...@apache.org on 2020/11/12 15:48:04 UTC
[ignite] branch ignite-13618 updated: WIP. Minors after review.
This is an automated email from the ASF dual-hosted git repository.
amashenkov pushed a commit to branch ignite-13618
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/ignite-13618 by this push:
new 7e57785 WIP. Minors after review.
7e57785 is described below
commit 7e57785614359f3c0fcef45725305d5b3292968b
Author: Andrew Mashenkov <an...@gmail.com>
AuthorDate: Thu Nov 12 16:23:10 2020 +0300
WIP. Minors after review.
---
.../schema/marshaller/BaseTypeMarshaller.java | 63 --------
.../schema/marshaller/ClassMarshaller.java | 91 -----------
.../internal/schema/marshaller/FieldAccessor.java | 98 +++++++++++-
.../internal/schema/marshaller/JavaSerializer.java | 167 +++++++++++++++++++--
.../internal/schema/marshaller/Marshaller.java | 91 +++++++++--
.../schema/marshaller/SerializationException.java | 13 +-
.../ignite/internal/util/IgniteUnsafeUtils.java | 57 +++++++
.../ignite/internal/schema/SchemaTestSuite.java | 3 +
.../schema/marshaller/JavaSerializerTest.java | 62 ++++++++
9 files changed, 451 insertions(+), 194 deletions(-)
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/BaseTypeMarshaller.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/BaseTypeMarshaller.java
deleted file mode 100644
index 7b9d0f4..0000000
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/BaseTypeMarshaller.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.internal.schema.marshaller;
-
-import java.util.Objects;
-import org.apache.ignite.internal.schema.Tuple;
-import org.apache.ignite.internal.schema.TupleAssembler;
-
-/**
- * (De)serializer handler for object of base types.
- */
-class BaseTypeMarshaller implements Marshaller {
- /** Write mode. */
- private final BinaryMode mode;
-
- /**
- * Constructor.
- *
- * @param mode Binary mode.
- */
- public BaseTypeMarshaller(BinaryMode mode) {
- this.mode = Objects.requireNonNull(mode);
- }
-
- /** {@inheritDoc} */
- @Override public int nonNullVarLenCols(Object obj) {
- return 0;
- }
-
- /** {@inheritDoc} */
- @Override public Object value(Object obj, int colIdx) {
- assert colIdx == 0 : "No columns expected for native types.";
-
- return obj;
- }
-
- /** {@inheritDoc} */
- @Override public Object readObject(Tuple reader) {
- return JavaSerializer.readRefValue(reader, 0, mode);
- }
-
- /** {@inheritDoc} */
- @Override public void writeObject(Object val, TupleAssembler writer) {
- Objects.requireNonNull(val, "Null values are not supported."); //TODO: Add 'tombstones' (null-values) support.
-
- JavaSerializer.writeRefObject(val, writer, mode);
- }
-}
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/ClassMarshaller.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/ClassMarshaller.java
deleted file mode 100644
index 3bc1d76..0000000
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/ClassMarshaller.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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.internal.schema.marshaller;
-
-import org.apache.ignite.internal.schema.Columns;
-import org.apache.ignite.internal.schema.Tuple;
-import org.apache.ignite.internal.schema.TupleAssembler;
-import org.jetbrains.annotations.Unmodifiable;
-
-/**
- * General purpose (de)serializer handler for objects of complex types.
- */
-public class ClassMarshaller<T> implements Marshaller {
- /** Mapped columns. */
- private final Columns cols;
-
- /**
- * Field accessors for mapped columns.
- * Array has same size and order as columns.
- */
- private final FieldAccessor[] fieldAccessors;
-
- /** Object factory for class. */
- private final ObjectFactory<T> factory;
-
- /**
- * Constructor.
- *
- * @param cols Mapped columns.
- * @param factory Object factory.
- * @param fieldAccessors Object field accessors for mapped columns.
- */
- @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType")
- public ClassMarshaller(Columns cols, ObjectFactory<T> factory, FieldAccessor[] fieldAccessors) {
- this.cols = cols;
- this.fieldAccessors = fieldAccessors;
- this.factory = factory;
- }
-
- /** {@inheritDoc} */
- @Override public int nonNullVarLenCols(Object obj) throws SerializationException {
- if (obj == null)
- return 0;
-
- int cnt = 0;
-
- for (int fldIdx = cols.firstVarlengthColumn(); fldIdx < cols.length(); fldIdx++) {
- if (fieldAccessors[fldIdx].value(obj) == null)
- cnt++;
- }
-
- return cnt;
- }
-
- /** {@inheritDoc} */
- @Override public Object value(Object obj, int fldIdx) throws SerializationException {
- return fieldAccessors[fldIdx].value(obj);
- }
-
- /** {@inheritDoc} */
- @Override public Object readObject(Tuple reader) throws SerializationException {
- final T obj = factory.newInstance();
-
- for (int fldIdx = 0; fldIdx < fieldAccessors.length; fldIdx++)
- fieldAccessors[fldIdx].read(obj, reader);
-
- return obj;
- }
-
- /** {@inheritDoc} */
- @Override public void writeObject(Object obj, TupleAssembler writer) throws SerializationException {
- for (int fldIdx = 0; fldIdx < fieldAccessors.length; fldIdx++) {
- fieldAccessors[fldIdx].write(obj, writer);
- }
- }
-}
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/FieldAccessor.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/FieldAccessor.java
index 45f79c7..df182bd 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/FieldAccessor.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/FieldAccessor.java
@@ -18,7 +18,9 @@
package org.apache.ignite.internal.schema.marshaller;
import java.lang.reflect.Field;
+import java.util.Objects;
import org.apache.ignite.internal.schema.Column;
+import org.apache.ignite.internal.schema.Columns;
import org.apache.ignite.internal.schema.Tuple;
import org.apache.ignite.internal.schema.TupleAssembler;
import org.jetbrains.annotations.Nullable;
@@ -44,7 +46,11 @@ public abstract class FieldAccessor {
/** Mode. */
protected final BinaryMode mode;
- /** Column index. */
+ /**
+ * Mapped column position in schema.
+ *
+ * NODE: Do not mix up with column index in {@link Columns} container.
+ */
protected final int colIdx;
/**
@@ -52,7 +58,7 @@ public abstract class FieldAccessor {
*
* @param field Field.
* @param col Mapped column.
- * @param colIdx Column index.
+ * @param colIdx Column index in schema.
* @return Accessor.
*/
//TODO: Extract a provider for this factory-method.
@@ -101,6 +107,44 @@ public abstract class FieldAccessor {
}
/**
+ * Create accessor for the field.
+ *
+ * @param col Column.
+ * @param colIdx Column index.
+ * @param mode Binary mode.
+ * @return Accessor.
+ */
+ static FieldAccessor createIdentityAccessor(Column col, int colIdx, BinaryMode mode) {
+ switch (mode) {
+ // Marshaller read/write object contract methods allowed boxed types only.
+ case P_BYTE:
+ case P_SHORT:
+ case P_INT:
+ case P_LONG:
+ case P_FLOAT:
+ case P_DOUBLE:
+ throw new IllegalArgumentException("Primitive key/value types are not possible by API contract.");
+
+ case BYTE:
+ case SHORT:
+ case INT:
+ case LONG:
+ case FLOAT:
+ case DOUBLE:
+ case STRING:
+ case UUID:
+ case BYTE_ARR:
+ case BITSET:
+ return new IdentityAccessor(colIdx, mode);
+
+ default:
+ assert false : "Invalid mode " + mode;
+ }
+
+ throw new IllegalArgumentException("Failed to create accessor for column [name=" + col.name() + ']');
+ }
+
+ /**
* Protected constructor.
*
* @param field Field.
@@ -108,7 +152,6 @@ public abstract class FieldAccessor {
* @param mode Binary mode;
*/
protected FieldAccessor(Field field, int colIdx, BinaryMode mode) {
- assert field != null;
assert colIdx >= 0;
assert mode != null;
@@ -116,7 +159,8 @@ public abstract class FieldAccessor {
this.colIdx = colIdx;
this.mode = mode;
- field.setAccessible(true);
+ if (field != null)
+ field.setAccessible(true);
}
/**
@@ -137,7 +181,7 @@ public abstract class FieldAccessor {
*/
public void write(Object obj, TupleAssembler writer) throws SerializationException {
try {
- write0(obj, writer);
+ write0(Objects.requireNonNull(obj), writer);
}
catch (Exception ex) {
if (includeSensitive())
@@ -165,7 +209,7 @@ public abstract class FieldAccessor {
*/
public void read(Object obj, Tuple reader) throws SerializationException {
try {
- read0(obj, reader);
+ read0(Objects.requireNonNull(obj), reader);
}
catch (Exception ex) {
if (includeSensitive())
@@ -185,6 +229,16 @@ public abstract class FieldAccessor {
protected abstract void read0(Object obj, Tuple reader) throws IllegalAccessException;
/**
+ * Read value.
+ *
+ * @param reader Tuple reader.
+ * @return Object.
+ */
+ public Object read(Tuple reader) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
* Reads object field value.
*
* @param obj Object.
@@ -193,7 +247,7 @@ public abstract class FieldAccessor {
*/
@Nullable Object value(Object obj) throws SerializationException {
try {
- return field.get(obj);
+ return field.get(Objects.requireNonNull(obj));
}
catch (IllegalAccessException ex) {
if (includeSensitive())
@@ -206,6 +260,36 @@ public abstract class FieldAccessor {
/**
* Accessor for field of primitive {@code byte} type.
*/
+ private static class IdentityAccessor extends FieldAccessor {
+ /**
+ * Constructor.
+ *
+ * @param colIdx Column index.
+ * @param mode Binary mode.
+ */
+ public IdentityAccessor(int colIdx, BinaryMode mode) {
+ super(null, colIdx, mode);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void write0(Object obj, TupleAssembler writer) {
+ JavaSerializer.writeRefObject(Objects.requireNonNull(obj, "Null values are not supported."), writer, mode);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void read0(Object obj, Tuple reader) {
+ throw new UnsupportedOperationException("Called identity accessor for object field.");
+ }
+
+ /** {@inheritDoc} */
+ @Override public Object read(Tuple reader) {
+ return JavaSerializer.readRefValue(reader, colIdx, mode);
+ }
+ }
+
+ /**
+ * Accessor for field of primitive {@code byte} type.
+ */
private static class BytePrimitiveAccessor extends FieldAccessor {
/**
* Constructor.
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/JavaSerializer.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/JavaSerializer.java
index ebecee9..cff95ef 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/JavaSerializer.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/JavaSerializer.java
@@ -17,9 +17,13 @@
package org.apache.ignite.internal.schema.marshaller;
+import java.lang.reflect.Field;
import java.util.BitSet;
import java.util.UUID;
+import org.apache.ignite.internal.schema.ByteBufferTuple;
import org.apache.ignite.internal.schema.Column;
+import org.apache.ignite.internal.schema.Columns;
+import org.apache.ignite.internal.schema.NativeType;
import org.apache.ignite.internal.schema.SchemaDescriptor;
import org.apache.ignite.internal.schema.Tuple;
import org.apache.ignite.internal.schema.TupleAssembler;
@@ -31,7 +35,6 @@ import org.jetbrains.annotations.NotNull;
* TODO: Extract interface.
*/
public class JavaSerializer {
-
/**
* Gets binary read/write mode for given class.
*
@@ -229,7 +232,10 @@ public class JavaSerializer {
/** Schema. */
private final SchemaDescriptor schema;
+ /** Key class. */
private final Class<?> keyClass;
+
+ /** Value class. */
private final Class<?> valClass;
/** Key marshaller. */
@@ -250,32 +256,48 @@ public class JavaSerializer {
this.keyClass = keyClass;
this.valClass = valClass;
- keyMarsh = createMarshaller(schema, keyClass);
- valMarsh = createMarshaller(schema, valClass);
+ keyMarsh = createMarshaller(schema.keyColumns(), 0, keyClass);
+ valMarsh = createMarshaller(schema.valueColumns(), schema.keyColumns().length(), valClass);
}
/**
* Creates marshaller for class.
*
- * @param schema Schema.
+ * @param cols Columns.
+ * @param firstColId First column position in schema.
* @param aClass Type.
* @return Marshaller.
*/
- @NotNull private <T> Marshaller createMarshaller(SchemaDescriptor schema, Class<T> aClass) {
+ @NotNull private static Marshaller createMarshaller(Columns cols, int firstColId, Class<?> aClass) {
final BinaryMode mode = mode(aClass);
if (mode != null) {
- final Column col = schema.keyColumns().column(0);
+ final Column col = cols.column(0);
+ assert cols.length() == 1;
assert mode.typeSpec() == col.type().spec() : "Target type is not compatible.";
- assert aClass.isPrimitive() && col.nullable() : "Non-nullable types are not allowed.";
+ assert !aClass.isPrimitive() : "Non-nullable types are not allowed.";
- return new BaseTypeMarshaller(mode);
+ return new Marshaller(FieldAccessor.createIdentityAccessor(col, firstColId, mode));
}
- // TODO: Build accessors
+ try {
+ FieldAccessor[] fieldAccessors = new FieldAccessor[cols.length()];
+
+ // Build accessors
+ for (int i = 0; i < cols.length(); i++) {
+ final Column col = cols.column(i);
+ final Field field = aClass.getDeclaredField(col.name());
- return new ClassMarshaller<>(schema.keyColumns(), ObjectFactory.classFactory(aClass), null);
+ final int colIdx = firstColId + i; /* Absolute column idx in schema. */
+ fieldAccessors[i] = FieldAccessor.create(field, col, colIdx);
+ }
+
+ return new Marshaller(ObjectFactory.classFactory(aClass), fieldAccessors);
+ }
+ catch (NoSuchFieldException | SecurityException ex) {
+ throw new IllegalStateException(ex);
+ }
}
/**
@@ -289,16 +311,129 @@ public class JavaSerializer {
assert keyClass.isInstance(key);
assert val == null || valClass.isInstance(val);
+ final TupleAssembler asm = createAssembler(key, val);
+
+ keyMarsh.writeObject(key, asm);
+
+ if (val != null)
+ valMarsh.writeObject(val, asm);
+ else
+ assert false; // TODO: add tomstone support and remove assertion.
+
+ return asm.build();
+ }
+
+ /**
+ * Creates TupleAssebler for key-value pair.
+ *
+ * @param key Key object.
+ * @param val Value object.
+ * @return Tuple assembler.
+ * @throws SerializationException If failed.
+ */
+ @NotNull private TupleAssembler createAssembler(Object key, Object val) throws SerializationException {
+ ObjectStatistic keyStat = collectObjectStats(schema.keyColumns(), keyMarsh, key);
+ ObjectStatistic valStat = collectObjectStats(schema.valueColumns(), valMarsh, val);
+
+ int size = TupleAssembler.tupleSize(
+ schema.keyColumns(), keyStat.nonNullFields, keyStat.nonNullFieldsSize,
+ schema.valueColumns(), valStat.nonNullFields, valStat.nonNullFieldsSize);
+
+ return new TupleAssembler(schema, size, keyStat.nonNullFields, valStat.nonNullFields);
+ }
+
+ /**
+ * Object statistic.
+ */
+ private static class ObjectStatistic {
+ /** Non-null fields of varlen type. */
+ int nonNullFields;
+
+ /** Length of all non-null fields of varlen types. */
+ int nonNullFieldsSize;
+
+ /** Constructor. */
+ public ObjectStatistic(int nonNullFields, int nonNullFieldsSize) {
+ this.nonNullFields = nonNullFields;
+ this.nonNullFieldsSize = nonNullFieldsSize;
+ }
+ }
+
+ /**
+ * Reads object fields and gather statistic.
+ *
+ * @param cols Schema columns.
+ * @param marsh Marshaller.
+ * @param obj Object.
+ * @return Object statistic.
+ * @throws SerializationException If failed.
+ */
+ private ObjectStatistic collectObjectStats(Columns cols, Marshaller marsh,
+ Object obj) throws SerializationException {
+ if (obj == null || cols.firstVarlengthColumn() < 0 /* No varlen columns */)
+ return new ObjectStatistic(0, 0);
+
+ int cnt = 0;
int size = 0;
- int nonNullVarLenKeyCols = keyMarsh.nonNullVarLenCols(key);
- int nonNullVarLenValCols = valMarsh.nonNullVarLenCols(val);
+ for (int i = cols.firstVarlengthColumn(); i < cols.length(); i++) {
+ final Object val = marsh.value(obj, i);
- final TupleAssembler asm = new TupleAssembler(schema, size, nonNullVarLenKeyCols, nonNullVarLenValCols);
+ if (val == null || cols.column(i).type().spec().fixedLength())
+ continue;
- keyMarsh.writeObject(key, asm);
- valMarsh.writeObject(val, asm); // TODO: support tomstones.
+ size += getValueSize(val, cols.column(i).type());
+ cnt++;
+ }
- return asm.build();
+ return new ObjectStatistic(cnt, size);
+ }
+
+ /**
+ * Calculates size for serialized value of varlen type.
+ *
+ * @param val Field value.
+ * @param type Mapped type.
+ * @return Serialized value size.
+ */
+ private int getValueSize(Object val, NativeType type) {
+ switch (type.spec()) {
+ case BYTES:
+ return ((byte[])val).length;
+
+ case STRING:
+ return TupleAssembler.utf8EncodedLength((CharSequence)val);
+
+ default:
+ throw new IllegalStateException("Unsupported test varsize type: " + type);
+ }
+ }
+
+ /**
+ * @return Key object.
+ */
+ public Object deserializeKey(byte[] data) throws SerializationException {
+ final Tuple tuple = new ByteBufferTuple(schema, data);
+
+ final Object o = keyMarsh.readObject(tuple);
+
+ assert keyClass.isInstance(o);
+
+ return o;
+ }
+
+ /**
+ * @return Value object.
+ */
+ public Object deserializeValue(byte[] data) throws SerializationException {
+ final Tuple tuple = new ByteBufferTuple(schema, data);
+
+ // TODO: add tomstone support.
+
+ final Object o = valMarsh.readObject(tuple);
+
+ assert valClass.isInstance(o);
+
+ return o;
}
}
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/Marshaller.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/Marshaller.java
index d1e0a12..eb886c2 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/Marshaller.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/Marshaller.java
@@ -15,34 +15,79 @@
* limitations under the License.
*/
+/*
+ * 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.internal.schema.marshaller;
+import java.util.Objects;
import org.apache.ignite.internal.schema.Tuple;
import org.apache.ignite.internal.schema.TupleAssembler;
/**
- * Marshaller interface.
+ * Marshaller.
*/
-public interface Marshaller {
+public class Marshaller {
/**
- * Counts number non-null fields of variable length types.
+ * Field accessors for mapped columns.
+ * Array has same size and order as columns.
+ */
+ private final FieldAccessor[] fieldAccessors;
+
+ /**
+ * Object factory for complex types or {@code null} for basic type.
+ */
+ private final ObjectFactory<?> factory;
+
+ /**
+ * Constructor.
+ * Creates marshaller for complex types.
*
- * @param obj Object to analyze.
- * @return Amount of non-null fields of variable length types.
- * @throws SerializationException If failed.
+ * @param factory Object factory.
+ * @param fieldAccessors Object field accessors for mapped columns.
*/
- //TODO: do we really need this to be 'public'? Would package-private in abstract class be better?
- int nonNullVarLenCols(Object obj) throws SerializationException;
+ @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType")
+ public Marshaller(ObjectFactory<?> factory, FieldAccessor[] fieldAccessors) {
+ this.fieldAccessors = fieldAccessors;
+ this.factory = Objects.requireNonNull(factory);
+ }
/**
- * Reads object field value mapped to column of given index in schema.
+ * Constructor.
+ * Creates marshaller for basic types.
+ *
+ * @param fieldAccessor Identity field accessor for object of basic type.
+ */
+ public Marshaller(FieldAccessor fieldAccessor) {
+ fieldAccessors = new FieldAccessor[] {fieldAccessor};
+ factory = null;
+ }
+
+ /**
+ * Reads object field.
*
* @param obj Object.
- * @param colIdx Column index.
+ * @param fldIdx Field index.
* @return Field value.
* @throws SerializationException If failed.
*/
- Object value(Object obj, int colIdx) throws SerializationException;
+ public Object value(Object obj, int fldIdx) throws SerializationException {
+ return fieldAccessors[fldIdx].value(obj);
+ }
/**
* Reads object from tuple.
@@ -51,7 +96,17 @@ public interface Marshaller {
* @return Object.
* @throws SerializationException If failed.
*/
- Object readObject(Tuple reader) throws SerializationException;
+ public Object readObject(Tuple reader) throws SerializationException {
+ if (isBasicMarshaller())
+ return fieldAccessors[0].read(reader);
+
+ final Object obj = factory.newInstance();
+
+ for (int fldIdx = 0; fldIdx < fieldAccessors.length; fldIdx++)
+ fieldAccessors[fldIdx].read(obj, reader);
+
+ return obj;
+ }
/**
* Write object to tuple.
@@ -60,5 +115,15 @@ public interface Marshaller {
* @param writer Tuple writer.
* @throws SerializationException If failed.
*/
- void writeObject(Object obj, TupleAssembler writer) throws SerializationException;
+ public void writeObject(Object obj, TupleAssembler writer) throws SerializationException {
+ for (int fldIdx = 0; fldIdx < fieldAccessors.length; fldIdx++)
+ fieldAccessors[fldIdx].write(obj, writer);
+ }
+
+ /**
+ * @return {@code true} if it is marshaller for basic type, {@code false} otherwise.
+ */
+ private boolean isBasicMarshaller() {
+ return factory == null;
+ }
}
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializationException.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializationException.java
index 4e3368e..aa8a497 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializationException.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/SerializationException.java
@@ -17,12 +17,17 @@
package org.apache.ignite.internal.schema.marshaller;
+/**
+ * Serialization exception.
+ */
public class SerializationException extends Exception {
+ /**
+ * Constructor.
+ *
+ * @param message Message.
+ * @param cause Cause.
+ */
public SerializationException(String message, Throwable cause) {
super(message, cause);
}
-
- public SerializationException(Throwable cause) {
- super(cause);
- }
}
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/util/IgniteUnsafeUtils.java b/modules/commons/src/main/java/org/apache/ignite/internal/util/IgniteUnsafeUtils.java
new file mode 100644
index 0000000..3bce3df
--- /dev/null
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/util/IgniteUnsafeUtils.java
@@ -0,0 +1,57 @@
+/*
+ *
+ * * 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.internal.util;
+
+import java.lang.reflect.Field;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import sun.misc.Unsafe;
+
+//TODO Move class to 'java-8' profile. Java9+ should use varhandles instead.
+public class IgniteUnsafeUtils {
+ /** Unsafe. */
+ private static final Unsafe UNSAFE = unsafe();
+ /**
+ * @return Instance of Unsafe class.
+ */
+ private static Unsafe unsafe() {
+ try {
+ return Unsafe.getUnsafe();
+ }
+ catch (SecurityException ignored) {
+ try {
+ return AccessController.doPrivileged(
+ new PrivilegedExceptionAction<Unsafe>() {
+ @Override public Unsafe run() throws Exception {
+ Field f = Unsafe.class.getDeclaredField("theUnsafe");
+
+ f.setAccessible(true);
+
+ return (Unsafe)f.get(null);
+ }
+ });
+ }
+ catch (PrivilegedActionException e) {
+ throw new RuntimeException("Could not initialize intrinsics.", e.getCause());
+ }
+ }
+ }
+}
diff --git a/modules/commons/src/test/java/org/apache/ignite/internal/schema/SchemaTestSuite.java b/modules/commons/src/test/java/org/apache/ignite/internal/schema/SchemaTestSuite.java
index 3eded6a..af2106e 100644
--- a/modules/commons/src/test/java/org/apache/ignite/internal/schema/SchemaTestSuite.java
+++ b/modules/commons/src/test/java/org/apache/ignite/internal/schema/SchemaTestSuite.java
@@ -17,6 +17,7 @@
package org.apache.ignite.internal.schema;
+import org.apache.ignite.internal.schema.marshaller.JavaSerializerTest;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.platform.suite.api.SelectClasses;
import org.junit.runner.RunWith;
@@ -24,8 +25,10 @@ import org.junit.runner.RunWith;
/**
*
*/
+@SuppressWarnings("JUnit5Platform")
@RunWith(JUnitPlatform.class)
@SelectClasses({
+ JavaSerializerTest.class,
NativeTypeTest.class,
ColumnTest.class,
ColumnsTest.class,
diff --git a/modules/commons/src/test/java/org/apache/ignite/internal/schema/marshaller/JavaSerializerTest.java b/modules/commons/src/test/java/org/apache/ignite/internal/schema/marshaller/JavaSerializerTest.java
new file mode 100644
index 0000000..e1b4d6c
--- /dev/null
+++ b/modules/commons/src/test/java/org/apache/ignite/internal/schema/marshaller/JavaSerializerTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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.internal.schema.marshaller;
+
+import java.util.Random;
+import org.apache.ignite.internal.schema.Column;
+import org.apache.ignite.internal.schema.Columns;
+import org.apache.ignite.internal.schema.SchemaDescriptor;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.apache.ignite.internal.schema.NativeType.BYTE;
+
+public class JavaSerializerTest {
+ /** */
+ private Random rnd;
+
+ /**
+ *
+ */
+ @BeforeEach
+ public void initRandom() {
+ long seed = System.currentTimeMillis();
+
+ System.out.println("Using seed: " + seed + "L; //");
+
+ rnd = new Random(seed);
+ }
+ @Test
+ public void testBasicTypes() throws Exception {
+ Column[] keyCols = new Column[] {new Column("key", BYTE, false)};
+ Column[] valCols = new Column[] {new Column("val", BYTE, false)};
+
+ final SchemaDescriptor schema = new SchemaDescriptor(1, new Columns(keyCols), new Columns(valCols));
+
+ final JavaSerializer serializer = new JavaSerializer(schema, Byte.class, Byte.class);
+
+ final Byte key = (byte)rnd.nextInt();
+ final Byte val = (byte)rnd.nextInt();
+
+ final byte[] bytes = serializer.serialize(key, val);
+
+ Assertions.assertEquals(key, serializer.deserializeKey(bytes));
+ Assertions.assertEquals(val, serializer.deserializeValue(bytes));
+ }
+}