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/12/15 14:09:49 UTC
[ignite-3] branch ignite-13618-javapoet created (now c688848)
This is an automated email from the ASF dual-hosted git repository.
amashenkov pushed a change to branch ignite-13618-javapoet
in repository https://gitbox.apache.org/repos/asf/ignite-3.git.
at c688848 WIP.
This branch includes the following new commits:
new b993d6b Rework reflection-based Serializer with using VarHandles.
new b3223bf wip. rewrite codegen with javapoet
new c688848 WIP.
The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
[ignite-3] 03/03: WIP.
Posted by am...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
amashenkov pushed a commit to branch ignite-13618-javapoet
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
commit c688848462841423ba6102188e6eeb88eb6881fd
Author: Andrew Mashenkov <an...@gmail.com>
AuthorDate: Tue Dec 15 17:09:29 2020 +0300
WIP.
---
.../apache/ignite/internal/schema/NativeType.java | 8 +
.../internal/schema/marshaller/MarshallerUtil.java | 239 ++++++++++-
.../generator/FieldAccessExprGenerator.java | 360 ----------------
.../IdentityObjectMarshallerExprGenerator.java | 35 +-
.../generator/JaninoSerializerGenerator.java | 451 +++++----------------
.../generator/MarshallerExprGenerator.java | 114 +++---
.../marshaller/generator/TupleAccessorExpr.java | 134 +++---
.../benchmarks/SerializerBenchmarkTest.java | 43 +-
.../schema/marshaller/JavaSerializerTest.java | 88 +++-
9 files changed, 612 insertions(+), 860 deletions(-)
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/NativeType.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/NativeType.java
index 211a1e1..e5d40c7 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/NativeType.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/NativeType.java
@@ -133,4 +133,12 @@ public class NativeType implements Comparable<NativeType> {
return typeSpec.name().compareTo(o.typeSpec.name());
}
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return "NativeType{" +
+ "typeSpec=" + typeSpec +
+ ", len=" + len +
+ '}';
+ }
}
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerUtil.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerUtil.java
index f43f9b5..d799ad8 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerUtil.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerUtil.java
@@ -17,11 +17,40 @@
package org.apache.ignite.internal.schema.marshaller;
+import com.squareup.javapoet.JavaFile;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLClassLoader;
import java.util.BitSet;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
import java.util.UUID;
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticCollector;
+import javax.tools.FileObject;
+import javax.tools.ForwardingJavaFileManager;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
import org.apache.ignite.internal.schema.NativeType;
import org.apache.ignite.internal.schema.TupleAssembler;
import org.apache.ignite.internal.util.ObjectFactory;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import static javax.tools.StandardLocation.CLASS_PATH;
/**
* Marshaller utility class.
@@ -97,7 +126,7 @@ public final class MarshallerUtil {
return null;
}
- public static <T> ObjectFactory<T> factoryForClass(Class<T> type) {
+ public static <T> ObjectFactory<T> factoryForClass(Class<T> type) {
if (mode(type) == null)
return new ObjectFactory<>(type);
else
@@ -109,4 +138,212 @@ public final class MarshallerUtil {
*/
private MarshallerUtil() {
}
+
+ public static ClassLoader compileCode(JavaFile javafile) {
+ return compileCode(javafile, null);
+ }
+
+ public static ClassLoader compileCode(JavaFile javafile, Map<String, byte[]> classes) {
+ final JavaCompiler cmp = ToolProvider.getSystemJavaCompiler();
+
+ final Map<String, byte[]> classes0 = classes == null ? new HashMap<>() : classes;
+
+ try (final MemoryJavaFileManager fileManager = new MemoryJavaFileManager(cmp.getStandardFileManager(null, null, null), classes0)) {
+ DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
+
+ JavaCompiler.CompilationTask task = cmp.getTask(null, fileManager, diagnostics, null, null, Collections.singletonList(javafile.toJavaFileObject()));
+
+ final MemoryClassLoader loader = new MemoryClassLoader(fileManager.getClasses(), ClassLoader.getSystemClassLoader());
+
+ if (task.call())
+ return loader;
+
+ // TODO: write to log.
+ for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
+ System.out.println(diagnostic.getCode());
+ System.out.println(diagnostic.getKind());
+ System.out.println(diagnostic.getPosition());
+ System.out.println(diagnostic.getStartPosition());
+ System.out.println(diagnostic.getEndPosition());
+ System.out.println(diagnostic.getSource());
+ System.out.println(diagnostic.getMessage(null));
+ }
+
+ throw new IllegalStateException("Failed to compile code:\n" + javafile.toString());
+ }
+ catch (IOException ex) {
+ throw new IllegalStateException("Failed to compile code.", ex);
+ }
+ }
+
+ private static class MemoryJavaFileManager extends ForwardingJavaFileManager<JavaFileManager> {
+ private final Map<String, byte[]> classes;
+
+ public MemoryJavaFileManager(JavaFileManager fileManager, Map<String, byte[]> classes) {
+ super(fileManager);
+
+ this.classes = classes;
+ }
+
+ Map<String, byte[]> getClasses() {
+ return classes;
+ }
+
+ /**
+ * A file object that stores Java bytecode into the classBytes map.
+ */
+ private class ClassOutputBuffer extends SimpleJavaFileObject {
+ private final String classname;
+
+ ClassOutputBuffer(String classname) {
+ super(URI.create(classname), Kind.CLASS);
+ this.classname = classname;
+ }
+
+ @Override public OutputStream openOutputStream() {
+ return new ByteArrayOutputStream() {
+ @Override public void close() throws IOException {
+ super.close();
+
+ classes.put(classname, toByteArray());
+ }
+ };
+ }
+ }
+
+ @Override public ClassLoader getClassLoader(Location location) {
+ return new MemoryClassLoader(classes, super.getClassLoader(location));
+ }
+ /*
+ @Override
+ public Iterable<JavaFileObject> list(Location location, String packageName, Set<JavaFileObject.Kind> kinds,
+ boolean recurse) throws IOException {
+ final Iterable<JavaFileObject> it = super.list(location, packageName, kinds, recurse);
+
+ if (location == CLASS_PATH) {
+ assert kinds.contains(JavaFileObject.Kind.CLASS);
+
+ Iterable<JavaFileObject> localClasses = new Iterable<>() {
+ @NotNull @Override public Iterator<JavaFileObject> iterator() {
+ return classes.keySet().stream().map(cn -> getJavaFileObjectByName(cn)).iterator();
+ }
+ };
+
+ return concat(localClasses, it);
+ }
+ else
+ return it;
+ }*/
+
+
+ @Override public boolean contains(Location location, FileObject fo) throws IOException {
+ return super.contains(location, fo);
+ }
+
+ @Override public JavaFileObject getJavaFileForInput(Location location, String className,
+ JavaFileObject.Kind kind) throws IOException {
+ if (location == StandardLocation.CLASS_OUTPUT) {
+ JavaFileObject javaFileObject = getJavaFileObjectByName(className);
+
+ if (javaFileObject != null)
+ return javaFileObject;
+ }
+
+ return fileManager.getJavaFileForInput(location, className, kind);
+ }
+
+ @Nullable private JavaFileObject getJavaFileObjectByName(String className) {
+ final byte[] bytes = classes.get(className);
+
+ if (bytes != null) {
+ return new SimpleJavaFileObject(URI.create(className), JavaFileObject.Kind.OTHER) {
+ @Override public InputStream openInputStream() {
+ return new ByteArrayInputStream(bytes);
+ }
+ };
+ }
+ return null;
+ }
+
+ @Override public JavaFileObject getJavaFileForOutput(Location location,
+ String className,
+ JavaFileObject.Kind kind,
+ FileObject sibling) throws IOException {
+ if (kind == JavaFileObject.Kind.CLASS)
+ return new ClassOutputBuffer(className);
+ else
+ return super.getJavaFileForOutput(location, className, kind, sibling);
+ }
+ }
+
+ private static final class MemoryClassLoader extends URLClassLoader {
+ private static final URL[] EMPTY_URLS = new URL[0];
+
+ private final Map<String, byte[]> classBytes;
+
+ public MemoryClassLoader(Map<String, byte[]> classBytes, ClassLoader parent) {
+ super(EMPTY_URLS, parent);
+
+ this.classBytes = classBytes;
+ }
+
+ @Override protected Class<?> findClass(String className) throws ClassNotFoundException {
+ byte[] buf = classBytes.get(className); // clear the bytes in map -- we don't need it anymore
+
+ if (buf != null)
+ return defineClass(className, buf, 0, buf.length);
+ else
+ return super.findClass(className);
+ }
+
+ @Override public Class<?> loadClass(String name) throws ClassNotFoundException {
+ return super.loadClass(name);
+ }
+ }
+
+ public static <E> Iterable<E> concat(
+ Iterable<? extends E> i1,
+ Iterable<? extends E> i2) {
+ return new Iterable<E>() {
+ @Override public Iterator<E> iterator() {
+ return new Iterator<E>() {
+ Iterator<? extends E> listIterator = i1.iterator();
+ Boolean checkedHasNext;
+ E nextValue;
+ private boolean startTheSecond;
+
+ void theNext() {
+ if (listIterator.hasNext()) {
+ checkedHasNext = true;
+ nextValue = listIterator.next();
+ }
+ else if (startTheSecond)
+ checkedHasNext = false;
+ else {
+ startTheSecond = true;
+ listIterator = i2.iterator();
+ theNext();
+ }
+ }
+
+ @Override public boolean hasNext() {
+ if (checkedHasNext == null)
+ theNext();
+ return checkedHasNext;
+ }
+
+ @Override public E next() {
+ if (!hasNext())
+ throw new NoSuchElementException();
+ checkedHasNext = null;
+ return nextValue;
+ }
+
+ @Override public void remove() {
+ listIterator.remove();
+ }
+ };
+ }
+ };
+ }
}
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/FieldAccessExprGenerator.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/FieldAccessExprGenerator.java
deleted file mode 100644
index fb3736a..0000000
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/FieldAccessExprGenerator.java
+++ /dev/null
@@ -1,360 +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.generator;
-
-import org.apache.ignite.internal.schema.marshaller.BinaryMode;
-import org.jetbrains.annotations.Nullable;
-
-import static org.apache.ignite.internal.schema.marshaller.generator.JaninoSerializerGenerator.LF;
-
-/**
- * Object field access expression generators.
- */
-class FieldAccessExprGenerator {
- /** Append null expression. */
- private static final String WRITE_NULL_EXPR = "asm.appendNull();";
-
- /**
- * Created object access expressions generator.
- *
- * @param mode Field access binary mode.
- * @param colIdx Column absolute index in schema.
- * @return Object field access expressions generator.
- */
- static FieldAccessExprGenerator createIdentityAccessor(BinaryMode mode, int colIdx) {
- return createAccessor(mode, colIdx, -1L);
- }
-
- /**
- * Created object field access expressions generator.
- *
- * @param mode Field access binary mode.
- * @param colIdx Column absolute index in schema.
- * @param offset Object field offset.
- * @return Object field access expressions generator.
- */
- static FieldAccessExprGenerator createAccessor(BinaryMode mode, int colIdx, long offset) {
- switch (mode) {
- case BYTE:
- return new FieldAccessExprGenerator(
- colIdx,
- "Byte",
- "tuple.byteValueBoxed",
- "asm.appendByte",
- offset);
-
- case P_BYTE:
- return new FieldAccessExprGenerator(
- colIdx,
- "tuple.byteValue",
- "asm.appendByte",
- offset,
- "IgniteUnsafeUtils.getByteField",
- "IgniteUnsafeUtils.putByteField"
- );
-
- case SHORT:
- return new FieldAccessExprGenerator(
- colIdx,
- "Short",
- "tuple.shortValueBoxed",
- "asm.appendShort",
- offset);
-
- case P_SHORT:
- return new FieldAccessExprGenerator(
- colIdx,
- "tuple.shortValue",
- "asm.appendShort",
- offset,
- "IgniteUnsafeUtils.getShortField",
- "IgniteUnsafeUtils.putShortField"
- );
-
- case INT:
- return new FieldAccessExprGenerator(
- colIdx,
- "Integer",
- "tuple.intValueBoxed",
- "asm.appendInt",
- offset);
-
- case P_INT:
- return new FieldAccessExprGenerator(
- colIdx,
- "tuple.intValue",
- "asm.appendInt",
- offset,
- "IgniteUnsafeUtils.getIntField",
- "IgniteUnsafeUtils.putIntField"
- );
-
- case LONG:
- return new FieldAccessExprGenerator(
- colIdx,
- "Long",
- "tuple.longValueBoxed",
- "asm.appendLong",
- offset);
-
- case P_LONG:
- return new FieldAccessExprGenerator(
- colIdx,
- "tuple.longValue",
- "asm.appendLong",
- offset,
- "IgniteUnsafeUtils.getLongField",
- "IgniteUnsafeUtils.putLongField"
- );
-
- case FLOAT:
- return new FieldAccessExprGenerator(
- colIdx,
- "Float",
- "tuple.floatValueBoxed",
- "asm.appendFloat",
- offset);
-
- case P_FLOAT:
- return new FieldAccessExprGenerator(
- colIdx,
- "tuple.floatValue",
- "asm.appendFloat",
- offset,
- "IgniteUnsafeUtils.getFloatField",
- "IgniteUnsafeUtils.putFloatField"
- );
-
- case DOUBLE:
- return new FieldAccessExprGenerator(
- colIdx,
- "Double",
- "tuple.doubleValueBoxed",
- "asm.appendDouble",
- offset);
-
- case P_DOUBLE:
- return new FieldAccessExprGenerator(
- colIdx,
- "tuple.doubleValue",
- "asm.appendDouble",
- offset,
- "IgniteUnsafeUtils.getDoubleField",
- "IgniteUnsafeUtils.putDoubleField"
- );
-
- case UUID:
- return new FieldAccessExprGenerator(
- colIdx,
- "UUID",
- "tuple.uuidValue", "asm.appendUuid",
- offset);
-
- case BITSET:
- return new FieldAccessExprGenerator(
- colIdx,
- "BitSet",
- "tuple.bitmaskValue", "asm.appendBitmask",
- offset);
-
- case STRING:
- return new FieldAccessExprGenerator(
- colIdx,
- "String",
- "tuple.stringValue", "asm.appendString",
- offset);
-
- case BYTE_ARR:
- return new FieldAccessExprGenerator(
- colIdx,
- "byte[]",
- "tuple.bytesValue", "asm.appendBytes",
- offset);
- default:
- throw new IllegalStateException("Unsupportd binary mode");
- }
- }
-
- /** Object field offset or {@code -1} for identity accessor. */
- private final long offset;
-
- /** Absolute schema index. */
- private final int colIdx;
-
- /** Class cast expression. */
- private final String classExpr;
-
- /** Write column value expression. */
- private final String writeColMethod;
-
- /** Read column value expression. */
- private final String readColMethod;
-
- /** Read object field expression. */
- private final String getFieldMethod;
-
- /** Write object field expression. */
- private final String putFieldMethod;
-
- /**
- * Constructor.
- *
- * @param colIdx Absolute schema index in schema.
- * @param castClassExpr Class cast expression
- * @param readColMethod Read column value expression.
- * @param writeColMethod Write column value expression.
- * @param offset Field offset or {@code -1} for identity accessor.
- */
- private FieldAccessExprGenerator(
- int colIdx,
- String castClassExpr,
- String readColMethod,
- String writeColMethod,
- long offset
- ) {
- this(colIdx, castClassExpr, readColMethod, writeColMethod, offset,
- "IgniteUnsafeUtils.getObjectField", "IgniteUnsafeUtils.putObjectField");
- }
-
- /**
- * Constructor.
- *
- * @param colIdx Absolute schema index in schema.
- * @param readColMethod Read column value expression.
- * @param writeColMethod Write column value expression.
- * @param offset Field offset or {@code -1} for identity accessor.
- * @param getFieldMethod Read object field expression.
- * @param putFieldMethod Read object field expression.
- */
- public FieldAccessExprGenerator(
- int colIdx,
- String readColMethod,
- String writeColMethod,
- long offset,
- String getFieldMethod,
- String putFieldMethod
- ) {
- this(colIdx, null /* primitive type */, readColMethod, writeColMethod, offset, getFieldMethod, putFieldMethod);
- }
-
- /**
- * Constructor.
- *
- * @param colIdx Absolute schema index in schema.
- * @param castClassExpr Class cast expression or {@code null} if not applicable.
- * @param readColMethod Read column value expression.
- * @param writeColMethod Write column value expression.
- * @param offset Field offset or {@code -1} for identity accessor.
- * @param getFieldMethod Read object field expression.
- * @param putFieldMethod Read object field expression.
- */
- private FieldAccessExprGenerator(
- int colIdx,
- @Nullable String castClassExpr,
- String readColMethod,
- String writeColMethod,
- long offset,
- String getFieldMethod,
- String putFieldMethod
- ) {
- this.offset = offset;
- this.colIdx = colIdx;
- this.classExpr = castClassExpr;
- this.putFieldMethod = putFieldMethod;
- this.getFieldMethod = getFieldMethod;
- this.writeColMethod = writeColMethod;
- this.readColMethod = readColMethod;
- }
-
- /**
- * @return {@code true} if it is primitive typed field accessor, {@code false} otherwise.
- */
- private boolean isPrimitive() {
- return classExpr == null;
- }
-
- /**
- * @return {@code true} if is identity accessor, {@code false} otherwise.
- */
- private boolean isIdentityAccessor() {
- return offset == -1;
- }
-
- /**
- * @return Object field value access expression or object value expression for simple types.
- */
- public String getFieldExpr() {
- if (isIdentityAccessor())
- return "obj"; // Identity accessor.
-
- return getFieldMethod + "(obj, " + offset + ')';
- }
-
- /**
- * Appends write value to field expression.
- *
- * @param sb String bulder.
- * @param valueExpression Value expression.
- * @param indent Line indentation.
- */
- public final void appendPutFieldExpr(StringBuilder sb, String valueExpression, String indent) {
- sb.append(indent).append(putFieldMethod).append("(obj, ").append(offset).append(", ").append(valueExpression).append(')');
- sb.append(";" + LF);
- }
-
- /**
- * Appends write value to column expression.
- *
- * @param sb String bulder.
- * @param valueExpr Value expression.
- * @param indent Line indentation.
- */
- public final void appendWriteColumnExpr(StringBuilder sb, String valueExpr, String indent) {
- if (isPrimitive() || isIdentityAccessor()) {
- // Translate to:
- // asm.appendX((T) %value%);
- // or for primitive value:
- // asm.appendX(%value%);
- sb.append(indent).append(writeColMethod).append('(');
-
- if (classExpr != null)
- sb.append("(").append(classExpr).append(")");
-
- sb.append(valueExpr).append(");" + LF);
-
- return;
- }
-
- assert classExpr != null;
-
- // Translate to:
- // { T fVal = (T)%value%;
- // if (fVal == null) asm.appendNull() else asm.appendX(fVal); }
- sb.append(indent).append("{ ").append(classExpr).append(" fVal = (").append(classExpr).append(')').append(valueExpr).append(";" + LF);
- sb.append(indent).append("if (fVal == null) " + WRITE_NULL_EXPR + LF);
- sb.append(indent).append("else ").append(writeColMethod).append("(fVal); }" + LF);
-
- }
-
- /**
- * @return Column value read expression.
- */
- public String readColumnExpr() {
- return readColMethod + "(" + colIdx + ")";
- }
-}
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/IdentityObjectMarshallerExprGenerator.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/IdentityObjectMarshallerExprGenerator.java
index f86bc0b..9d292c7 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/IdentityObjectMarshallerExprGenerator.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/IdentityObjectMarshallerExprGenerator.java
@@ -18,6 +18,7 @@
package org.apache.ignite.internal.schema.marshaller.generator;
import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.TypeSpec;
import org.apache.ignite.internal.schema.marshaller.Serializer;
/**
@@ -27,37 +28,37 @@ class IdentityObjectMarshallerExprGenerator extends MarshallerExprGenerator {
/**
* Constructor.
*
- * @param accessor Object field access expression generators.
- * @param tupleAccessorGen
+ * @param aClass
+ * @param tupleAccessorGen Object field access expression generators.
*/
- IdentityObjectMarshallerExprGenerator(FieldAccessExprGenerator accessor,
- TupleAccessorExpr tupleAccessorGen) {
- super(
- null /* no instantiation needed */,
- new FieldAccessExprGenerator[] {accessor},
- new TupleAccessorExpr[] {tupleAccessorGen}
- );
-
+ IdentityObjectMarshallerExprGenerator(Class<?> aClass, TupleAccessorExpr tupleAccessorGen) {
+ super(aClass, null /* no instantiation needed */, new TupleAccessorExpr[] {tupleAccessorGen});
}
/** {@inheritDoc} */
- @Override public void appendMarshallObjectExpr(StringBuilder sb, String indent) {
- for (int i = 0; i < accessors.length; i++)
- accessors[i].appendWriteColumnExpr(sb, "obj", indent);
+ @Override boolean isSimpleType() {
+ return true;
}
/** {@inheritDoc} */
- @Override public void appendUnmarshallObjectExpr(StringBuilder sb, String indent) {
- sb.append(indent).append("Object obj = ").append(accessors[0].readColumnExpr()).append(";" + JaninoSerializerGenerator.LF);
- }
-
@Override public CodeBlock unmarshallObjectCode(String tupleExpr) {
return CodeBlock.builder()
.add("return ").addStatement(tupleAccessors[0].read(tupleExpr))
.build();
}
+ /** {@inheritDoc} */
@Override public CodeBlock marshallObjectCode(String asm, String objVar) {
return tupleAccessors[0].write(asm, objVar);
}
+
+ /** {@inheritDoc} */
+ @Override public CodeBlock getValueCode(String objVar, int colIdx) {
+ return CodeBlock.of(objVar);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void staticHandlers(TypeSpec.Builder builder, CodeBlock.Builder staticBuilder) {
+
+ }
}
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/JaninoSerializerGenerator.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/JaninoSerializerGenerator.java
index a45a8be..9de4011 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/JaninoSerializerGenerator.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/JaninoSerializerGenerator.java
@@ -24,15 +24,13 @@ import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
-import java.lang.invoke.VarHandle;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
+import java.util.Map;
import javax.annotation.processing.Generated;
import javax.lang.model.element.Modifier;
-import javax.tools.JavaCompiler;
import javax.tools.JavaFileManager;
-import javax.tools.ToolProvider;
import org.apache.ignite.internal.schema.ByteBufferTuple;
import org.apache.ignite.internal.schema.Columns;
import org.apache.ignite.internal.schema.SchemaDescriptor;
@@ -44,16 +42,9 @@ import org.apache.ignite.internal.schema.marshaller.SerializationException;
import org.apache.ignite.internal.schema.marshaller.Serializer;
import org.apache.ignite.internal.schema.marshaller.SerializerFactory;
import org.apache.ignite.internal.util.ObjectFactory;
-import org.codehaus.commons.compiler.IClassBodyEvaluator;
-import org.codehaus.janino.ClassLoaderIClassLoader;
-import org.codehaus.janino.Compiler;
-import org.codehaus.janino.util.ResourceFinderClassLoader;
-import org.codehaus.janino.util.resource.MapResourceCreator;
-import org.codehaus.janino.util.resource.MapResourceFinder;
-import org.codehaus.janino.util.resource.Resource;
-import org.codehaus.janino.util.resource.StringResource;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.TestOnly;
/**
* {@link Serializer} code generator backed with Janino.
@@ -64,17 +55,7 @@ public class JaninoSerializerGenerator implements SerializerFactory {
public static final String SERIALIZER_CLASS_NAME_PREFIX = "JaninoSerializerForSchema_";
- /** Tabulate. */
- static final String TAB = " ";
-
- /** Line feed. */
- static final char LF = '\n';
-
- /** String buffer initial size. */
- public static final int INITIAL_BUFFER_SIZE = 8 * 1024;
-
- /** Debug flag. */
- private static final boolean enabledDebug = true;
+ private Map<String, byte[]> classes;
/** {@inheritDoc} */
@Override public Serializer create(
@@ -85,52 +66,31 @@ public class JaninoSerializerGenerator implements SerializerFactory {
// Generate Serializer code.
final String className = SERIALIZER_CLASS_NAME_PREFIX + schema.version();
- String code = generateSerializerClassCode(className, schema, keyClass, valClass);
+ JavaFile javaFile = generateSerializerClassCode(className, schema, keyClass, valClass);
//TODO: pass code to logger on trace level.
+ System.out.println(javaFile.toString());
- final HashMap<String, byte[]> classes = new HashMap<>();
- final Compiler cmp = new Compiler(
- new MapResourceFinder(classes),
- new ClassLoaderIClassLoader(getClass().getClassLoader())
- );
-
- cmp.setClassFileCreator(new MapResourceCreator(classes));
-
- if (enabledDebug) {
- cmp.setDebugSource(true);
- cmp.setDebugLines(true);
- cmp.setDebugVars(true);
- cmp.setVerbose(true);
-
- System.out.print(code);
- }
-
- try { // Compile code.
- cmp.compile(new Resource[] {
- new StringResource("file", code)});
-
- ClassLoader cl = new ResourceFinderClassLoader(
- new MapResourceFinder(classes),
- getClass().getClassLoader()
- );
+ final ClassLoader loader = MarshallerUtil.compileCode(javaFile, classes);
- // Load class and create instance.
- final Class<?> aClass = cl.loadClass(SERIALIZER_PACKAGE_NAME + '.' + className);
+ try {
+ final Class<?> aClass = loader.loadClass(javaFile.packageName + '.' + className);
- final Constructor<Serializer> ctor = (Constructor<Serializer>)aClass
- .getDeclaredConstructor(schema.getClass(), Class.class, Class.class);
+ return (Serializer)aClass
+ .getDeclaredConstructor(SchemaDescriptor.class, Class.class, Class.class)
+ .newInstance(schema, keyClass, valClass);
- return ctor.newInstance(schema, keyClass, valClass);
}
- catch (Throwable ex) {
- if (enabledDebug)
- throw new IllegalStateException("Failed to compile generated Serializer code:\n" + code, ex);
- else
- throw new IllegalStateException("Failed to compile/instantiate generated Serializer.", ex);
+ catch (InstantiationException | ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+ throw new IllegalStateException(e);
}
}
+ @TestOnly
+ public void setClasses(Map<String, byte[]> classes) {
+ this.classes = classes;
+ }
+
/**
* Generates serializer code.
*
@@ -138,50 +98,46 @@ public class JaninoSerializerGenerator implements SerializerFactory {
* @param valClass Value class.
* @return Generated class code.
*/
- private String generateSerializerClassCode(String className, SchemaDescriptor schema, Class<?> keyClass,
+ private JavaFile generateSerializerClassCode(String className, SchemaDescriptor schema, Class<?> keyClass,
Class<?> valClass) {
try {
- final StringBuilder sb = new StringBuilder();
-
// Build field accessor generators.
- final MarshallerExprGenerator keyMarsh = createObjectMarshaller(valClass, "valFactory", schema.valueColumns(), schema.keyColumns().length());
- final MarshallerExprGenerator valMarsh = createObjectMarshaller(valClass, "valFactory", schema.valueColumns(), schema.keyColumns().length());
-
- JavaFile
- .builder(
- SERIALIZER_PACKAGE_NAME,
- TypeSpec.classBuilder(className)
- .addSuperinterface(Serializer.class)
+ final MarshallerExprGenerator keyMarsh = createObjectMarshaller(keyClass, "keyFactory", schema.keyColumns(), 0);
+ final MarshallerExprGenerator valMarsh = createObjectMarshaller(valClass, "valFactory", schema.valueColumns(), schema.valueColumns().length());
+
+ final TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className)
+ .addSuperinterface(Serializer.class)
+ .addModifiers(Modifier.PUBLIC)
+ .addAnnotation(AnnotationSpec.builder(Generated.class).addMember("value", "$S", getClass().getCanonicalName()).build());
+
+ initFieldHandlers(keyMarsh, valMarsh, classBuilder);
+
+ classBuilder.addField(SchemaDescriptor.class, "schema", Modifier.PRIVATE, Modifier.FINAL)
+ .addField(ObjectFactory.class, "keyFactory", Modifier.PRIVATE, Modifier.FINAL)
+ .addField(ObjectFactory.class, "valFactory", Modifier.PRIVATE, Modifier.FINAL)
+ .addMethod(
+ MethodSpec.constructorBuilder()
.addModifiers(Modifier.PUBLIC)
- .addAnnotation(AnnotationSpec.builder(Generated.class).addMember("value", getClass().getCanonicalName()).build())
- .addField(SchemaDescriptor.class, "schema", Modifier.PRIVATE, Modifier.FINAL)
- .addField(ObjectFactory.class, "keyFactory", Modifier.PRIVATE, Modifier.FINAL)
- .addField(ObjectFactory.class, "valFactory", Modifier.PRIVATE, Modifier.FINAL)
- .addField(ArrayTypeName.of(VarHandle.class), "fieldAccessors", Modifier.PRIVATE, Modifier.FINAL)
- .addMethod(
- MethodSpec.constructorBuilder()
- .addModifiers(Modifier.PUBLIC)
- .addParameter(SchemaDescriptor.class, "schema")
- .addParameter(Class.class, "keyClass")
- .addParameter(Class.class, "valClass")
- .addStatement("this.schema = schema")
- .addStatement("this.keyFactory = $T.factoryForClass(keyClass)", MarshallerUtil.class)
- .addStatement("this.valFactory = $T.factoryForClass(keyClass)", MarshallerUtil.class)
- .addStatement("this.fieldAccessors = null")
- .build()
- )
- .addMethod(generateHelpersMetod(schema))
- .addMethod(generateSerializeMethod(keyMarsh, valMarsh))
- .addMethod(generateDeserializeKeyMethod(keyMarsh))
- .addMethod(generateDeserializeValueMethod())
+ .addParameter(SchemaDescriptor.class, "schema")
+ .addParameter(Class.class, "keyClass")
+ .addParameter(Class.class, "valClass")
+ .addStatement("this.schema = schema")
+ .addStatement("this.keyFactory = $T.factoryForClass(keyClass)", MarshallerUtil.class)
+ .addStatement("this.valFactory = $T.factoryForClass(valClass)", MarshallerUtil.class)
.build()
)
+ .addMethod(generateHelpersMetod(schema, keyMarsh, valMarsh))
+ .addMethod(generateSerializeMethod(keyMarsh, valMarsh))
+ .addMethod(generateDeserializeKeyMethod(keyMarsh))
+ .addMethod(generateDeserializeValueMethod(valMarsh));
+
+ return JavaFile
+ .builder(SERIALIZER_PACKAGE_NAME, classBuilder.build())
+ .addStaticImport(TupleAccessorExpr.class, "*")
+ .addStaticImport(MethodHandles.class, "Lookup")
.skipJavaLangImports(true)
- .indent(TAB)
- .build()
- .writeTo(sb);
-
- return sb.toString();
+ .indent(" ")
+ .build();
}
catch (Exception ex) {
//TODO: fallback to java serializer?
@@ -189,7 +145,33 @@ public class JaninoSerializerGenerator implements SerializerFactory {
}
}
- private MethodSpec generateHelpersMetod(SchemaDescriptor schema) {
+ private void initFieldHandlers(MarshallerExprGenerator keyMarsh, MarshallerExprGenerator valMarsh,
+ TypeSpec.Builder classBuilder) {
+ if (keyMarsh.isSimpleType() && valMarsh.isSimpleType())
+ return;
+
+ final CodeBlock.Builder staticInitBuilder = CodeBlock.builder()
+ .addStatement("$T.Lookup lookup", MethodHandles.class)
+ .beginControlFlow("try");
+
+ if (!keyMarsh.isSimpleType()) {
+ staticInitBuilder.addStatement("lookup = $T.privateLookupIn($T.class, $T.lookup())", MethodHandles.class, keyMarsh.getClazz(), MethodHandles.class);
+ keyMarsh.staticHandlers(classBuilder, staticInitBuilder);
+ }
+
+ if (!valMarsh.isSimpleType()) {
+ staticInitBuilder.addStatement("lookup = $T.privateLookupIn($T.class, $T.lookup())", MethodHandles.class, valMarsh.getClazz(), MethodHandles.class);
+ valMarsh.staticHandlers(classBuilder, staticInitBuilder);
+ }
+
+ staticInitBuilder.nextControlFlow("catch ($T | $T ex)", ReflectiveOperationException.class, SecurityException.class)
+ .addStatement("throw new $T(ex)", IllegalStateException.class)
+ .endControlFlow();
+
+ classBuilder.addStaticBlock(staticInitBuilder.build());
+ }
+
+ private MethodSpec generateHelpersMetod(SchemaDescriptor schema, MarshallerExprGenerator keyMarsh, MarshallerExprGenerator valMarsh) {
final MethodSpec.Builder builder = MethodSpec
.methodBuilder("createAssembler")
.addModifiers(Modifier.PRIVATE)
@@ -210,9 +192,9 @@ public class JaninoSerializerGenerator implements SerializerFactory {
for (int i = keyCols.firstVarlengthColumn(); i < keyCols.length(); i++) {
assert !keyCols.column(i).type().spec().fixedLength();
- block.addStatement("assert !keyCols.column($L).type().spec().fixedLength()", i)
- .addStatement("fVal = fieldAccessors[$L].get(key)", i)
- .beginControlFlow("if (fVal != null)")
+ block.addStatement("fVal = $L", keyMarsh.getValueCode("key", i).toString());
+
+ block.beginControlFlow("if (fVal != null)")
.addStatement("nonNullVarlenKeysSize += $T.getValueSize(fVal, keyCols.column($L).type())", MarshallerUtil.class, i)
.addStatement("nonNullVarlenKeys++")
.endControlFlow();
@@ -225,7 +207,7 @@ public class JaninoSerializerGenerator implements SerializerFactory {
.addCode("}\n");
}
- Columns valCols = schema.keyColumns();
+ Columns valCols = schema.valueColumns();
if (valCols.firstVarlengthColumn() >= 0) {
final CodeBlock.Builder block = CodeBlock.builder().indent()
.addStatement("$T fVal", Object.class);// Temporary vars.
@@ -233,9 +215,9 @@ public class JaninoSerializerGenerator implements SerializerFactory {
for (int i = valCols.firstVarlengthColumn(); i < valCols.length(); i++) {
assert !valCols.column(i).type().spec().fixedLength();
- block.addStatement("assert !valCols.column($L).type().spec().fixedLength()", i)
- .addStatement("fVal = fieldAccessors[$L].get(val)", i + schema.keyColumns().length())
- .beginControlFlow("if (fVal != null)")
+ block.addStatement("fVal = $L", valMarsh.getValueCode("val", i).toString());
+
+ block.beginControlFlow("if (fVal != null)")
.addStatement("nonNullVarlenValuesSize += $T.getValueSize(fVal, valCols.column($L).type())", MarshallerUtil.class, i)
.addStatement("nonNullVarlenValues++")
.endControlFlow();
@@ -256,7 +238,7 @@ public class JaninoSerializerGenerator implements SerializerFactory {
return builder.build();
}
- @NotNull private MethodSpec generateDeserializeValueMethod() {
+ @NotNull private MethodSpec generateDeserializeValueMethod(MarshallerExprGenerator valMarsh) {
return MethodSpec
.methodBuilder("deserializeValue")
.addAnnotation(Override.class)
@@ -264,12 +246,18 @@ public class JaninoSerializerGenerator implements SerializerFactory {
.addParameter(ArrayTypeName.of(TypeName.BYTE), "data")
.addException(SerializationException.class)
.returns(TypeName.OBJECT)
- .addStatement("return null")
- .build();
+
+ .beginControlFlow("try")
+ .addStatement("$T tuple = new $T(schema, data)", Tuple.class, ByteBufferTuple.class)
+ .addCode(valMarsh.unmarshallObjectCode("tuple"))
+
+ .nextControlFlow("catch($T th)", Throwable.class)
+ .addStatement("throw new $T(th)", SerializationException.class)
+ .endControlFlow().build();
}
@NotNull private MethodSpec generateDeserializeKeyMethod(MarshallerExprGenerator keyMarsh) {
- final MethodSpec.Builder builder = MethodSpec
+ return MethodSpec
.methodBuilder("deserializeKey")
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
@@ -283,9 +271,7 @@ public class JaninoSerializerGenerator implements SerializerFactory {
.nextControlFlow("catch($T th)", Throwable.class)
.addStatement("throw new $T(th)", SerializationException.class)
- .endControlFlow();
-
- return builder.build();
+ .endControlFlow().build();
}
@NotNull
@@ -297,7 +283,7 @@ public class JaninoSerializerGenerator implements SerializerFactory {
.addParameter(TypeName.OBJECT, "key")
.addParameter(TypeName.OBJECT, "val")
.addException(SerializationException.class)
- .returns(ArrayTypeName.of(TypeName.BYTE.unbox()))
+ .returns(ArrayTypeName.of(TypeName.BYTE))
.beginControlFlow("try")
.addStatement("$T asm = createAssembler(key, val)", TupleAssembler.class)
@@ -312,74 +298,6 @@ public class JaninoSerializerGenerator implements SerializerFactory {
}
/**
- * Generates serializer code.
- *
- * @param ce Class body evaluator.
- * @param schema Schema descriptor.
- * @param keyClass Key class.
- * @param valClass Value class.
- * @return Generated class code.
- */
- private String generateSerializerClassCode(
- IClassBodyEvaluator ce,
- SchemaDescriptor schema,
- Class<?> keyClass,
- Class<?> valClass
- ) {
- final String className = SERIALIZER_CLASS_NAME_PREFIX + schema.version();
-
- // Prerequisites.
- ce.setClassName(SERIALIZER_PACKAGE_NAME + className);
- ce.setImplementedInterfaces(new Class[] {Serializer.class});
- ce.setDefaultImports(
- "java.util.UUID",
- "java.util.BitSet",
-
- "org.apache.ignite.internal.schema.ByteBufferTuple",
- "org.apache.ignite.internal.schema.Columns",
- "org.apache.ignite.internal.schema.SchemaDescriptor",
- "org.apache.ignite.internal.schema.Tuple",
- "org.apache.ignite.internal.schema.TupleAssembler",
- "org.apache.ignite.internal.util.IgniteUnsafeUtils",
- "org.apache.ignite.internal.util.ObjectFactory"
- );
-
- // Build field accessor generators.
- final MarshallerExprGenerator keyMarsh = createObjectMarshaller(keyClass, "keyFactory", schema.keyColumns(), 0);
- final MarshallerExprGenerator valMarsh = createObjectMarshaller(valClass, "valFactory", schema.valueColumns(), schema.keyColumns().length());
-
- // Create buffer.
- final StringBuilder sb = new StringBuilder(INITIAL_BUFFER_SIZE);
-
- // Append class fields desctiption.
- sb.append("private final SchemaDescriptor schema;" + LF);
-
- if (!keyMarsh.isSimpleTypeMarshaller())
- sb.append("private final ObjectFactory keyFactory;" + LF);
- if (!valMarsh.isSimpleTypeMarshaller())
- sb.append("private final ObjectFactory valFactory;" + LF);
-
- // Append constructor code.
- sb.append(LF + "public ").append(className).append("(SchemaDescriptor schema, Class kClass, Class vClass) {" + LF);
- sb.append(TAB + "this.schema = schema; " + LF);
- if (!keyMarsh.isSimpleTypeMarshaller())
- sb.append(TAB + "keyFactory = new ObjectFactory(kClass);" + LF);
- if (!valMarsh.isSimpleTypeMarshaller())
- sb.append(TAB + "valFactory = new ObjectFactory(vClass);" + LF);
- sb.append("}" + LF);
-
- // Generate and append helper-methods.
- generateTupleFactoryMethod(sb, schema, keyMarsh, valMarsh);
-
- // Generate and append Serializer interface methods.
- appendSerializeMethod(sb, keyMarsh, valMarsh);
- writeDeserializeKeyMethod(sb, keyMarsh);
- writeDeserializeValueMethod(sb, valMarsh);
-
- return sb.toString();
- }
-
- /**
* Creates marshal/unmarshall expressions generator for object.
*
* @param aClass Object class.
@@ -397,173 +315,8 @@ public class JaninoSerializerGenerator implements SerializerFactory {
BinaryMode mode = MarshallerUtil.mode(aClass);
if (mode != null)
- return new IdentityObjectMarshallerExprGenerator(
- FieldAccessExprGenerator.createIdentityAccessor(mode, firstColIdx),
- TupleAccessorExpr.createAccessor(mode, firstColIdx)
- );
-
- FieldAccessExprGenerator[] accessors = new FieldAccessExprGenerator[columns.length()];
- TupleAccessorExpr[] tupleAccessorExprs = new TupleAccessorExpr[] {};
- try {
- for (int i = 0; i < columns.length(); i++) {
- final Field field = aClass.getDeclaredField(columns.column(i).name());
-
- accessors[i] = FieldAccessExprGenerator.createAccessor(
- MarshallerUtil.mode(field.getType()),
- firstColIdx + i /* schma absolute index. */,
- 0L);// IgniteUnsafeUtils.objectFieldOffset(field));
- }
- }
- catch (NoSuchFieldException ex) {
- throw new IllegalStateException(ex);
- }
-
- return new MarshallerExprGenerator(factoryRefExpr, accessors, tupleAccessorExprs);
- }
-
- /**
- * Appends {@link Serializer#serialize(Object, Object)} method code.
- *
- * @param sb String buffer to append to.
- * @param keyMarsh Marshall expression generator for key.
- * @param valMarsh Marshall expression generator for value.
- */
- private void appendSerializeMethod(
- StringBuilder sb,
- MarshallerExprGenerator keyMarsh,
- MarshallerExprGenerator valMarsh
- ) {
- // Mehtod signature.
- sb.append(LF + "@Override public byte[] serialize(Object key, Object val) throws SerializationException {" + LF);
- sb.append(TAB + "TupleAssembler asm = createAssembler(key, val);" + LF);
-
- // Key marshal script.
- sb.append(TAB + "{" + LF);
- sb.append(TAB + TAB + "Object obj = key;" + LF);
- keyMarsh.appendMarshallObjectExpr(sb, TAB + TAB);
- sb.append(TAB + "}" + LF);
-
- // Value marshal script.
- sb.append(TAB + " {" + LF);
- sb.append(TAB + TAB + "Object obj = val;" + LF);
- valMarsh.appendMarshallObjectExpr(sb, TAB + TAB);
- sb.append(TAB + "}" + LF);
-
- // Return statement.
- sb.append(TAB + "return asm.build();" + LF);
- sb.append("}" + LF);
- }
-
- /**
- * Appends {@link Serializer#deserializeKey(byte[])} method code.
- *
- * @param sb String buffer to append to.
- * @param keyMarsh Unmarshall expression generator for key.
- */
- private void writeDeserializeKeyMethod(StringBuilder sb, MarshallerExprGenerator keyMarsh) {
- // Mehtod signature.
- sb.append(LF + "@Override public Object deserializeKey(byte[] data) throws SerializationException {" + LF);
- sb.append(TAB + "Tuple tuple = new ByteBufferTuple(schema, data);" + LF);
-
- // Key unmarshal script.
- keyMarsh.appendUnmarshallObjectExpr(sb, TAB);
-
- // Return statement.
- sb.append(TAB + "return obj;" + LF);
- sb.append("}" + LF);
- }
-
- /**
- * Appends {@link Serializer#deserializeValue(byte[])} method code.
- *
- * @param sb String buffer to append to.
- * @param valMarsh Unmarshall expression generator for value.
- */
- private void writeDeserializeValueMethod(StringBuilder sb, MarshallerExprGenerator valMarsh) {
- // Mehtod signature.
- sb.append(LF + "@Override public Object deserializeValue(byte[] data) throws SerializationException {" + LF);
- sb.append(TAB + "Tuple tuple = new ByteBufferTuple(schema, data);" + LF);
-
- // Key unmarshal script.
- valMarsh.appendUnmarshallObjectExpr(sb, TAB);
-
- // Return statement.
- sb.append(TAB + "return obj;" + LF);
- sb.append("}" + LF);
- }
-
- /**
- * Appends helper methods code.
- *
- * @param sb String buffer to append to.
- * @param schema Schema descriptor.
- * @param keyMarsh Marshall expression generator for key.
- * @param valMarsh Marshall expression generator for value.
- */
- private void generateTupleFactoryMethod(
- StringBuilder sb,
- SchemaDescriptor schema,
- MarshallerExprGenerator keyMarsh,
- MarshallerExprGenerator valMarsh
- ) {
- // Method signature.
- sb.append(LF + "TupleAssembler createAssembler(Object key, Object val) {" + LF);
- // Local variables.
- sb.append(TAB + "int nonNullVarlenKeys = 0; int nonNullVarlenValues = 0;" + LF);
- sb.append(TAB + "int nonNullVarlenKeysSize = 0; int nonNullVarlenValuesSize = 0;" + LF);
- sb.append(LF);
- sb.append(TAB + "Columns keyCols = schema.keyColumns();" + LF);
- sb.append(TAB + "Columns valCols = schema.valueColumns();" + LF);
- sb.append(LF);
-
- Columns keyCols = schema.keyColumns();
- if (keyCols.firstVarlengthColumn() >= 0) {
- // Appends key analyzer code-block.
- sb.append(TAB + "{" + LF);
- sb.append(TAB + TAB + "Object fVal, obj = key;" + LF); // Temporary vars.
-
- for (int i = keyCols.firstVarlengthColumn(); i < keyCols.length(); i++) {
- assert !keyCols.column(i).type().spec().fixedLength();
-
- sb.append(TAB + TAB + "assert !keyCols.column(").append(i).append(").type().spec().fixedLength();" + LF);
- sb.append(TAB + TAB + "fVal = ").append(keyMarsh.accessors[i].getFieldExpr()).append(";" + LF);
- sb.append(TAB + TAB + "if (fVal != null) {" + LF);
- sb.append(TAB + TAB + TAB + "nonNullVarlenKeysSize += MarshallerUtil.getValueSize(fVal, keyCols.column(").append(i).append(").type());").append(LF);
- sb.append(TAB + TAB + TAB + "nonNullVarlenKeys++;" + LF);
- sb.append(TAB + TAB + "}" + LF);
- }
-
- sb.append(TAB + "}" + LF);
- }
-
- Columns valCols = schema.valueColumns();
- if (valCols.firstVarlengthColumn() >= 0) {
- // Appends value analyzer code-block.
- sb.append(TAB + "{" + LF);
- sb.append(TAB + TAB + "Object fVal, obj = val;" + LF); // Temporary vars.
-
- for (int i = valCols.firstVarlengthColumn(); i < valCols.length(); i++) {
- assert !valCols.column(i).type().spec().fixedLength();
-
- sb.append(TAB + TAB + "assert !valCols.column(").append(i).append(").type().spec().fixedLength();" + LF);
- sb.append(TAB + TAB + "fVal = ").append(valMarsh.accessors[i].getFieldExpr()).append(";" + LF);
- sb.append(TAB + TAB + "if (fVal != null) {" + LF);
- sb.append(TAB + TAB + TAB + "nonNullVarlenValuesSize += MarshallerUtil.getValueSize(fVal, valCols.column(").append(i).append(").type());" + LF);
- sb.append(TAB + TAB + TAB + "nonNullVarlenValues++;" + LF);
- sb.append(TAB + TAB + "}" + LF);
- }
- sb.append(TAB + "}" + LF);
- }
-
- // Calculate tuple size.
- sb.append(LF);
- sb.append(TAB + "int size = TupleAssembler.tupleSize(" + LF);
- sb.append(TAB + TAB + "keyCols, nonNullVarlenKeys, nonNullVarlenKeysSize, " + LF);
- sb.append(TAB + TAB + "valCols, nonNullVarlenValues, nonNullVarlenValuesSize); " + LF);
- sb.append(LF);
-
- // Return statement.
- sb.append(TAB + "return new TupleAssembler(schema, size, nonNullVarlenKeys, nonNullVarlenValues);" + LF);
- sb.append("}" + LF);
+ return new IdentityObjectMarshallerExprGenerator(aClass, TupleAccessorExpr.createAccessor(mode, firstColIdx));
+ else
+ return new MarshallerExprGenerator(aClass, factoryRefExpr, columns, firstColIdx);
}
}
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/MarshallerExprGenerator.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/MarshallerExprGenerator.java
index 8087e2c..53be5ed 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/MarshallerExprGenerator.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/MarshallerExprGenerator.java
@@ -18,7 +18,13 @@
package org.apache.ignite.internal.schema.marshaller.generator;
import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.TypeSpec;
import java.lang.invoke.VarHandle;
+import java.lang.reflect.Field;
+import javax.lang.model.element.Modifier;
+import org.apache.ignite.internal.schema.Columns;
+import org.apache.ignite.internal.schema.marshaller.MarshallerUtil;
import org.apache.ignite.internal.schema.marshaller.Serializer;
/**
@@ -28,93 +34,91 @@ class MarshallerExprGenerator {
/** Object factory regerence expression. */
private final String factoryRefExpr;
+ private final Class<?> tClass;
+
+ private final Columns columns;
+
/** Object field access expression generators. */
- protected FieldAccessExprGenerator[] accessors;
protected TupleAccessorExpr[] tupleAccessors;
/**
* Constructor.
*
+ * @param tClass
* @param factoryRefExpr Object factory regerence expression.
- * @param accessors Object field access expression generators.
*/
- public MarshallerExprGenerator(String factoryRefExpr, FieldAccessExprGenerator[] accessors,
- TupleAccessorExpr[] tupleAccessors) {
- this.accessors = accessors;
+ public MarshallerExprGenerator(Class<?> tClass, String factoryRefExpr, Columns columns, int firstColIdx) {
this.factoryRefExpr = factoryRefExpr;
- this.tupleAccessors = tupleAccessors;
+ this.tClass = tClass;
+
+ this.columns = columns;
+ tupleAccessors = new TupleAccessorExpr[this.columns.length()];
+ try {
+ for (int i = 0; i < columns.length(); i++) {
+ final Field field = tClass.getDeclaredField(columns.column(i).name());
+
+ tupleAccessors[i] = TupleAccessorExpr.createAccessor(MarshallerUtil.mode(field.getType()), i + firstColIdx);
+ }
+ }
+ catch (NoSuchFieldException ex) {
+ throw new IllegalStateException(ex);
+ }
}
- /**
- * @return {@code true} if it is simple object marshaller, {@code false} otherwise.
- */
- boolean isSimpleTypeMarshaller() {
- return factoryRefExpr == null;
+ public MarshallerExprGenerator(Class<?> tClass, Object expr, TupleAccessorExpr[] tupleAccessorExprs) {
+ this.factoryRefExpr = null;
+ this.tClass = tClass;
+ columns = null;
+ this.tupleAccessors = tupleAccessorExprs;
}
/**
- * Appends unmashall object code to string builder.
- *
- * @param sb String builder.
- * @param indent Line indentation.
+ * @return {@code true} if it is simple object marshaller, {@code false} otherwise.
*/
- public void appendUnmarshallObjectExpr(StringBuilder sb, String indent) {
- assert factoryRefExpr != null;
-
- sb.append(indent).append("Object obj;" + JaninoSerializerGenerator.LF);
- // Try.
- sb.append(indent).append("try {" + JaninoSerializerGenerator.LF);
- sb.append(indent).append(JaninoSerializerGenerator.TAB + "obj = ").append(factoryRefExpr).append(".create();" + JaninoSerializerGenerator.LF);
-
- // Read column from tuple to object field.
- for (int i = 0; i < accessors.length; i++)
- accessors[i].appendPutFieldExpr(sb, accessors[i].readColumnExpr(), indent + JaninoSerializerGenerator.TAB);
-
- // Catch and rethrow wrapped exeption.
- sb.append(indent).append("} catch (Exception ex) {" + JaninoSerializerGenerator.LF);
- sb.append(indent).append(JaninoSerializerGenerator.TAB + "throw new SerializationException(\"Failed to instantiate object: \" + ")
- .append(factoryRefExpr).append(".getClazz().getName(), ex);").append(JaninoSerializerGenerator.LF);
- sb.append(indent).append("}" + JaninoSerializerGenerator.LF);
+ boolean isSimpleType() {
+ return false;
}
- /**
- * Appends mashall object code to string builder.
- *
- * @param sb String builder.
- * @param indent Line indentation.
- */
- public void appendMarshallObjectExpr(StringBuilder sb, String indent) {
- // Try.
- sb.append(indent).append("try {" + JaninoSerializerGenerator.LF);
-
- // Write object field to tuple assembler.
- for (int i = 0; i < accessors.length; i++)
- accessors[i].appendWriteColumnExpr(sb, accessors[i].getFieldExpr(), indent + JaninoSerializerGenerator.TAB);
-
- // Catch and rethrow wrapped exeption.
- sb.append(indent).append("} catch (Exception ex) {" + JaninoSerializerGenerator.LF);
- sb.append(indent).append(JaninoSerializerGenerator.TAB + "throw new SerializationException(ex);").append(JaninoSerializerGenerator.LF);
- sb.append(indent).append("}" + JaninoSerializerGenerator.LF);
+ Class<?> getClazz() {
+ return tClass;
}
public CodeBlock unmarshallObjectCode(String tupleExpr) {
final CodeBlock.Builder builder = CodeBlock.builder()
.add("Object obj = ").add(factoryRefExpr).addStatement(".create()");
- for (int i = 0; i < tupleAccessors.length; i++) {
- builder.addStatement("fieldAccessor[$L].set(obj, $L)", i, tupleAccessors[i].read(tupleExpr).toString());
- }
+ for (int i = 0; i < tupleAccessors.length; i++)
+ builder.addStatement("FIELD_HANDLE_$L.set(obj, $L)", tupleAccessors[i].colIdx, tupleAccessors[i].read(tupleExpr).toString());
- builder.addStatement("return obj");
+ builder.addStatement("return obj");
return builder.build();
}
+ public CodeBlock getValueCode(String objVar, int i) {
+ return CodeBlock.of("FIELD_HANDLE_$L.get($L)", tupleAccessors[i].colIdx, objVar);
+ }
+
public CodeBlock marshallObjectCode(String asm, String objVar) {
final CodeBlock.Builder builder = CodeBlock.builder();
for (int i = 0; i < tupleAccessors.length; i++)
- builder.addStatement(tupleAccessors[i].write(asm, CodeBlock.of("fieldAccessor[$L].get($L)", i, objVar).toString()));
+ builder.addStatement(tupleAccessors[i].write(asm, getValueCode(objVar, i).toString()).toString());
return builder.build();
}
+
+ public void staticHandlers(TypeSpec.Builder builder, CodeBlock.Builder staticBuilder) {
+ for (int i = 0; i < tupleAccessors.length; i++) {
+ builder.addField(FieldSpec.builder(
+ VarHandle.class,
+ CodeBlock.of("FIELD_HANDLE_$L", tupleAccessors[i].colIdx).toString(),
+ Modifier.PRIVATE,
+ Modifier.FINAL,
+ Modifier.STATIC)
+ .build());
+
+ staticBuilder.addStatement("FIELD_HANDLE_$L = lookup.unreflectVarHandle($T.class.getDeclaredField($S))",
+ tupleAccessors[i].colIdx, tClass, columns.column(i).name());
+ }
+ }
}
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/TupleAccessorExpr.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/TupleAccessorExpr.java
index e1b782d..ccca864 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/TupleAccessorExpr.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/TupleAccessorExpr.java
@@ -21,6 +21,8 @@ import com.squareup.javapoet.CodeBlock;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import java.util.BitSet;
+import java.util.UUID;
import org.apache.ignite.internal.schema.Tuple;
import org.apache.ignite.internal.schema.TupleAssembler;
import org.apache.ignite.internal.schema.marshaller.BinaryMode;
@@ -29,52 +31,68 @@ import org.apache.ignite.internal.schema.marshaller.BinaryMode;
* Object field access expression generators.
*/
public class TupleAccessorExpr {
- public static final MethodHandle BYTE_READ;
- public static final MethodHandle SHORT_READ;
- public static final MethodHandle INT_READ;
- public static final MethodHandle LONG_READ;
- public static final MethodHandle FLOAT_READ;
- public static final MethodHandle DOUBLE_READ;
- public static final MethodHandle BYTE_BOXED_READ;
- public static final MethodHandle SHORT_BOXED_READ;
- public static final MethodHandle INT_BOXED_READ;
- public static final MethodHandle LONG_BOXED_READ;
- public static final MethodHandle FLOAT_BOXED_READ;
- public static final MethodHandle DOUBLE_BOXED_READ;
+ public static final MethodHandle READ_BYTE;
+ public static final MethodHandle READ_SHORT;
+ public static final MethodHandle READ_INT;
+ public static final MethodHandle READ_LONG;
+ public static final MethodHandle READ_FLOAT;
+ public static final MethodHandle READ_DOUBLE;
+ public static final MethodHandle READ_BYTE_BOXED;
+ public static final MethodHandle READ_SHORT_BOXED;
+ public static final MethodHandle READ_INT_BOXED;
+ public static final MethodHandle READ_LONG_BOXED;
+ public static final MethodHandle READ_FLOAT_BOXED;
+ public static final MethodHandle READ_DOUBLE_BOXED;
+ public static final MethodHandle READ_UUID;
+ public static final MethodHandle READ_BITSET;
+ public static final MethodHandle READ_STRING;
+ public static final MethodHandle READ_BYTE_ARR;
- public static final MethodHandle BYTE_WRITE;
- public static final MethodHandle SHORT_WRITE;
- public static final MethodHandle INT_WRITE;
- public static final MethodHandle LONG_WRITE;
- public static final MethodHandle FLOAT_WRITE;
- public static final MethodHandle DOUBLE_WRITE;
- public static final MethodHandle NULL_WRITE;
+ public static final MethodHandle WRITE_NULL;
+ public static final MethodHandle WRITE_BYTE;
+ public static final MethodHandle WRITE_SHORT;
+ public static final MethodHandle WRITE_INT;
+ public static final MethodHandle WRITE_LONG;
+ public static final MethodHandle WRITE_FLOAT;
+ public static final MethodHandle WRITE_DOUBLE;
+ public static final MethodHandle WRITE_UUID;
+ public static final MethodHandle WRITE_BITSET;
+ public static final MethodHandle WRITE_STRING;
+ public static final MethodHandle WRITE_BYTE_ARR;
static {
try {
- MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(Tuple.class,MethodHandles.lookup());
+ MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(Tuple.class, MethodHandles.lookup());
- BYTE_READ = lookup.findVirtual(Tuple.class, "byteValue", MethodType.methodType(byte.class, int.class));
- SHORT_READ = lookup.findVirtual(Tuple.class, "shortValue", MethodType.methodType(short.class, int.class));
- INT_READ = lookup.findVirtual(Tuple.class, "intValue", MethodType.methodType(int.class, int.class));
- LONG_READ = lookup.findVirtual(Tuple.class, "longValue", MethodType.methodType(long.class, int.class));
- FLOAT_READ = lookup.findVirtual(Tuple.class, "floatValue", MethodType.methodType(float.class, int.class));
- DOUBLE_READ = lookup.findVirtual(Tuple.class, "doubleValue", MethodType.methodType(double.class, int.class));
- BYTE_BOXED_READ = lookup.findVirtual(Tuple.class, "byteValueBoxed", MethodType.methodType(Byte.class, int.class));
- SHORT_BOXED_READ = lookup.findVirtual(Tuple.class, "shortValueBoxed", MethodType.methodType(Short.class, int.class));
- INT_BOXED_READ = lookup.findVirtual(Tuple.class, "intValueBoxed", MethodType.methodType(Integer.class, int.class));
- LONG_BOXED_READ = lookup.findVirtual(Tuple.class, "longValueBoxed", MethodType.methodType(Long.class, int.class));
- FLOAT_BOXED_READ = lookup.findVirtual(Tuple.class, "floatValueBoxed", MethodType.methodType(Float.class, int.class));
- DOUBLE_BOXED_READ = lookup.findVirtual(Tuple.class, "doubleValueBoxed", MethodType.methodType(Double.class, int.class));
+ READ_BYTE = lookup.findVirtual(Tuple.class, "byteValue", MethodType.methodType(byte.class, int.class));
+ READ_SHORT = lookup.findVirtual(Tuple.class, "shortValue", MethodType.methodType(short.class, int.class));
+ READ_INT = lookup.findVirtual(Tuple.class, "intValue", MethodType.methodType(int.class, int.class));
+ READ_LONG = lookup.findVirtual(Tuple.class, "longValue", MethodType.methodType(long.class, int.class));
+ READ_FLOAT = lookup.findVirtual(Tuple.class, "floatValue", MethodType.methodType(float.class, int.class));
+ READ_DOUBLE = lookup.findVirtual(Tuple.class, "doubleValue", MethodType.methodType(double.class, int.class));
+ READ_BYTE_BOXED = lookup.findVirtual(Tuple.class, "byteValueBoxed", MethodType.methodType(Byte.class, int.class));
+ READ_SHORT_BOXED = lookup.findVirtual(Tuple.class, "shortValueBoxed", MethodType.methodType(Short.class, int.class));
+ READ_INT_BOXED = lookup.findVirtual(Tuple.class, "intValueBoxed", MethodType.methodType(Integer.class, int.class));
+ READ_LONG_BOXED = lookup.findVirtual(Tuple.class, "longValueBoxed", MethodType.methodType(Long.class, int.class));
+ READ_FLOAT_BOXED = lookup.findVirtual(Tuple.class, "floatValueBoxed", MethodType.methodType(Float.class, int.class));
+ READ_DOUBLE_BOXED = lookup.findVirtual(Tuple.class, "doubleValueBoxed", MethodType.methodType(Double.class, int.class));
+ READ_UUID = lookup.findVirtual(Tuple.class, "uuidValue", MethodType.methodType(UUID.class, int.class));
+ READ_BITSET = lookup.findVirtual(Tuple.class, "bitmaskValue", MethodType.methodType(BitSet.class, int.class));
+ READ_STRING = lookup.findVirtual(Tuple.class, "stringValue", MethodType.methodType(String.class, int.class));
+ READ_BYTE_ARR = lookup.findVirtual(Tuple.class, "bytesValue", MethodType.methodType(byte[].class, int.class));
- lookup = MethodHandles.privateLookupIn(TupleAssembler.class,MethodHandles.lookup());
- NULL_WRITE = lookup.findVirtual(TupleAssembler.class, "appendNull", MethodType.methodType(void.class));
- BYTE_WRITE = lookup.findVirtual(TupleAssembler.class, "appendByte", MethodType.methodType(void.class, byte.class));
- SHORT_WRITE = lookup.findVirtual(TupleAssembler.class, "appendShort", MethodType.methodType(void.class, short.class));
- INT_WRITE = lookup.findVirtual(TupleAssembler.class, "appendInt", MethodType.methodType(void.class, int.class));
- LONG_WRITE = lookup.findVirtual(TupleAssembler.class, "appendLong", MethodType.methodType(void.class, long.class));
- FLOAT_WRITE = lookup.findVirtual(TupleAssembler.class, "appendFloat", MethodType.methodType(void.class, float.class));
- DOUBLE_WRITE = lookup.findVirtual(TupleAssembler.class, "appendDouble", MethodType.methodType(void.class, double.class));
+ lookup = MethodHandles.privateLookupIn(TupleAssembler.class, MethodHandles.lookup());
+ WRITE_NULL = lookup.findVirtual(TupleAssembler.class, "appendNull", MethodType.methodType(void.class));
+ WRITE_BYTE = lookup.findVirtual(TupleAssembler.class, "appendByte", MethodType.methodType(void.class, byte.class));
+ WRITE_SHORT = lookup.findVirtual(TupleAssembler.class, "appendShort", MethodType.methodType(void.class, short.class));
+ WRITE_INT = lookup.findVirtual(TupleAssembler.class, "appendInt", MethodType.methodType(void.class, int.class));
+ WRITE_LONG = lookup.findVirtual(TupleAssembler.class, "appendLong", MethodType.methodType(void.class, long.class));
+ WRITE_FLOAT = lookup.findVirtual(TupleAssembler.class, "appendFloat", MethodType.methodType(void.class, float.class));
+ WRITE_DOUBLE = lookup.findVirtual(TupleAssembler.class, "appendDouble", MethodType.methodType(void.class, double.class));
+ WRITE_UUID = lookup.findVirtual(TupleAssembler.class, "appendUuid", MethodType.methodType(void.class, UUID.class));
+ WRITE_BITSET = lookup.findVirtual(TupleAssembler.class, "appendBitmask", MethodType.methodType(void.class, BitSet.class));
+ WRITE_STRING = lookup.findVirtual(TupleAssembler.class, "appendString", MethodType.methodType(void.class, String.class));
+ WRITE_BYTE_ARR = lookup.findVirtual(TupleAssembler.class, "appendBytes", MethodType.methodType(void.class, byte[].class));
}
catch (NoSuchMethodException | IllegalAccessException e) {
throw new IllegalStateException(e);
@@ -87,37 +105,37 @@ public class TupleAccessorExpr {
static TupleAccessorExpr createAccessor(BinaryMode mode, int colIdx) {
switch (mode) {
case P_BYTE:
- return new TupleAccessorExpr("BYTE_READ", "BYTE_WRITE", byte.class, colIdx);
+ return new TupleAccessorExpr("READ_BYTE", "WRITE_BYTE", byte.class, colIdx);
case P_SHORT:
- break;
+ return new TupleAccessorExpr("READ_SHORT", "WRITE_SHORT", short.class, colIdx);
case P_INT:
- break;
+ return new TupleAccessorExpr("READ_INT", "WRITE_INT", int.class, colIdx);
case P_LONG:
- break;
+ return new TupleAccessorExpr("READ_LONG", "WRITE_LONG", long.class, colIdx);
case P_FLOAT:
- break;
+ return new TupleAccessorExpr("READ_FLOAT", "WRITE_FLOAT", float.class, colIdx);
case P_DOUBLE:
- break;
+ return new TupleAccessorExpr("READ_DOUBLE", "WRITE_DOUBLE", double.class, colIdx);
case BYTE:
- return new TupleAccessorExpr("BYTE_BOXED_READ", "BYTE_WRITE", Byte.class, colIdx);
+ return new TupleAccessorExpr("READ_BYTE_BOXED", "WRITE_BYTE", Byte.class, colIdx);
case SHORT:
- break;
+ return new TupleAccessorExpr("READ_SHORT_BOXED", "WRITE_SHORT", Short.class, colIdx);
case INT:
- break;
+ return new TupleAccessorExpr("READ_INT_BOXED", "WRITE_INT", Integer.class, colIdx);
case LONG:
- break;
+ return new TupleAccessorExpr("READ_LONG_BOXED", "WRITE_LONG", Long.class, colIdx);
case FLOAT:
- break;
+ return new TupleAccessorExpr("READ_FLOAT_BOXED", "WRITE_FLOAT", Float.class, colIdx);
case DOUBLE:
- break;
+ return new TupleAccessorExpr("READ_DOUBLE_BOXED", "WRITE_DOUBLE", Double.class, colIdx);
case STRING:
- break;
+ return new TupleAccessorExpr("READ_STRING", "WRITE_STRING", String.class, colIdx);
case UUID:
- break;
+ return new TupleAccessorExpr("READ_UUID", "WRITE_UUID", UUID.class, colIdx);
case BYTE_ARR:
- break;
+ return new TupleAccessorExpr("READ_BYTE_ARR", "WRITE_BYTE_ARR", byte[].class, colIdx);
case BITSET:
- break;
+ return new TupleAccessorExpr("READ_BITSET", "WRITE_BITSET", BitSet.class, colIdx);
}
throw new IllegalStateException("Unsupported binary mode: " + mode);
@@ -125,7 +143,7 @@ public class TupleAccessorExpr {
private final String readExpr;
private final String writeExpr;
- private final int colIdx;
+ final int colIdx;
private TupleAccessorExpr(String readExpr, String writeExpr, Class<?> rType, int colIdx) {
this.readExpr = readExpr;
@@ -146,7 +164,7 @@ public class TupleAccessorExpr {
.add("{\n").indent()
.addStatement("$T fVal", rType)
.beginControlFlow("if((fVal = ($T)$L) == null)", rType, valExpr)
- .addStatement("$T.NULL_WRITE.invokeExact($L)", TupleAccessorExpr.class, asmVar)
+ .addStatement("$T.WRITE_NULL.invoke($L)", TupleAccessorExpr.class, asmVar)
.nextControlFlow("else")
.addStatement("$T.$L.invoke($L, fVal)", TupleAccessorExpr.class, writeExpr, asmVar)
.endControlFlow()
diff --git a/modules/commons/src/test/java/org/apache/ignite/internal/benchmarks/SerializerBenchmarkTest.java b/modules/commons/src/test/java/org/apache/ignite/internal/benchmarks/SerializerBenchmarkTest.java
index 1f0ebef..e84e73b 100644
--- a/modules/commons/src/test/java/org/apache/ignite/internal/benchmarks/SerializerBenchmarkTest.java
+++ b/modules/commons/src/test/java/org/apache/ignite/internal/benchmarks/SerializerBenchmarkTest.java
@@ -17,18 +17,21 @@
package org.apache.ignite.internal.benchmarks;
+import com.squareup.javapoet.JavaFile;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeSpec;
import java.lang.reflect.Field;
import java.util.Random;
import java.util.concurrent.TimeUnit;
+import javax.lang.model.element.Modifier;
import org.apache.ignite.internal.schema.Column;
import org.apache.ignite.internal.schema.Columns;
import org.apache.ignite.internal.schema.SchemaDescriptor;
+import org.apache.ignite.internal.schema.marshaller.MarshallerUtil;
import org.apache.ignite.internal.schema.marshaller.Serializer;
import org.apache.ignite.internal.schema.marshaller.SerializerFactory;
import org.apache.ignite.internal.util.Factory;
import org.apache.ignite.internal.util.ObjectFactory;
-import org.codehaus.commons.compiler.CompilerFactoryFactory;
-import org.codehaus.commons.compiler.IClassBodyEvaluator;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
@@ -155,28 +158,32 @@ public class SerializerBenchmarkTest {
* @return Generated test object class.
* @throws Exception If failed.
*/
- private Class<?> createGeneratedObjectClass(int maxFields, Class<?> fieldType) throws Exception {
- final IClassBodyEvaluator ce = CompilerFactoryFactory.getDefaultCompilerFactory().newClassBodyEvaluator();
+ private Class<?> createGeneratedObjectClass(int maxFields, Class<?> fieldType) {
+ final String packageName = "org.apache.ignite.internal.benchmarks";
+ final String className = "TestObject";
- ce.setClassName("TestObject");
- ce.setDefaultImports("java.util.Random");
+ final TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC);
- final StringBuilder sb = new StringBuilder();
for (int i = 0; i < maxFields; i++)
- sb.append(fieldType.getName()).append(" col").append(i).append(";\n");
+ classBuilder.addField(fieldType, "col" + i, Modifier.PRIVATE);
- // Constructor.
- sb.append("public TestObject() {\n");
- sb.append(" Random rnd = new Random();\n");
- for (int i = 0; i < maxFields; i++)
- sb.append(" col").append(i).append(" = rnd.nextLong();\n");
- sb.append("}\n");
+ { // Build constructor.
+ final MethodSpec.Builder builder = MethodSpec.constructorBuilder()
+ .addModifiers(Modifier.PUBLIC)
+ .addStatement("$T rnd = new $T()", Random.class, Random.class);
- try {
- ce.setParentClassLoader(getClass().getClassLoader());
- ce.cook(sb.toString());
+ for (int i = 0; i < maxFields; i++)
+ builder.addStatement("col$L = rnd.nextLong()", i);
+
+ classBuilder.addMethod(builder.build());
+ }
- return ce.getClazz();
+ final JavaFile javaFile = JavaFile.builder(packageName, classBuilder.build()).build();
+
+ final ClassLoader loader = MarshallerUtil.compileCode(javaFile);
+
+ try {
+ return loader.loadClass(packageName + '.' + className);
}
catch (Exception ex) {
throw new IllegalStateException("Failed to compile/instantiate generated Serializer.", ex);
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
index d172e86..a9589e9 100644
--- 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
@@ -17,13 +17,19 @@
package org.apache.ignite.internal.schema.marshaller;
+import com.squareup.javapoet.JavaFile;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeSpec;
import java.util.Arrays;
import java.util.BitSet;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.UUID;
import java.util.stream.Stream;
+import javax.lang.model.element.Modifier;
import org.apache.ignite.internal.schema.Bitmask;
import org.apache.ignite.internal.schema.Column;
import org.apache.ignite.internal.schema.Columns;
@@ -33,6 +39,7 @@ import org.apache.ignite.internal.schema.SchemaDescriptor;
import org.apache.ignite.internal.schema.TestUtils;
import org.apache.ignite.internal.schema.marshaller.generator.JaninoSerializerGenerator;
import org.apache.ignite.internal.schema.marshaller.reflection.JavaSerializerFactory;
+import org.apache.ignite.internal.util.ObjectFactory;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DynamicNode;
import org.junit.jupiter.api.TestFactory;
@@ -261,6 +268,45 @@ public class JavaSerializerTest {
);
}
+
+ /**
+ *
+ */
+ @ParameterizedTest
+ @MethodSource("serializerFactoryProvider")
+ public void testClassLoader(SerializerFactory factory) throws SerializationException {
+ Column[] keyCols = new Column[] {
+ new Column("key", LONG, false)
+ };
+
+ Column[] valCols = new Column[] {
+ new Column("col0", LONG, false),
+ new Column("col1", LONG, false),
+ new Column("col2", LONG, false),
+ };
+
+ SchemaDescriptor schema = new SchemaDescriptor(1, new Columns(keyCols), new Columns(valCols));
+
+ final Map<String, byte[]> classes = new HashMap<>();
+ final Class<?> valClass = createGeneratedObjectClass(Long.class, classes);
+ final ObjectFactory<?> objFactory = new ObjectFactory<>(valClass);
+
+ final Long key = rnd.nextLong();
+
+ if (factory instanceof JaninoSerializerGenerator)
+ ((JaninoSerializerGenerator)factory).setClasses(classes);
+
+ Serializer serializer = factory.create(schema, key.getClass(), valClass);
+
+ byte[] bytes = serializer.serialize(key, objFactory.create());
+
+ Object key1 = serializer.deserializeKey(bytes);
+ Object val1 = serializer.deserializeValue(bytes);
+
+ assertTrue(key.getClass().isInstance(key1));
+ assertTrue(valClass.isInstance(val1));
+ }
+
/**
* Generate random key-value pair of given types and
* check serialization and deserialization works fine.
@@ -318,6 +364,45 @@ public class JavaSerializerTest {
}
/**
+ * Generate class for test objects.
+ *
+ * @param fieldType Field type.
+ * @param classes
+ * @return Generated test object class.
+ */
+ private Class<?> createGeneratedObjectClass(Class<?> fieldType, Map<String, byte[]> classes) {
+ final String packageName = getClass().getPackageName();
+ final String className = "GeneratedTestObject";
+
+ final TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC);
+
+ for (int i = 0; i < 3; i++)
+ classBuilder.addField(fieldType, "col" + i, Modifier.PRIVATE);
+
+ { // Build constructor.
+ final MethodSpec.Builder builder = MethodSpec.constructorBuilder()
+ .addModifiers(Modifier.PUBLIC)
+ .addStatement("$T rnd = new $T()", Random.class, Random.class);
+
+ for (int i = 0; i < 3; i++)
+ builder.addStatement("col$L = rnd.nextLong()", i);
+
+ classBuilder.addMethod(builder.build());
+ }
+
+ final JavaFile javaFile = JavaFile.builder(packageName, classBuilder.build()).build();
+
+ final ClassLoader loader = MarshallerUtil.compileCode(javaFile, classes);
+
+ try {
+ return loader.loadClass(packageName + '.' + className);
+ }
+ catch (Exception ex) {
+ throw new IllegalStateException("Failed to compile/instantiate generated Serializer.", ex);
+ }
+ }
+
+ /**
* Test object.
*/
public static class TestObject {
@@ -413,7 +498,7 @@ public class JavaSerializerTest {
/**
* Test object with private constructor.
*/
- private static class PrivateTestObject {
+ public static class PrivateTestObject {
/**
* @return Random TestObject.
*/
@@ -431,7 +516,6 @@ public class JavaSerializerTest {
/**
* Private constructor.
*/
- @SuppressWarnings("RedundantNoArgConstructor")
private PrivateTestObject() {
}
[ignite-3] 02/03: wip. rewrite codegen with javapoet
Posted by am...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
amashenkov pushed a commit to branch ignite-13618-javapoet
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
commit b3223bfd05fb9d9fa48098d823df787d8d10212a
Author: Andrew Mashenkov <an...@gmail.com>
AuthorDate: Sat Dec 12 22:19:31 2020 +0300
wip.
rewrite codegen with javapoet
---
modules/commons/pom.xml | 7 +-
.../internal/schema/marshaller/MarshallerUtil.java | 11 +-
.../IdentityObjectMarshallerExprGenerator.java | 22 +-
.../generator/JaninoSerializerGenerator.java | 289 ++++++++++++++++++---
.../generator/MarshallerExprGenerator.java | 28 +-
.../marshaller/generator/TupleAccessorExpr.java | 158 +++++++++++
.../marshaller/reflection/FieldAccessor.java | 4 +-
.../apache/ignite/internal/util/ObjectFactory.java | 26 +-
pom.xml | 1 +
9 files changed, 485 insertions(+), 61 deletions(-)
diff --git a/modules/commons/pom.xml b/modules/commons/pom.xml
index 05a2fff..a5b64e8 100644
--- a/modules/commons/pom.xml
+++ b/modules/commons/pom.xml
@@ -43,12 +43,11 @@
<version>${jetbrains.annotations.version}</version>
</dependency>
<dependency>
- <groupId>org.codehaus.janino</groupId>
- <artifactId>janino</artifactId>
- <version>${janino.version}</version>
+ <groupId>com.squareup</groupId>
+ <artifactId>javapoet</artifactId>
+ <version>${javapoet.version}</version>
</dependency>
-
<!-- Test dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerUtil.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerUtil.java
index c111ba8..f43f9b5 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerUtil.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/MarshallerUtil.java
@@ -21,6 +21,7 @@ import java.util.BitSet;
import java.util.UUID;
import org.apache.ignite.internal.schema.NativeType;
import org.apache.ignite.internal.schema.TupleAssembler;
+import org.apache.ignite.internal.util.ObjectFactory;
/**
* Marshaller utility class.
@@ -96,8 +97,16 @@ public final class MarshallerUtil {
return null;
}
+ public static <T> ObjectFactory<T> factoryForClass(Class<T> type) {
+ if (mode(type) == null)
+ return new ObjectFactory<>(type);
+ else
+ return null;
+ }
+
/**
* Stub.
*/
- private MarshallerUtil() {}
+ private MarshallerUtil() {
+ }
}
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/IdentityObjectMarshallerExprGenerator.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/IdentityObjectMarshallerExprGenerator.java
index e574e61..f86bc0b 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/IdentityObjectMarshallerExprGenerator.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/IdentityObjectMarshallerExprGenerator.java
@@ -17,6 +17,7 @@
package org.apache.ignite.internal.schema.marshaller.generator;
+import com.squareup.javapoet.CodeBlock;
import org.apache.ignite.internal.schema.marshaller.Serializer;
/**
@@ -27,9 +28,16 @@ class IdentityObjectMarshallerExprGenerator extends MarshallerExprGenerator {
* Constructor.
*
* @param accessor Object field access expression generators.
+ * @param tupleAccessorGen
*/
- IdentityObjectMarshallerExprGenerator(FieldAccessExprGenerator accessor) {
- super(null /* no instantiation needed */, new FieldAccessExprGenerator[] {accessor});
+ IdentityObjectMarshallerExprGenerator(FieldAccessExprGenerator accessor,
+ TupleAccessorExpr tupleAccessorGen) {
+ super(
+ null /* no instantiation needed */,
+ new FieldAccessExprGenerator[] {accessor},
+ new TupleAccessorExpr[] {tupleAccessorGen}
+ );
+
}
/** {@inheritDoc} */
@@ -42,4 +50,14 @@ class IdentityObjectMarshallerExprGenerator extends MarshallerExprGenerator {
@Override public void appendUnmarshallObjectExpr(StringBuilder sb, String indent) {
sb.append(indent).append("Object obj = ").append(accessors[0].readColumnExpr()).append(";" + JaninoSerializerGenerator.LF);
}
+
+ @Override public CodeBlock unmarshallObjectCode(String tupleExpr) {
+ return CodeBlock.builder()
+ .add("return ").addStatement(tupleAccessors[0].read(tupleExpr))
+ .build();
+ }
+
+ @Override public CodeBlock marshallObjectCode(String asm, String objVar) {
+ return tupleAccessors[0].write(asm, objVar);
+ }
}
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/JaninoSerializerGenerator.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/JaninoSerializerGenerator.java
index 654bf97..a45a8be 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/JaninoSerializerGenerator.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/JaninoSerializerGenerator.java
@@ -17,23 +17,53 @@
package org.apache.ignite.internal.schema.marshaller.generator;
+import com.squareup.javapoet.AnnotationSpec;
+import com.squareup.javapoet.ArrayTypeName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.JavaFile;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeName;
+import com.squareup.javapoet.TypeSpec;
+import java.lang.invoke.VarHandle;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
+import java.util.HashMap;
+import javax.annotation.processing.Generated;
+import javax.lang.model.element.Modifier;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileManager;
+import javax.tools.ToolProvider;
+import org.apache.ignite.internal.schema.ByteBufferTuple;
import org.apache.ignite.internal.schema.Columns;
import org.apache.ignite.internal.schema.SchemaDescriptor;
+import org.apache.ignite.internal.schema.Tuple;
+import org.apache.ignite.internal.schema.TupleAssembler;
import org.apache.ignite.internal.schema.marshaller.BinaryMode;
import org.apache.ignite.internal.schema.marshaller.MarshallerUtil;
+import org.apache.ignite.internal.schema.marshaller.SerializationException;
import org.apache.ignite.internal.schema.marshaller.Serializer;
import org.apache.ignite.internal.schema.marshaller.SerializerFactory;
-import org.apache.ignite.internal.util.IgniteUnsafeUtils;
-import org.codehaus.commons.compiler.CompilerFactoryFactory;
+import org.apache.ignite.internal.util.ObjectFactory;
import org.codehaus.commons.compiler.IClassBodyEvaluator;
+import org.codehaus.janino.ClassLoaderIClassLoader;
+import org.codehaus.janino.Compiler;
+import org.codehaus.janino.util.ResourceFinderClassLoader;
+import org.codehaus.janino.util.resource.MapResourceCreator;
+import org.codehaus.janino.util.resource.MapResourceFinder;
+import org.codehaus.janino.util.resource.Resource;
+import org.codehaus.janino.util.resource.StringResource;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* {@link Serializer} code generator backed with Janino.
*/
public class JaninoSerializerGenerator implements SerializerFactory {
+
+ public static final String SERIALIZER_PACKAGE_NAME = "org.apache.ignite.internal.schema.marshaller";
+
+ public static final String SERIALIZER_CLASS_NAME_PREFIX = "JaninoSerializerForSchema_";
+
/** Tabulate. */
static final String TAB = " ";
@@ -52,38 +82,106 @@ public class JaninoSerializerGenerator implements SerializerFactory {
Class<?> keyClass,
Class<?> valClass
) {
- try {
- final IClassBodyEvaluator ce = CompilerFactoryFactory.getDefaultCompilerFactory().newClassBodyEvaluator();
+ // Generate Serializer code.
+ final String className = SERIALIZER_CLASS_NAME_PREFIX + schema.version();
- // Generate Serializer code.
- String code = generateSerializerClassCode(ce, schema, keyClass, valClass);
+ String code = generateSerializerClassCode(className, schema, keyClass, valClass);
- //TODO: pass code to logger on trace level.
+ //TODO: pass code to logger on trace level.
- if (enabledDebug) {
- ce.setDebuggingInformation(true, true, true);
+ final HashMap<String, byte[]> classes = new HashMap<>();
+ final Compiler cmp = new Compiler(
+ new MapResourceFinder(classes),
+ new ClassLoaderIClassLoader(getClass().getClassLoader())
+ );
- //TODO: dump code to log.
-// System.out.println(code);
- }
+ cmp.setClassFileCreator(new MapResourceCreator(classes));
- try { // Compile and load class.
- ce.setParentClassLoader(getClass().getClassLoader());
- ce.cook(code);
+ if (enabledDebug) {
+ cmp.setDebugSource(true);
+ cmp.setDebugLines(true);
+ cmp.setDebugVars(true);
+ cmp.setVerbose(true);
- // Create and return Serializer instance.
- final Constructor<Serializer> ctor = (Constructor<Serializer>)ce.getClazz()
- .getDeclaredConstructor(schema.getClass(), Class.class, Class.class);
+ System.out.print(code);
+ }
- return ctor.newInstance(schema, keyClass, valClass);
- }
- catch (Exception ex) {
- if (enabledDebug)
- throw new IllegalStateException("Failed to compile/instantiate generated Serializer: code=" +
- LF + code + LF, ex);
- else
- throw new IllegalStateException("Failed to compile/instantiate generated Serializer.", ex);
- }
+ try { // Compile code.
+ cmp.compile(new Resource[] {
+ new StringResource("file", code)});
+
+ ClassLoader cl = new ResourceFinderClassLoader(
+ new MapResourceFinder(classes),
+ getClass().getClassLoader()
+ );
+
+ // Load class and create instance.
+ final Class<?> aClass = cl.loadClass(SERIALIZER_PACKAGE_NAME + '.' + className);
+
+ final Constructor<Serializer> ctor = (Constructor<Serializer>)aClass
+ .getDeclaredConstructor(schema.getClass(), Class.class, Class.class);
+
+ return ctor.newInstance(schema, keyClass, valClass);
+ }
+ catch (Throwable ex) {
+ if (enabledDebug)
+ throw new IllegalStateException("Failed to compile generated Serializer code:\n" + code, ex);
+ else
+ throw new IllegalStateException("Failed to compile/instantiate generated Serializer.", ex);
+ }
+ }
+
+ /**
+ * Generates serializer code.
+ *
+ * @param className Serializer class name.
+ * @param valClass Value class.
+ * @return Generated class code.
+ */
+ private String generateSerializerClassCode(String className, SchemaDescriptor schema, Class<?> keyClass,
+ Class<?> valClass) {
+ try {
+ final StringBuilder sb = new StringBuilder();
+
+ // Build field accessor generators.
+ final MarshallerExprGenerator keyMarsh = createObjectMarshaller(valClass, "valFactory", schema.valueColumns(), schema.keyColumns().length());
+ final MarshallerExprGenerator valMarsh = createObjectMarshaller(valClass, "valFactory", schema.valueColumns(), schema.keyColumns().length());
+
+ JavaFile
+ .builder(
+ SERIALIZER_PACKAGE_NAME,
+ TypeSpec.classBuilder(className)
+ .addSuperinterface(Serializer.class)
+ .addModifiers(Modifier.PUBLIC)
+ .addAnnotation(AnnotationSpec.builder(Generated.class).addMember("value", getClass().getCanonicalName()).build())
+ .addField(SchemaDescriptor.class, "schema", Modifier.PRIVATE, Modifier.FINAL)
+ .addField(ObjectFactory.class, "keyFactory", Modifier.PRIVATE, Modifier.FINAL)
+ .addField(ObjectFactory.class, "valFactory", Modifier.PRIVATE, Modifier.FINAL)
+ .addField(ArrayTypeName.of(VarHandle.class), "fieldAccessors", Modifier.PRIVATE, Modifier.FINAL)
+ .addMethod(
+ MethodSpec.constructorBuilder()
+ .addModifiers(Modifier.PUBLIC)
+ .addParameter(SchemaDescriptor.class, "schema")
+ .addParameter(Class.class, "keyClass")
+ .addParameter(Class.class, "valClass")
+ .addStatement("this.schema = schema")
+ .addStatement("this.keyFactory = $T.factoryForClass(keyClass)", MarshallerUtil.class)
+ .addStatement("this.valFactory = $T.factoryForClass(keyClass)", MarshallerUtil.class)
+ .addStatement("this.fieldAccessors = null")
+ .build()
+ )
+ .addMethod(generateHelpersMetod(schema))
+ .addMethod(generateSerializeMethod(keyMarsh, valMarsh))
+ .addMethod(generateDeserializeKeyMethod(keyMarsh))
+ .addMethod(generateDeserializeValueMethod())
+ .build()
+ )
+ .skipJavaLangImports(true)
+ .indent(TAB)
+ .build()
+ .writeTo(sb);
+
+ return sb.toString();
}
catch (Exception ex) {
//TODO: fallback to java serializer?
@@ -91,6 +189,128 @@ public class JaninoSerializerGenerator implements SerializerFactory {
}
}
+ private MethodSpec generateHelpersMetod(SchemaDescriptor schema) {
+ final MethodSpec.Builder builder = MethodSpec
+ .methodBuilder("createAssembler")
+ .addModifiers(Modifier.PRIVATE)
+ .addParameter(Object.class, "key")
+ .addParameter(Object.class, "val")
+ .returns(TupleAssembler.class)
+
+ .addStatement("int nonNullVarlenKeys = 0; int nonNullVarlenValues = 0")
+ .addStatement("int nonNullVarlenKeysSize = 0; int nonNullVarlenValuesSize = 0")
+ .addStatement("$T keyCols = schema.keyColumns()", Columns.class)
+ .addStatement("$T valCols = schema.valueColumns()", Columns.class);
+
+ Columns keyCols = schema.keyColumns();
+ if (keyCols.firstVarlengthColumn() >= 0) {
+ final CodeBlock.Builder block = CodeBlock.builder().indent()
+ .addStatement("$T fVal", Object.class);// Temporary vars.
+
+ for (int i = keyCols.firstVarlengthColumn(); i < keyCols.length(); i++) {
+ assert !keyCols.column(i).type().spec().fixedLength();
+
+ block.addStatement("assert !keyCols.column($L).type().spec().fixedLength()", i)
+ .addStatement("fVal = fieldAccessors[$L].get(key)", i)
+ .beginControlFlow("if (fVal != null)")
+ .addStatement("nonNullVarlenKeysSize += $T.getValueSize(fVal, keyCols.column($L).type())", MarshallerUtil.class, i)
+ .addStatement("nonNullVarlenKeys++")
+ .endControlFlow();
+ }
+ block.unindent();
+
+ builder
+ .addCode("{\n")
+ .addCode(block.build())
+ .addCode("}\n");
+ }
+
+ Columns valCols = schema.keyColumns();
+ if (valCols.firstVarlengthColumn() >= 0) {
+ final CodeBlock.Builder block = CodeBlock.builder().indent()
+ .addStatement("$T fVal", Object.class);// Temporary vars.
+
+ for (int i = valCols.firstVarlengthColumn(); i < valCols.length(); i++) {
+ assert !valCols.column(i).type().spec().fixedLength();
+
+ block.addStatement("assert !valCols.column($L).type().spec().fixedLength()", i)
+ .addStatement("fVal = fieldAccessors[$L].get(val)", i + schema.keyColumns().length())
+ .beginControlFlow("if (fVal != null)")
+ .addStatement("nonNullVarlenValuesSize += $T.getValueSize(fVal, valCols.column($L).type())", MarshallerUtil.class, i)
+ .addStatement("nonNullVarlenValues++")
+ .endControlFlow();
+ }
+ block.unindent();
+
+ builder
+ .addCode("{\n")
+ .addCode(block.build())
+ .addCode("}\n");
+ }
+
+ builder.addStatement("int size = $T.tupleSize(keyCols, nonNullVarlenKeys, nonNullVarlenKeysSize," +
+ "valCols, nonNullVarlenValues, nonNullVarlenValuesSize)", TupleAssembler.class);
+
+ builder.addStatement("return new $T(schema, size, nonNullVarlenKeys, nonNullVarlenValues)", TupleAssembler.class);
+
+ return builder.build();
+ }
+
+ @NotNull private MethodSpec generateDeserializeValueMethod() {
+ return MethodSpec
+ .methodBuilder("deserializeValue")
+ .addAnnotation(Override.class)
+ .addModifiers(Modifier.PUBLIC)
+ .addParameter(ArrayTypeName.of(TypeName.BYTE), "data")
+ .addException(SerializationException.class)
+ .returns(TypeName.OBJECT)
+ .addStatement("return null")
+ .build();
+ }
+
+ @NotNull private MethodSpec generateDeserializeKeyMethod(MarshallerExprGenerator keyMarsh) {
+ final MethodSpec.Builder builder = MethodSpec
+ .methodBuilder("deserializeKey")
+ .addAnnotation(Override.class)
+ .addModifiers(Modifier.PUBLIC)
+ .addParameter(ArrayTypeName.of(TypeName.BYTE), "data")
+ .addException(SerializationException.class)
+ .returns(TypeName.OBJECT)
+
+ .beginControlFlow("try")
+ .addStatement("$T tuple = new $T(schema, data)", Tuple.class, ByteBufferTuple.class)
+ .addCode(keyMarsh.unmarshallObjectCode("tuple"))
+
+ .nextControlFlow("catch($T th)", Throwable.class)
+ .addStatement("throw new $T(th)", SerializationException.class)
+ .endControlFlow();
+
+ return builder.build();
+ }
+
+ @NotNull
+ private MethodSpec generateSerializeMethod(MarshallerExprGenerator keyMarsh, MarshallerExprGenerator valMarsh) {
+ return MethodSpec.
+ methodBuilder("serialize")
+ .addAnnotation(Override.class)
+ .addModifiers(Modifier.PUBLIC)
+ .addParameter(TypeName.OBJECT, "key")
+ .addParameter(TypeName.OBJECT, "val")
+ .addException(SerializationException.class)
+ .returns(ArrayTypeName.of(TypeName.BYTE.unbox()))
+
+ .beginControlFlow("try")
+ .addStatement("$T asm = createAssembler(key, val)", TupleAssembler.class)
+ .addCode(keyMarsh.marshallObjectCode("asm", "key"))
+ .addCode(valMarsh.marshallObjectCode("asm", "val"))
+ .addStatement("return asm.build()")
+
+ .nextControlFlow("catch($T th)", Throwable.class)
+ .addStatement("throw new $T(th)", SerializationException.class)
+ .endControlFlow()
+ .build();
+ }
+
/**
* Generates serializer code.
*
@@ -106,11 +326,10 @@ public class JaninoSerializerGenerator implements SerializerFactory {
Class<?> keyClass,
Class<?> valClass
) {
- final String packageName = "org.apache.ignite.internal.schema.marshaller.";
- final String className = "JaninoSerializerForSchema_" + schema.version();
+ final String className = SERIALIZER_CLASS_NAME_PREFIX + schema.version();
// Prerequisites.
- ce.setClassName(packageName + className);
+ ce.setClassName(SERIALIZER_PACKAGE_NAME + className);
ce.setImplementedInterfaces(new Class[] {Serializer.class});
ce.setDefaultImports(
"java.util.UUID",
@@ -178,9 +397,13 @@ public class JaninoSerializerGenerator implements SerializerFactory {
BinaryMode mode = MarshallerUtil.mode(aClass);
if (mode != null)
- return new IdentityObjectMarshallerExprGenerator(FieldAccessExprGenerator.createIdentityAccessor(mode, firstColIdx));
+ return new IdentityObjectMarshallerExprGenerator(
+ FieldAccessExprGenerator.createIdentityAccessor(mode, firstColIdx),
+ TupleAccessorExpr.createAccessor(mode, firstColIdx)
+ );
FieldAccessExprGenerator[] accessors = new FieldAccessExprGenerator[columns.length()];
+ TupleAccessorExpr[] tupleAccessorExprs = new TupleAccessorExpr[] {};
try {
for (int i = 0; i < columns.length(); i++) {
final Field field = aClass.getDeclaredField(columns.column(i).name());
@@ -188,14 +411,14 @@ public class JaninoSerializerGenerator implements SerializerFactory {
accessors[i] = FieldAccessExprGenerator.createAccessor(
MarshallerUtil.mode(field.getType()),
firstColIdx + i /* schma absolute index. */,
- IgniteUnsafeUtils.objectFieldOffset(field));
+ 0L);// IgniteUnsafeUtils.objectFieldOffset(field));
}
}
catch (NoSuchFieldException ex) {
throw new IllegalStateException(ex);
}
- return new MarshallerExprGenerator(factoryRefExpr, accessors);
+ return new MarshallerExprGenerator(factoryRefExpr, accessors, tupleAccessorExprs);
}
/**
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/MarshallerExprGenerator.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/MarshallerExprGenerator.java
index 433b567..8087e2c 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/MarshallerExprGenerator.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/MarshallerExprGenerator.java
@@ -17,6 +17,8 @@
package org.apache.ignite.internal.schema.marshaller.generator;
+import com.squareup.javapoet.CodeBlock;
+import java.lang.invoke.VarHandle;
import org.apache.ignite.internal.schema.marshaller.Serializer;
/**
@@ -28,6 +30,7 @@ class MarshallerExprGenerator {
/** Object field access expression generators. */
protected FieldAccessExprGenerator[] accessors;
+ protected TupleAccessorExpr[] tupleAccessors;
/**
* Constructor.
@@ -35,9 +38,11 @@ class MarshallerExprGenerator {
* @param factoryRefExpr Object factory regerence expression.
* @param accessors Object field access expression generators.
*/
- public MarshallerExprGenerator(String factoryRefExpr, FieldAccessExprGenerator[] accessors) {
+ public MarshallerExprGenerator(String factoryRefExpr, FieldAccessExprGenerator[] accessors,
+ TupleAccessorExpr[] tupleAccessors) {
this.accessors = accessors;
this.factoryRefExpr = factoryRefExpr;
+ this.tupleAccessors = tupleAccessors;
}
/**
@@ -91,4 +96,25 @@ class MarshallerExprGenerator {
sb.append(indent).append(JaninoSerializerGenerator.TAB + "throw new SerializationException(ex);").append(JaninoSerializerGenerator.LF);
sb.append(indent).append("}" + JaninoSerializerGenerator.LF);
}
+
+ public CodeBlock unmarshallObjectCode(String tupleExpr) {
+ final CodeBlock.Builder builder = CodeBlock.builder()
+ .add("Object obj = ").add(factoryRefExpr).addStatement(".create()");
+
+ for (int i = 0; i < tupleAccessors.length; i++) {
+ builder.addStatement("fieldAccessor[$L].set(obj, $L)", i, tupleAccessors[i].read(tupleExpr).toString());
+ }
+
+ builder.addStatement("return obj");
+ return builder.build();
+ }
+
+ public CodeBlock marshallObjectCode(String asm, String objVar) {
+ final CodeBlock.Builder builder = CodeBlock.builder();
+
+ for (int i = 0; i < tupleAccessors.length; i++)
+ builder.addStatement(tupleAccessors[i].write(asm, CodeBlock.of("fieldAccessor[$L].get($L)", i, objVar).toString()));
+
+ return builder.build();
+ }
}
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/TupleAccessorExpr.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/TupleAccessorExpr.java
new file mode 100644
index 0000000..e1b782d
--- /dev/null
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/generator/TupleAccessorExpr.java
@@ -0,0 +1,158 @@
+/*
+ * 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.generator;
+
+import com.squareup.javapoet.CodeBlock;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import org.apache.ignite.internal.schema.Tuple;
+import org.apache.ignite.internal.schema.TupleAssembler;
+import org.apache.ignite.internal.schema.marshaller.BinaryMode;
+
+/**
+ * Object field access expression generators.
+ */
+public class TupleAccessorExpr {
+ public static final MethodHandle BYTE_READ;
+ public static final MethodHandle SHORT_READ;
+ public static final MethodHandle INT_READ;
+ public static final MethodHandle LONG_READ;
+ public static final MethodHandle FLOAT_READ;
+ public static final MethodHandle DOUBLE_READ;
+ public static final MethodHandle BYTE_BOXED_READ;
+ public static final MethodHandle SHORT_BOXED_READ;
+ public static final MethodHandle INT_BOXED_READ;
+ public static final MethodHandle LONG_BOXED_READ;
+ public static final MethodHandle FLOAT_BOXED_READ;
+ public static final MethodHandle DOUBLE_BOXED_READ;
+
+ public static final MethodHandle BYTE_WRITE;
+ public static final MethodHandle SHORT_WRITE;
+ public static final MethodHandle INT_WRITE;
+ public static final MethodHandle LONG_WRITE;
+ public static final MethodHandle FLOAT_WRITE;
+ public static final MethodHandle DOUBLE_WRITE;
+ public static final MethodHandle NULL_WRITE;
+
+ static {
+ try {
+ MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(Tuple.class,MethodHandles.lookup());
+
+ BYTE_READ = lookup.findVirtual(Tuple.class, "byteValue", MethodType.methodType(byte.class, int.class));
+ SHORT_READ = lookup.findVirtual(Tuple.class, "shortValue", MethodType.methodType(short.class, int.class));
+ INT_READ = lookup.findVirtual(Tuple.class, "intValue", MethodType.methodType(int.class, int.class));
+ LONG_READ = lookup.findVirtual(Tuple.class, "longValue", MethodType.methodType(long.class, int.class));
+ FLOAT_READ = lookup.findVirtual(Tuple.class, "floatValue", MethodType.methodType(float.class, int.class));
+ DOUBLE_READ = lookup.findVirtual(Tuple.class, "doubleValue", MethodType.methodType(double.class, int.class));
+ BYTE_BOXED_READ = lookup.findVirtual(Tuple.class, "byteValueBoxed", MethodType.methodType(Byte.class, int.class));
+ SHORT_BOXED_READ = lookup.findVirtual(Tuple.class, "shortValueBoxed", MethodType.methodType(Short.class, int.class));
+ INT_BOXED_READ = lookup.findVirtual(Tuple.class, "intValueBoxed", MethodType.methodType(Integer.class, int.class));
+ LONG_BOXED_READ = lookup.findVirtual(Tuple.class, "longValueBoxed", MethodType.methodType(Long.class, int.class));
+ FLOAT_BOXED_READ = lookup.findVirtual(Tuple.class, "floatValueBoxed", MethodType.methodType(Float.class, int.class));
+ DOUBLE_BOXED_READ = lookup.findVirtual(Tuple.class, "doubleValueBoxed", MethodType.methodType(Double.class, int.class));
+
+ lookup = MethodHandles.privateLookupIn(TupleAssembler.class,MethodHandles.lookup());
+ NULL_WRITE = lookup.findVirtual(TupleAssembler.class, "appendNull", MethodType.methodType(void.class));
+ BYTE_WRITE = lookup.findVirtual(TupleAssembler.class, "appendByte", MethodType.methodType(void.class, byte.class));
+ SHORT_WRITE = lookup.findVirtual(TupleAssembler.class, "appendShort", MethodType.methodType(void.class, short.class));
+ INT_WRITE = lookup.findVirtual(TupleAssembler.class, "appendInt", MethodType.methodType(void.class, int.class));
+ LONG_WRITE = lookup.findVirtual(TupleAssembler.class, "appendLong", MethodType.methodType(void.class, long.class));
+ FLOAT_WRITE = lookup.findVirtual(TupleAssembler.class, "appendFloat", MethodType.methodType(void.class, float.class));
+ DOUBLE_WRITE = lookup.findVirtual(TupleAssembler.class, "appendDouble", MethodType.methodType(void.class, double.class));
+ }
+ catch (NoSuchMethodException | IllegalAccessException e) {
+ throw new IllegalStateException(e);
+ }
+
+ }
+
+ private final Class<?> rType;
+
+ static TupleAccessorExpr createAccessor(BinaryMode mode, int colIdx) {
+ switch (mode) {
+ case P_BYTE:
+ return new TupleAccessorExpr("BYTE_READ", "BYTE_WRITE", byte.class, colIdx);
+ case P_SHORT:
+ break;
+ case P_INT:
+ break;
+ case P_LONG:
+ break;
+ case P_FLOAT:
+ break;
+ case P_DOUBLE:
+ break;
+ case BYTE:
+ return new TupleAccessorExpr("BYTE_BOXED_READ", "BYTE_WRITE", Byte.class, colIdx);
+ case SHORT:
+ break;
+ case INT:
+ break;
+ case LONG:
+ break;
+ case FLOAT:
+ break;
+ case DOUBLE:
+ break;
+ case STRING:
+ break;
+ case UUID:
+ break;
+ case BYTE_ARR:
+ break;
+ case BITSET:
+ break;
+ }
+
+ throw new IllegalStateException("Unsupported binary mode: " + mode);
+ }
+
+ private final String readExpr;
+ private final String writeExpr;
+ private final int colIdx;
+
+ private TupleAccessorExpr(String readExpr, String writeExpr, Class<?> rType, int colIdx) {
+ this.readExpr = readExpr;
+ this.writeExpr = writeExpr;
+ this.colIdx = colIdx;
+ this.rType = rType;
+ }
+
+ public CodeBlock read(String tuple) {
+ return CodeBlock.of("($T)$T.$L.invoke($L, $L)", rType, TupleAccessorExpr.class, readExpr, tuple, colIdx);
+ }
+
+ public CodeBlock write(String asmVar, String valExpr) {
+ if (rType.isPrimitive())
+ return CodeBlock.of("$T.$L.invoke($L, $L)", TupleAccessorExpr.class, writeExpr, asmVar, valExpr);
+ else {
+ return CodeBlock.builder()
+ .add("{\n").indent()
+ .addStatement("$T fVal", rType)
+ .beginControlFlow("if((fVal = ($T)$L) == null)", rType, valExpr)
+ .addStatement("$T.NULL_WRITE.invokeExact($L)", TupleAccessorExpr.class, asmVar)
+ .nextControlFlow("else")
+ .addStatement("$T.$L.invoke($L, fVal)", TupleAccessorExpr.class, writeExpr, asmVar)
+ .endControlFlow()
+ .unindent()
+ .add("}\n")
+ .build();
+ }
+ }
+}
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/FieldAccessor.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/FieldAccessor.java
index 97ea038..812b02e 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/FieldAccessor.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/FieldAccessor.java
@@ -478,9 +478,7 @@ public abstract class FieldAccessor {
assert obj != null;
assert writer != null;
- Object val;
-
- val = varHandle.get(obj);
+ Object val = varHandle.get(obj);
if (val == null) {
writer.appendNull();
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/util/ObjectFactory.java b/modules/commons/src/main/java/org/apache/ignite/internal/util/ObjectFactory.java
index f31965f..b888955 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/util/ObjectFactory.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/util/ObjectFactory.java
@@ -17,15 +17,16 @@
package org.apache.ignite.internal.util;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
/**
* Object factory.
*/
public class ObjectFactory<T> implements Factory<T> {
/** Class default constructor. */
- private final Constructor<T> cnstr;
+ private final MethodHandle constr;
/**
* Constructor.
@@ -34,11 +35,9 @@ public class ObjectFactory<T> implements Factory<T> {
*/
public ObjectFactory(Class<T> tClass) {
try {
- cnstr = tClass.getDeclaredConstructor();
-
- cnstr.setAccessible(true);
+ constr = MethodHandles.privateLookupIn(tClass, MethodHandles.lookup()).findConstructor(tClass, MethodType.methodType(void.class));
}
- catch (NoSuchMethodException e) {
+ catch (NoSuchMethodException | IllegalAccessException e) {
throw new IllegalStateException("Class has no default constructor: class=" + tClass.getName(), e);
}
}
@@ -46,17 +45,10 @@ public class ObjectFactory<T> implements Factory<T> {
/** {@inheritDoc} */
@Override public T create() throws IllegalStateException {
try {
- return cnstr.newInstance();
+ return (T)constr.invoke();
}
- catch (IllegalAccessException | InvocationTargetException | InstantiationException e) {
- throw new IllegalStateException("Failed to instantiate class: " + cnstr.getDeclaringClass().getName(), e);
+ catch (Throwable e) {
+ throw new IllegalStateException("Failed to instantiate class: " + constr.type().returnType(), e);
}
}
-
- /**
- * @return Class of object created by the factory.
- */
- public Class<T> getClazz() {
- return cnstr.getDeclaringClass();
- }
}
diff --git a/pom.xml b/pom.xml
index 7d1a734..0ad6c7c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -50,6 +50,7 @@
<!-- Dependencies versions. -->
<janino.version>3.0.11</janino.version>
+ <javapoet.version>1.13.0</javapoet.version>
<javax.annotation.api.version>1.3.2</javax.annotation.api.version>
<jetbrains.annotations.version>20.1.0</jetbrains.annotations.version>
<jmh.framework.verion>1.9.3</jmh.framework.verion>
[ignite-3] 01/03: Rework reflection-based Serializer with using
VarHandles.
Posted by am...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
amashenkov pushed a commit to branch ignite-13618-javapoet
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
commit b993d6b7a8a6da702b167abcd442f545f4470c4d
Author: Andrew Mashenkov <an...@gmail.com>
AuthorDate: Fri Dec 11 13:12:21 2020 +0300
Rework reflection-based Serializer with using VarHandles.
---
modules/commons/pom.xml | 5 +-
...UnsafeFieldAccessor.java => FieldAccessor.java} | 166 +++++++++------------
.../schema/marshaller/reflection/Marshaller.java | 14 +-
.../benchmarks/SerializerBenchmarkTest.java | 2 +-
.../schema/marshaller/JavaSerializerTest.java | 4 +-
.../marshaller/reflection/FieldAccessorTest.java | 14 +-
pom.xml | 5 +-
7 files changed, 94 insertions(+), 116 deletions(-)
diff --git a/modules/commons/pom.xml b/modules/commons/pom.xml
index fc78231..05a2fff 100644
--- a/modules/commons/pom.xml
+++ b/modules/commons/pom.xml
@@ -29,7 +29,7 @@
<artifactId>apache-ignite</artifactId>
<groupId>org.apache.ignite</groupId>
<version>3.0.0-SNAPSHOT</version>
- <relativePath>../..</relativePath>
+ <relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>ignite-commons</artifactId>
@@ -56,11 +56,10 @@
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
-
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
- <version>${mockito.version}</version>
+ <version>${mockito.core.version}</version>
<scope>test</scope>
</dependency>
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/UnsafeFieldAccessor.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/FieldAccessor.java
similarity index 69%
rename from modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/UnsafeFieldAccessor.java
rename to modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/FieldAccessor.java
index 72b2491..97ea038 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/UnsafeFieldAccessor.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/FieldAccessor.java
@@ -17,6 +17,8 @@
package org.apache.ignite.internal.schema.marshaller.reflection;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
import java.lang.reflect.Field;
import java.util.Objects;
import org.apache.ignite.internal.schema.Column;
@@ -26,32 +28,18 @@ import org.apache.ignite.internal.schema.TupleAssembler;
import org.apache.ignite.internal.schema.marshaller.BinaryMode;
import org.apache.ignite.internal.schema.marshaller.MarshallerUtil;
import org.apache.ignite.internal.schema.marshaller.SerializationException;
-import org.apache.ignite.internal.util.IgniteUnsafeUtils;
import org.jetbrains.annotations.Nullable;
/**
* Field accessor to speedup access.
*/
-// TODO: Extract interface, move to java-8 profile and add Java9+ implementation using VarHandles.
-public abstract class UnsafeFieldAccessor {
- /**
- * TODO: implement sesitive information filtering.
- *
- * @return {@code False} if sensitive information exoising is prohibited, {@code false} otherwise.
- */
- private static boolean includeSensitive() {
- return true;
- }
-
- /** Offset. */
- protected final long offset;
+public abstract class FieldAccessor {
+ /** VarHandle. */
+ protected final VarHandle varHandle;
/** Mode. */
protected final BinaryMode mode;
- /** Field name */
- protected final String name;
-
/**
* Mapped column position in schema.
* <p>
@@ -67,7 +55,7 @@ public abstract class UnsafeFieldAccessor {
* @param colIdx Column index in schema.
* @return Accessor.
*/
- static UnsafeFieldAccessor create(Class<?> type, Column col, int colIdx) {
+ static FieldAccessor create(Class<?> type, Column col, int colIdx) {
try {
final Field field = type.getDeclaredField(col.name());
@@ -75,25 +63,28 @@ public abstract class UnsafeFieldAccessor {
throw new IllegalArgumentException("Failed to map non-nullable field to nullable column [name=" + field.getName() + ']');
BinaryMode mode = MarshallerUtil.mode(field.getType());
+ final MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(type, MethodHandles.lookup());
+
+ VarHandle varHandle = lookup.unreflectVarHandle(field);
switch (mode) {
case P_BYTE:
- return new BytePrimitiveAccessor(field, colIdx);
+ return new BytePrimitiveAccessor(varHandle, colIdx);
case P_SHORT:
- return new ShortPrimitiveAccessor(field, colIdx);
+ return new ShortPrimitiveAccessor(varHandle, colIdx);
case P_INT:
- return new IntPrimitiveAccessor(field, colIdx);
+ return new IntPrimitiveAccessor(varHandle, colIdx);
case P_LONG:
- return new LongPrimitiveAccessor(field, colIdx);
+ return new LongPrimitiveAccessor(varHandle, colIdx);
case P_FLOAT:
- return new FloatPrimitiveAccessor(field, colIdx);
+ return new FloatPrimitiveAccessor(varHandle, colIdx);
case P_DOUBLE:
- return new DoublePrimitiveAccessor(field, colIdx);
+ return new DoublePrimitiveAccessor(varHandle, colIdx);
case BYTE:
case SHORT:
@@ -105,7 +96,7 @@ public abstract class UnsafeFieldAccessor {
case UUID:
case BYTE_ARR:
case BITSET:
- return new ReferenceFieldAccessor(field, colIdx, mode);
+ return new ReferenceFieldAccessor(varHandle, colIdx, mode);
default:
assert false : "Invalid mode " + mode;
@@ -113,7 +104,7 @@ public abstract class UnsafeFieldAccessor {
throw new IllegalArgumentException("Failed to create accessor for field [name=" + field.getName() + ']');
}
- catch (NoSuchFieldException | SecurityException ex) {
+ catch (NoSuchFieldException | SecurityException | IllegalAccessException ex) {
throw new IllegalArgumentException(ex);
}
}
@@ -126,7 +117,7 @@ public abstract class UnsafeFieldAccessor {
* @param mode Binary mode.
* @return Accessor.
*/
- static UnsafeFieldAccessor createIdentityAccessor(Column col, int colIdx, BinaryMode mode) {
+ static FieldAccessor createIdentityAccessor(Column col, int colIdx, BinaryMode mode) {
switch (mode) {
// Marshaller read/write object contract methods allowed boxed types only.
case P_BYTE:
@@ -159,19 +150,18 @@ public abstract class UnsafeFieldAccessor {
/**
* Protected constructor.
*
- * @param field Field.
+ * @param varHandle Field.
* @param colIdx Column index.
* @param mode Binary mode;
*/
- protected UnsafeFieldAccessor(Field field, int colIdx, BinaryMode mode) {
- assert field != null;
+ protected FieldAccessor(VarHandle varHandle, int colIdx, BinaryMode mode) {
+ assert varHandle != null;
assert colIdx >= 0;
assert mode != null;
this.colIdx = colIdx;
this.mode = mode;
- offset = IgniteUnsafeUtils.objectFieldOffset(field);
- name = field.getName();
+ this.varHandle = varHandle;
}
/**
@@ -180,23 +170,13 @@ public abstract class UnsafeFieldAccessor {
* @param colIdx Column index.
* @param mode Binary mode;
*/
- private UnsafeFieldAccessor(int colIdx, BinaryMode mode) {
+ private FieldAccessor(int colIdx, BinaryMode mode) {
assert colIdx >= 0;
assert mode != null;
this.colIdx = colIdx;
this.mode = mode;
- offset = 0;
- name = null;
- }
-
- /**
- * Get binary read/write mode.
- *
- * @return Binary mode.
- */
- public BinaryMode mode() {
- return mode;
+ varHandle = null;
}
/**
@@ -211,10 +191,7 @@ public abstract class UnsafeFieldAccessor {
write0(Objects.requireNonNull(obj), writer);
}
catch (Exception ex) {
- if (includeSensitive() && name != null)
- throw new SerializationException("Failed to read field [id=" + colIdx + ']', ex);
- else
- throw new SerializationException("Failed to write field [id=" + colIdx + ']', ex);
+ throw new SerializationException("Failed to write field [id=" + colIdx + ']', ex);
}
}
@@ -239,10 +216,7 @@ public abstract class UnsafeFieldAccessor {
read0(Objects.requireNonNull(obj), reader);
}
catch (Exception ex) {
- if (includeSensitive() && name != null)
- throw new SerializationException("Failed to read field [name=" + name + ']', ex);
- else
- throw new SerializationException("Failed to read field [id=" + colIdx + ']', ex);
+ throw new SerializationException("Failed to read field [id=" + colIdx + ']', ex);
}
}
@@ -272,13 +246,13 @@ public abstract class UnsafeFieldAccessor {
* @return Field value of given object.
*/
@Nullable Object value(Object obj) {
- return IgniteUnsafeUtils.getObjectField(Objects.requireNonNull(obj), offset);
+ return varHandle.get(Objects.requireNonNull(obj));
}
/**
* Accessor for field of primitive {@code byte} type.
*/
- private static class IdentityAccessor extends UnsafeFieldAccessor {
+ private static class IdentityAccessor extends FieldAccessor {
/**
* Constructor.
*
@@ -313,20 +287,20 @@ public abstract class UnsafeFieldAccessor {
/**
* Accessor for field of primitive {@code byte} type.
*/
- private static class BytePrimitiveAccessor extends UnsafeFieldAccessor {
+ private static class BytePrimitiveAccessor extends FieldAccessor {
/**
* Constructor.
*
- * @param field Field.
+ * @param varHandle VarHandle.
* @param colIdx Column index.
*/
- public BytePrimitiveAccessor(Field field, int colIdx) {
- super(field, colIdx, BinaryMode.P_BYTE);
+ public BytePrimitiveAccessor(VarHandle varHandle, int colIdx) {
+ super(varHandle, colIdx, BinaryMode.P_BYTE);
}
/** {@inheritDoc} */
@Override protected void write0(Object obj, TupleAssembler writer) {
- final byte val = IgniteUnsafeUtils.getByteField(obj, offset);
+ final byte val = (byte)varHandle.get(obj);
writer.appendByte(val);
}
@@ -335,27 +309,27 @@ public abstract class UnsafeFieldAccessor {
@Override protected void read0(Object obj, Tuple reader) {
final byte val = reader.byteValue(colIdx);
- IgniteUnsafeUtils.putByteField(obj, offset, val);
+ varHandle.set(obj, val);
}
}
/**
* Accessor for field of primitive {@code short} type.
*/
- private static class ShortPrimitiveAccessor extends UnsafeFieldAccessor {
+ private static class ShortPrimitiveAccessor extends FieldAccessor {
/**
* Constructor.
*
- * @param field Field.
+ * @param varHandle VarHandle.
* @param colIdx Column index.
*/
- public ShortPrimitiveAccessor(Field field, int colIdx) {
- super(field, colIdx, BinaryMode.P_SHORT);
+ public ShortPrimitiveAccessor(VarHandle varHandle, int colIdx) {
+ super(varHandle, colIdx, BinaryMode.P_SHORT);
}
/** {@inheritDoc} */
@Override protected void write0(Object obj, TupleAssembler writer) {
- final short val = IgniteUnsafeUtils.getShortField(obj, offset);
+ final short val = (short)varHandle.get(obj);
writer.appendShort(val);
}
@@ -364,27 +338,27 @@ public abstract class UnsafeFieldAccessor {
@Override protected void read0(Object obj, Tuple reader) {
final short val = reader.shortValue(colIdx);
- IgniteUnsafeUtils.putShortField(obj, offset, val);
+ varHandle.set(obj, val);
}
}
/**
* Accessor for field of primitive {@code int} type.
*/
- private static class IntPrimitiveAccessor extends UnsafeFieldAccessor {
+ private static class IntPrimitiveAccessor extends FieldAccessor {
/**
* Constructor.
*
- * @param field Field.
+ * @param varHandle VarHandle.
* @param colIdx Column index.
*/
- public IntPrimitiveAccessor(Field field, int colIdx) {
- super(field, colIdx, BinaryMode.P_INT);
+ public IntPrimitiveAccessor(VarHandle varHandle, int colIdx) {
+ super(varHandle, colIdx, BinaryMode.P_INT);
}
/** {@inheritDoc} */
@Override protected void write0(Object obj, TupleAssembler writer) {
- final int val = IgniteUnsafeUtils.getIntField(obj, offset);
+ final int val = (int)varHandle.get(obj);
writer.appendInt(val);
}
@@ -393,27 +367,27 @@ public abstract class UnsafeFieldAccessor {
@Override protected void read0(Object obj, Tuple reader) {
final int val = reader.intValue(colIdx);
- IgniteUnsafeUtils.putIntField(obj, offset, val);
+ varHandle.set(obj, val);
}
}
/**
* Accessor for field of primitive {@code long} type.
*/
- private static class LongPrimitiveAccessor extends UnsafeFieldAccessor {
+ private static class LongPrimitiveAccessor extends FieldAccessor {
/**
* Constructor.
*
- * @param field Field.
+ * @param varHandle VarHandle.
* @param colIdx Column index.
*/
- public LongPrimitiveAccessor(Field field, int colIdx) {
- super(field, colIdx, BinaryMode.P_LONG);
+ public LongPrimitiveAccessor(VarHandle varHandle, int colIdx) {
+ super(varHandle, colIdx, BinaryMode.P_LONG);
}
/** {@inheritDoc} */
@Override protected void write0(Object obj, TupleAssembler writer) {
- final long val = IgniteUnsafeUtils.getLongField(obj, offset);
+ final long val = (long)varHandle.get(obj);
writer.appendLong(val);
}
@@ -422,27 +396,27 @@ public abstract class UnsafeFieldAccessor {
@Override protected void read0(Object obj, Tuple reader) {
final long val = reader.longValue(colIdx);
- IgniteUnsafeUtils.putLongField(obj, offset, val);
+ varHandle.set(obj, val);
}
}
/**
* Accessor for field of primitive {@code float} type.
*/
- private static class FloatPrimitiveAccessor extends UnsafeFieldAccessor {
+ private static class FloatPrimitiveAccessor extends FieldAccessor {
/**
* Constructor.
*
- * @param field Field.
+ * @param varHandle VarHandle.
* @param colIdx Column index.
*/
- public FloatPrimitiveAccessor(Field field, int colIdx) {
- super(field, colIdx, BinaryMode.P_FLOAT);
+ public FloatPrimitiveAccessor(VarHandle varHandle, int colIdx) {
+ super(varHandle, colIdx, BinaryMode.P_FLOAT);
}
/** {@inheritDoc} */
@Override protected void write0(Object obj, TupleAssembler writer) {
- final float val = IgniteUnsafeUtils.getFloatField(obj, offset);
+ final float val = (float)varHandle.get(obj);
writer.appendFloat(val);
}
@@ -451,27 +425,27 @@ public abstract class UnsafeFieldAccessor {
@Override protected void read0(Object obj, Tuple reader) {
final float val = reader.floatValue(colIdx);
- IgniteUnsafeUtils.putFloatField(obj, offset, val);
+ varHandle.set(obj, val);
}
}
/**
* Accessor for field of primitive {@code double} type.
*/
- private static class DoublePrimitiveAccessor extends UnsafeFieldAccessor {
+ private static class DoublePrimitiveAccessor extends FieldAccessor {
/**
* Constructor.
*
- * @param field Field.
+ * @param varHandle VarHandle.
* @param colIdx Column index.
*/
- public DoublePrimitiveAccessor(Field field, int colIdx) {
- super(field, colIdx, BinaryMode.P_DOUBLE);
+ public DoublePrimitiveAccessor(VarHandle varHandle, int colIdx) {
+ super(varHandle, colIdx, BinaryMode.P_DOUBLE);
}
/** {@inheritDoc} */
@Override protected void write0(Object obj, TupleAssembler writer) {
- final double val = IgniteUnsafeUtils.getDoubleField(obj, offset);
+ final double val = (double)varHandle.get(obj);
writer.appendDouble(val);
}
@@ -480,23 +454,23 @@ public abstract class UnsafeFieldAccessor {
@Override protected void read0(Object obj, Tuple reader) {
final double val = reader.doubleValue(colIdx);
- IgniteUnsafeUtils.putDoubleField(obj, offset, val);
+ varHandle.set(obj, val);
}
}
/**
* Accessor for field of reference type.
*/
- private static class ReferenceFieldAccessor extends UnsafeFieldAccessor {
+ private static class ReferenceFieldAccessor extends FieldAccessor {
/**
* Constructor.
*
- * @param field Field.
+ * @param varHandle VarHandle.
* @param colIdx Column index.
* @param mode Binary mode.
*/
- ReferenceFieldAccessor(Field field, int colIdx, BinaryMode mode) {
- super(field, colIdx, mode);
+ ReferenceFieldAccessor(VarHandle varHandle, int colIdx, BinaryMode mode) {
+ super(varHandle, colIdx, mode);
}
/** {@inheritDoc} */
@@ -506,7 +480,7 @@ public abstract class UnsafeFieldAccessor {
Object val;
- val = IgniteUnsafeUtils.getObjectField(obj, offset);
+ val = varHandle.get(obj);
if (val == null) {
writer.appendNull();
@@ -521,7 +495,7 @@ public abstract class UnsafeFieldAccessor {
@Override public void read0(Object obj, Tuple reader) {
Object val = JavaSerializer.readRefValue(reader, colIdx, mode);
- IgniteUnsafeUtils.putObjectField(obj, offset, val);
+ varHandle.set(obj, val);
}
}
}
diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/Marshaller.java b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/Marshaller.java
index 506c3a3..a89158b 100644
--- a/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/Marshaller.java
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/schema/marshaller/reflection/Marshaller.java
@@ -51,17 +51,17 @@ public class Marshaller {
assert mode.typeSpec() == col.type().spec() : "Target type is not compatible.";
assert !aClass.isPrimitive() : "Non-nullable types are not allowed.";
- return new Marshaller(UnsafeFieldAccessor.createIdentityAccessor(col, firstColId, mode));
+ return new Marshaller(FieldAccessor.createIdentityAccessor(col, firstColId, mode));
}
- UnsafeFieldAccessor[] fieldAccessors = new UnsafeFieldAccessor[cols.length()];
+ FieldAccessor[] fieldAccessors = new FieldAccessor[cols.length()];
// Build accessors
for (int i = 0; i < cols.length(); i++) {
final Column col = cols.column(i);
final int colIdx = firstColId + i; /* Absolute column idx in schema. */
- fieldAccessors[i] = UnsafeFieldAccessor.create(aClass, col, colIdx);
+ fieldAccessors[i] = FieldAccessor.create(aClass, col, colIdx);
}
return new Marshaller(new ObjectFactory<>(aClass), fieldAccessors);
@@ -71,7 +71,7 @@ public class Marshaller {
* Field accessors for mapped columns.
* Array has same size and order as columns.
*/
- private final UnsafeFieldAccessor[] fieldAccessors;
+ private final FieldAccessor[] fieldAccessors;
/**
* Object factory for complex types or {@code null} for basic type.
@@ -86,7 +86,7 @@ public class Marshaller {
* @param fieldAccessors Object field accessors for mapped columns.
*/
@SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType")
- public Marshaller(Factory<?> factory, UnsafeFieldAccessor[] fieldAccessors) {
+ public Marshaller(Factory<?> factory, FieldAccessor[] fieldAccessors) {
this.fieldAccessors = fieldAccessors;
this.factory = Objects.requireNonNull(factory);
}
@@ -97,8 +97,8 @@ public class Marshaller {
*
* @param fieldAccessor Identity field accessor for object of basic type.
*/
- public Marshaller(UnsafeFieldAccessor fieldAccessor) {
- fieldAccessors = new UnsafeFieldAccessor[] {fieldAccessor};
+ public Marshaller(FieldAccessor fieldAccessor) {
+ fieldAccessors = new FieldAccessor[] {fieldAccessor};
factory = null;
}
diff --git a/modules/commons/src/test/java/org/apache/ignite/internal/benchmarks/SerializerBenchmarkTest.java b/modules/commons/src/test/java/org/apache/ignite/internal/benchmarks/SerializerBenchmarkTest.java
index 23193ba..1f0ebef 100644
--- a/modules/commons/src/test/java/org/apache/ignite/internal/benchmarks/SerializerBenchmarkTest.java
+++ b/modules/commons/src/test/java/org/apache/ignite/internal/benchmarks/SerializerBenchmarkTest.java
@@ -56,7 +56,7 @@ import static org.apache.ignite.internal.schema.NativeType.LONG;
@Measurement(time = 10, iterations = 5, timeUnit = TimeUnit.SECONDS)
@BenchmarkMode({Mode.Throughput, Mode.AverageTime})
@OutputTimeUnit(TimeUnit.MICROSECONDS)
-@Fork(1)
+@Fork(jvmArgs = "-Djava.lang.invoke.stringConcat=BC_SB" /* Workaround for Java 9+ */, value = 1)
public class SerializerBenchmarkTest {
/** Random. */
private Random rnd = new Random();
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
index 49ef554..d172e86 100644
--- 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
@@ -245,7 +245,7 @@ public class JavaSerializerTest {
*/
@ParameterizedTest
@MethodSource("serializerFactoryProvider")
- public void testClassWithNoDefaultConstructor(SerializerFactory factory) throws SerializationException {
+ public void testClassWithNoDefaultConstructor(SerializerFactory factory) {
Column[] cols = new Column[] {
new Column("pLongCol", LONG, false),
};
@@ -340,7 +340,9 @@ public class JavaSerializerTest {
obj.longCol = rnd.nextLong();
obj.floatCol = rnd.nextFloat();
obj.doubleCol = rnd.nextDouble();
+ obj.nullLongCol = null;
+ obj.nullBytesCol = null;
obj.uuidCol = new UUID(rnd.nextLong(), rnd.nextLong());
obj.bitmaskCol = TestUtils.randomBitSet(rnd, 42);
obj.stringCol = TestUtils.randomString(rnd, rnd.nextInt(255));
diff --git a/modules/commons/src/test/java/org/apache/ignite/internal/schema/marshaller/reflection/FieldAccessorTest.java b/modules/commons/src/test/java/org/apache/ignite/internal/schema/marshaller/reflection/FieldAccessorTest.java
index 8e864d6..2cec0b3 100644
--- a/modules/commons/src/test/java/org/apache/ignite/internal/schema/marshaller/reflection/FieldAccessorTest.java
+++ b/modules/commons/src/test/java/org/apache/ignite/internal/schema/marshaller/reflection/FieldAccessorTest.java
@@ -103,7 +103,7 @@ public class FieldAccessorTest {
final TestObject obj = TestObject.randomObject(rnd);
for (int i = 0; i < cols.length; i++) {
- UnsafeFieldAccessor accessor = UnsafeFieldAccessor.create(TestObject.class, cols[i], i);
+ FieldAccessor accessor = FieldAccessor.create(TestObject.class, cols[i], i);
accessor.write(obj, tupleAssembler);
}
@@ -111,7 +111,7 @@ public class FieldAccessorTest {
final TestObject restoredObj = new TestObject();
for (int i = 0; i < cols.length; i++) {
- UnsafeFieldAccessor accessor = UnsafeFieldAccessor.create(TestObject.class, cols[i], i);
+ FieldAccessor accessor = FieldAccessor.create(TestObject.class, cols[i], i);
accessor.read(restoredObj, tuple);
}
@@ -159,7 +159,7 @@ public class FieldAccessorTest {
obj.stringCol = TestUtils.randomString(rnd, 255);
for (int i = 0; i < cols.length; i++) {
- UnsafeFieldAccessor accessor = UnsafeFieldAccessor.create(TestSimpleObject.class, cols[i], i);
+ FieldAccessor accessor = FieldAccessor.create(TestSimpleObject.class, cols[i], i);
accessor.write(obj, tupleAssembler);
}
@@ -167,7 +167,7 @@ public class FieldAccessorTest {
final TestSimpleObject restoredObj = new TestSimpleObject();
for (int i = 0; i < cols.length; i++) {
- UnsafeFieldAccessor accessor = UnsafeFieldAccessor.create(TestSimpleObject.class, cols[i], i);
+ FieldAccessor accessor = FieldAccessor.create(TestSimpleObject.class, cols[i], i);
accessor.read(restoredObj, tuple);
}
@@ -184,7 +184,7 @@ public class FieldAccessorTest {
*/
@Test
public void testIdentityAccessor() throws Exception {
- final UnsafeFieldAccessor accessor = UnsafeFieldAccessor.createIdentityAccessor(
+ final FieldAccessor accessor = FieldAccessor.createIdentityAccessor(
new Column("col0", STRING, true),
0,
BinaryMode.STRING);
@@ -202,7 +202,7 @@ public class FieldAccessorTest {
*/
@Test
public void testWrongIdentityAccessor() throws Exception {
- final UnsafeFieldAccessor accessor = UnsafeFieldAccessor.createIdentityAccessor(
+ final FieldAccessor accessor = FieldAccessor.createIdentityAccessor(
new Column("col0", STRING, true),
42,
BinaryMode.UUID);
@@ -242,7 +242,7 @@ public class FieldAccessorTest {
final Answer<Object> tupleAnswer = new Answer<Object>() {
@Override public Object answer(InvocationOnMock invocation) {
- final int idx = invocation.getArgumentAt(0, Integer.class);
+ final int idx = invocation.getArgument(0, Integer.class);
return vals.get(idx);
}
diff --git a/pom.xml b/pom.xml
index 2d460d4..7d1a734 100644
--- a/pom.xml
+++ b/pom.xml
@@ -54,9 +54,12 @@
<jetbrains.annotations.version>20.1.0</jetbrains.annotations.version>
<jmh.framework.verion>1.9.3</jmh.framework.verion>
<junit.jupiter.version>5.7.0</junit.jupiter.version>
- <mockito.version>1.10.19</mockito.version>
+ <mockito.core.version>3.6.28</mockito.core.version>
<!-- Maven plugins -->
+ <maven.compiler.source>11</maven.compiler.source> <!-- Requires for correct compilation in IDEA. -->
+ <maven.compiler.target>11</maven.compiler.target>
+
<maven.compiler.plugin.version>3.8.1</maven.compiler.plugin.version>
<maven.surefire.plugin.version>3.0.0-M4</maven.surefire.plugin.version>
<apache.rat.plugin.version>0.13</apache.rat.plugin.version>