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 <andrey.mashen...@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)); + } +}