Repository: ignite Updated Branches: refs/heads/ignite-2100 43a3de5ad -> 3e6fbb1ed
IGNITE-2100: WIP. Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/19651460 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/19651460 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/19651460 Branch: refs/heads/ignite-2100 Commit: 196514600a578a05f5a20445c2097d1155ccda35 Parents: 43a3de5 Author: vozerov-gridgain <voze...@gridgain.com> Authored: Wed Dec 16 12:56:26 2015 +0300 Committer: vozerov-gridgain <voze...@gridgain.com> Committed: Wed Dec 16 12:56:26 2015 +0300 ---------------------------------------------------------------------- .../binary/BinaryReflectiveSerializer.java | 33 ++++++++ .../ignite/binary/BinaryTypeConfiguration.java | 47 +----------- .../internal/binary/BinaryClassDescriptor.java | 28 ++++--- .../ignite/internal/binary/BinaryContext.java | 79 +++++++++----------- .../ignite/internal/binary/BinaryUtils.java | 22 +++++- .../processors/query/GridQueryProcessor.java | 24 +++--- 6 files changed, 117 insertions(+), 116 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/19651460/modules/core/src/main/java/org/apache/ignite/binary/BinaryReflectiveSerializer.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/binary/BinaryReflectiveSerializer.java b/modules/core/src/main/java/org/apache/ignite/binary/BinaryReflectiveSerializer.java new file mode 100644 index 0000000..fd0f841 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/binary/BinaryReflectiveSerializer.java @@ -0,0 +1,33 @@ +/* + * 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.binary; + +/** + * Binary serializer which writes object fields using reflection. Transient fields are not written. + */ +public class BinaryReflectiveSerializer implements BinarySerializer { + /** {@inheritDoc} */ + @Override public void writeBinary(Object obj, BinaryWriter writer) throws BinaryObjectException { + assert false : "Method should not be called directly."; + } + + /** {@inheritDoc} */ + @Override public void readBinary(Object obj, BinaryReader reader) throws BinaryObjectException { + assert false : "Method should not be called directly."; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/19651460/modules/core/src/main/java/org/apache/ignite/binary/BinaryTypeConfiguration.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/binary/BinaryTypeConfiguration.java b/modules/core/src/main/java/org/apache/ignite/binary/BinaryTypeConfiguration.java index c9bdac1..a00c061 100644 --- a/modules/core/src/main/java/org/apache/ignite/binary/BinaryTypeConfiguration.java +++ b/modules/core/src/main/java/org/apache/ignite/binary/BinaryTypeConfiguration.java @@ -17,13 +17,10 @@ package org.apache.ignite.binary; -import org.apache.ignite.internal.binary.BinaryMarshaller; +import org.apache.ignite.configuration.BinaryConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.internal.util.typedef.internal.A; import org.apache.ignite.internal.util.typedef.internal.S; -import org.apache.ignite.configuration.IgniteConfiguration; -import org.apache.ignite.configuration.BinaryConfiguration; - -import java.io.Externalizable; /** * Defines configuration properties for a specific binary type. Providing per-type @@ -33,9 +30,6 @@ import java.io.Externalizable; * binary type without affecting configuration for other binary types. */ public class BinaryTypeConfiguration { - /** Default value of "ignore Java serialization" flag. */ - public static final boolean DFLT_IGNORE_JAVA_SER = false; - /** Class name. */ private String typeName; @@ -48,9 +42,6 @@ public class BinaryTypeConfiguration { /** Enum flag. */ private boolean isEnum; - /** Ignore Java serialization flag. */ - private boolean ignoreJavaSer = DFLT_IGNORE_JAVA_SER; - /** * Constructor. */ @@ -70,7 +61,6 @@ public class BinaryTypeConfiguration { idMapper = other.idMapper; serializer = other.serializer; isEnum = other.isEnum; - ignoreJavaSer = other.ignoreJavaSer; } /** @@ -152,39 +142,6 @@ public class BinaryTypeConfiguration { this.isEnum = isEnum; } - /** - * Gets whether to ignore Java serialization mechanisms. - * <p> - * {@link BinaryMarshaller} allows for objects to be used without deserialization. To achieve this fields metadata - * must be written along with their values. When custom Java serialization mechanics is present (such as - * {@link Externalizable} or {@code writeObject()} method), Ignite has to respect it. But fields metadata cannot - * be written in this case and so objects will be deserialized on the server. - * <p> - * To avoid deserialization on the server you can set this property to {@code true}. In this case Ignite will - * ignore custom Java serialization and will write all objects fields (except of transient ones) directly. - * <p> - * Note that there are other ways to achieve the same things: - * <ul> - * <li>Implement {@link Binarylizable} interface;</li> - * <li>Define custom {@link BinaryIdMapper} using {@link #setIdMapper(BinaryIdMapper)}.</li> - * </ul> - * Defaults to {@link #DFLT_IGNORE_JAVA_SER}. - * - * @return {@code True} if Java serialization should be ignored. - */ - public boolean isIgnoreJavaSerialization() { - return ignoreJavaSer; - } - - /** - * Sets whether to ignore Java serialization mechanisms. See {@link #isIgnoreJavaSerialization()} for details. - * - * @param ignoreJavaSer {@code True} if Java serialization should be ignored. - */ - public void setIgnoreJavaSerialization(boolean ignoreJavaSer) { - this.ignoreJavaSer = ignoreJavaSer; - } - /** {@inheritDoc} */ @Override public String toString() { return S.toString(BinaryTypeConfiguration.class, this, super.toString()); http://git-wip-us.apache.org/repos/asf/ignite/blob/19651460/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryClassDescriptor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryClassDescriptor.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryClassDescriptor.java index ab1a858..7d19c18 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryClassDescriptor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryClassDescriptor.java @@ -20,6 +20,7 @@ package org.apache.ignite.internal.binary; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.binary.BinaryIdMapper; import org.apache.ignite.binary.BinaryObjectException; +import org.apache.ignite.binary.BinaryReflectiveSerializer; import org.apache.ignite.binary.BinarySerializer; import org.apache.ignite.binary.Binarylizable; import org.apache.ignite.internal.processors.cache.CacheObjectImpl; @@ -61,7 +62,7 @@ public class BinaryClassDescriptor { /** */ private final Class<?> cls; - /** */ + /** Configured serializer. */ private final BinarySerializer serializer; /** ID mapper. */ @@ -124,7 +125,6 @@ public class BinaryClassDescriptor { * @param metaDataEnabled Metadata enabled flag. * @param registered Whether typeId has been successfully registered by MarshallerContext or not. * @param predefined Whether the class is predefined or not. - * @param useDfltSerialization Whether to use default configuration. * @throws BinaryObjectException In case of error. */ BinaryClassDescriptor( @@ -137,14 +137,19 @@ public class BinaryClassDescriptor { @Nullable BinaryIdMapper idMapper, @Nullable BinarySerializer serializer, boolean metaDataEnabled, - boolean registered, - boolean predefined, - boolean useDfltSerialization + boolean registered ) throws BinaryObjectException { assert ctx != null; assert cls != null; assert idMapper != null; + // If serializer is not defined at this point, then we have to user OptimizedMarshaller. + useOptMarshaller = serializer == null; + + // Reset reflective serializer so that we rely on existing reflection-based serialization. + if (serializer instanceof BinaryReflectiveSerializer) + serializer = null; + this.ctx = ctx; this.cls = cls; this.typeId = typeId; @@ -159,10 +164,10 @@ public class BinaryClassDescriptor { excluded = MarshallerExclusions.isExcluded(cls); - useOptMarshaller = !predefined && useDfltSerialization && BinaryUtils.requireOptimizedMarshaller(cls); - if (excluded) mode = BinaryWriteMode.EXCLUSION; + else if (useOptMarshaller) + mode = BinaryWriteMode.OBJECT; // Will not be used anywhere. else { if (cls == BinaryEnumObjectImpl.class) mode = BinaryWriteMode.BINARY_ENUM; @@ -171,10 +176,11 @@ public class BinaryClassDescriptor { } if (useOptMarshaller) { - // TODO: IGNITE-2100: Correct warning. - - U.warn(ctx.log(), "Ignored \"Externalizable\" interface for class (use " + - "BinaryTypeConfiguration.setUseDefaultSerialization(true) to enable it): " + cls.getName()); + U.warn(ctx.log(), "Class \"" + cls.getName() + "\" cannot be written in binary format because it " + + "either implements Externalizable interface or have writeObject/readObject methods. Please ensure " + + "that all nodes have this class in classpath. To enable binary serialization either implement " + + Binarylizable.class.getSimpleName() + " interface or set explicit serializer using " + + "BinaryTypeConfiguration.setSerializer() method." ); } switch (mode) { http://git-wip-us.apache.org/repos/asf/ignite/blob/19651460/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java index 2f32629..fbbec80 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java @@ -22,6 +22,7 @@ import org.apache.ignite.IgniteLogger; import org.apache.ignite.binary.BinaryIdMapper; import org.apache.ignite.binary.BinaryInvalidTypeException; import org.apache.ignite.binary.BinaryObjectException; +import org.apache.ignite.binary.BinaryReflectiveSerializer; import org.apache.ignite.binary.BinarySerializer; import org.apache.ignite.binary.BinaryType; import org.apache.ignite.binary.BinaryTypeConfiguration; @@ -115,8 +116,7 @@ public class BinaryContext implements Externalizable { private final Map<String, BinaryIdMapper> typeMappers = new ConcurrentHashMap8<>(0); /** Non-default serialization flags. */ - private final Set<Integer> nonDfltSerializationFlags = - Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>()); + private final Set<String> forceBinaryFlags = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>()); /** */ private BinaryMetadataHandler metaHnd; @@ -214,7 +214,7 @@ public class BinaryContext implements Externalizable { registerPredefinedType(HashMap.class, 0); registerPredefinedType(LinkedHashMap.class, 0); - // Classes with overriden default serialziation flag. + // Classes with overriden default serialization flag. registerPredefinedType(AffinityKey.class, 0, false); registerPredefinedType(BinaryObjectImpl.class, 0, false); registerPredefinedType(BinaryObjectOffheapImpl.class, 0, false); @@ -241,15 +241,15 @@ public class BinaryContext implements Externalizable { } /** - * Whether binary marshalling is forced for class. + * Check whether class must be deserialized anyway. * * @param cls Class. - * @return {@code True} if forced. + * @return {@code True} if must be deserialized. */ - public boolean forceBinaryMarshalling(Class cls) { - int typeId = typeId(cls.getName()); + public boolean mustDeserialize(Class cls) { + BinaryClassDescriptor desc = descriptorForClass(cls, false); - return nonDfltSerializationFlags.contains(typeId); + return desc.useOptimizedMarshaller(); } /** @@ -334,17 +334,16 @@ public class BinaryContext implements Externalizable { for (String clsName0 : classesInPackage(pkgName)) descs.add(clsName0, idMapper, serializer, affFields.get(clsName0), - typeCfg.isEnum(), !typeCfg.isIgnoreJavaSerialization(), true); + typeCfg.isEnum(), true); } else descs.add(clsName, idMapper, serializer, affFields.get(clsName), - typeCfg.isEnum(), !typeCfg.isIgnoreJavaSerialization(), false); + typeCfg.isEnum(), false); } } for (TypeDescriptor desc : descs.descriptors()) - registerUserType(desc.clsName, desc.idMapper, desc.serializer, desc.affKeyFieldName, desc.isEnum, - desc.useJavaSerialization); + registerUserType(desc.clsName, desc.idMapper, desc.serializer, desc.affKeyFieldName, desc.isEnum); BinaryInternalIdMapper dfltMapper = BinaryInternalIdMapper.create(globalIdMapper); @@ -541,9 +540,7 @@ public class BinaryContext implements Externalizable { BinaryInternalIdMapper.defaultInstance(), null, false, - true, /* registered */ - false, /* predefined */ - true /* prefer default serialization */ + true /* registered */ ); BinaryClassDescriptor old = descByCls.putIfAbsent(cls, desc); @@ -579,6 +576,9 @@ public class BinaryContext implements Externalizable { throw new BinaryObjectException("Failed to register class.", e); } + BinarySerializer serializer = BinaryUtils.isBinarylizable(cls) || !BinaryUtils.isCustomJavaSerialization(cls) ? + new BinaryReflectiveSerializer() : null; + String affFieldName = affinityFieldName(cls); BinaryClassDescriptor desc = new BinaryClassDescriptor(this, @@ -588,11 +588,9 @@ public class BinaryContext implements Externalizable { typeName, affFieldName, idMapper, - null, + serializer, true, - registered, - false /* predefined */, - !nonDfltSerializationFlags.contains(typeId) + registered ); if (!deserialize) { @@ -743,10 +741,10 @@ public class BinaryContext implements Externalizable { /** * @param cls Class. * @param id Type ID. - * @param useDfltSerialization Use default serialization flag. + * @param javaSerialization Use default serialization flag. * @return GridBinaryClassDescriptor. */ - public BinaryClassDescriptor registerPredefinedType(Class<?> cls, int id, boolean useDfltSerialization) { + public BinaryClassDescriptor registerPredefinedType(Class<?> cls, int id, boolean javaSerialization) { String typeName = typeName(cls.getName()); if (id == 0) @@ -760,11 +758,9 @@ public class BinaryContext implements Externalizable { typeName, null, BinaryInternalIdMapper.defaultInstance(), - null, + javaSerialization ? null : new BinaryReflectiveSerializer(), false, - true, /* registered */ - true, /* predefined */ - useDfltSerialization /* default serialization */ + true /* registered */ ); predefinedTypeNames.put(typeName, id); @@ -781,7 +777,6 @@ public class BinaryContext implements Externalizable { * @param serializer Serializer. * @param affKeyFieldName Affinity key field name. * @param isEnum If enum. - * @param useJavaSerialization Use default serialization flag. * @throws BinaryObjectException In case of error. */ @SuppressWarnings("ErrorNotRethrown") @@ -789,8 +784,7 @@ public class BinaryContext implements Externalizable { BinaryIdMapper idMapper, @Nullable BinarySerializer serializer, @Nullable String affKeyFieldName, - boolean isEnum, - boolean useJavaSerialization) + boolean isEnum) throws BinaryObjectException { assert idMapper != null; @@ -821,13 +815,21 @@ public class BinaryContext implements Externalizable { typeMappers.put(typeName, idMapper); - if (!useJavaSerialization) - nonDfltSerializationFlags.add(id); - Map<String, Integer> fieldsMeta = null; Collection<BinarySchema> schemas = null; if (cls != null) { + if (serializer == null) { + // At this point we must decide whether to rely on Java serialization mechanics or not. + // If no serializer is provided, we examine the class and if it doesn't contain non-trivial + // serialization logic we are safe to fallback to reflective binary serialization. + if (BinaryUtils.isBinarylizable(cls) || !BinaryUtils.isCustomJavaSerialization(cls)) + serializer = new BinaryReflectiveSerializer(); + } + + if (serializer != null) + forceBinaryFlags.add(cls.getName()); + BinaryClassDescriptor desc = new BinaryClassDescriptor( this, cls, @@ -838,9 +840,7 @@ public class BinaryContext implements Externalizable { idMapper, serializer, true, - true, /* registered */ - false, /* predefined */ - useJavaSerialization + true /* registered */ ); fieldsMeta = desc.fieldsMeta(); @@ -1028,7 +1028,6 @@ public class BinaryContext implements Externalizable { * @param serializer Serializer. * @param affKeyFieldName Affinity key field name. * @param isEnum Enum flag. - * @param useJavaSer Whether to use Java serialization. * @param canOverride Whether this descriptor can be override. * @throws BinaryObjectException If failed. */ @@ -1037,7 +1036,6 @@ public class BinaryContext implements Externalizable { BinarySerializer serializer, String affKeyFieldName, boolean isEnum, - boolean useJavaSer, boolean canOverride) throws BinaryObjectException { TypeDescriptor desc = new TypeDescriptor(clsName, @@ -1045,7 +1043,6 @@ public class BinaryContext implements Externalizable { serializer, affKeyFieldName, isEnum, - useJavaSer, canOverride); TypeDescriptor oldDesc = descs.get(clsName); @@ -1085,9 +1082,6 @@ public class BinaryContext implements Externalizable { /** Enum flag. */ private boolean isEnum; - /** Use default serialization flag. */ - private boolean useJavaSerialization; - /** Whether this descriptor can be override. */ private boolean canOverride; @@ -1099,17 +1093,15 @@ public class BinaryContext implements Externalizable { * @param serializer Serializer. * @param affKeyFieldName Affinity key field name. * @param isEnum Enum type. - * @param useJavaSerialization Use default serialization flag. * @param canOverride Whether this descriptor can be override. */ private TypeDescriptor(String clsName, BinaryIdMapper idMapper, BinarySerializer serializer, - String affKeyFieldName, boolean isEnum, boolean useJavaSerialization, boolean canOverride) { + String affKeyFieldName, boolean isEnum, boolean canOverride) { this.clsName = clsName; this.idMapper = idMapper; this.serializer = serializer; this.affKeyFieldName = affKeyFieldName; this.isEnum = isEnum; - this.useJavaSerialization = useJavaSerialization; this.canOverride = canOverride; } @@ -1126,6 +1118,7 @@ public class BinaryContext implements Externalizable { idMapper = other.idMapper; serializer = other.serializer; affKeyFieldName = other.affKeyFieldName; + isEnum = other.isEnum; canOverride = other.canOverride; } else if (!other.canOverride) http://git-wip-us.apache.org/repos/asf/ignite/blob/19651460/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java index 2a7415a..52a14f0 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java @@ -1842,14 +1842,28 @@ public class BinaryUtils { } /** - * Determines whether to use {@link OptimizedMarshaller} for serialization or - * not. + * Check if class is binarylizable. * * @param cls Class. - * @return {@code true} if to use, {@code false} otherwise. + * @return {@code True} if binarylizable. + */ + public static boolean isBinarylizable(Class cls) { + for (Class c = cls; c != null && !c.equals(Object.class); c = c.getSuperclass()) { + if (Binarylizable.class.isAssignableFrom(c)) + return true; + } + + return false; + } + + /** + * Determines whether class contains custom Java serialization logic. + * + * @param cls Class. + * @return {@code true} if custom Java serialization logic exists, {@code false} otherwise. */ @SuppressWarnings("unchecked") - public static boolean requireOptimizedMarshaller(Class cls) { + public static boolean isCustomJavaSerialization(Class cls) { for (Class c = cls; c != null && !c.equals(Object.class); c = c.getSuperclass()) { if (Externalizable.class.isAssignableFrom(c)) return true; http://git-wip-us.apache.org/repos/asf/ignite/blob/19651460/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java index 4d6e66b..b75f473 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java @@ -217,8 +217,8 @@ public class GridQueryProcessor extends GridProcessorAdapter { Class<?> valCls = U.classForName(qryEntity.getValueType(), null); // If local node has the classes and they are externalizable, we must use reflection properties. - boolean binaryKeyAsOptimized = binaryAsOptimized(keyCls); - boolean binaryValAsOptimized = binaryAsOptimized(valCls); + boolean binaryKeyAsOptimized = mustDeserializeBinary(keyCls); + boolean binaryValAsOptimized = mustDeserializeBinary(valCls); boolean binaryKeyOrValAsOptimized = binaryKeyAsOptimized || binaryValAsOptimized; @@ -308,8 +308,8 @@ public class GridQueryProcessor extends GridProcessorAdapter { Class<?> valCls = U.classForName(meta.getValueType(), null); // If local node has the classes and they are externalizable, we must use reflection properties. - boolean binaryKeyAsOptimized = binaryAsOptimized(keyCls); - boolean binaryValAsOptimized= binaryAsOptimized(valCls); + boolean binaryKeyAsOptimized = mustDeserializeBinary(keyCls); + boolean binaryValAsOptimized= mustDeserializeBinary(valCls); boolean binaryKeyOrValAsOptimized = binaryKeyAsOptimized || binaryValAsOptimized; @@ -388,21 +388,19 @@ public class GridQueryProcessor extends GridProcessorAdapter { } /** - * Check whether class will be deserialized anyways. + * Check whether type still must be deserialized when binary marshaller is set. * * @param cls Class. * @return {@code True} if will be deserialized. */ - private boolean binaryAsOptimized(Class cls) { - if (BinaryUtils.requireOptimizedMarshaller(cls)) { - if (ctx.config().getMarshaller() instanceof BinaryMarshaller) { - CacheObjectBinaryProcessorImpl proc0 = (CacheObjectBinaryProcessorImpl)ctx.cacheObjects(); + private boolean mustDeserializeBinary(Class cls) { + if (ctx.config().getMarshaller() instanceof BinaryMarshaller) { + CacheObjectBinaryProcessorImpl proc0 = (CacheObjectBinaryProcessorImpl)ctx.cacheObjects(); - return !proc0.binaryContext().forceBinaryMarshalling(cls); - } + return proc0.binaryContext().mustDeserialize(cls); } - - return false; + else + return false; } /**