You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by il...@apache.org on 2019/12/31 13:08:27 UTC
[ignite] branch master updated: IGNITE-12479 Make binary metadata
be registered only once per type creation - Fixes #7178.
This is an automated email from the ASF dual-hosted git repository.
ilyak pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new 66593af IGNITE-12479 Make binary metadata be registered only once per type creation - Fixes #7178.
66593af is described below
commit 66593af03aeac37d0e76b6c010e8386f6f0c36c7
Author: Denis Mekhanikov <dm...@gmail.com>
AuthorDate: Tue Dec 31 15:31:12 2019 +0300
IGNITE-12479 Make binary metadata be registered only once per type creation - Fixes #7178.
Signed-off-by: Ilya Kasnacheev <il...@gmail.com>
---
.../internal/binary/BinaryClassDescriptor.java | 64 ++++
.../ignite/internal/binary/BinaryContext.java | 321 +++++++++------------
.../internal/binary/BinaryEnumObjectImpl.java | 11 +-
.../ignite/internal/binary/BinaryReaderExImpl.java | 6 +-
.../apache/ignite/internal/binary/BinaryUtils.java | 12 +-
.../ignite/internal/binary/BinaryWriterExImpl.java | 29 +-
.../internal/binary/builder/BinaryBuilderEnum.java | 2 +-
.../binary/builder/BinaryBuilderSerializer.java | 2 +-
.../binary/builder/BinaryEnumArrayLazyValue.java | 2 +-
.../binary/builder/BinaryObjectArrayLazyValue.java | 2 +-
.../binary/builder/BinaryObjectBuilderImpl.java | 2 +-
.../cache/binary/BinaryMetadataTransport.java | 2 +-
.../distributed/dht/atomic/GridDhtAtomicCache.java | 2 +-
.../processors/query/GridQueryProcessor.java | 2 +-
.../internal/binary/BinaryMarshallerSelfTest.java | 4 +-
.../binary/BinaryMetadataRegistrationTest.java | 230 +++++++++++++++
.../testsuites/IgniteBinaryObjectsTestSuite.java | 2 +
17 files changed, 470 insertions(+), 225 deletions(-)
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 4ae17cf..da6b5e0 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
@@ -405,6 +405,20 @@ public class BinaryClassDescriptor {
}
/**
+ * @return {@code True} if the type is registered as an OBJECT.
+ */
+ boolean isObject() {
+ return mode == BinaryWriteMode.OBJECT;
+ }
+
+ /**
+ * @return {@code True} if the type is registered as a BINARY object.
+ */
+ boolean isBinary() {
+ return mode == BinaryWriteMode.BINARY;
+ }
+
+ /**
* @return Described class.
*/
Class<?> describedClass() {
@@ -915,6 +929,56 @@ public class BinaryClassDescriptor {
}
/**
+ * @return A copy of this {@code BinaryClassDescriptor} marked as registered.
+ */
+ BinaryClassDescriptor makeRegistered() {
+ if (registered)
+ return this;
+ else
+ return new BinaryClassDescriptor(ctx,
+ cls,
+ userType,
+ typeId,
+ typeName,
+ affKeyFieldName,
+ mapper,
+ initialSerializer,
+ stableFieldsMeta != null,
+ true);
+ }
+
+ /**
+ * @return Instance of {@link BinaryMetadata} for this type.
+ */
+ BinaryMetadata metadata() {
+ return new BinaryMetadata(
+ typeId,
+ typeName,
+ stableFieldsMeta,
+ affKeyFieldName,
+ null,
+ isEnum(),
+ cls.isEnum() ? enumMap(cls) : null);
+ }
+
+ /**
+ * @param cls Enum class.
+ * @return Enum name to ordinal mapping.
+ */
+ private static Map<String, Integer> enumMap(Class<?> cls) {
+ assert cls.isEnum();
+
+ Object[] enumVals = cls.getEnumConstants();
+
+ Map<String, Integer> enumMap = new LinkedHashMap<>(enumVals.length);
+
+ for (Object enumVal : enumVals)
+ enumMap.put(((Enum)enumVal).name(), ((Enum)enumVal).ordinal());
+
+ return enumMap;
+ }
+
+ /**
* Pre-write phase.
*
* @param writer Writer.
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 5e05fea..825da30 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
@@ -120,6 +120,7 @@ import org.apache.ignite.lang.IgniteBiTuple;
import org.apache.ignite.lang.IgniteUuid;
import org.apache.ignite.marshaller.MarshallerContext;
import org.apache.ignite.marshaller.MarshallerUtils;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static org.apache.ignite.internal.MarshallerPlatformIds.JAVA_ID;
@@ -611,92 +612,129 @@ public class BinaryContext {
}
/**
- * @param cls Class.
+ * Attempts registration of the provided class. If the type is already registered, then an existing descriptor is
+ * returned.
+ *
+ * @param cls Class to register.
+ * @param registerMeta If {@code true}, then metadata will be registered along with the class descriptor.
* @param failIfUnregistered Throw exception if class isn't registered.
* @return Class descriptor.
* @throws BinaryObjectException In case of error.
*/
- public BinaryClassDescriptor descriptorForClass(Class<?> cls, boolean deserialize, boolean failIfUnregistered)
- throws BinaryObjectException {
- return descriptorForClass(cls, deserialize, failIfUnregistered, false);
+ @NotNull public BinaryClassDescriptor registerClass(
+ Class<?> cls,
+ boolean registerMeta,
+ boolean failIfUnregistered
+ ) throws BinaryObjectException {
+ return registerClass(cls, registerMeta, failIfUnregistered, false);
}
/**
* @param cls Class.
* @param failIfUnregistered Throw exception if class isn't registered.
+ * @param registerMeta If {@code true}, then metadata will be registered along with the class descriptor.
* @param onlyLocReg {@code true} if descriptor need to register only locally when registration is required at all.
* @return Class descriptor.
* @throws BinaryObjectException In case of error.
*/
- public BinaryClassDescriptor descriptorForClass(
+ @NotNull public BinaryClassDescriptor registerClass(
Class<?> cls,
- boolean deserialize,
+ boolean registerMeta,
boolean failIfUnregistered,
boolean onlyLocReg
) throws BinaryObjectException {
assert cls != null;
- BinaryClassDescriptor desc = descByCls.get(cls);
+ BinaryClassDescriptor desc = descriptorForClass(cls);
- if (desc == null) {
+ if (!desc.registered()) {
if (failIfUnregistered)
throw new UnregisteredClassException(cls);
-
- desc = registerClassDescriptor(cls, deserialize, onlyLocReg);
+ else
+ desc = registerDescriptor(desc, registerMeta, onlyLocReg);
}
- else if (!desc.registered()) {
- if (!desc.userType()) {
- BinaryClassDescriptor desc0 = new BinaryClassDescriptor(
- this,
- desc.describedClass(),
- false,
- desc.typeId(),
- desc.typeName(),
- desc.affFieldKeyName(),
- desc.mapper(),
- desc.initialSerializer(),
- false,
- true
- );
-
- if (descByCls.replace(cls, desc, desc0)) {
- Collection<BinarySchema> schemas =
- desc0.schema() != null ? Collections.singleton(desc.schema()) : null;
-
- BinaryMetadata meta = new BinaryMetadata(desc0.typeId(),
- desc0.typeName(),
- desc0.fieldsMeta(),
- desc0.affFieldKeyName(),
- schemas, desc0.isEnum(),
- cls.isEnum() ? enumMap(cls) : null);
-
- metaHnd.addMeta(desc0.typeId(), meta.wrap(this), false);
-
- return desc0;
- }
- }
- else {
- if (failIfUnregistered)
- throw new UnregisteredClassException(cls);
- desc = registerUserClassDescriptor(desc, onlyLocReg);
- }
+ return desc;
+ }
+
+ /**
+ * @param cls Class.
+ * @return A descriptor for the given class. If the class hasn't been registered yet, then a new descriptor will be
+ * created, but its {@link BinaryClassDescriptor#registered()} will be {@code false}.
+ */
+ @NotNull BinaryClassDescriptor descriptorForClass(Class<?> cls) {
+ assert cls != null;
+
+ BinaryClassDescriptor desc = descByCls.get(cls);
+
+ if (desc != null)
+ return desc;
+ else
+ return createDescriptorForClass(cls);
+ }
+
+ /**
+ * @param cls Class to create a descriptor for.
+ * @return A descriptor for the given class. The descriptor needs to be registered in order to be used.
+ */
+ @NotNull private BinaryClassDescriptor createDescriptorForClass(Class<?> cls) {
+ String clsName = cls.getName();
+
+ if (marshCtx.isSystemType(clsName)) {
+ BinarySerializer serializer = null;
+
+ if (BINARYLIZABLE_SYS_CLSS.contains(clsName))
+ serializer = new BinaryReflectiveSerializer();
+
+ return new BinaryClassDescriptor(this,
+ cls,
+ false,
+ clsName.hashCode(),
+ clsName,
+ null,
+ SIMPLE_NAME_LOWER_CASE_MAPPER,
+ serializer,
+ false,
+ false
+ );
}
+ else {
+ BinaryInternalMapper mapper = userTypeMapper(clsName);
- return desc;
+ final String typeName = mapper.typeName(clsName);
+
+ final int typeId = mapper.typeId(clsName);
+
+ BinarySerializer serializer = serializerForClass(cls);
+
+ String affFieldName = affinityFieldName(cls);
+
+ return new BinaryClassDescriptor(this,
+ cls,
+ true,
+ typeId,
+ typeName,
+ affFieldName,
+ mapper,
+ serializer,
+ true,
+ false
+ );
+ }
}
/**
* @param userType User type or not.
* @param typeId Type ID.
* @param ldr Class loader.
+ * @param registerMeta If {@code true}, then metadata will be registered along with the type descriptor.
* @return Class descriptor.
*/
public BinaryClassDescriptor descriptorForTypeId(
boolean userType,
int typeId,
ClassLoader ldr,
- boolean deserialize
+ boolean registerMeta
) {
assert typeId != GridBinaryMarshaller.UNREGISTERED_TYPE_ID;
@@ -718,21 +756,21 @@ public class BinaryContext {
}
catch (ClassNotFoundException e) {
// Class might have been loaded by default class loader.
- if (userType && !ldr.equals(sysLdr) && (desc = descriptorForTypeId(true, typeId, sysLdr, deserialize)) != null)
+ if (userType && !ldr.equals(sysLdr) && (desc = descriptorForTypeId(true, typeId, sysLdr, registerMeta)) != null)
return desc;
throw new BinaryInvalidTypeException(e);
}
catch (IgniteCheckedException e) {
// Class might have been loaded by default class loader.
- if (userType && !ldr.equals(sysLdr) && (desc = descriptorForTypeId(true, typeId, sysLdr, deserialize)) != null)
+ if (userType && !ldr.equals(sysLdr) && (desc = descriptorForTypeId(true, typeId, sysLdr, registerMeta)) != null)
return desc;
throw new BinaryObjectException("Failed resolve class for ID: " + typeId, e);
}
if (desc == null) {
- desc = registerClassDescriptor(cls, deserialize, false);
+ desc = registerClass(cls, registerMeta, false);
assert desc.typeId() == typeId : "Duplicate typeId [typeId=" + typeId + ", cls=" + cls
+ ", desc=" + desc + "]";
@@ -742,141 +780,71 @@ public class BinaryContext {
}
/**
- * Creates and registers {@link BinaryClassDescriptor} for the given {@code class}.
+ * Attempts registration of the provided {@link BinaryClassDescriptor} in the cluster.
*
- * @param cls Class.
+ * @param desc Class descriptor to register.
+ * @param registerMeta If {@code true}, then metadata will be registered along with the class descriptor.
* @param onlyLocReg {@code true} if descriptor need to register only locally when registration is required at all.
- * @return Class descriptor.
+ * @return Registered class descriptor.
*/
- private BinaryClassDescriptor registerClassDescriptor(Class<?> cls, boolean deserialize, boolean onlyLocReg) {
- BinaryClassDescriptor desc;
-
- String clsName = cls.getName();
-
- if (marshCtx.isSystemType(clsName)) {
- BinarySerializer serializer = null;
-
- if (BINARYLIZABLE_SYS_CLSS.contains(clsName))
- serializer = new BinaryReflectiveSerializer();
-
- desc = new BinaryClassDescriptor(this,
- cls,
- false,
- clsName.hashCode(),
- clsName,
- null,
- SIMPLE_NAME_LOWER_CASE_MAPPER,
- serializer,
- false,
- true /* registered */
- );
+ @NotNull public BinaryClassDescriptor registerDescriptor(
+ BinaryClassDescriptor desc,
+ boolean registerMeta,
+ boolean onlyLocReg
+ ) {
+ if (desc.userType())
+ return registerUserClassDescriptor(desc, registerMeta, onlyLocReg);
+ else {
+ BinaryClassDescriptor regDesc = desc.makeRegistered();
- BinaryClassDescriptor old = descByCls.putIfAbsent(cls, desc);
+ BinaryClassDescriptor old = descByCls.putIfAbsent(desc.describedClass(), regDesc);
- if (old != null)
- desc = old;
+ return old != null
+ ? old
+ : regDesc;
}
- else
- desc = registerUserClassDescriptor(cls, deserialize, onlyLocReg);
-
- return desc;
}
/**
- * Creates and registers {@link BinaryClassDescriptor} for the given user {@code class}.
+ * Attempts registration of the provided {@link BinaryClassDescriptor} in the cluster. The provided descriptor should correspond
+ * to a user class.
*
- * @param cls Class.
+ * @param desc Class descriptor to register.
+ * @param registerMeta If {@code true}, then metadata will be registered along with the class descriptor.
* @param onlyLocReg {@code true} if descriptor need to register only locally.
* @return Class descriptor.
*/
- private BinaryClassDescriptor registerUserClassDescriptor(Class<?> cls, boolean deserialize, boolean onlyLocReg) {
- boolean registered;
-
- final String clsName = cls.getName();
-
- BinaryInternalMapper mapper = userTypeMapper(clsName);
-
- final String typeName = mapper.typeName(clsName);
-
- final int typeId = mapper.typeId(clsName);
-
- registered = registerUserClassName(typeId, cls.getName(), false, onlyLocReg);
-
- BinarySerializer serializer = serializerForClass(cls);
-
- String affFieldName = affinityFieldName(cls);
-
- BinaryClassDescriptor desc = new BinaryClassDescriptor(this,
- cls,
- true,
- typeId,
- typeName,
- affFieldName,
- mapper,
- serializer,
- true,
- registered
- );
-
- if (!deserialize) {
- BinaryMetadata binaryMetadata = new BinaryMetadata(
- typeId,
- typeName,
- desc.fieldsMeta(),
- affFieldName,
- null,
- desc.isEnum(),
- cls.isEnum() ? enumMap(cls) : null
- );
-
- if (onlyLocReg)
- metaHnd.addMetaLocally(typeId, binaryMetadata.wrap(this), false);
- else
- metaHnd.addMeta(typeId, binaryMetadata.wrap(this), false);
- }
+ @NotNull private BinaryClassDescriptor registerUserClassDescriptor(
+ BinaryClassDescriptor desc,
+ boolean registerMeta,
+ boolean onlyLocReg
+ ) {
+ assert desc.userType() : "The descriptor doesn't correspond to a user class.";
- descByCls.put(cls, desc);
+ Class<?> cls = desc.describedClass();
- typeId2Mapper.putIfAbsent(typeId, mapper);
+ int typeId = desc.typeId();
- return desc;
- }
-
- /**
- * Creates and registers {@link BinaryClassDescriptor} for the given user {@code class}.
- *
- * @param desc Old descriptor that should be re-registered.
- * @param onlyLocReg {@code true} if descriptor need to register only locally.
- * @return Class descriptor.
- */
- private BinaryClassDescriptor registerUserClassDescriptor(BinaryClassDescriptor desc, boolean onlyLocReg) {
- boolean registered;
-
- registered = registerUserClassName(desc.typeId(), desc.describedClass().getName(), false, onlyLocReg);
+ boolean registered = registerUserClassName(typeId, cls.getName(), false, onlyLocReg);
if (registered) {
- BinarySerializer serializer = desc.initialSerializer();
+ BinaryClassDescriptor regDesc = desc.makeRegistered();
- if (serializer == null)
- serializer = serializerForClass(desc.describedClass());
+ if (registerMeta) {
+ if (onlyLocReg)
+ metaHnd.addMetaLocally(typeId, regDesc.metadata().wrap(this), false);
+ else
+ metaHnd.addMeta(typeId, regDesc.metadata().wrap(this), false);
+ }
- desc = new BinaryClassDescriptor(
- this,
- desc.describedClass(),
- true,
- desc.typeId(),
- desc.typeName(),
- desc.affFieldKeyName(),
- desc.mapper(),
- serializer,
- true,
- true
- );
+ descByCls.put(cls, regDesc);
- descByCls.put(desc.describedClass(), desc);
- }
+ typeId2Mapper.putIfAbsent(typeId, regDesc.mapper());
- return desc;
+ return regDesc;
+ }
+ else
+ return desc;
}
/**
@@ -1217,10 +1185,10 @@ public class BinaryContext {
}
/**
- * Register "type ID to class name" mapping on all nodes to allow for mapping requests resolution form client. Other
- * {@link BinaryContext}'s "register" methods and method {@link BinaryContext#descriptorForClass(Class, boolean,
- * boolean)} already call this functionality so use this method only when registering class names whose {@link
- * Class} is unknown.
+ * Register "type ID to class name" mapping on all nodes to allow for mapping requests resolution form client.
+ * Other {@link BinaryContext}'s "register" methods and method
+ * {@link BinaryContext#registerClass(Class, boolean, boolean)} already call this functionality
+ * so use this method only when registering class names whose {@link Class} is unknown.
*
* @param typeId Type ID.
* @param clsName Class Name.
@@ -1476,23 +1444,6 @@ public class BinaryContext {
}
/**
- * @param cls Class
- * @return Enum name to ordinal mapping.
- */
- private static Map<String, Integer> enumMap(Class<?> cls) {
- assert cls.isEnum();
-
- Object[] enumVals = cls.getEnumConstants();
-
- Map<String, Integer> enumMap = new LinkedHashMap<>(enumVals.length);
-
- for (Object enumVal : enumVals)
- enumMap.put(((Enum)enumVal).name(), ((Enum)enumVal).ordinal());
-
- return enumMap;
- }
-
- /**
* Type descriptors.
*/
private static class TypeDescriptors {
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java
index 02bfe39..e6d80fd 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java
@@ -175,7 +175,7 @@ public class BinaryEnumObjectImpl implements BinaryObjectEx, Externalizable, Cac
/** {@inheritDoc} */
@Override public <T> T deserialize() throws BinaryObjectException {
- Class cls = BinaryUtils.resolveClass(ctx, typeId, clsName, ctx.configuration().getClassLoader(), true);
+ Class cls = BinaryUtils.resolveClass(ctx, typeId, clsName, ctx.configuration().getClassLoader(), false);
return (T)BinaryEnumCache.get(cls, ord);
}
@@ -429,13 +429,4 @@ public class BinaryEnumObjectImpl implements BinaryObjectEx, Externalizable, Cac
return reader.afterMessageRead(BinaryEnumObjectImpl.class);
}
-
- /**
- * @param cls type to examine.
- * @return true if typeId equals for passed type and current
- * binary enum.
- */
- public boolean isTypeEquals(final Class<?> cls) {
- return ctx.descriptorForClass(cls, false, false).typeId() == typeId();
- }
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java
index 02d6d4b..f81ee0b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java
@@ -266,7 +266,7 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Bina
if (forUnmarshal) {
// Registers class by type ID, at least locally if the cache is not ready yet.
- desc = ctx.descriptorForClass(BinaryUtils.doReadClass(in, ctx, ldr, typeId0), false, false);
+ desc = ctx.registerClass(BinaryUtils.doReadClass(in, ctx, ldr, typeId0), true, false);
typeId = desc.typeId();
}
@@ -315,7 +315,7 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Bina
*/
BinaryClassDescriptor descriptor() {
if (desc == null)
- desc = ctx.descriptorForTypeId(userType, typeId, ldr, true);
+ desc = ctx.descriptorForTypeId(userType, typeId, ldr, false);
return desc;
}
@@ -1754,7 +1754,7 @@ public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, Bina
case OBJ:
if (desc == null)
- desc = ctx.descriptorForTypeId(userType, typeId, ldr, true);
+ desc = ctx.descriptorForTypeId(userType, typeId, ldr, false);
streamPosition(dataStart);
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 7139b8a..9568c4b 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
@@ -1635,7 +1635,7 @@ public class BinaryUtils {
Class cls;
if (typeId != GridBinaryMarshaller.UNREGISTERED_TYPE_ID)
- cls = ctx.descriptorForTypeId(true, typeId, ldr, true).describedClass();
+ cls = ctx.descriptorForTypeId(true, typeId, ldr, false).describedClass();
else {
String clsName = doReadClassName(in);
@@ -1646,8 +1646,7 @@ public class BinaryUtils {
throw new BinaryInvalidTypeException("Failed to load the class: " + clsName, e);
}
- // forces registering of class by type id, at least locally
- ctx.descriptorForClass(cls, true, false);
+ ctx.registerClass(cls, false, false);
}
return cls;
@@ -1663,11 +1662,11 @@ public class BinaryUtils {
* @return Resovled class.
*/
public static Class resolveClass(BinaryContext ctx, int typeId, @Nullable String clsName,
- @Nullable ClassLoader ldr, boolean deserialize) {
+ @Nullable ClassLoader ldr, boolean registerMeta) {
Class cls;
if (typeId != GridBinaryMarshaller.UNREGISTERED_TYPE_ID)
- cls = ctx.descriptorForTypeId(true, typeId, ldr, deserialize).describedClass();
+ cls = ctx.descriptorForTypeId(true, typeId, ldr, registerMeta).describedClass();
else {
try {
cls = U.forName(clsName, ldr);
@@ -1676,8 +1675,7 @@ public class BinaryUtils {
throw new BinaryInvalidTypeException("Failed to load the class: " + clsName, e);
}
- // forces registering of class by type id, at least locally
- ctx.descriptorForClass(cls, true, false);
+ ctx.registerClass(cls, false, false);
}
return cls;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterExImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterExImpl.java
index 29f8e73..461ea28 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterExImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriterExImpl.java
@@ -33,6 +33,7 @@ import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.binary.BinaryObjectException;
import org.apache.ignite.binary.BinaryRawWriter;
import org.apache.ignite.binary.BinaryWriter;
+import org.apache.ignite.internal.UnregisteredClassException;
import org.apache.ignite.internal.binary.streams.BinaryHeapOutputStream;
import org.apache.ignite.internal.binary.streams.BinaryOutputStream;
import org.apache.ignite.internal.util.IgniteUtils;
@@ -178,10 +179,18 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
Class<?> cls = obj.getClass();
- BinaryClassDescriptor desc = ctx.descriptorForClass(cls, false, failIfUnregistered);
+ BinaryClassDescriptor desc = ctx.descriptorForClass(cls);
- if (desc == null)
- throw new BinaryObjectException("Object is not binary: [class=" + cls + ']');
+ if (!desc.registered()) {
+ if (failIfUnregistered)
+ throw new UnregisteredClassException(cls);
+ else {
+ // Metadata is registered for OBJECT and BINARY during actual writing.
+ boolean registerMeta = !(desc.isObject() || desc.isBinary());
+
+ desc = ctx.registerDescriptor(desc, registerMeta, false);
+ }
+ }
if (desc.excluded()) {
out.writeByte(GridBinaryMarshaller.NULL);
@@ -743,9 +752,9 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
if (tryWriteAsHandle(val))
return;
- BinaryClassDescriptor desc = ctx.descriptorForClass(
+ BinaryClassDescriptor desc = ctx.registerClass(
val.getClass().getComponentType(),
- false,
+ true,
failIfUnregistered);
out.unsafeEnsure(1 + 4);
@@ -817,7 +826,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
if (val == null)
out.writeByte(GridBinaryMarshaller.NULL);
else {
- BinaryClassDescriptor desc = ctx.descriptorForClass(val.getDeclaringClass(), false, failIfUnregistered);
+ BinaryClassDescriptor desc = ctx.registerClass(val.getDeclaringClass(), true, failIfUnregistered);
out.unsafeEnsure(1 + 4);
@@ -870,9 +879,9 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
if (val == null)
out.writeByte(GridBinaryMarshaller.NULL);
else {
- BinaryClassDescriptor desc = ctx.descriptorForClass(
+ BinaryClassDescriptor desc = ctx.registerClass(
val.getClass().getComponentType(),
- false,
+ true,
failIfUnregistered);
out.unsafeEnsure(1 + 4);
@@ -902,7 +911,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
if (val == null)
out.writeByte(GridBinaryMarshaller.NULL);
else {
- BinaryClassDescriptor desc = ctx.descriptorForClass(val, false, failIfUnregistered);
+ BinaryClassDescriptor desc = ctx.registerClass(val, true, failIfUnregistered);
out.unsafeEnsure(1 + 4);
@@ -931,7 +940,7 @@ public class BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, Obje
out.unsafeWriteInt(intfs.length);
for (Class<?> intf : intfs) {
- BinaryClassDescriptor desc = ctx.descriptorForClass(intf, false, failIfUnregistered);
+ BinaryClassDescriptor desc = ctx.registerClass(intf, true, failIfUnregistered);
if (desc.registered())
out.writeInt(desc.typeId());
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderEnum.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderEnum.java
index 3930c46..25f17d5 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderEnum.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderEnum.java
@@ -63,7 +63,7 @@ public class BinaryBuilderEnum implements BinaryBuilderSerializationAware {
throw new BinaryInvalidTypeException("Failed to load the class: " + clsName, e);
}
- this.typeId = reader.binaryContext().descriptorForClass(cls, false, false).typeId();
+ this.typeId = reader.binaryContext().registerClass(cls, true, false).typeId();
}
else {
this.typeId = typeId;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderSerializer.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderSerializer.java
index edc80b6..9e6411f 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderSerializer.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderSerializer.java
@@ -129,7 +129,7 @@ class BinaryBuilderSerializer {
writer.context().updateMetadata(typeId, meta, writer.failIfUnregistered());
// Need register class for marshaller to be able to deserialize enum value.
- writer.context().descriptorForClass(((Enum)val).getDeclaringClass(), false, false);
+ writer.context().registerClass(((Enum)val).getDeclaringClass(), true, false);
writer.writeByte(GridBinaryMarshaller.ENUM);
writer.writeInt(typeId);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryEnumArrayLazyValue.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryEnumArrayLazyValue.java
index c0e79ec..eaacbd5 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryEnumArrayLazyValue.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryEnumArrayLazyValue.java
@@ -56,7 +56,7 @@ class BinaryEnumArrayLazyValue extends BinaryAbstractLazyValue {
throw new BinaryInvalidTypeException("Failed to load the class: " + clsName, e);
}
- compTypeId = reader.binaryContext().descriptorForClass(cls, true, false).typeId();
+ compTypeId = reader.binaryContext().registerClass(cls, false, false).typeId();
}
else {
compTypeId = typeId;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectArrayLazyValue.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectArrayLazyValue.java
index d4882dc..bd90569 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectArrayLazyValue.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectArrayLazyValue.java
@@ -55,7 +55,7 @@ class BinaryObjectArrayLazyValue extends BinaryAbstractLazyValue {
throw new BinaryInvalidTypeException("Failed to load the class: " + clsName, e);
}
- compTypeId = reader.binaryContext().descriptorForClass(cls, true, false).typeId();
+ compTypeId = reader.binaryContext().registerClass(cls, false, false).typeId();
}
else {
compTypeId = typeId;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectBuilderImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectBuilderImpl.java
index b3d3d83..45a13c0 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectBuilderImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectBuilderImpl.java
@@ -157,7 +157,7 @@ public class BinaryObjectBuilderImpl implements BinaryObjectBuilder {
throw new BinaryInvalidTypeException("Failed to load the class: " + clsNameToWrite, e);
}
- this.typeId = ctx.descriptorForClass(cls, false, false).typeId();
+ this.typeId = ctx.registerClass(cls, true, false).typeId();
registeredType = false;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/BinaryMetadataTransport.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/BinaryMetadataTransport.java
index 0d2f6f9..3a95586 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/BinaryMetadataTransport.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/BinaryMetadataTransport.java
@@ -167,7 +167,7 @@ final class BinaryMetadataTransport {
* @param newMeta Metadata proposed for update.
* @return Future to wait for update result on.
*/
- GridFutureAdapter<MetadataUpdateResult> requestMetadataUpdate(BinaryMetadata newMeta) {
+ GridFutureAdapter<MetadataUpdateResult> requestMetadataUpdate(BinaryMetadata newMeta) {
int typeId = newMeta.typeId();
MetadataUpdateResultFuture resFut;
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java
index c944862..9f8271a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java
@@ -1938,7 +1938,7 @@ public class GridDhtAtomicCache<K, V> extends GridDhtCacheAdapter<K, V> {
assert cacheObjProc instanceof CacheObjectBinaryProcessorImpl;
((CacheObjectBinaryProcessorImpl)cacheObjProc)
- .binaryContext().descriptorForClass(ex.cls(), false, false);
+ .binaryContext().registerClass(ex.cls(), true, false);
}
catch (UnregisteredBinaryTypeException ex) {
if (ex.future() != null) {
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 5eadedf..5dfffee 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
@@ -1029,7 +1029,7 @@ public class GridQueryProcessor extends GridProcessorAdapter {
if (cacheObjProc instanceof CacheObjectBinaryProcessorImpl) {
((CacheObjectBinaryProcessorImpl)cacheObjProc)
.binaryContext()
- .descriptorForClass(cls, false, false, true);
+ .registerClass(cls, true, false, true);
}
}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryMarshallerSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryMarshallerSelfTest.java
index a71834b..acae773 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryMarshallerSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryMarshallerSelfTest.java
@@ -1982,7 +1982,7 @@ public class BinaryMarshallerSelfTest extends GridCommonAbstractTest {
int typeId = ctx.typeId(Value.class.getName());
- BinaryClassDescriptor descriptor = ctx.descriptorForTypeId(true, typeId, null, false);
+ BinaryClassDescriptor descriptor = ctx.descriptorForTypeId(true, typeId, null, true);
assertEquals(Value.class, descriptor.describedClass());
assertEquals(true, descriptor.registered());
@@ -3003,7 +3003,7 @@ public class BinaryMarshallerSelfTest extends GridCommonAbstractTest {
if (id == GridBinaryMarshaller.UNREGISTERED_TYPE_ID)
continue;
- BinaryClassDescriptor desc = bCtx.descriptorForTypeId(false, entry.getValue(), null, false);
+ BinaryClassDescriptor desc = bCtx.descriptorForTypeId(false, entry.getValue(), null, true);
assertEquals(desc.typeId(), bCtx.typeId(desc.describedClass().getName()));
}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/binary/BinaryMetadataRegistrationTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/binary/BinaryMetadataRegistrationTest.java
new file mode 100644
index 0000000..9e4fc1f
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/binary/BinaryMetadataRegistrationTest.java
@@ -0,0 +1,230 @@
+/*
+ * 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.processors.cache.binary;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.binary.BinaryObjectBuilder;
+import org.apache.ignite.binary.BinaryObjectException;
+import org.apache.ignite.binary.BinaryReader;
+import org.apache.ignite.binary.BinaryWriter;
+import org.apache.ignite.binary.Binarylizable;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.managers.discovery.DiscoveryCustomMessage;
+import org.apache.ignite.internal.util.IgniteUtils;
+import org.apache.ignite.spi.discovery.DiscoverySpiCustomMessage;
+import org.apache.ignite.spi.discovery.DiscoverySpiListener;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Test;
+
+/**
+ * Test for discovery message exchange, that is performed upon binary type registration.
+ */
+public class BinaryMetadataRegistrationTest extends GridCommonAbstractTest {
+ /**
+ * Number of {@link MetadataUpdateProposedMessage} that have been sent since a test was start.
+ */
+ private static final AtomicInteger proposeMsgNum = new AtomicInteger();
+
+ /** {@inheritDoc} */
+ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+ IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+ GridTestUtils.DiscoveryHook discoveryHook = new GridTestUtils.DiscoveryHook() {
+ @Override public void handleDiscoveryMessage(DiscoverySpiCustomMessage msg) {
+ DiscoveryCustomMessage customMsg = msg == null ? null
+ : (DiscoveryCustomMessage)IgniteUtils.field(msg, "delegate");
+
+ if (customMsg instanceof MetadataUpdateProposedMessage)
+ proposeMsgNum.incrementAndGet();
+ }
+ };
+
+ TcpDiscoverySpi discoSpi = new TcpDiscoverySpi() {
+ @Override public void setListener(@Nullable DiscoverySpiListener lsnr) {
+ super.setListener(GridTestUtils.DiscoverySpiListenerWrapper.wrap(lsnr, discoveryHook));
+ }
+ };
+
+ cfg.setDiscoverySpi(discoSpi);
+
+ return cfg;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTestsStarted() throws Exception {
+ startGrid();
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTest() throws Exception {
+ proposeMsgNum.set(0);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void afterTestsStopped() throws Exception {
+ stopAllGrids();
+ }
+
+ /**
+ * Tests registration of user classes.
+ */
+ @Test
+ public void testMetadataRegisteredOnceForUserClass() {
+ checkMetadataRegisteredOnce(new TestValue(1));
+ }
+
+ /**
+ * Tests type registration upon writing binary objects to a cache.
+ */
+ @Test
+ public void testMetadataRegisteredOnceForBinaryObject() {
+ BinaryObjectBuilder builder = grid().binary().builder("TestBinaryType");
+
+ builder.setField("testField", 1);
+
+ checkMetadataRegisteredOnce(builder.build());
+ }
+
+ /**
+ * Tests registration of {@link Binarylizable} user classes.
+ */
+ @Test
+ public void testMetadataRegisteredOnceForBinarylizable() {
+ checkMetadataRegisteredOnce(new TestBinarylizableValue(1));
+ }
+
+ /**
+ * Tests registration of {@link Externalizable} user classes.
+ */
+ @Test
+ public void testMetadataRegisteredOnceForExternalizable() {
+ checkMetadataRegisteredOnce(new TestExternalizableValue(1));
+ }
+
+ /**
+ * Tests registration of enums.
+ */
+ @Test
+ public void testMetadataRegisteredOnceForEnum() {
+ checkMetadataRegisteredOnce(TestEnum.ONE);
+ }
+
+ /**
+ * Checks that only one {@link MetadataUpdateProposedMessage} is sent to discovery when a binary type is
+ * registered.
+ *
+ * @param val Value to insert into a cache to trigger type registration.
+ */
+ private void checkMetadataRegisteredOnce(Object val) {
+ IgniteCache<Integer, Object> cache = grid().getOrCreateCache("cache");
+
+ cache.put(1, val);
+
+ assertEquals("Unexpected number of MetadataUpdateProposedMessages have been received.",
+ 1, proposeMsgNum.get());
+ }
+
+ /**
+ * A dummy class for testing of metadata registration.
+ */
+ private static class TestValue {
+ /** */
+ int val;
+
+ /**
+ * @param val Value.
+ */
+ TestValue(int val) {
+ this.val = val;
+ }
+ }
+
+ /**
+ * A dummy {@link Binarylizable} class for testing of metadata registration.
+ */
+ private static class TestBinarylizableValue implements Binarylizable {
+ /** */
+ int val;
+
+ /**
+ * @param val Value.
+ */
+ TestBinarylizableValue(int val) {
+ this.val = val;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeBinary(BinaryWriter writer) throws BinaryObjectException {
+ writer.writeInt("val", val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void readBinary(BinaryReader reader) throws BinaryObjectException {
+ this.val = reader.readInt("val");
+ }
+ }
+
+ /**
+ * A dummy {@link Externalizable} class for testing of metadata registration.
+ */
+ private static class TestExternalizableValue implements Externalizable {
+ /** */
+ int val;
+
+ /**
+ * @param val Value.
+ */
+ TestExternalizableValue(int val) {
+ this.val = val;
+ }
+
+ /** */
+ public TestExternalizableValue() {
+ }
+
+ /** {@inheritDoc} */
+ @Override public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeInt(val);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+ this.val = in.readInt();
+ }
+ }
+
+ /**
+ * A enum for testing of metadata registration.
+ */
+ private enum TestEnum {
+ /** */
+ ONE,
+ /** */
+ TWO,
+ /** */
+ THREE
+ }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsTestSuite.java
index 05ea5b8..6f818d9 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBinaryObjectsTestSuite.java
@@ -55,6 +55,7 @@ import org.apache.ignite.internal.binary.streams.BinaryAbstractOutputStreamTest;
import org.apache.ignite.internal.binary.streams.BinaryHeapStreamByteOrderSelfTest;
import org.apache.ignite.internal.binary.streams.BinaryOffheapStreamByteOrderSelfTest;
import org.apache.ignite.internal.processors.cache.binary.BinaryAtomicCacheLocalEntriesSelfTest;
+import org.apache.ignite.internal.processors.cache.binary.BinaryMetadataRegistrationTest;
import org.apache.ignite.internal.processors.cache.binary.BinaryMetadataUpdatesFlowTest;
import org.apache.ignite.internal.processors.cache.binary.BinaryTxCacheLocalEntriesSelfTest;
import org.apache.ignite.internal.processors.cache.binary.GridCacheBinaryObjectMetadataExchangeMultinodeTest;
@@ -141,6 +142,7 @@ import org.junit.runners.Suite;
GridCacheClientNodeBinaryObjectMetadataTest.class,
GridCacheBinaryObjectMetadataExchangeMultinodeTest.class,
BinaryMetadataUpdatesFlowTest.class,
+ BinaryMetadataRegistrationTest.class,
GridCacheClientNodeBinaryObjectMetadataMultinodeTest.class,
IgniteBinaryMetadataUpdateChangingTopologySelfTest.class,