ignite-5966 IgniteCache#get() fails with "Requesting mapping from grid failed" when deserialising binary object loaded from CacheJdbcPojoStoreFactory
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/075f48dc Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/075f48dc Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/075f48dc Branch: refs/heads/ignite-5896 Commit: 075f48dc6cbc8213e92de388251e99b98ce44f2c Parents: 29ce1fa Author: Alexey Kukushkin <[email protected]> Authored: Thu Aug 31 17:44:11 2017 +0300 Committer: Andrey Gura <[email protected]> Committed: Mon Sep 4 16:21:22 2017 +0300 ---------------------------------------------------------------------- .../internal/DuplicateTypeIdException.java | 74 ++++++++++++++++++++ .../ignite/internal/MarshallerContextImpl.java | 24 +------ .../ignite/internal/binary/BinaryContext.java | 52 ++++++++++---- .../binary/builder/BinaryObjectBuilderImpl.java | 2 + .../BinaryObjectBuilderAdditionalSelfTest.java | 22 ++++++ 5 files changed, 139 insertions(+), 35 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/075f48dc/modules/core/src/main/java/org/apache/ignite/internal/DuplicateTypeIdException.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/DuplicateTypeIdException.java b/modules/core/src/main/java/org/apache/ignite/internal/DuplicateTypeIdException.java new file mode 100644 index 0000000..9ca66ab --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/DuplicateTypeIdException.java @@ -0,0 +1,74 @@ +/* + * 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; + +import org.apache.ignite.IgniteCheckedException; + +/** + * The exception indicates a duplicate type ID was encountered. + */ +public class DuplicateTypeIdException extends IgniteCheckedException { + /** Serialization version. */ + private static final long serialVersionUID = 0L; + + /** Platform ID. */ + private final byte platformId; + + /** Type ID. */ + private final int typeId; + + /** Name of already registered class. */ + private final String oldClsName; + + /** Name of new class being registered. */ + private final String newClsName; + + /** + * Initializes new instance of {@link DuplicateTypeIdException} class. + * + * @param platformId Platform ID. + * @param typeId Type ID. + * @param oldClsName Name of already registered class. + * @param newClsName Name of new class being registered. + */ + DuplicateTypeIdException(byte platformId, int typeId, String oldClsName, String newClsName) { + this.platformId = platformId; + this.typeId = typeId; + this.oldClsName = oldClsName; + this.newClsName = newClsName; + } + + /** {@inheritDoc} */ + @Override public String getMessage() { + return "Duplicate ID [platformId=" + + platformId + + ", typeId=" + + typeId + + ", oldCls=" + + oldClsName + + ", newCls=" + + newClsName + ']'; + } + + /** + * @return Name of already registered class. + */ + public String getRegisteredClassName() { + return oldClsName; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/075f48dc/modules/core/src/main/java/org/apache/ignite/internal/MarshallerContextImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/MarshallerContextImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/MarshallerContextImpl.java index d133676..0b3f220 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/MarshallerContextImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/MarshallerContextImpl.java @@ -238,7 +238,7 @@ public class MarshallerContextImpl implements MarshallerContext { if (mappedName != null) { if (!mappedName.className().equals(clsName)) - throw duplicateIdException(platformId, typeId, mappedName.className(), clsName); + throw new DuplicateTypeIdException(platformId, typeId, mappedName.className(), clsName); else { if (mappedName.accepted()) return true; @@ -289,28 +289,6 @@ public class MarshallerContextImpl implements MarshallerContext { } /** - * @param platformId Platform id. - * @param typeId Type id. - * @param conflictingClsName Conflicting class name. - * @param clsName Class name. - */ - private IgniteCheckedException duplicateIdException( - byte platformId, - int typeId, - String conflictingClsName, - String clsName - ) { - return new IgniteCheckedException("Duplicate ID [platformId=" - + platformId - + ", typeId=" - + typeId - + ", oldCls=" - + conflictingClsName - + ", newCls=" - + clsName + "]"); - } - - /** * * @param item type mapping to propose * @return null if cache doesn't contain any mappings for given (platformId, typeId) pair, http://git-wip-us.apache.org/repos/asf/ignite/blob/075f48dc/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 eaac7b8..afa40e6 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 @@ -64,6 +64,7 @@ import org.apache.ignite.cache.affinity.AffinityKeyMapped; import org.apache.ignite.configuration.BinaryConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.igfs.IgfsPath; +import org.apache.ignite.internal.DuplicateTypeIdException; import org.apache.ignite.internal.marshaller.optimized.OptimizedMarshaller; import org.apache.ignite.internal.processors.cache.binary.BinaryMetadataKey; import org.apache.ignite.internal.processors.closure.GridClosureProcessor; @@ -770,12 +771,7 @@ public class BinaryContext { final int typeId = mapper.typeId(clsName); - try { - registered = marshCtx.registerClassName(JAVA_ID, typeId, cls.getName()); - } - catch (IgniteCheckedException e) { - throw new BinaryObjectException("Failed to register class.", e); - } + registered = registerUserClassName(typeId, cls.getName()); BinarySerializer serializer = serializerForClass(cls); @@ -813,12 +809,7 @@ public class BinaryContext { private BinaryClassDescriptor registerUserClassDescriptor(BinaryClassDescriptor desc) { boolean registered; - try { - registered = marshCtx.registerClassName(JAVA_ID, desc.typeId(), desc.describedClass().getName()); - } - catch (IgniteCheckedException e) { - throw new BinaryObjectException("Failed to register class.", e); - } + registered = registerUserClassName(desc.typeId(), desc.describedClass().getName()); if (registered) { BinarySerializer serializer = desc.initialSerializer(); @@ -1173,6 +1164,43 @@ 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)} 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. + * @return {@code True} if the mapping was registered successfully. + */ + public boolean registerUserClassName(int typeId, String clsName) { + IgniteCheckedException e = null; + + boolean res = false; + + try { + res = marshCtx.registerClassName(JAVA_ID, typeId, clsName); + } + catch (DuplicateTypeIdException dupEx) { + // Ignore if trying to register mapped type name of the already registered class name and vise versa + BinaryInternalMapper mapper = userTypeMapper(typeId); + + String oldName = dupEx.getRegisteredClassName(); + + if (!(mapper.typeName(oldName).equals(clsName) || mapper.typeName(clsName).equals(oldName))) + e = dupEx; + } + catch (IgniteCheckedException igniteEx) { + e = igniteEx; + } + + if (e != null) + throw new BinaryObjectException("Failed to register class.", e); + + return res; + } + + /** * Throw exception on class duplication. * * @param clsName Class name. http://git-wip-us.apache.org/repos/asf/ignite/blob/075f48dc/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectBuilderImpl.java ---------------------------------------------------------------------- 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 fa9f1c3..9108f89 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 @@ -357,6 +357,8 @@ public class BinaryObjectBuilderImpl implements BinaryObjectBuilder { if (affFieldName0 == null) affFieldName0 = ctx.affinityKeyFieldName(typeId); + ctx.registerUserClassName(typeId, typeName); + ctx.updateMetadata(typeId, new BinaryMetadata(typeId, typeName, fieldsMeta, affFieldName0, Collections.singleton(curSchema), false, null)); http://git-wip-us.apache.org/repos/asf/ignite/blob/075f48dc/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryObjectBuilderAdditionalSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryObjectBuilderAdditionalSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryObjectBuilderAdditionalSelfTest.java index 82ff383..4ac2758 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryObjectBuilderAdditionalSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryObjectBuilderAdditionalSelfTest.java @@ -56,6 +56,8 @@ import org.apache.ignite.binary.BinaryType; import org.apache.ignite.configuration.BinaryConfiguration; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.MarshallerPlatformIds; import org.apache.ignite.internal.binary.builder.BinaryBuilderEnum; import org.apache.ignite.internal.binary.builder.BinaryObjectBuilderImpl; import org.apache.ignite.internal.binary.mutabletest.GridBinaryMarshalerAwareTestClass; @@ -64,6 +66,7 @@ import org.apache.ignite.internal.binary.test.GridBinaryTestClass2; import org.apache.ignite.internal.processors.cache.binary.CacheObjectBinaryProcessorImpl; import org.apache.ignite.internal.processors.cache.binary.IgniteBinaryImpl; import org.apache.ignite.internal.util.lang.GridMapEntry; +import org.apache.ignite.marshaller.MarshallerContext; import org.apache.ignite.testframework.GridTestUtils; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; import org.junit.Assert; @@ -1580,6 +1583,25 @@ public class BinaryObjectBuilderAdditionalSelfTest extends GridCommonAbstractTes } /** + * Test {@link BinaryObjectBuilder#build()} adds type mapping to the binary marshaller's cache. + */ + public void testMarshallerMappings() throws IgniteCheckedException, ClassNotFoundException { + String typeName = "TestType"; + + int typeId = BinaryContext.defaultIdMapper().typeId(typeName); + + BinaryObjectBuilder builder = newWrapper(typeName); + + builder.build(); + + MarshallerContext marshCtx = grid(0).context().marshallerContext(); + + String actualTypeName = marshCtx.getClassName(MarshallerPlatformIds.JAVA_ID, typeId); + + assertEquals(typeName, actualTypeName); + } + + /** * @param obj BinaryObject array. * @return Deserialized enums. */
