diff --git a/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/direct/JmhDirectMessageReaderBenchmark.java b/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/direct/JmhDirectMessageReaderBenchmark.java index 7c93e2be90b60..22701785a6524 100644 --- a/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/direct/JmhDirectMessageReaderBenchmark.java +++ b/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/direct/JmhDirectMessageReaderBenchmark.java @@ -44,6 +44,7 @@ import org.openjdk.jmh.annotations.Warmup; import static java.util.concurrent.TimeUnit.SECONDS; +import static org.apache.ignite.internal.MessageSerializationContext.LATEST_SCHEMA; import static org.openjdk.jmh.annotations.Mode.Throughput; /** Benchmarks the {@link DirectMessageReader} compressed-field hot path. */ @@ -96,7 +97,7 @@ public void setup() { writer.setBuffer(buf); - boolean finished = writer.writeMessage(msg, true); + boolean finished = writer.writeMessage(msg, true, LATEST_SCHEMA); if (!finished) throw new IllegalStateException("Message does not fit into the buffer."); @@ -111,7 +112,7 @@ public Message compressedMessage() { reader.setBuffer(buf); - Message msg = reader.readMessage(true); + Message msg = reader.readMessage(true, LATEST_SCHEMA); reader.reset(); diff --git a/modules/codegen/src/main/java/org/apache/ignite/internal/FeatureGated.java b/modules/codegen/src/main/java/org/apache/ignite/internal/FeatureGated.java new file mode 100644 index 0000000000000..82d646b816023 --- /dev/null +++ b/modules/codegen/src/main/java/org/apache/ignite/internal/FeatureGated.java @@ -0,0 +1,49 @@ +/* + * 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 java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.apache.ignite.internal.processors.rollingupgrade.feature.IgniteFeature; + +/** + * Optional complement to the {@link Order} annotations of a class, telling where the {@link IgniteFeature}s named in + * {@link Order#introducedBy()} and {@link Order#deprecatedBy()} are declared. + * + *

Feature names are resolved as constants of the {@link #registry()} class. Without this annotation they are resolved + * against the Ignite Core Feature Registry, so it is needed primarily by classes whose fields are gated by features of + * another registry, such as the features of a plugin:

+ *
+ * @FeatureGated(registry = MyPluginFeatures.class)
+ * public class MyPluginMessage implements Message {
+ *     @Order(value = 0, introducedBy = "MY_FEATURE")
+ *     String fld;
+ * }
+ * 
+ * + * @see Order + * @see IgniteFeature + */ +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.TYPE) +public @interface FeatureGated { + /** @return Class of the feature registry, or {@link Void} if the Ignite Core Feature Registry is used. */ + Class registry() default Void.class; +} diff --git a/modules/codegen/src/main/java/org/apache/ignite/internal/MessageProcessor.java b/modules/codegen/src/main/java/org/apache/ignite/internal/MessageProcessor.java index 8b4ead738ee22..b5edc8553a9d2 100644 --- a/modules/codegen/src/main/java/org/apache/ignite/internal/MessageProcessor.java +++ b/modules/codegen/src/main/java/org/apache/ignite/internal/MessageProcessor.java @@ -41,6 +41,7 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.MirroredTypeException; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.ElementFilter; import javax.lang.model.util.Elements; @@ -48,9 +49,11 @@ import org.apache.ignite.internal.systemview.SystemViewRowAttributeWalkerProcessor; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.lang.IgniteBiTuple; +import org.jetbrains.annotations.Nullable; import static org.apache.ignite.internal.MessageSerializerGenerator.DLFT_ENUM_MAPPER_CLS; import static org.apache.ignite.internal.MessageSerializerGenerator.enumType; +import static org.apache.ignite.internal.MessageSerializerGenerator.qualifiedClassName; /** * Annotation processor that generates serialization and deserialization code for classes implementing the {@code Message} interface. @@ -96,6 +99,13 @@ public class MessageProcessor extends AbstractProcessor { /** Checked exception declared by the generated methods. */ static final String IGNITE_CHECKED_EXCEPTION_CLS = "org.apache.ignite.IgniteCheckedException"; + /** Feature registry a message resolves its feature gates against unless it declares one with {@link FeatureGated#registry()}. */ + static final String DFLT_FEATURE_REG_CLS = + "org.apache.ignite.internal.processors.rollingupgrade.feature.CoreFeatureRegistry"; + + /** */ + static final String IGNITE_FEATURE_CLS = "org.apache.ignite.internal.processors.rollingupgrade.feature.IgniteFeature"; + /** */ public static final String GRID_H2_NULL = "org.apache.ignite.internal.processors.query.h2.twostep.msg.GridH2Null"; @@ -425,4 +435,102 @@ TypeMirror type(String clazz) { TypeElement typeElement = elementUtils.getTypeElement(clazz); return typeElement != null ? typeElement.asType() : null; } + + /** */ + @Nullable public static FieldFeatureGate buildFieldFeatureGate(ProcessingEnvironment env, VariableElement field) { + Order ann = field.getAnnotation(Order.class); + + String introducingFeature = ann.introducedBy(); + String deprecatingFeature = ann.deprecatedBy(); + + if (introducingFeature.isEmpty() && deprecatingFeature.isEmpty()) + return null; + + if (introducingFeature.equals(deprecatingFeature)) { + printError(env, field, "Elements introducedBy and deprecatedBy of the @Order annotation must not reference the same feature."); + + return null; + } + + String regCls = resolveFeatureRegistry(field.getEnclosingElement()); + + String regName = regCls.substring(regCls.lastIndexOf('.') + 1); + + List conditions = new ArrayList<>(); + + if (!introducingFeature.isEmpty()) { + validateFeature(env, field, introducingFeature, regCls); + + conditions.add("ctx.includeFieldIntroducedBy(" + regName + '.' + introducingFeature + ")"); + } + + if (!deprecatingFeature.isEmpty()) { + validateFeature(env, field, deprecatingFeature, regCls); + + conditions.add("ctx.includeFieldDeprecatedBy(" + regName + '.' + deprecatingFeature + ")"); + } + + return new FieldFeatureGate(regCls, String.join(" && ", conditions)); + } + + /** */ + private static void validateFeature(ProcessingEnvironment env, VariableElement field, String featureName, String regCls) { + TypeElement regElem = env.getElementUtils().getTypeElement(regCls); + + if (regElem == null) { + printError(env, field, "Cannot resolve the feature registry class [reg=" + regCls + ']'); + + return; + } + + for (Element featureElem : regElem.getEnclosedElements()) { + if (featureElem.getKind() != ElementKind.FIELD || !featureElem.getSimpleName().contentEquals(featureName)) + continue; + + Set mods = featureElem.getModifiers(); + + if (!mods.contains(Modifier.PUBLIC) || !mods.contains(Modifier.STATIC) || !mods.contains(Modifier.FINAL)) + printError(env, field, "Feature constant must be public static final [reg=" + regCls + ", feature=" + featureName + ']'); + else if (!isIgniteFeature(env, featureElem)) + printError(env, field, "Feature constant must be of type IgniteFeature [reg=" + regCls + ", feature=" + featureName + ']'); + + return; + } + + printError(env, field, "Failed to resolve feature in the registry by its name [reg=" + regCls + ", feature=" + featureName + ']'); + } + + /** */ + private static boolean isIgniteFeature(ProcessingEnvironment env, Element featureElem) { + TypeElement igniteFeatureType = env.getElementUtils().getTypeElement(IGNITE_FEATURE_CLS); + + return igniteFeatureType != null && env.getTypeUtils().isAssignable(featureElem.asType(), igniteFeatureType.asType()); + } + + /** */ + private static void printError(ProcessingEnvironment env, Element el, String msg) { + env.getMessager().printMessage(Diagnostic.Kind.ERROR, msg, el); + } + + /** */ + private static String resolveFeatureRegistry(Element cls) { + FeatureGated ann = cls.getAnnotation(FeatureGated.class); + + if (ann == null) + return DFLT_FEATURE_REG_CLS; + + String regCls; + + try { + regCls = ann.registry().getName(); + } + catch (MirroredTypeException e) { + regCls = qualifiedClassName(e.getTypeMirror()); + } + + return Void.class.getName().equals(regCls) ? DFLT_FEATURE_REG_CLS : regCls; + } + + /** */ + public record FieldFeatureGate(String registry, String expression) { } } diff --git a/modules/codegen/src/main/java/org/apache/ignite/internal/MessageSerializerGenerator.java b/modules/codegen/src/main/java/org/apache/ignite/internal/MessageSerializerGenerator.java index 81680f1b1088c..5956fdbbfa1e3 100644 --- a/modules/codegen/src/main/java/org/apache/ignite/internal/MessageSerializerGenerator.java +++ b/modules/codegen/src/main/java/org/apache/ignite/internal/MessageSerializerGenerator.java @@ -41,6 +41,7 @@ import javax.lang.model.type.PrimitiveType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; +import org.apache.ignite.internal.MessageProcessor.FieldFeatureGate; import org.apache.ignite.internal.systemview.SystemViewRowAttributeWalkerProcessor; import org.apache.ignite.internal.util.typedef.F; import org.jetbrains.annotations.Nullable; @@ -50,6 +51,7 @@ import static org.apache.ignite.internal.MessageProcessor.GRID_H2_NULL; import static org.apache.ignite.internal.MessageProcessor.KEY_CACHE_OBJECT_CLS; import static org.apache.ignite.internal.MessageProcessor.MESSAGE_INTERFACE; +import static org.apache.ignite.internal.MessageProcessor.buildFieldFeatureGate; /** Generates {@code *Serializer} classes for {@code Message} types. */ public class MessageSerializerGenerator extends MessageCompanionGenerator { @@ -68,6 +70,9 @@ public class MessageSerializerGenerator extends MessageCompanionGenerator { /** */ private static final String MESSAGE_READER_CLS = "org.apache.ignite.plugin.extensions.communication.MessageReader"; + /** */ + private static final String MESSAGE_SER_CTX_CLS = "org.apache.ignite.internal.MessageSerializationContext"; + /** */ private static final String ENUM_MAPPER_CLS = "org.apache.ignite.plugin.extensions.communication.mappers.EnumMapper"; @@ -145,6 +150,7 @@ public class MessageSerializerGenerator extends MessageCompanionGenerator { imports.add(MESSAGE_SERIALIZER_CLS); imports.add(MESSAGE_WRITER_CLS); imports.add(MESSAGE_READER_CLS); + imports.add(MESSAGE_SER_CTX_CLS); writeClassHeader(writer, "MessageSerializer", serClsName); @@ -195,8 +201,10 @@ private void generateMethods(List fields) throws Exception { private void generateMethod(List code, List fields, boolean write) throws Exception { code.add(indentedLine(METHOD_JAVADOC)); - code.add(indentedLine("@Override public final boolean %s(" + simpleNameWithGeneric(type) + " msg, %s) {", - write ? "writeTo" : "readFrom", write ? "MessageWriter writer" : "MessageReader reader")); + code.add(indentedLine( + "@Override public final boolean %s(" + simpleNameWithGeneric(type) + " msg, %s, MessageSerializationContext ctx) {", + write ? "writeTo" : "readFrom", + write ? "MessageWriter writer" : "MessageReader reader")); indent++; @@ -261,7 +269,7 @@ private void processField(VariableElement field, int opt, boolean write) throws throw new UnsupportedOperationException("You should use ErrorMessage for serialization of throwables."); if (write) - writeField(opt, callExpr(field, true)); + writeField(field, opt, callExpr(field, true)); else readField(field, opt, callExpr(field, false)); } @@ -301,13 +309,29 @@ private String callExpr(VariableElement field, boolean write) throws Exception { * @param opt Case option. * @param writeExpr Writer call expression. */ - private void writeField(int opt, String writeExpr) { + private void writeField(VariableElement field, int opt, String writeExpr) { write.add(indentedLine("case %d:", opt)); indent++; + FieldFeatureGate gate = buildFieldFeatureGate(env, field); + + if (gate != null) { + imports.add(gate.registry()); + + write.add(indentedLine("if (%s) {", gate.expression())); + + indent++; + } + returnFalseIf(write, "!" + writeExpr); + if (gate != null) { + indent--; + + write.add(indentedLine("}")); + } + write.add(EMPTY); write.add(indentedLine("writer.incrementState();")); write.add(EMPTY); @@ -335,11 +359,27 @@ private void readField(VariableElement field, int opt, String readExpr) { indent++; + FieldFeatureGate gate = buildFieldFeatureGate(env, field); + + if (gate != null) { + imports.add(gate.registry()); + + read.add(indentedLine("if (%s) {", gate.expression())); + + indent++; + } + read.add(indentedLine("%s = %s;", fieldRef(field), readExpr)); read.add(EMPTY); returnFalseIf(read, "!reader.isLastRead()"); + if (gate != null) { + indent--; + + read.add(indentedLine("}")); + } + read.add(EMPTY); read.add(indentedLine("reader.incrementState();")); read.add(EMPTY); @@ -360,13 +400,13 @@ private FieldCall fieldCall(VariableElement field) throws Exception { checkTypeForCompress(type); if (type.getKind().isPrimitive()) - return new FieldCall(capitalizeOnlyFirst(type.getKind().name()), null, false); + return FieldCall.scalar(capitalizeOnlyFirst(type.getKind().name())); if (type.getKind() == TypeKind.ARRAY) { TypeMirror compType = ((ArrayType)type).getComponentType(); if (compType.getKind().isPrimitive()) - return new FieldCall(capitalizeOnlyFirst(compType.getKind().name()) + "Array", null, false); + return FieldCall.scalar(capitalizeOnlyFirst(compType.getKind().name()) + "Array"); if (compType.getKind() == TypeKind.DECLARED) { Element compElem = ((DeclaredType)compType).asElement(); @@ -375,52 +415,52 @@ private FieldCall fieldCall(VariableElement field) throws Exception { imports.add(((QualifiedNameable)compElem).getQualifiedName().toString()); } - return new FieldCall("ObjectArray", messageCollectionItemTypes(field, type), false); + return FieldCall.collection("ObjectArray", messageCollectionItemTypes(field, type), false); } if (type.getKind() == TypeKind.DECLARED) { if (sameType(type, String.class)) - return new FieldCall("String", null, false); + return FieldCall.scalar("String"); if (sameType(type, BitSet.class)) - return new FieldCall("BitSet", null, false); + return FieldCall.scalar("BitSet"); if (sameType(type, UUID.class)) - return new FieldCall("Uuid", null, false); + return FieldCall.scalar("Uuid"); if (sameType(type, IGNITE_UUID_CLS)) - return new FieldCall("IgniteUuid", null, false); + return FieldCall.scalar("IgniteUuid"); if (sameType(type, AFFINITY_TOPOLOGY_VERSION_CLS)) - return new FieldCall("AffinityTopologyVersion", null, false); + return FieldCall.scalar("AffinityTopologyVersion"); if (assignableFrom(erasedType(type), type(Map.class.getName()))) - return new FieldCall("Map", messageCollectionItemTypes(field, type), compress); + return FieldCall.collection("Map", messageCollectionItemTypes(field, type), compress); if (assignableFrom(type, type(KEY_CACHE_OBJECT_CLS))) - return new FieldCall("KeyCacheObject", null, false); + return FieldCall.scalar("KeyCacheObject"); if (assignableFrom(type, type(CACHE_OBJECT_CLS))) - return new FieldCall("CacheObject", null, false); + return FieldCall.scalar("CacheObject"); if (assignableFrom(type, type(GRID_LONG_LIST_CLS))) - return new FieldCall("GridLongList", null, false); + return FieldCall.scalar("GridLongList"); if (assignableFrom(type, type(IGNITE_PRODUCT_VERSION_CLS))) - return new FieldCall("IgniteProductVersion", null, false); + return FieldCall.scalar("IgniteProductVersion"); if (assignableFrom(type, type(GRID_CACHE_VERSION_CLS))) - return new FieldCall("GridCacheVersion", null, false); + return FieldCall.scalar("GridCacheVersion"); if (assignableFrom(type, type(MESSAGE_INTERFACE))) { if (sameType(type, COMPRESSED_MESSAGE_CLASS)) throw new IllegalArgumentException(COMPRESSED_MSG_ERROR); - return new FieldCall("Message", null, compress); + return FieldCall.message(compress); } if (assignableFrom(erasedType(type), type(Collection.class.getName()))) - return new FieldCall("Collection", messageCollectionItemTypes(field, type), false); + return FieldCall.collection("Collection", messageCollectionItemTypes(field, type), false); throw new IllegalArgumentException("Unsupported declared type: " + type); } @@ -756,10 +796,14 @@ private static final class FieldCall { private final boolean compress; /** */ - private FieldCall(String mtd, @Nullable String collDesc, boolean compress) { + private final boolean isSerCtxRequired; + + /** */ + private FieldCall(String mtd, @Nullable String collDesc, boolean compress, boolean isSerCtxRequired) { this.mtd = mtd; this.collDesc = collDesc; this.compress = compress; + this.isSerCtxRequired = isSerCtxRequired; } /** @return Full call expression; {@code valArg}, when given, is passed as the first argument (write side). */ @@ -775,8 +819,26 @@ private String expr(String mtdPrefix, @Nullable String valArg) { if (compress) args.add("true"); + if (isSerCtxRequired) + args.add("ctx"); + return mtdPrefix + mtd + "(" + String.join(", ", args) + ")"; } + + /** */ + private static FieldCall scalar(String mtd) { + return new FieldCall(mtd, null, false, false); + } + + /** */ + private static FieldCall collection(String mtd, String collDesc, boolean compress) { + return new FieldCall(mtd, collDesc, compress, true); + } + + /** */ + private static FieldCall message(boolean compress) { + return new FieldCall("Message", null, compress, true); + } } /** */ diff --git a/modules/codegen/src/main/java/org/apache/ignite/internal/Order.java b/modules/codegen/src/main/java/org/apache/ignite/internal/Order.java index 0e4562537c435..03cec3b0e0538 100644 --- a/modules/codegen/src/main/java/org/apache/ignite/internal/Order.java +++ b/modules/codegen/src/main/java/org/apache/ignite/internal/Order.java @@ -21,6 +21,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.apache.ignite.internal.processors.rollingupgrade.feature.IgniteFeature; /** * The annotation specifies the position of a field in the serialized and deserialized byte sequence of a {@code Message} class. @@ -28,14 +29,38 @@ * The {@code value} indicates the index of the field in the serialization order. * Fields annotated with {@code @Order} are processed in ascending order of their index. *

By default, it is assumed that getters and setters are named as the annotated fields, - * e.g. field 'val' should have getters and satters with name 'val' (according Ignite's to code-style). + * e.g. field 'val' should have getters and setters with name 'val' (according Ignite's to code-style). *

This annotation must be used on non-static fields, and access to those fields * should be performed strictly through corresponding getter and setter methods * following the naming convention: {@code fieldName()} for getter and {@code fieldName(Type)} for setter. + * + * @see FeatureGated */ @Retention(RetentionPolicy.CLASS) @Target(ElementType.FIELD) public @interface Order { /** @return Order of the field. */ int value(); + + /** + * {@link IgniteFeature} that introduced the field marked with the current annotation. + * + *

An annotated field is included in message serialization only when doing so does not break backward compatibility + * during a Rolling Upgrade.

+ * + * @return Name of the Ignite feature that introduced this field, or an empty string if the field is not gated. + */ + String introducedBy() default ""; + + /** + * {@link IgniteFeature} that deprecated the field marked with the current annotation. + * + *

Deprecation means that the field is planned for removal in a future release.

+ * + *

An annotated field is excluded from message serialization only when doing so does not break backward compatibility + * during a Rolling Upgrade.

+ * + * @return Name of the Ignite feature that deprecated this field, or an empty string if the field is not gated. + */ + String deprecatedBy() default ""; } diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/MessageSerializationContext.java b/modules/commons/src/main/java/org/apache/ignite/internal/MessageSerializationContext.java new file mode 100644 index 0000000000000..3bb16926a054f --- /dev/null +++ b/modules/commons/src/main/java/org/apache/ignite/internal/MessageSerializationContext.java @@ -0,0 +1,90 @@ +/* + * 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.internal.processors.rollingupgrade.feature.IgniteFeature; + +/** Represents the context that determines how message fields are serialized and deserialized when transmitted between nodes. */ +public interface MessageSerializationContext { + /** + * @param feature Feature that deprecated the field. + * @return {@code true} if the message field should be included during message serialization or deserialization. + */ + boolean includeFieldDeprecatedBy(IgniteFeature feature); + + /** + * @param feature Feature that introduced the field. + * @return {@code true} if the message field should be included during message serialization or deserialization. + */ + boolean includeFieldIntroducedBy(IgniteFeature feature); + + /** + * {@link MessageSerializationContext} implementation that instructs the serialization framework to always + * serialize the latest message fields schema: all newly introduced fields are included, and all deprecated fields are + * excluded. + */ + MessageSerializationContext LATEST_SCHEMA = new MessageSerializationContext() { + /** {@inheritDoc} */ + @Override public boolean includeFieldDeprecatedBy(IgniteFeature feature) { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean includeFieldIntroducedBy(IgniteFeature feature) { + return true; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return "MessageSerializationContext [LATEST_SCHEMA]"; + } + }; + + /** + * {@link MessageSerializationContext} implementation that permits only messages whose schema is immutable across + * versions, i.e. declares no fields gated by an {@link IgniteFeature}: evaluating any feature gate throws + * {@link IllegalStateException}. + * + *

Used between connection establishment and serialization protocol negotiation, when the peer's features are not + * yet known. Messages exchanged during this period must therefore declare no fields gated by + * {@code @Order(introducedBy = ...)} or {@code @Order(deprecatedBy = ...)}.

+ */ + MessageSerializationContext IMMUTABLE_SCHEMA = new MessageSerializationContext() { + /** {@inheritDoc} */ + @Override public boolean includeFieldDeprecatedBy(IgniteFeature feature) { + throw buildError(feature); + } + + /** {@inheritDoc} */ + @Override public boolean includeFieldIntroducedBy(IgniteFeature feature) { + throw buildError(feature); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return "MessageSerializationContext [IMMUTABLE_SCHEMA]"; + } + + /** */ + private IllegalStateException buildError(IgniteFeature feature) { + return new IllegalStateException( + "A feature-gated field was serialized before the peer's features were negotiated [feature=" + feature + ']' + ); + } + }; +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rollingupgrade/feature/IgniteFeature.java b/modules/commons/src/main/java/org/apache/ignite/internal/processors/rollingupgrade/feature/IgniteFeature.java similarity index 100% rename from modules/core/src/main/java/org/apache/ignite/internal/processors/rollingupgrade/feature/IgniteFeature.java rename to modules/commons/src/main/java/org/apache/ignite/internal/processors/rollingupgrade/feature/IgniteFeature.java diff --git a/modules/core/src/main/java/org/apache/ignite/internal/direct/DirectMessageReader.java b/modules/core/src/main/java/org/apache/ignite/internal/direct/DirectMessageReader.java index 9ec9b68cc189e..b070629a38ba3 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/direct/DirectMessageReader.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/direct/DirectMessageReader.java @@ -24,6 +24,7 @@ import java.util.UUID; import java.util.function.Function; import org.apache.ignite.IgniteException; +import org.apache.ignite.internal.MessageSerializationContext; import org.apache.ignite.internal.direct.state.DirectMessageState; import org.apache.ignite.internal.direct.state.DirectMessageStateItem; import org.apache.ignite.internal.direct.stream.DirectByteBufferStream; @@ -344,7 +345,7 @@ public ByteBuffer getBuffer() { } /** {@inheritDoc} */ - @Nullable @Override public T readMessage(boolean compress) { + @Nullable @Override public T readMessage(boolean compress, MessageSerializationContext ctx) { DirectByteBufferStream stream = curStream; T msg; @@ -352,10 +353,11 @@ public ByteBuffer getBuffer() { if (compress) msg = readCompressedMessageAndDeserialize( stream, - r -> r.state.item().stream.readMessage(r) + r -> r.state.item().stream.readMessage(r, ctx), + ctx ); else { - msg = stream.readMessage(this); + msg = stream.readMessage(this, ctx); lastRead = stream.lastFinished(); } @@ -397,10 +399,10 @@ public ByteBuffer getBuffer() { } /** {@inheritDoc} */ - @Override public T[] readObjectArray(MessageArrayType type) { + @Override public T[] readObjectArray(MessageArrayType type, MessageSerializationContext ctx) { DirectByteBufferStream stream = curStream; - T[] msg = stream.readObjectArray(type, this); + T[] msg = stream.readObjectArray(type, this, ctx); lastRead = stream.lastFinished(); @@ -408,10 +410,10 @@ public ByteBuffer getBuffer() { } /** {@inheritDoc} */ - @Override public > C readCollection(MessageCollectionType type) { + @Override public > C readCollection(MessageCollectionType type, MessageSerializationContext ctx) { DirectByteBufferStream stream = curStream; - C col = stream.readCollection(type, this); + C col = stream.readCollection(type, this, ctx); lastRead = stream.lastFinished(); @@ -419,7 +421,7 @@ public ByteBuffer getBuffer() { } /** {@inheritDoc} */ - @Override public > M readMap(MessageMapType type, boolean compress) { + @Override public > M readMap(MessageMapType type, boolean compress, MessageSerializationContext ctx) { DirectByteBufferStream stream = curStream; M map; @@ -427,10 +429,11 @@ public ByteBuffer getBuffer() { if (compress) map = readCompressedMessageAndDeserialize( stream, - r -> r.state.item().stream.readMap(type, r) + r -> r.state.item().stream.readMap(type, r, ctx), + ctx ); else { - map = stream.readMap(type, this); + map = stream.readMap(type, this, ctx); lastRead = stream.lastFinished(); } @@ -509,8 +512,12 @@ public ByteBuffer getBuffer() { } /** @return Deserialized object. */ - private T readCompressedMessageAndDeserialize(DirectByteBufferStream stream, Function fun) { - Message msg = stream.readMessage(this); + private T readCompressedMessageAndDeserialize( + DirectByteBufferStream stream, + Function fun, + MessageSerializationContext ctx + ) { + Message msg = stream.readMessage(this, ctx); lastRead = stream.lastFinished(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/direct/DirectMessageWriter.java b/modules/core/src/main/java/org/apache/ignite/internal/direct/DirectMessageWriter.java index 319aae7b7e947..f09632cfbac4e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/direct/DirectMessageWriter.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/direct/DirectMessageWriter.java @@ -23,6 +23,7 @@ import java.util.Map; import java.util.UUID; import java.util.function.Consumer; +import org.apache.ignite.internal.MessageSerializationContext; import org.apache.ignite.internal.direct.state.DirectMessageState; import org.apache.ignite.internal.direct.state.DirectMessageStateItem; import org.apache.ignite.internal.direct.stream.DirectByteBufferStream; @@ -334,17 +335,18 @@ public ByteBuffer getBuffer() { } /** {@inheritDoc} */ - @Override public boolean writeMessage(@Nullable Message msg, boolean compress) { + @Override public boolean writeMessage(@Nullable Message msg, boolean compress, MessageSerializationContext ctx) { DirectByteBufferStream stream = curStream; if (compress) writeCompressedMessage( - w -> w.state.item().stream.writeMessage(msg, w), + w -> w.state.item().stream.writeMessage(msg, w, ctx), msg == null, - stream + stream, + ctx ); else - stream.writeMessage(msg, this); + stream.writeMessage(msg, this, ctx); return stream.lastFinished(); } @@ -377,35 +379,36 @@ public ByteBuffer getBuffer() { } /** {@inheritDoc} */ - @Override public boolean writeObjectArray(T[] arr, MessageArrayType type) { + @Override public boolean writeObjectArray(T[] arr, MessageArrayType type, MessageSerializationContext ctx) { DirectByteBufferStream stream = curStream; - stream.writeObjectArray(arr, type, this); + stream.writeObjectArray(arr, type, this, ctx); return stream.lastFinished(); } /** {@inheritDoc} */ - @Override public boolean writeCollection(Collection col, MessageCollectionType type) { + @Override public boolean writeCollection(Collection col, MessageCollectionType type, MessageSerializationContext ctx) { DirectByteBufferStream stream = curStream; - stream.writeCollection(col, type, this); + stream.writeCollection(col, type, this, ctx); return stream.lastFinished(); } /** {@inheritDoc} */ - @Override public boolean writeMap(Map map, MessageMapType type, boolean compress) { + @Override public boolean writeMap(Map map, MessageMapType type, boolean compress, MessageSerializationContext ctx) { DirectByteBufferStream stream = curStream; if (compress) writeCompressedMessage( - w -> w.state.item().stream.writeMap(map, type, w), + w -> w.state.item().stream.writeMap(map, type, w, ctx), map == null, - stream + stream, + ctx ); else - stream.writeMap(map, type, this); + stream.writeMap(map, type, this, ctx); return stream.lastFinished(); } @@ -485,8 +488,14 @@ public ByteBuffer getBuffer() { * @param consumer Consumer. * @param isNull {@code True} if message is null. * @param stream Byte buffer stream. + * @param ctx Serialization context. */ - private void writeCompressedMessage(Consumer consumer, boolean isNull, DirectByteBufferStream stream) { + private void writeCompressedMessage( + Consumer consumer, + boolean isNull, + DirectByteBufferStream stream, + MessageSerializationContext ctx + ) { if (isNull) { stream.writeShort(Short.MIN_VALUE); @@ -536,7 +545,7 @@ private void writeCompressedMessage(Consumer consumer, bool stream.serializeFinished(true); } - stream.writeMessage(stream.compressedMessage(), this); + stream.writeMessage(stream.compressedMessage(), this, ctx); if (stream.lastFinished()) { stream.compressedMessage(null); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/direct/IgniteMessageSerializationContext.java b/modules/core/src/main/java/org/apache/ignite/internal/direct/IgniteMessageSerializationContext.java new file mode 100644 index 0000000000000..f4248588cedb9 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/direct/IgniteMessageSerializationContext.java @@ -0,0 +1,231 @@ +/* + * 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.direct; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import org.apache.ignite.Ignite; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.MessageSerializationContext; +import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException; +import org.apache.ignite.internal.processors.rollingupgrade.feature.IgniteComponentFeatureSet; +import org.apache.ignite.internal.processors.rollingupgrade.feature.IgniteFeature; +import org.apache.ignite.internal.processors.rollingupgrade.feature.IgniteFeatureSet; +import org.apache.ignite.internal.processors.rollingupgrade.feature.IgniteNodeFeatureSet; +import org.apache.ignite.internal.util.tostring.GridToStringInclude; +import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.spi.discovery.tcp.internal.UnsupportedNodeVersionException; +import org.jetbrains.annotations.Nullable; + +/** */ +public class IgniteMessageSerializationContext implements MessageSerializationContext { + /** */ + @GridToStringInclude + private final Map ctxByComponent; + + /** */ + private IgniteMessageSerializationContext(Map ctxByComponent) { + this.ctxByComponent = ctxByComponent; + } + + /** {@inheritDoc} */ + @Override public boolean includeFieldIntroducedBy(IgniteFeature feature) { + return componentContext(feature.componentName()).includeFieldIntroducedBy(feature.id()); + } + + /** {@inheritDoc} */ + @Override public boolean includeFieldDeprecatedBy(IgniteFeature feature) { + return componentContext(feature.componentName()).includeFieldDeprecatedBy(feature.id()); + } + + /** */ + private ComponentMessageSerializationContext componentContext(String cmpName) { + ComponentMessageSerializationContext cmpCtx = ctxByComponent.get(cmpName); + + if (cmpCtx == null) { + throw new IllegalStateException("A field is gated by a feature of an undeclared component" + + " [component=" + cmpName + + ", declaredComponents=" + ctxByComponent.keySet() + ']' + ); + } + + return cmpCtx; + } + + /** */ + public static IgniteMessageSerializationContext buildForPeers( + Ignite loc, + ClusterNode rmt + ) throws UnsupportedNodeVersionException, ClusterTopologyCheckedException { + GridKernalContext ctx = ((IgniteEx)loc).context(); + + return buildForPeers(ctx.localNodeFeatures(), ctx.discovery().resolveNodeFeatures(rmt)); + } + + /** */ + public static IgniteMessageSerializationContext buildForPeers( + IgniteNodeFeatureSet loc, + IgniteNodeFeatureSet rmt + ) throws UnsupportedNodeVersionException { + assert loc != null; + + if (rmt == null) { + throw new UnsupportedNodeVersionException("Failed to build the message serialization context for the remote node." + + " The remote node's feature set is unavailable."); + } + + Set components = new HashSet<>(loc.components()); + + components.addAll(rmt.components()); + + Map ctxByComponent = new HashMap<>(); + + for (String cmp : components) { + ComponentMessageSerializationContext ctx = resolveComponentSerializationContext( + cmp, + loc.componentFeatures(cmp), + rmt.componentFeatures(cmp) + ); + + ctxByComponent.put(cmp, ctx); + } + + return new IgniteMessageSerializationContext(ctxByComponent); + } + + /** */ + private static ComponentMessageSerializationContext resolveComponentSerializationContext( + String cmpName, + @Nullable IgniteComponentFeatureSet locCmpFeatures, + @Nullable IgniteComponentFeatureSet rmtCmpFeatures + ) throws UnsupportedNodeVersionException { + assert locCmpFeatures != null || rmtCmpFeatures != null; + + // One of the sides has no component configured. This may happen when one side uses an RU-unaware plugin version + // while the other uses an RU-aware version. In this case, all newly introduced fields are skipped, while all + // deprecated fields are included. + if (locCmpFeatures == null || rmtCmpFeatures == null) + return new ComponentMessageSerializationContext(null, null); + + int c = locCmpFeatures.version().compareTo(rmtCmpFeatures.version()); + + if (c == 0) { + assert locCmpFeatures.features().equals(rmtCmpFeatures.features()); + + // Both newly introduced and deprecated fields are included. During an RU, a node builds messages according + // to both the old logical version (while RU is in progress, deprecated fields are used and newly introduced + // fields are not) and the new logical version (after RU is finished, newly introduced fields are used and + // deprecated fields are not). + return new ComponentMessageSerializationContext(null, rmtCmpFeatures.features()); + } + else { + IgniteComponentFeatureSet src = c < 0 ? locCmpFeatures : rmtCmpFeatures; + IgniteComponentFeatureSet target = c < 0 ? rmtCmpFeatures : locCmpFeatures; + + if (!src.isUpgradableTo(target)) { + throw new UnsupportedNodeVersionException("Remote node component versions are not supported" + + " [component=" + cmpName + + ", locComponent=" + locCmpFeatures + + ", rmtComponent=" + rmtCmpFeatures + ']'); + } + + // The old version dictates the serialization rules. + return new ComponentMessageSerializationContext(src.features(), src.features()); + } + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(IgniteMessageSerializationContext.class, this); + } + + /** {@inheritDoc} */ + @Override public boolean equals(Object o) { + if (this == o) + return true; + + if (o == null || getClass() != o.getClass()) + return false; + + return Objects.equals(ctxByComponent, ((IgniteMessageSerializationContext)o).ctxByComponent); + } + + /** {@inheritDoc} */ + @Override public int hashCode() { + return Objects.hashCode(ctxByComponent); + } + + /** */ + private static final class ComponentMessageSerializationContext { + /** */ + @GridToStringInclude + @Nullable private final IgniteFeatureSet excludedDeprecatedFields; + + /** */ + @GridToStringInclude + @Nullable private final IgniteFeatureSet includedIntroducedFields; + + /** */ + private ComponentMessageSerializationContext( + @Nullable IgniteFeatureSet excludedDeprecatedFields, + @Nullable IgniteFeatureSet includedIntroducedFields + ) { + this.excludedDeprecatedFields = excludedDeprecatedFields; + this.includedIntroducedFields = includedIntroducedFields; + } + + /** */ + boolean includeFieldIntroducedBy(int featureId) { + return includedIntroducedFields != null && includedIntroducedFields.contains(featureId); + } + + /** */ + boolean includeFieldDeprecatedBy(int featureId) { + return excludedDeprecatedFields == null || !excludedDeprecatedFields.contains(featureId); + } + + /** {@inheritDoc} */ + @Override public boolean equals(Object o) { + if (this == o) + return true; + + if (o == null || getClass() != o.getClass()) + return false; + + ComponentMessageSerializationContext other = (ComponentMessageSerializationContext)o; + + return Objects.equals(excludedDeprecatedFields, other.excludedDeprecatedFields) + && Objects.equals(includedIntroducedFields, other.includedIntroducedFields); + } + + /** {@inheritDoc} */ + @Override public int hashCode() { + return Objects.hash(includedIntroducedFields, excludedDeprecatedFields); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(ComponentMessageSerializationContext.class, this); + } + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/direct/stream/DirectByteBufferStream.java b/modules/core/src/main/java/org/apache/ignite/internal/direct/stream/DirectByteBufferStream.java index d2176dfb6f617..cdabbaa7c5699 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/direct/stream/DirectByteBufferStream.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/direct/stream/DirectByteBufferStream.java @@ -34,6 +34,7 @@ import java.util.function.Supplier; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteException; +import org.apache.ignite.internal.MessageSerializationContext; import org.apache.ignite.internal.binary.StringWriter; import org.apache.ignite.internal.managers.communication.CompressedMessage; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; @@ -932,11 +933,12 @@ public void writeGridLongList(@Nullable GridLongList val) { /** * @param msg Message. * @param writer Writer. + * @param ctx Serialization context. */ - public void writeMessage(Message msg, MessageWriter writer) { + public void writeMessage(Message msg, MessageWriter writer, MessageSerializationContext ctx) { if (msg != null) { if (buf.hasRemaining()) - nestedWrite(writer, () -> MessageSerialization.writeTo(msgFactory, msg, writer)); + nestedWrite(writer, () -> MessageSerialization.writeTo(msgFactory, msg, writer, ctx)); else lastFinished = false; } @@ -948,8 +950,9 @@ public void writeMessage(Message msg, MessageWriter writer) { * @param arr Array. * @param type Type. * @param writer Writer. + * @param ctx Serialization context. */ - public void writeObjectArray(T[] arr, MessageArrayType type, MessageWriter writer) { + public void writeObjectArray(T[] arr, MessageArrayType type, MessageWriter writer, MessageSerializationContext ctx) { if (arr != null) { int len = arr.length; @@ -966,7 +969,7 @@ public void writeObjectArray(T[] arr, MessageArrayType type, MessageWriter w if (arrCur == NULL) arrCur = arr[arrPos++]; - write(type.valueType(), arrCur, writer); + write(type.valueType(), arrCur, writer, ctx); if (!lastFinished) return; @@ -984,11 +987,12 @@ public void writeObjectArray(T[] arr, MessageArrayType type, MessageWriter w * @param col Collection. * @param type Type. * @param writer Writer. + * @param ctx Serialization context. */ - public void writeCollection(Collection col, MessageCollectionType type, MessageWriter writer) { + public void writeCollection(Collection col, MessageCollectionType type, MessageWriter writer, MessageSerializationContext ctx) { if (col != null) { if (col instanceof List && col instanceof RandomAccess) - writeRandomAccessList((List)col, type, writer); + writeRandomAccessList((List)col, type, writer, ctx); else { if (it == null) { writeInt(col.size()); @@ -1003,7 +1007,7 @@ public void writeCollection(Collection col, MessageCollectionType type, M if (cur == NULL) cur = it.next(); - write(type.valueType(), cur, writer); + write(type.valueType(), cur, writer, ctx); if (!lastFinished) return; @@ -1022,8 +1026,14 @@ public void writeCollection(Collection col, MessageCollectionType type, M * @param list List. * @param type Type. * @param writer Writer. - */ - private void writeRandomAccessList(List list, MessageCollectionType type, MessageWriter writer) { + * @param ctx Serialization context. + */ + private void writeRandomAccessList( + List list, + MessageCollectionType type, + MessageWriter writer, + MessageSerializationContext ctx + ) { assert list instanceof RandomAccess; int size = list.size(); @@ -1041,7 +1051,7 @@ private void writeRandomAccessList(List list, MessageCollectionType type, if (arrCur == NULL) arrCur = list.get(arrPos++); - write(type.valueType(), arrCur, writer); + write(type.valueType(), arrCur, writer, ctx); if (!lastFinished) return; @@ -1056,8 +1066,9 @@ private void writeRandomAccessList(List list, MessageCollectionType type, * @param map Map. * @param type Type. * @param writer Writer. + * @param ctx Serialization context. */ - public void writeMap(Map map, MessageMapType type, MessageWriter writer) { + public void writeMap(Map map, MessageMapType type, MessageWriter writer, MessageSerializationContext ctx) { if (map != null) { if (mapIt == null) { writeInt(map.size()); @@ -1077,7 +1088,7 @@ public void writeMap(Map map, MessageMapType type, MessageWriter wr e = (Map.Entry)mapCur; if (!keyDone) { - write(type.keyType(), e.getKey(), writer); + write(type.keyType(), e.getKey(), writer, ctx); if (!lastFinished) return; @@ -1085,7 +1096,7 @@ public void writeMap(Map map, MessageMapType type, MessageWriter wr keyDone = true; } - write(type.valueType(), e.getValue(), writer); + write(type.valueType(), e.getValue(), writer, ctx); if (!lastFinished) return; @@ -1561,9 +1572,10 @@ public GridLongList readGridLongList() { /** * @param reader Reader. + * @param ctx Serialization context. * @return Message. */ - public T readMessage(MessageReader reader) { + public T readMessage(MessageReader reader, MessageSerializationContext ctx) { if (!msgTypeDone) { if (buf.remaining() < Message.DIRECT_TYPE_SIZE) { lastFinished = false; @@ -1582,7 +1594,7 @@ public T readMessage(MessageReader reader) { try { reader.beforeNestedRead(); - lastFinished = MessageSerialization.readFrom(msgFactory, msg, reader); + lastFinished = MessageSerialization.readFrom(msgFactory, msg, reader, ctx); } finally { reader.afterNestedRead(lastFinished); @@ -1606,9 +1618,10 @@ public T readMessage(MessageReader reader) { /** * @param type Item type. * @param reader Reader. + * @param ctx Serialization context. * @return Array. */ - public T[] readObjectArray(MessageArrayType type, MessageReader reader) { + public T[] readObjectArray(MessageArrayType type, MessageReader reader, MessageSerializationContext ctx) { if (readSize == -1) { int size = readInt(); @@ -1623,7 +1636,7 @@ public T[] readObjectArray(MessageArrayType type, MessageReader reader) { objArr = type.clazz() != null ? (Object[])Array.newInstance(type.clazz(), readSize) : new Object[readSize]; for (int i = readItems; i < readSize; i++) { - Object item = read(type.valueType(), reader); + Object item = read(type.valueType(), reader, ctx); if (!lastFinished) return null; @@ -1650,9 +1663,10 @@ public T[] readObjectArray(MessageArrayType type, MessageReader reader) { * * @param type Item type. * @param reader Reader. + * @param ctx Serialization context. * @return {@link ArrayList}, {@link HashSet} or {@link EnumSet}. */ - public > C readCollection(MessageCollectionType type, MessageReader reader) { + public > C readCollection(MessageCollectionType type, MessageReader reader, MessageSerializationContext ctx) { if (readSize == -1) { int size = readInt(); @@ -1667,7 +1681,7 @@ public > C readCollection(MessageCollectionType type, Me col = newCollection(type); for (int i = readItems; i < readSize; i++) { - Object item = read(type.valueType(), reader); + Object item = read(type.valueType(), reader, ctx); if (!lastFinished) return null; @@ -1702,9 +1716,10 @@ private Collection newCollection(MessageCollectionType type) { /** * @param type Value type. * @param reader Reader. + * @param ctx Serialization context. * @return Map. */ - public > M readMap(MessageMapType type, MessageReader reader) { + public > M readMap(MessageMapType type, MessageReader reader, MessageSerializationContext ctx) { if (readSize == -1) { int size = readInt(); @@ -1720,7 +1735,7 @@ private Collection newCollection(MessageCollectionType type) { for (int i = readItems; i < readSize; i++) { if (!keyDone) { - Object key = read(type.keyType(), reader); + Object key = read(type.keyType(), reader, ctx); if (!lastFinished) return null; @@ -1729,7 +1744,7 @@ private Collection newCollection(MessageCollectionType type) { keyDone = true; } - Object val = read(type.valueType(), reader); + Object val = read(type.valueType(), reader, ctx); if (!lastFinished) return null; @@ -2009,8 +2024,9 @@ T readArrayLE(ArrayCreator creator, int typeSize, int lenShift, long off) * @param type Type. * @param val Value. * @param writer Writer. + * @param ctx Serialization context. */ - protected void write(MessageType type, Object val, MessageWriter writer) { + protected void write(MessageType type, Object val, MessageWriter writer, MessageSerializationContext ctx) { switch (type.type()) { case BYTE: writeByte((Byte)val); @@ -2138,17 +2154,17 @@ protected void write(MessageType type, Object val, MessageWriter writer) break; case MAP: - nestedWrite(writer, () -> writer.writeMap((Map)val, (MessageMapType)type)); + nestedWrite(writer, () -> writer.writeMap((Map)val, (MessageMapType)type, ctx)); break; case COLLECTION: - nestedWrite(writer, () -> writer.writeCollection((Collection)val, (MessageCollectionType)type)); + nestedWrite(writer, () -> writer.writeCollection((Collection)val, (MessageCollectionType)type, ctx)); break; case ARRAY: - nestedWrite(writer, () -> writer.writeObjectArray((V[])val, (MessageArrayType)type)); + nestedWrite(writer, () -> writer.writeObjectArray((V[])val, (MessageArrayType)type, ctx)); break; @@ -2158,7 +2174,7 @@ protected void write(MessageType type, Object val, MessageWriter writer) break; case MSG: - writeMessage((Message)val, writer); + writeMessage((Message)val, writer, ctx); break; @@ -2182,9 +2198,10 @@ private void nestedWrite(MessageWriter writer, BooleanSupplier s) { /** * @param type Type. * @param reader Reader. + * @param ctx Serialization context. * @return Value. */ - protected Object read(MessageType type, MessageReader reader) { + protected Object read(MessageType type, MessageReader reader, MessageSerializationContext ctx) { switch (type.type()) { case BYTE: return readByte(); @@ -2262,19 +2279,19 @@ protected Object read(MessageType type, MessageReader reader) { return readGridLongList(); case MAP: - return nestedRead(reader, () -> reader.readMap((MessageMapType)type)); + return nestedRead(reader, () -> reader.readMap((MessageMapType)type, ctx)); case COLLECTION: - return nestedRead(reader, () -> reader.readCollection((MessageCollectionType)type)); + return nestedRead(reader, () -> reader.readCollection((MessageCollectionType)type, ctx)); case ARRAY: - return nestedRead(reader, () -> reader.readObjectArray((MessageArrayType)type)); + return nestedRead(reader, () -> reader.readObjectArray((MessageArrayType)type, ctx)); case ENUM: return ((MessageEnumType)type).decode(readByte()); case MSG: - return readMessage(reader); + return readMessage(reader, ctx); default: throw new IllegalArgumentException("Unknown type: " + type); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/CompressedMessageSerializer.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/CompressedMessageSerializer.java index 7661a11421972..4f96b37f88e63 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/CompressedMessageSerializer.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/CompressedMessageSerializer.java @@ -19,6 +19,7 @@ import java.util.ArrayList; import org.apache.ignite.IgniteException; +import org.apache.ignite.internal.MessageSerializationContext; import org.apache.ignite.plugin.extensions.communication.MessageReader; import org.apache.ignite.plugin.extensions.communication.MessageSerializer; import org.apache.ignite.plugin.extensions.communication.MessageWriter; @@ -28,7 +29,7 @@ /** Message serializer for compressed message. */ public class CompressedMessageSerializer implements MessageSerializer { /** {@inheritDoc} */ - @Override public boolean writeTo(CompressedMessage msg, MessageWriter writer) { + @Override public boolean writeTo(CompressedMessage msg, MessageWriter writer, MessageSerializationContext ctx) { if (!writer.isHeaderWritten()) { if (!writer.writeHeader(msg.directType())) return false; @@ -74,7 +75,7 @@ public class CompressedMessageSerializer implements MessageSerializer T readMessage() throws IgniteCheckedException, IOException { readBuf.limit(read); - finished = MessageSerialization.readFrom(msgFactory, msg, msgReader); + finished = MessageSerialization.readFrom(msgFactory, msg, msgReader, serCtx); // Server Discovery only sends next message to next Server upon receiving a receipt for the previous one. // This behaviour guarantees that we never read a next message from the buffer right after the end of diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java index 17352d1f72bbc..19903ffb5fb17 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java @@ -58,8 +58,6 @@ import org.apache.ignite.internal.managers.communication.UnknownMessageException; import org.apache.ignite.internal.managers.discovery.IgniteDiscoverySpi; import org.apache.ignite.internal.processors.metric.MetricRegistryImpl; -import org.apache.ignite.internal.processors.rollingupgrade.feature.IgniteComponentFeatureSet; -import org.apache.ignite.internal.processors.rollingupgrade.feature.IgniteNodeFeatureSet; import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.X; @@ -98,7 +96,6 @@ import org.apache.ignite.spi.discovery.tcp.internal.DiscoveryDataPacket; import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoveryNode; import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoveryStatistics; -import org.apache.ignite.spi.discovery.tcp.internal.UnsupportedNodeVersionException; import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder; import org.apache.ignite.spi.discovery.tcp.ipfinder.jdbc.TcpDiscoveryJdbcIpFinder; import org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder; @@ -1681,36 +1678,6 @@ Socket createSocket() throws IOException { } } - /** */ - void validateRemoteFeatures(IgniteNodeFeatureSet rmtFeatures) throws IgniteCheckedException { - if (rmtFeatures == null) { - throw new UnsupportedNodeVersionException( - "Failed to obtain remote node features. The remote node may be running an unsupported Ignite version," + - " which may result in unexpected handshake message serialization"); - } - - for (IgniteComponentFeatureSet rmtCmpFeatures : rmtFeatures.values()) { - IgniteComponentFeatureSet locCmpFeatures = locNode.features().componentFeatures(rmtCmpFeatures.componentName()); - - if (locCmpFeatures == null) - continue; - - int c = locCmpFeatures.version().compareTo(rmtCmpFeatures.version()); - - if (c == 0) - continue; - - IgniteComponentFeatureSet src = c > 0 ? rmtCmpFeatures : locCmpFeatures; - IgniteComponentFeatureSet target = c > 0 ? locCmpFeatures : rmtCmpFeatures; - - if (!src.isUpgradableTo(target)) { - throw new UnsupportedNodeVersionException("Remote node component versions are not supported" + - " [locComponents=" + locNode.features() + - ", rmtComponents=" + rmtFeatures + ']'); - } - } - } - /** * Writes raw data to the session socket. * diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/ClientMessageHolder.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/ClientMessageHolder.java index 1652824dd155b..047da61b2d247 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/ClientMessageHolder.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/ClientMessageHolder.java @@ -17,7 +17,10 @@ package org.apache.ignite.spi.discovery.tcp.internal; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.MessageSerializationContext; import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryAbstractMessage; import org.jetbrains.annotations.Nullable; @@ -27,7 +30,7 @@ public class ClientMessageHolder { private final TcpDiscoveryAbstractMessage msg; /** */ - private volatile byte[] msgBytes; + private final Map bytesByCtx = new ConcurrentHashMap<>(1); /** */ public ClientMessageHolder(TcpDiscoveryAbstractMessage msg) { @@ -42,14 +45,14 @@ public TcpDiscoveryAbstractMessage message() { } /** */ - public byte @Nullable [] messageBytes() { - return msgBytes; + public byte @Nullable [] messageBytes(MessageSerializationContext ctx) { + return bytesByCtx.get(ctx); } /** */ - public void serialize(TcpDiscoveryMessageSerializer ser) throws IgniteCheckedException { - if (msgBytes == null) - msgBytes = ser.serialize(msg); + public void serialize(TcpDiscoveryMessageSerializer ser, MessageSerializationContext ctx) throws IgniteCheckedException { + if (!bytesByCtx.containsKey(ctx)) + bytesByCtx.put(ctx, ser.serialize(msg, ctx)); } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/TcpDiscoveryMessageSerializer.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/TcpDiscoveryMessageSerializer.java index 45aa1d9b76743..9102876206bd4 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/TcpDiscoveryMessageSerializer.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/TcpDiscoveryMessageSerializer.java @@ -22,6 +22,7 @@ import java.nio.ByteBuffer; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.MessageSerializationContext; import org.apache.ignite.internal.direct.DirectMessageWriter; import org.apache.ignite.internal.managers.communication.DiscoveryMarshalling; import org.apache.ignite.internal.util.io.GridByteArrayOutputStream; @@ -54,10 +55,15 @@ public TcpDiscoveryMessageSerializer(GridKernalContext ctx) { * * @param msg Discovery message to serialize. * @param out Output stream to write serialized message. + * @param serCtx Serialization context the recipient agreed on. * @throws IgniteCheckedException If serialization fails. * @throws IOException If serialization fails. */ - public void writeTo(TcpDiscoveryAbstractMessage msg, OutputStream out) throws IgniteCheckedException, IOException { + public void writeTo( + TcpDiscoveryAbstractMessage msg, + OutputStream out, + MessageSerializationContext serCtx + ) throws IgniteCheckedException, IOException { DiscoveryMarshalling.marshal(msg, ctx, null); writer.reset(); @@ -69,7 +75,7 @@ public void writeTo(TcpDiscoveryAbstractMessage msg, OutputStream out) throws Ig // Should be cleared before first operation. buf.clear(); - finished = MessageSerialization.writeTo(ctx.messageFactory(), msg, writer); + finished = MessageSerialization.writeTo(ctx.messageFactory(), msg, writer, serCtx); out.write(buf.array(), 0, buf.position()); } @@ -80,12 +86,16 @@ public void writeTo(TcpDiscoveryAbstractMessage msg, OutputStream out) throws Ig * Serializes a discovery message into a byte array. * * @param msg Discovery message to serialize. + * @param serCtx Serialization context the recipient agreed on. * @return Serialized byte array containing the message data. * @throws IgniteCheckedException If serialization fails. */ - public byte[] serialize(TcpDiscoveryAbstractMessage msg) throws IgniteCheckedException { + public byte[] serialize( + TcpDiscoveryAbstractMessage msg, + MessageSerializationContext serCtx + ) throws IgniteCheckedException { try (GridByteArrayOutputStream out = new GridByteArrayOutputStream()) { - writeTo(msg, out); + writeTo(msg, out, serCtx); return out.toByteArray(); } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java b/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java index 1105f85cf3fd9..862b2d88b65e7 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java @@ -93,6 +93,46 @@ public void testProcessorGeneratesSerializer() { .hasSourceEquivalentTo(javaFile("TestMessageMarshaller.java")); } + /** */ + @Test + public void testRollingUpgradeAwareMessage() { + Compilation compilation = compile("TestFeatureRegistry.java", "TestRollingUpgradeAwareMessage.java"); + + assertThat(compilation).succeeded(); + + assertThat(compilation) + .generatedSourceFile("org.apache.ignite.internal.TestRollingUpgradeAwareMessageSerializer") + .hasSourceEquivalentTo(javaFile("TestRollingUpgradeAwareMessageSerializer.java")); + } + + /** */ + @Test + public void testUnknownFeatureConstantRejected() { + Compilation compilation = compile("TestUnknownFeatureMessage.java"); + + assertThat(compilation).failed(); + assertThat(compilation).hadErrorContaining("Failed to resolve feature in the registry by its name [reg="); + assertThat(compilation).hadErrorContaining(", feature=NO_SUCH_FEATURE]"); + } + + /** */ + @Test + public void testSameFeatureInBothGatesRejected() { + Compilation compilation = compile("TestFeatureConflictMessage.java"); + + assertThat(compilation).failed(); + assertThat(compilation).hadErrorContaining("must not reference the same feature"); + } + + /** */ + @Test + public void testFeatureConstantOfWrongTypeRejected() { + Compilation compilation = compile("TestInvalidFeatureRegistry.java", "TestInvalidFeatureMessage.java"); + + assertThat(compilation).failed(); + assertThat(compilation).hadErrorContaining("must be of type IgniteFeature [reg="); + } + /** */ @Test public void testCollectionsMessage() { diff --git a/modules/core/src/test/java/org/apache/ignite/internal/direct/DirectMarshallingMessagesTest.java b/modules/core/src/test/java/org/apache/ignite/internal/direct/DirectMarshallingMessagesTest.java index e9874e03055fc..5eab512eb6e2e 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/direct/DirectMarshallingMessagesTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/direct/DirectMarshallingMessagesTest.java @@ -31,6 +31,7 @@ import org.apache.ignite.transactions.TransactionIsolation; import org.junit.Test; +import static org.apache.ignite.internal.MessageSerializationContext.LATEST_SCHEMA; import static org.apache.ignite.transactions.TransactionIsolation.READ_COMMITTED; import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ; import static org.apache.ignite.transactions.TransactionIsolation.SERIALIZABLE; @@ -139,7 +140,7 @@ private T doMarshalUnmarshalChunked(T srcMsg) { writer.setBuffer(chunk); - fullyWritten = writer.writeMessage(srcMsg, false); + fullyWritten = writer.writeMessage(srcMsg, false, LATEST_SCHEMA); chunk.flip(); @@ -168,7 +169,7 @@ private T doMarshalUnmarshalChunked(T srcMsg) { reader.setBuffer(chunk); - resMsg = reader.readMessage(false); + resMsg = reader.readMessage(false, LATEST_SCHEMA); pos += chunk.position(); } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/managers/AbstractMessageSerializationTest.java b/modules/core/src/test/java/org/apache/ignite/internal/managers/AbstractMessageSerializationTest.java index bfa3c8e314204..88c11a10eb3ca 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/managers/AbstractMessageSerializationTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/managers/AbstractMessageSerializationTest.java @@ -25,6 +25,7 @@ import java.util.Map; import java.util.Set; import java.util.UUID; +import org.apache.ignite.internal.MessageSerializationContext; import org.apache.ignite.internal.managers.communication.IgniteMessageFactoryImpl; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.CacheObject; @@ -47,6 +48,7 @@ import org.junit.Test; import static java.lang.Integer.MAX_VALUE; +import static org.apache.ignite.internal.MessageSerializationContext.LATEST_SCHEMA; import static org.apache.ignite.plugin.extensions.communication.CollectionImplementationType.HASH_SET; import static org.junit.Assert.assertEquals; @@ -106,13 +108,13 @@ private void checkSerializationAndDeserializationConsistency( initializeMessage(msg); - while (!MessageSerialization.writeTo(msgFactory, msg, writer)) { + while (!MessageSerialization.writeTo(msgFactory, msg, writer, LATEST_SCHEMA)) { // No-op. } msg = msgFactory.create(msgType); - while (!MessageSerialization.readFrom(msgFactory, msg, reader)) { + while (!MessageSerialization.readFrom(msgFactory, msg, reader, LATEST_SCHEMA)) { // No-op. } @@ -295,22 +297,22 @@ private boolean writeField(Class type) { } /** {@inheritDoc} */ - @Override public boolean writeMessage(Message val, boolean compress) { + @Override public boolean writeMessage(Message val, boolean compress, MessageSerializationContext ctx) { return writeField(Message.class); } /** {@inheritDoc} */ - @Override public boolean writeObjectArray(T[] arr, MessageArrayType type) { + @Override public boolean writeObjectArray(T[] arr, MessageArrayType type, MessageSerializationContext ctx) { return writeField(Object[].class); } /** {@inheritDoc} */ - @Override public boolean writeCollection(Collection col, MessageCollectionType type) { + @Override public boolean writeCollection(Collection col, MessageCollectionType type, MessageSerializationContext ctx) { return writeField(type.collectionImplementationType() == HASH_SET ? Set.class : Collection.class); } /** {@inheritDoc} */ - @Override public boolean writeMap(Map map, MessageMapType type, boolean compress) { + @Override public boolean writeMap(Map map, MessageMapType type, boolean compress, MessageSerializationContext ctx) { return writeField(type.linked() ? LinkedHashMap.class : HashMap.class); } @@ -537,7 +539,7 @@ private void readField(Class type) { } /** {@inheritDoc} */ - @Override public T readMessage(boolean compress) { + @Override public T readMessage(boolean compress, MessageSerializationContext ctx) { readField(Message.class); return null; @@ -565,21 +567,21 @@ private void readField(Class type) { } /** {@inheritDoc} */ - @Override public T[] readObjectArray(MessageArrayType type) { + @Override public T[] readObjectArray(MessageArrayType type, MessageSerializationContext ctx) { readField(Object[].class); return null; } /** {@inheritDoc} */ - @Override public > C readCollection(MessageCollectionType type) { + @Override public > C readCollection(MessageCollectionType type, MessageSerializationContext ctx) { readField(type.collectionImplementationType() == HASH_SET ? Set.class : Collection.class); return null; } /** {@inheritDoc} */ - @Override public > M readMap(MessageMapType type, boolean compress) { + @Override public > M readMap(MessageMapType type, boolean compress, MessageSerializationContext ctx) { readField(type.linked() ? LinkedHashMap.class : HashMap.class); return null; diff --git a/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/CompressedMessageTest.java b/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/CompressedMessageTest.java index 046dbbb6f55b0..2f9c77e429919 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/CompressedMessageTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/CompressedMessageTest.java @@ -42,6 +42,7 @@ import org.apache.ignite.testframework.GridTestUtils; import org.junit.Test; +import static org.apache.ignite.internal.MessageSerializationContext.LATEST_SCHEMA; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -70,7 +71,7 @@ public void testWriteReadHugeMessage() { ByteBuffer msgBuf = ByteBuffer.allocate(40_960); while (!finished) { - finished = writer.writeMessage(fullMsg, true); + finished = writer.writeMessage(fullMsg, true, LATEST_SCHEMA); if (checkChunkCnt) { DirectMessageState state = U.field(writer, "state"); @@ -104,7 +105,7 @@ public void testWriteReadHugeMessage() { reader.setBuffer(msgBuf); - Message readMsg = reader.readMessage(true); + Message readMsg = reader.readMessage(true, LATEST_SCHEMA); assertTrue(readMsg instanceof GridDhtPartitionsFullMessage); @@ -133,7 +134,7 @@ public void testReadFailsOnNullChunk() { reader.setBuffer(buf); GridTestUtils.assertThrows(null, - () -> MessageSerialization.readFrom(MSG_FACTORY, new CompressedMessage(), reader), + () -> MessageSerialization.readFrom(MSG_FACTORY, new CompressedMessage(), reader, LATEST_SCHEMA), IgniteException.class, "unexpected null chunk"); } @@ -156,7 +157,7 @@ public void testReadFailsOnNegativeDataSize() { reader.setBuffer(buf); GridTestUtils.assertThrows(null, - () -> MessageSerialization.readFrom(MSG_FACTORY, new CompressedMessage(), reader), + () -> MessageSerialization.readFrom(MSG_FACTORY, new CompressedMessage(), reader, LATEST_SCHEMA), IgniteException.class, "Invalid compressed message data size"); } @@ -217,7 +218,7 @@ public void testReadFailsOnTruncatedPayload() { writer.setBuffer(tmpBuf); - assertTrue(writer.writeMessage(fullMessage(), false)); + assertTrue(writer.writeMessage(fullMessage(), false, LATEST_SCHEMA)); tmpBuf.flip(); @@ -231,7 +232,7 @@ public void testReadFailsOnTruncatedPayload() { wireWriter.setBuffer(wire); - assertTrue(wireWriter.writeMessage(compressedMsg, false)); + assertTrue(wireWriter.writeMessage(compressedMsg, false, LATEST_SCHEMA)); wire.flip(); @@ -239,7 +240,7 @@ public void testReadFailsOnTruncatedPayload() { reader.setBuffer(wire); - GridTestUtils.assertThrows(null, () -> reader.readMessage(true), IgniteException.class, "ended unexpectedly"); + GridTestUtils.assertThrows(null, () -> reader.readMessage(true, LATEST_SCHEMA), IgniteException.class, "ended unexpectedly"); } /** */ diff --git a/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/GridIoManagerOrderedUnmarshalFailureTest.java b/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/GridIoManagerOrderedUnmarshalFailureTest.java index 4b51337eac099..2a5ce91b96302 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/GridIoManagerOrderedUnmarshalFailureTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/GridIoManagerOrderedUnmarshalFailureTest.java @@ -28,6 +28,7 @@ import org.apache.ignite.internal.CoreMessagesProvider; import org.apache.ignite.internal.GridKernalContext; import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.MessageSerializationContext; import org.apache.ignite.internal.processors.cache.CacheObjectContext; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.marshaller.Marshaller; @@ -186,7 +187,7 @@ private static class FailingUnmarshalMessage implements Message { /** Writes the two fields behind the header. */ private static class Serializer implements MessageSerializer { /** {@inheritDoc} */ - @Override public boolean writeTo(FailingUnmarshalMessage msg, MessageWriter writer) { + @Override public boolean writeTo(FailingUnmarshalMessage msg, MessageWriter writer, MessageSerializationContext ctx) { if (!writer.isHeaderWritten()) { if (!writer.writeHeader(msg.directType())) return false; @@ -212,7 +213,7 @@ private static class Serializer implements MessageSerializer @@ -121,7 +123,7 @@ public void testCacheSize() throws Exception { // 2kb should be enough for an empty message even if it is a relatively large metrics message. msgWritter.setBuffer(ByteBuffer.allocate(2048)); - assertTrue(MessageSerialization.writeTo(msgFactory, msg, msgWritter)); + assertTrue(MessageSerialization.writeTo(msgFactory, msg, msgWritter, LATEST_SCHEMA)); assertTrue(msgWritter.getBuffer().hasRemaining()); @@ -133,7 +135,7 @@ public void testCacheSize() throws Exception { TcpDiscoveryMetricsUpdateMessage msg2 = new TcpDiscoveryMetricsUpdateMessage(); - assertTrue(MessageSerialization.readFrom(msgFactory, msg2, msgReader)); + assertTrue(MessageSerialization.readFrom(msgFactory, msg2, msgReader, LATEST_SCHEMA)); Map cacheMetrics2 = msg2.serversFullMetricsMessages().values().iterator().next() .cachesMetricsMessages(); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/IgniteCacheContinuousQueryImmutableEntryTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/IgniteCacheContinuousQueryImmutableEntryTest.java index 45a5fb3381fd5..572c733e82682 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/IgniteCacheContinuousQueryImmutableEntryTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/IgniteCacheContinuousQueryImmutableEntryTest.java @@ -45,6 +45,7 @@ import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC; import static org.apache.ignite.cache.CacheMode.PARTITIONED; import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC; +import static org.apache.ignite.internal.MessageSerializationContext.LATEST_SCHEMA; /** * @@ -204,7 +205,7 @@ private CacheContinuousQueryEntry roundTrip(CacheContinuousQueryEntry e) throws // Skip write class header. writer.onHeaderWritten(); - MessageSerialization.writeTo(msgFactory, e, writer); + MessageSerialization.writeTo(msgFactory, e, writer, LATEST_SCHEMA); CacheContinuousQueryEntry res = new CacheContinuousQueryEntry(); @@ -212,7 +213,7 @@ private CacheContinuousQueryEntry roundTrip(CacheContinuousQueryEntry e) throws reader.setBuffer(ByteBuffer.wrap(buf.array())); - MessageSerialization.readFrom(msgFactory, res, reader); + MessageSerialization.readFrom(msgFactory, res, reader, LATEST_SCHEMA); return res; } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/query/schema/message/QueryEntityMessageSerializationTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/query/schema/message/QueryEntityMessageSerializationTest.java index f7fea391425dd..0397c89a65a26 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/query/schema/message/QueryEntityMessageSerializationTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/query/schema/message/QueryEntityMessageSerializationTest.java @@ -48,6 +48,7 @@ import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; import org.junit.Test; +import static org.apache.ignite.internal.MessageSerializationContext.LATEST_SCHEMA; import static org.apache.ignite.internal.util.CommonUtils.makeMessageType; /** Test for serialization round-trip of {@link QueryEntityMessage} and {@link QueryEntityExMessage}. */ @@ -173,7 +174,7 @@ private T writeAndReadBack(T msg, long expReadsWritesCnt) th DirectMessageWriter writer = new DirectMessageWriter(msgFactory); writer.setBuffer(buf); - assertTrue(MessageSerialization.writeTo(msgFactory, msg, writer)); + assertTrue(MessageSerialization.writeTo(msgFactory, msg, writer, LATEST_SCHEMA)); assertEquals("Writes" + ERROR_SUFFIX, expReadsWritesCnt, writer.state()); @@ -184,7 +185,7 @@ private T writeAndReadBack(T msg, long expReadsWritesCnt) th T res = (T)msgFactory.create(makeMessageType(buf.get(), buf.get())); - assertTrue(MessageSerialization.readFrom(msgFactory, res, reader)); + assertTrue(MessageSerialization.readFrom(msgFactory, res, reader, LATEST_SCHEMA)); assertEquals("Reads" + ERROR_SUFFIX, expReadsWritesCnt, reader.state()); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/feature/TestPluginReleaseFeatures_2_0_0.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/feature/TestPluginReleaseFeatures_2_0_0.java index d661f5cff66bc..066d0403917df 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/feature/TestPluginReleaseFeatures_2_0_0.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/feature/TestPluginReleaseFeatures_2_0_0.java @@ -19,6 +19,9 @@ /** */ public class TestPluginReleaseFeatures_2_0_0 { + /** */ + public static final IgniteFeature VER_1_0_0_ID_0_FEATURE = TestPluginReleaseFeatures_1_0_0.VER_1_0_0_ID_0_FEATURE; + /** */ public static final IgniteFeature VER_2_0_0_ID_1_FEATURE = new TestPluginFeature(1); } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/feature/TestPluginReleaseFeatures_2_1_0.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/feature/TestPluginReleaseFeatures_2_1_0.java index edb4b3b3646ac..385f7ded6a900 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/feature/TestPluginReleaseFeatures_2_1_0.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/feature/TestPluginReleaseFeatures_2_1_0.java @@ -20,7 +20,10 @@ /** */ public class TestPluginReleaseFeatures_2_1_0 { /** */ - public static final IgniteFeature VER_2_1_0_ID_1_FEATURE = new TestPluginFeature(1); + public static final IgniteFeature VER_1_0_0_ID_0_FEATURE = TestPluginReleaseFeatures_2_0_0.VER_1_0_0_ID_0_FEATURE; + + /** */ + public static final IgniteFeature VER_2_0_0_ID_1_FEATURE = TestPluginReleaseFeatures_2_0_0.VER_2_0_0_ID_1_FEATURE; /** */ public static final IgniteFeature VER_2_1_0_ID_2_FEATURE = new TestPluginFeature(2); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/message/RollingUpgradeMessageSerializationTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/message/RollingUpgradeMessageSerializationTest.java new file mode 100644 index 0000000000000..8ba97aa82c1c7 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/message/RollingUpgradeMessageSerializationTest.java @@ -0,0 +1,510 @@ +/* + * 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.rollingupgrade.message; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; +import org.apache.ignite.Ignite; +import org.apache.ignite.Ignition; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.managers.communication.GridIoPolicy; +import org.apache.ignite.internal.managers.discovery.DiscoveryCustomMessage; +import org.apache.ignite.internal.processors.rollingupgrade.AbstractRollingUpgradeTest; +import org.apache.ignite.plugin.extensions.communication.Message; +import org.apache.ignite.spi.MessagesPluginProvider; +import org.junit.Test; + +import static org.apache.ignite.internal.processors.rollingupgrade.message.TestMessage.A; +import static org.apache.ignite.internal.processors.rollingupgrade.message.TestMessage.B; +import static org.apache.ignite.internal.processors.rollingupgrade.message.TestMessage.C; +import static org.apache.ignite.internal.processors.rollingupgrade.message.TestMessage.D; +import static org.apache.ignite.internal.processors.rollingupgrade.message.TestMessage.E; +import static org.apache.ignite.internal.processors.rollingupgrade.message.TestMessage.F; + +/** */ +public class RollingUpgradeMessageSerializationTest extends AbstractRollingUpgradeTest { + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName, String ver) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName, ver); + + cfg.setPluginProviders(org.apache.ignite.internal.util.typedef.F.concat( + cfg.getPluginProviders(), + new MessagesPluginProvider( + TestCoreMessage.class, + TestPluginMessage.class, + TestDefaultRegistryMessage.class)) + ); + + return cfg; + } + + /** */ + @Test + public void testSameOldVersion() throws Exception { + checkMutualCoreMessageSend("2.19.0", "2.19.0", A, B, C, null, null, null); + } + + /** */ + @Test + public void testMixedPair() throws Exception { + checkMutualCoreMessageSend("2.19.0", "2.20.0", A, B, C, null, null, null); + } + + /** */ + @Test + public void testSameNewVersion() throws Exception { + checkMutualCoreMessageSend("2.20.0", "2.20.0", A, B, C, D, E, null); + } + + /** */ + @Test + public void testWindowOpenSameVersion() throws Exception { + checkMutualCoreMessageSend("2.19.2", "2.19.2", A, B, C, D, null, null); + } + + /** */ + @Test + public void testWindowOpenMixedPair() throws Exception { + checkMutualCoreMessageSend("2.19.2", "2.20.0", A, B, C, D, null, null); + } + + /** */ + @Test + public void testWindowClosed() throws Exception { + checkMutualCoreMessageSend("2.20.0", "2.20.1", A, null, C, null, E, null); + } + + /** */ + @Test + public void testDiscoveryNewerClient() throws Exception { + IgniteEx srv = startGrid(0, "2.19.0"); + + ru(srv).enableVersionUpgrade(); + + startClientGrid(1, "2.20.0"); + + checkCoreMessageBroadcast(srv, A, B, C, null, null, null); + } + + /** */ + @Test + public void testDiscoveryClientOriginated() throws Exception { + IgniteEx srv = startGrid(0, "2.19.0"); + + ru(srv).enableVersionUpgrade(); + + IgniteEx cli1 = startClientGrid(1, "2.20.0"); + + startClientGrid(2, "2.19.0"); + + checkCoreMessageBroadcast(cli1, A, B, C, null, null, null); + } + + /** */ + @Test + public void testDiscoveryClientsOnDifferentVersions() throws Exception { + startGrid(0, "2.19.0"); + startGrid(1, "2.19.0"); + + ru(1).enableVersionUpgrade(); + + upgradeNodeVersion(0, "2.20.0"); + upgradeNodeVersion(1, "2.20.0"); + + IgniteEx newVerCli = startClientGrid(2, "2.20.0"); + IgniteEx oldVerCli = startClientGrid(3, "2.19.0"); + + Map receivedMsgs = sendOverDiscovery(grid(1), TestCoreMessage.build()); + + assertFields(A, B, C, D, E, null, receivedMsgs.get(newVerCli.name())); + assertFields(A, B, C, null, null, null, receivedMsgs.get(oldVerCli.name())); + } + + /** */ + @Test + public void testCommunicationWithClient() throws Exception { + IgniteEx srv = startGrid(0, "2.19.0"); + + ru(srv).enableVersionUpgrade(); + + IgniteEx client = startClientGrid(1, "2.20.0"); + + checkMutualCoreMessageSend(srv, client, A, B, C, null, null, null); + } + + /** */ + @Test + public void testDefaultRegistryMixedPair() throws Exception { + startServerNodes("2.19.0", "2.20.0"); + + checkMutualMessageSend(grid(0), grid(1), TestDefaultRegistryMessage::build, A, null, C, D, E, F); + } + + /** */ + @Test + public void testDiscoveryUniformRing() throws Exception { + startGrid(0, "2.20.0"); + startGrid(1, "2.20.0"); + startGrid(2, "2.20.0"); + + checkCoreMessageBroadcast(grid(1), A, B, C, D, E, null); + } + + /** */ + @Test + public void testDiscoveryMixedRing() throws Exception { + startGrid(0, "2.19.0"); + + ru(grid(0)).enableVersionUpgrade(); + + startGrid(1, "2.20.0"); + startGrid(2, "2.20.0"); + + checkCoreMessageBroadcast(grid(1), A, B, C, null, null, null); + } + + /** */ + @Test + public void testCommunicationUpgradeOpensWindow() throws Exception { + startGrid(0, "2.19.0"); + startGrid(1, "2.19.0"); + + checkMutualCoreMessageSend(grid(0), grid(1), A, B, C, null, null, null); + + ru(1).enableVersionUpgrade(); + + upgradeNodeVersion(0, "2.19.2"); + upgradeNodeVersion(1, "2.19.2"); + + checkMutualCoreMessageSend(grid(0), grid(1), A, B, C, D, null, null); + } + + /** */ + @Test + public void testCommunicationUpgradeAgreesNewFeature() throws Exception { + startGrid(0, "2.19.2"); + startGrid(1, "2.19.2"); + + checkMutualCoreMessageSend(grid(0), grid(1), A, B, C, D, null, null); + + ru(1).enableVersionUpgrade(); + + upgradeNodeVersion(0, "2.19.2", "2.20.0"); + + checkMutualCoreMessageSend(grid(0), grid(1), A, B, C, D, null, null); + + upgradeNodeVersion(1, "2.19.2", "2.20.0"); + + checkMutualCoreMessageSend(grid(0), grid(1), A, B, C, D, E, null); + } + + /** */ + @Test + public void testPluginDiffersCoreMatches() throws Exception { + startServerNodes("2.20.0 | 1.0.0", "2.20.0 | 2.0.0"); + + checkMutualCoreMessageSend(grid(0), grid(1), A, B, C, D, E, null); + + checkMutualMessageSend(grid(0), grid(1), TestPluginMessage::build, A, B, C, D, null, null); + } + + /** */ + @Test + public void testPluginSameVersion() throws Exception { + startServerNodes("2.20.0 | 2.0.0", "2.20.0 | 2.0.0"); + + checkMutualCoreMessageSend(grid(0), grid(1), A, B, C, D, E, null); + + checkMutualMessageSend(grid(0), grid(1), TestPluginMessage::build, A, B, C, D, E, null); + } + + /** */ + @Test + public void testPluginMissingOnClient() throws Exception { + IgniteEx srv = startGrid(0, "2.20.0 | 2.0.0"); + + ru(srv).enableVersionUpgrade(); + + IgniteEx cli = startClientGrid(1, "2.20.0"); + + checkMutualMessageSend(srv, cli, TestPluginMessage::build, A, B, C, null, null, null); + + checkMutualCoreMessageSend(srv, cli, A, B, C, D, E, null); + } + + /** */ + @Test + public void testWholeUpgradeProcess() throws Exception { + startGrid(0, "2.19.0"); + startGrid(1, "2.19.0"); + startClientGrid(2, "2.19.0"); + + checkMessagesTransmissionBetweenAllNodes(A, B, C, null, null, null); + + ru(1).enableVersionUpgrade(); + + checkMessagesTransmissionBetweenAllNodes(A, B, C, null, null, null); + + upgradeNodeVersion(0, "2.19.0", "2.19.2"); + + checkMessagesTransmissionBetweenAllNodes(A, B, C, null, null, null); + + upgradeNodeVersion(1, "2.19.0", "2.19.2"); + + checkMutualCoreMessageSend(grid(0), grid(1), A, B, C, D, null, null); + checkMutualCoreMessageSend(grid(0), grid(2), A, B, C, null, null, null); + checkMutualCoreMessageSend(grid(1), grid(2), A, B, C, null, null, null); + + upgradeNodeVersion(2, "2.19.0", "2.19.2"); + + checkMessagesTransmissionBetweenAllNodes(A, B, C, D, null, null); + + finalizeClusterVersion(0, "2.19.2"); + + checkMessagesTransmissionBetweenAllNodes(A, B, C, D, null, null); + + ru(1).enableVersionUpgrade(); + + upgradeNodeVersion(0, "2.19.2", "2.20.0"); + + checkMessagesTransmissionBetweenAllNodes(A, B, C, D, null, null); + + upgradeNodeVersion(1, "2.19.2", "2.20.0"); + + checkMutualCoreMessageSend(grid(0), grid(1), A, B, C, D, E, null); + checkMutualCoreMessageSend(grid(0), grid(2), A, B, C, D, null, null); + checkMutualCoreMessageSend(grid(1), grid(2), A, B, C, D, null, null); + + upgradeNodeVersion(2, "2.19.2", "2.20.0"); + + checkMessagesTransmissionBetweenAllNodes(A, B, C, D, E, null); + + finalizeClusterVersion(0, "2.20.0"); + + checkMessagesTransmissionBetweenAllNodes(A, B, C, D, E, null); + + ru(1).enableVersionUpgrade(); + + upgradeNodeVersion(0, "2.20.0", "2.20.1"); + + checkMutualCoreMessageSend(grid(0), grid(1), A, null, C, null, E, null); + checkMutualCoreMessageSend(grid(0), grid(2), A, null, C, null, E, null); + checkMutualCoreMessageSend(grid(1), grid(2), A, B, C, D, E, null); + + upgradeNodeVersion(1, "2.20.0", "2.20.1"); + + checkMutualCoreMessageSend(grid(0), grid(1), A, B, C, D, E, F); + checkMutualCoreMessageSend(grid(0), grid(2), A, null, C, null, E, null); + checkMutualCoreMessageSend(grid(1), grid(2), A, null, C, null, E, null); + + upgradeNodeVersion(2, "2.20.0", "2.20.1"); + + checkMessagesTransmissionBetweenAllNodes(A, B, C, D, E, F); + + finalizeClusterVersion(0, "2.20.1"); + + checkMessagesTransmissionBetweenAllNodes(A, B, C, D, E, F); + } + + /** */ + private void checkMessagesTransmissionBetweenAllNodes( + String expA, + String expB, + String expC, + String expD, + String expE, + String expF + ) throws Exception { + List clusterNodes = Ignition.allGrids(); + + for (int i = 0; i < clusterNodes.size(); i++) { + for (int j = i + 1; j < clusterNodes.size(); j++) { + checkMutualCoreMessageSend( + (IgniteEx)clusterNodes.get(i), (IgniteEx)clusterNodes.get(j), expA, expB, expC, expD, expE, expF); + } + } + } + + /** */ + private void checkMutualCoreMessageSend( + String firstVer, + String secondVer, + String expA, + String expB, + String expC, + String expD, + String expE, + String expF + ) throws Exception { + startServerNodes(firstVer, secondVer); + + checkMutualCoreMessageSend(grid(0), grid(1), expA, expB, expC, expD, expE, expF); + } + + /** */ + private void checkMutualCoreMessageSend( + IgniteEx first, + IgniteEx second, + String expA, + String expB, + String expC, + String expD, + String expE, + String expF + ) throws Exception { + checkMutualMessageSend(first, second, TestCoreMessage::build, expA, expB, expC, expD, expE, expF); + } + + /** */ + private void checkCoreMessageBroadcast( + IgniteEx from, + String expA, + String expB, + String expC, + String expD, + String expE, + String expF + ) throws Exception { + Collection receivedMsgs = sendOverDiscovery(from, TestCoreMessage.build()).values(); + + for (TestCoreMessage msg : receivedMsgs) + assertFields(expA, expB, expC, expD, expE, expF, msg); + } + + /** */ + private void checkMutualMessageSend( + IgniteEx first, + IgniteEx second, + Supplier msgFactory, + String expA, + String expB, + String expC, + String expD, + String expE, + String expF + ) throws Exception { + checkReceivedMessageFields(first, second, msgFactory, expA, expB, expC, expD, expE, expF); + checkReceivedMessageFields(second, first, msgFactory, expA, expB, expC, expD, expE, expF); + } + + /** */ + private void checkReceivedMessageFields( + IgniteEx from, + IgniteEx to, + Supplier msgFactory, + String expA, + String expB, + String expC, + String expD, + String expE, + String expF + ) throws Exception { + assertFields(expA, expB, expC, expD, expE, expF, send(from, to, msgFactory.get())); + + assertFields(expA, expB, expC, expD, expE, expF, sendOverDiscovery(from, msgFactory.get()).get(to.name())); + } + + /** */ + private T send(IgniteEx from, IgniteEx to, T msg) throws Exception { + AtomicReference got = new AtomicReference<>(); + CountDownLatch latch = new CountDownLatch(1); + + String topic = msg.getClass().getName(); + + to.context().io().addMessageListener(topic, (nodeId, rcvd, plc) -> { + got.set((T)rcvd); + + latch.countDown(); + }); + + ClusterNode rcvNode = from.context().discovery().node(to.localNode().id()); + + from.context().io().sendToCustomTopic(rcvNode, topic, msg, GridIoPolicy.PUBLIC_POOL); + + assertTrue(latch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); + + return got.get(); + } + + /** */ + private Map sendOverDiscovery( + IgniteEx from, + T msg + ) throws Exception { + List clusterNodes = Ignition.allGrids(); + + Map receivedMsgs = new ConcurrentHashMap<>(); + + CountDownLatch latch = new CountDownLatch(clusterNodes.size()); + + for (Ignite rcv : clusterNodes) { + String name = rcv.name(); + + ((IgniteEx)rcv).context().discovery().setCustomEventListener((Class)msg.getClass(), + (v, n, m) -> { + receivedMsgs.put(name, m); + + latch.countDown(); + }); + } + + from.context().discovery().sendCustomEvent(msg); + + assertTrue(latch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); + + receivedMsgs.remove(from.name()); + + return receivedMsgs; + } + + /** */ + private void startServerNodes(String firstVer, String secondVer) throws Exception { + IgniteEx first = startGrid(0, firstVer); + + if (!firstVer.equals(secondVer)) + ru(first).enableVersionUpgrade(); + + startGrid(1, secondVer); + } + + /** */ + private static void assertFields( + String expA, + String expB, + String expC, + String expD, + String expE, + String expF, + TestMessage msg + ) { + assertEquals(expA, msg.fldA()); + assertEquals(expB, msg.fldB()); + assertEquals(expC, msg.fldC()); + assertEquals(expD, msg.fldD()); + assertEquals(expE, msg.fldE()); + assertEquals(expF, msg.fldF()); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/message/TestCoreMessage.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/message/TestCoreMessage.java new file mode 100644 index 0000000000000..35234fac1a5ac --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/message/TestCoreMessage.java @@ -0,0 +1,107 @@ +/* + * 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.rollingupgrade.message; + +import org.apache.ignite.internal.FeatureGated; +import org.apache.ignite.internal.Order; +import org.apache.ignite.internal.managers.discovery.DiscoveryCustomMessage; +import org.apache.ignite.internal.processors.rollingupgrade.feature.TestIgniteReleaseFeatures_2_20_1; +import org.apache.ignite.lang.IgniteUuid; +import org.jetbrains.annotations.Nullable; + +/** */ +@FeatureGated(registry = TestIgniteReleaseFeatures_2_20_1.class) +public class TestCoreMessage extends DiscoveryCustomMessage implements TestMessage { + /** */ + @Order(0) + String fldA; + + /** */ + @Order(value = 1, deprecatedBy = "VER_2_20_0_ID_3_FEATURE") + String fldB; + + /** */ + @Order(2) + String fldC; + + /** */ + @Order(value = 3, introducedBy = "VER_2_19_2_ID_1_FEATURE", deprecatedBy = "VER_2_20_0_ID_3_FEATURE") + String fldD; + + /** */ + @Order(value = 4, introducedBy = "VER_2_20_0_ID_3_FEATURE") + String fldE; + + /** */ + @Order(value = 5, introducedBy = "VER_2_20_1_ID_6_FEATURE") + String fldF; + + /** */ + public TestCoreMessage() { + super(IgniteUuid.randomUuid()); + } + + /** {@inheritDoc} */ + @Nullable @Override public DiscoveryCustomMessage ackMessage() { + return null; + } + + /** */ + public static TestCoreMessage build() { + TestCoreMessage msg = new TestCoreMessage(); + + msg.fldA = A; + msg.fldB = B; + msg.fldC = C; + msg.fldD = D; + msg.fldE = E; + msg.fldF = F; + + return msg; + } + + /** {@inheritDoc} */ + @Override public String fldA() { + return fldA; + } + + /** {@inheritDoc} */ + @Override public String fldB() { + return fldB; + } + + /** {@inheritDoc} */ + @Override public String fldC() { + return fldC; + } + + /** {@inheritDoc} */ + @Override public String fldD() { + return fldD; + } + + /** {@inheritDoc} */ + @Override public String fldE() { + return fldE; + } + + /** {@inheritDoc} */ + @Override public String fldF() { + return fldF; + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/message/TestDefaultRegistryMessage.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/message/TestDefaultRegistryMessage.java new file mode 100644 index 0000000000000..02e6173990b11 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/message/TestDefaultRegistryMessage.java @@ -0,0 +1,104 @@ +/* + * 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.rollingupgrade.message; + +import org.apache.ignite.internal.Order; +import org.apache.ignite.internal.managers.discovery.DiscoveryCustomMessage; +import org.apache.ignite.lang.IgniteUuid; +import org.jetbrains.annotations.Nullable; + +/** */ +public class TestDefaultRegistryMessage extends DiscoveryCustomMessage implements TestMessage { + /** */ + @Order(0) + String fldA; + + /** */ + @Order(value = 1, deprecatedBy = "ROLLING_UPGRADE_FEATURE") + String fldB; + + /** */ + @Order(2) + String fldC; + + /** */ + @Order(3) + String fldD; + + /** */ + @Order(4) + String fldE; + + /** */ + @Order(value = 5, introducedBy = "ROLLING_UPGRADE_FEATURE") + String fldF; + + /** */ + public TestDefaultRegistryMessage() { + super(IgniteUuid.randomUuid()); + } + + /** {@inheritDoc} */ + @Nullable @Override public DiscoveryCustomMessage ackMessage() { + return null; + } + + /** */ + public static TestDefaultRegistryMessage build() { + TestDefaultRegistryMessage msg = new TestDefaultRegistryMessage(); + + msg.fldA = A; + msg.fldB = B; + msg.fldC = C; + msg.fldD = D; + msg.fldE = E; + msg.fldF = F; + + return msg; + } + + /** {@inheritDoc} */ + @Override public String fldA() { + return fldA; + } + + /** {@inheritDoc} */ + @Override public String fldB() { + return fldB; + } + + /** {@inheritDoc} */ + @Override public String fldC() { + return fldC; + } + + /** {@inheritDoc} */ + @Override public String fldD() { + return fldD; + } + + /** {@inheritDoc} */ + @Override public String fldE() { + return fldE; + } + + /** {@inheritDoc} */ + @Override public String fldF() { + return fldF; + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/message/TestMessage.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/message/TestMessage.java new file mode 100644 index 0000000000000..15c639bf6fdaa --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/message/TestMessage.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.processors.rollingupgrade.message; + +/** */ +public interface TestMessage { + /** */ + public static final String A = "A"; + + /** */ + public static final String B = "B"; + + /** */ + public static final String C = "C"; + + /** */ + public static final String D = "D"; + + /** */ + public static final String E = "E"; + + /** */ + public static final String F = "F"; + + /** */ + public String fldA(); + + /** */ + public String fldB(); + + /** */ + public String fldC(); + + /** */ + public String fldD(); + + /** */ + public String fldE(); + + /** */ + public String fldF(); +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/message/TestPluginMessage.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/message/TestPluginMessage.java new file mode 100644 index 0000000000000..f901f7667bf54 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/message/TestPluginMessage.java @@ -0,0 +1,107 @@ +/* + * 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.rollingupgrade.message; + +import org.apache.ignite.internal.FeatureGated; +import org.apache.ignite.internal.Order; +import org.apache.ignite.internal.managers.discovery.DiscoveryCustomMessage; +import org.apache.ignite.internal.processors.rollingupgrade.feature.TestPluginReleaseFeatures_2_1_0; +import org.apache.ignite.lang.IgniteUuid; +import org.jetbrains.annotations.Nullable; + +/** */ +@FeatureGated(registry = TestPluginReleaseFeatures_2_1_0.class) +public class TestPluginMessage extends DiscoveryCustomMessage implements TestMessage { + /** */ + @Order(0) + String fldA; + + /** */ + @Order(value = 1, deprecatedBy = "VER_2_0_0_ID_1_FEATURE") + String fldB; + + /** */ + @Order(2) + String fldC; + + /** */ + @Order(value = 3, introducedBy = "VER_1_0_0_ID_0_FEATURE", deprecatedBy = "VER_2_0_0_ID_1_FEATURE") + String fldD; + + /** */ + @Order(value = 4, introducedBy = "VER_2_0_0_ID_1_FEATURE") + String fldE; + + /** */ + @Order(value = 5, introducedBy = "VER_2_1_0_ID_2_FEATURE") + String fldF; + + /** */ + public TestPluginMessage() { + super(IgniteUuid.randomUuid()); + } + + /** {@inheritDoc} */ + @Nullable @Override public DiscoveryCustomMessage ackMessage() { + return null; + } + + /** */ + public static TestPluginMessage build() { + TestPluginMessage msg = new TestPluginMessage(); + + msg.fldA = A; + msg.fldB = B; + msg.fldC = C; + msg.fldD = D; + msg.fldE = E; + msg.fldF = F; + + return msg; + } + + /** {@inheritDoc} */ + @Override public String fldA() { + return fldA; + } + + /** {@inheritDoc} */ + @Override public String fldB() { + return fldB; + } + + /** {@inheritDoc} */ + @Override public String fldC() { + return fldC; + } + + /** {@inheritDoc} */ + @Override public String fldD() { + return fldD; + } + + /** {@inheritDoc} */ + @Override public String fldE() { + return fldE; + } + + /** {@inheritDoc} */ + @Override public String fldF() { + return fldF; + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/service/LazyServiceConfigurationMessageSerializationTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/LazyServiceConfigurationMessageSerializationTest.java index 1536b53e9926d..909be2c0ba87b 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/service/LazyServiceConfigurationMessageSerializationTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/LazyServiceConfigurationMessageSerializationTest.java @@ -37,6 +37,7 @@ import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; import org.junit.Test; +import static org.apache.ignite.internal.MessageSerializationContext.LATEST_SCHEMA; import static org.apache.ignite.internal.util.CommonUtils.makeMessageType; import static org.junit.Assert.assertArrayEquals; @@ -126,7 +127,7 @@ private T writeAndReadBack(T msg, long expReadsWritesCnt) th DirectMessageWriter writer = new DirectMessageWriter(msgFactory); writer.setBuffer(buf); - assertTrue(MessageSerialization.writeTo(msgFactory, msg, writer)); + assertTrue(MessageSerialization.writeTo(msgFactory, msg, writer, LATEST_SCHEMA)); assertEquals("Writes" + ERROR_SUFFIX, expReadsWritesCnt, writer.state()); buf.flip(); @@ -136,7 +137,7 @@ private T writeAndReadBack(T msg, long expReadsWritesCnt) th T res = (T)msgFactory.create(makeMessageType(buf.get(), buf.get())); - assertTrue(MessageSerialization.readFrom(msgFactory, res, reader)); + assertTrue(MessageSerialization.readFrom(msgFactory, res, reader, LATEST_SCHEMA)); assertEquals("Reads" + ERROR_SUFFIX, expReadsWritesCnt, reader.state()); DiscoveryMarshalling.unmarshal(res, kctx); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/util/distributed/DistributedProcessResultMarshallingTest.java b/modules/core/src/test/java/org/apache/ignite/internal/util/distributed/DistributedProcessResultMarshallingTest.java index 0286297db11e4..8a8f0521739c4 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/util/distributed/DistributedProcessResultMarshallingTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/util/distributed/DistributedProcessResultMarshallingTest.java @@ -29,6 +29,7 @@ import org.apache.ignite.internal.CoreMessagesProvider; import org.apache.ignite.internal.GridKernalContext; import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.MessageSerializationContext; import org.apache.ignite.internal.TestRecordingCommunicationSpi; import org.apache.ignite.internal.managers.communication.CommunicationMarshalling; import org.apache.ignite.internal.managers.communication.GridIoMessage; @@ -239,7 +240,7 @@ public PayloadMessage() { /** */ private static class PayloadSerializer implements MessageSerializer { /** {@inheritDoc} */ - @Override public boolean writeTo(PayloadMessage msg, MessageWriter writer) { + @Override public boolean writeTo(PayloadMessage msg, MessageWriter writer, MessageSerializationContext ctx) { if (!writer.isHeaderWritten()) { if (!writer.writeHeader(msg.directType())) return false; @@ -255,7 +256,7 @@ private static class PayloadSerializer implements MessageSerializer { /** {@inheritDoc} */ - @Override public boolean writeTo(MarshalOnceCheckMessage msg, MessageWriter writer) { + @Override public boolean writeTo(MarshalOnceCheckMessage msg, MessageWriter writer, MessageSerializationContext ctx) { if (!writer.isHeaderWritten()) { if (!writer.writeHeader(msg.directType())) return false; @@ -169,7 +170,7 @@ private static class Serializer implements MessageSerializer { /** {@inheritDoc} */ - @Override public boolean writeTo(RetryCheckMessage msg, MessageWriter writer) { + @Override public boolean writeTo(RetryCheckMessage msg, MessageWriter writer, MessageSerializationContext ctx) { if (!writer.isHeaderWritten()) { if (!writer.writeHeader(msg.directType())) return false; @@ -221,7 +222,7 @@ private static class RetrySerializer implements MessageSerializer T writeAndReadBack(T msg) throws IgniteCheckedExcept DirectMessageWriter writer = new DirectMessageWriter(msgFactory); writer.setBuffer(buf); - assertTrue(MessageSerialization.writeTo(msgFactory, msg, writer)); + assertTrue(MessageSerialization.writeTo(msgFactory, msg, writer, LATEST_SCHEMA)); buf.flip(); @@ -126,7 +127,7 @@ private T writeAndReadBack(T msg) throws IgniteCheckedExcept T res = (T)msgFactory.create(makeMessageType(buf.get(), buf.get())); - assertTrue(MessageSerialization.readFrom(msgFactory, res, reader)); + assertTrue(MessageSerialization.readFrom(msgFactory, res, reader, LATEST_SCHEMA)); return res; } diff --git a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TestDelayMessageSerializer.java b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TestDelayMessageSerializer.java index ce905b9806f70..1d61f44f57fa7 100644 --- a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TestDelayMessageSerializer.java +++ b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TestDelayMessageSerializer.java @@ -18,6 +18,7 @@ package org.apache.ignite.spi.communication.tcp; import org.apache.ignite.internal.IgniteInterruptedCheckedException; +import org.apache.ignite.internal.MessageSerializationContext; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.plugin.extensions.communication.MessageReader; import org.apache.ignite.plugin.extensions.communication.MessageSerializer; @@ -26,7 +27,7 @@ /** Serializer for {@link TestDelayMessage} that injects an optional write delay for testing. */ public class TestDelayMessageSerializer implements MessageSerializer { /** {@inheritDoc} */ - @Override public boolean writeTo(TestDelayMessage msg, MessageWriter writer) { + @Override public boolean writeTo(TestDelayMessage msg, MessageWriter writer, MessageSerializationContext ctx) { if (!writer.isHeaderWritten()) { if (!writer.writeHeader(msg.directType())) return false; @@ -47,7 +48,7 @@ public class TestDelayMessageSerializer implements MessageSerializer serde; /** {@inheritDoc} */ - @Override public boolean writeTo(ExploitMessage msg, MessageWriter writer) { + @Override public boolean writeTo(ExploitMessage msg, MessageWriter writer, MessageSerializationContext ctx) { initIfNecessary(); - return serde.writeTo(msg, writer); + return serde.writeTo(msg, writer, ctx); } /** {@inheritDoc} */ - @Override public boolean readFrom(ExploitMessage msg, MessageReader reader) { + @Override public boolean readFrom(ExploitMessage msg, MessageReader reader, MessageSerializationContext ctx) { initIfNecessary(); - return serde.readFrom(msg, reader); + return serde.readFrom(msg, reader, ctx); } /** {@inheritDoc} */ diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/GridTestNode.java b/modules/core/src/test/java/org/apache/ignite/testframework/GridTestNode.java index cd76954a1a274..e90cc86847564 100644 --- a/modules/core/src/test/java/org/apache/ignite/testframework/GridTestNode.java +++ b/modules/core/src/test/java/org/apache/ignite/testframework/GridTestNode.java @@ -17,15 +17,19 @@ package org.apache.ignite.testframework; +import java.io.Serializable; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; +import org.apache.ignite.cache.CacheMetrics; import org.apache.ignite.cluster.ClusterMetrics; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.internal.IgniteNodeAttributes; +import org.apache.ignite.internal.managers.discovery.IgniteClusterNode; +import org.apache.ignite.internal.processors.rollingupgrade.feature.IgniteNodeFeatureSet; import org.apache.ignite.internal.util.lang.GridMetadataAwareAdapter; import org.apache.ignite.lang.IgniteProductVersion; @@ -34,7 +38,7 @@ /** * Test node. */ -public class GridTestNode extends GridMetadataAwareAdapter implements ClusterNode { +public class GridTestNode extends GridMetadataAwareAdapter implements IgniteClusterNode { /** */ private static final IgniteProductVersion VERSION = fromString("99.99.99"); @@ -103,13 +107,6 @@ public GridTestNode(UUID id, ClusterMetrics metrics) { return id; } - /** - * @param consistentId Consistent ID. - */ - public void consistentId(Object consistentId) { - this.consistentId = consistentId; - } - /** {@inheritDoc} */ @Override public Object consistentId() { return consistentId; @@ -213,6 +210,16 @@ public void order(long order) { return VERSION; } + /** {@inheritDoc} */ + @Override public IgniteNodeFeatureSet features() { + return IgniteNodeFeatureSet.LOCAL_CORE_FEATURES; + } + + /** {@inheritDoc} */ + @Override public void setConsistentId(Serializable consistentId) { + this.consistentId = consistentId; + } + /** * Sets node metrics. * @@ -222,6 +229,16 @@ public void setMetrics(ClusterMetrics metrics) { this.metrics = metrics; } + /** {@inheritDoc} */ + @Override public Map cacheMetrics() { + return Collections.emptyMap(); + } + + /** {@inheritDoc} */ + @Override public void setCacheMetrics(Map cacheMetrics) { + // No-op. + } + /** {@inheritDoc} */ @Override public boolean isLocal() { return false; diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/common/GridCommonAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/common/GridCommonAbstractTest.java index 3b2a188e8b14a..2ad409701d0f1 100755 --- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/common/GridCommonAbstractTest.java +++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/common/GridCommonAbstractTest.java @@ -1398,7 +1398,7 @@ protected final List movingKeysAfterJoin(Ignite ign, String cacheName, if (nodeInitializer != null) nodeInitializer.apply(fakeNode); - fakeNode.consistentId(joiningNodeConsistentId == null ? getTestIgniteInstanceName(nodes.size()) : + fakeNode.setConsistentId(joiningNodeConsistentId == null ? getTestIgniteInstanceName(nodes.size()) : joiningNodeConsistentId); nodes.add(fakeNode); @@ -1449,7 +1449,7 @@ protected List evictingPartitionsAfterJoin(Ignite ign, IgniteCache { /** */ - @Override public final boolean writeTo(ChildMessage msg, MessageWriter writer) { + @Override public final boolean writeTo(ChildMessage msg, MessageWriter writer, MessageSerializationContext ctx) { if (!writer.isHeaderWritten()) { if (!writer.writeHeader(msg.directType())) return false; @@ -68,7 +69,7 @@ public final class ChildMessageSerializer implements MessageSerializer { /** */ - @Override public final boolean writeTo(CorrectEmptyMessage msg, MessageWriter writer) { + @Override public final boolean writeTo(CorrectEmptyMessage msg, MessageWriter writer, MessageSerializationContext ctx) { if (!writer.isHeaderWritten()) { if (!writer.writeHeader(msg.directType())) return false; @@ -44,7 +45,7 @@ public final class CorrectEmptyMessageSerializer implements MessageSerializer(TransactionIsolation.class, transactionIsolationMapper::encode, transactionIsolationMapper::decode), CollectionImplementationType.ARRAY_LIST), CollectionImplementationType.ARRAY_LIST); /** */ - @Override public final boolean writeTo(CustomMapperEnumFieldsMessage msg, MessageWriter writer) { + @Override public final boolean writeTo(CustomMapperEnumFieldsMessage msg, MessageWriter writer, MessageSerializationContext ctx) { if (!writer.isHeaderWritten()) { if (!writer.writeHeader(msg.directType())) return false; @@ -57,7 +58,7 @@ public final class CustomMapperEnumFieldsMessageSerializer implements MessageSer writer.incrementState(); case 1: - if (!writer.writeCollection(msg.isolations, isolationsCollDesc)) + if (!writer.writeCollection(msg.isolations, isolationsCollDesc, ctx)) return false; writer.incrementState(); @@ -67,7 +68,7 @@ public final class CustomMapperEnumFieldsMessageSerializer implements MessageSer } /** */ - @Override public final boolean readFrom(CustomMapperEnumFieldsMessage msg, MessageReader reader) { + @Override public final boolean readFrom(CustomMapperEnumFieldsMessage msg, MessageReader reader, MessageSerializationContext ctx) { switch (reader.state()) { case 0: msg.txMode = transactionIsolationMapper.decode(reader.readByte()); @@ -78,7 +79,7 @@ public final class CustomMapperEnumFieldsMessageSerializer implements MessageSer reader.incrementState(); case 1: - msg.isolations = reader.readCollection(isolationsCollDesc); + msg.isolations = reader.readCollection(isolationsCollDesc, ctx); if (!reader.isLastRead()) return false; diff --git a/modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessageSerializer.java b/modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessageSerializer.java index dba15be284691..9e707da48c770 100644 --- a/modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessageSerializer.java +++ b/modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessageSerializer.java @@ -18,6 +18,7 @@ package org.apache.ignite.internal; import org.apache.ignite.internal.DefaultMapperEnumFieldsMessage; +import org.apache.ignite.internal.MessageSerializationContext; import org.apache.ignite.internal.processors.cache.GridCacheOperation; import org.apache.ignite.internal.processors.cache.verify.PartitionHashRecord.PartitionState; import org.apache.ignite.plugin.extensions.communication.CollectionImplementationType; @@ -50,7 +51,7 @@ public final class DefaultMapperEnumFieldsMessageSerializer implements MessageSe private static final MessageMapType isolationStringMapCollDesc = new MessageMapType(new MessageCollectionType(new MessageEnumType<>(TransactionIsolation.class, DefaultEnumMapper.INSTANCE::encode, b -> DefaultEnumMapper.INSTANCE.decode(transactionIsolationVals, b)), CollectionImplementationType.ARRAY_LIST), new MessageItemType(MessageCollectionItemType.STRING), false); /** */ - @Override public final boolean writeTo(DefaultMapperEnumFieldsMessage msg, MessageWriter writer) { + @Override public final boolean writeTo(DefaultMapperEnumFieldsMessage msg, MessageWriter writer, MessageSerializationContext ctx) { if (!writer.isHeaderWritten()) { if (!writer.writeHeader(msg.directType())) return false; @@ -72,13 +73,13 @@ public final class DefaultMapperEnumFieldsMessageSerializer implements MessageSe writer.incrementState(); case 2: - if (!writer.writeMap(msg.isolationStringMap, isolationStringMapCollDesc)) + if (!writer.writeMap(msg.isolationStringMap, isolationStringMapCollDesc, ctx)) return false; writer.incrementState(); case 3: - if (!writer.writeCollection(msg.partStates, partStatesCollDesc)) + if (!writer.writeCollection(msg.partStates, partStatesCollDesc, ctx)) return false; writer.incrementState(); @@ -88,7 +89,7 @@ public final class DefaultMapperEnumFieldsMessageSerializer implements MessageSe } /** */ - @Override public final boolean readFrom(DefaultMapperEnumFieldsMessage msg, MessageReader reader) { + @Override public final boolean readFrom(DefaultMapperEnumFieldsMessage msg, MessageReader reader, MessageSerializationContext ctx) { switch (reader.state()) { case 0: msg.publicEnum = DefaultEnumMapper.INSTANCE.decode(transactionIsolationVals, reader.readByte()); @@ -107,7 +108,7 @@ public final class DefaultMapperEnumFieldsMessageSerializer implements MessageSe reader.incrementState(); case 2: - msg.isolationStringMap = reader.readMap(isolationStringMapCollDesc); + msg.isolationStringMap = reader.readMap(isolationStringMapCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -115,7 +116,7 @@ public final class DefaultMapperEnumFieldsMessageSerializer implements MessageSe reader.incrementState(); case 3: - msg.partStates = reader.readCollection(partStatesCollDesc); + msg.partStates = reader.readCollection(partStatesCollDesc, ctx); if (!reader.isLastRead()) return false; diff --git a/modules/core/src/test/resources/codegen/TestCollectionsMessageSerializer.java b/modules/core/src/test/resources/codegen/TestCollectionsMessageSerializer.java index bd79c20a48c26..d1814946151ce 100644 --- a/modules/core/src/test/resources/codegen/TestCollectionsMessageSerializer.java +++ b/modules/core/src/test/resources/codegen/TestCollectionsMessageSerializer.java @@ -17,6 +17,7 @@ package org.apache.ignite.internal; +import org.apache.ignite.internal.MessageSerializationContext; import org.apache.ignite.internal.TestCollectionsMessage; import org.apache.ignite.plugin.extensions.communication.CollectionImplementationType; import org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType; @@ -86,7 +87,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer private static final MessageCollectionType uuidListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.UUID), CollectionImplementationType.ARRAY_LIST); /** */ - @Override public final boolean writeTo(TestCollectionsMessage msg, MessageWriter writer) { + @Override public final boolean writeTo(TestCollectionsMessage msg, MessageWriter writer, MessageSerializationContext ctx) { if (!writer.isHeaderWritten()) { if (!writer.writeHeader(msg.directType())) return false; @@ -96,157 +97,157 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer switch (writer.state()) { case 0: - if (!writer.writeCollection(msg.booleanArrayList, booleanArrayListCollDesc)) + if (!writer.writeCollection(msg.booleanArrayList, booleanArrayListCollDesc, ctx)) return false; writer.incrementState(); case 1: - if (!writer.writeCollection(msg.byteArrayList, byteArrayListCollDesc)) + if (!writer.writeCollection(msg.byteArrayList, byteArrayListCollDesc, ctx)) return false; writer.incrementState(); case 2: - if (!writer.writeCollection(msg.shortArrayList, shortArrayListCollDesc)) + if (!writer.writeCollection(msg.shortArrayList, shortArrayListCollDesc, ctx)) return false; writer.incrementState(); case 3: - if (!writer.writeCollection(msg.intArrayList, intArrayListCollDesc)) + if (!writer.writeCollection(msg.intArrayList, intArrayListCollDesc, ctx)) return false; writer.incrementState(); case 4: - if (!writer.writeCollection(msg.longArrayList, longArrayListCollDesc)) + if (!writer.writeCollection(msg.longArrayList, longArrayListCollDesc, ctx)) return false; writer.incrementState(); case 5: - if (!writer.writeCollection(msg.charArrayList, charArrayListCollDesc)) + if (!writer.writeCollection(msg.charArrayList, charArrayListCollDesc, ctx)) return false; writer.incrementState(); case 6: - if (!writer.writeCollection(msg.floatArrayList, floatArrayListCollDesc)) + if (!writer.writeCollection(msg.floatArrayList, floatArrayListCollDesc, ctx)) return false; writer.incrementState(); case 7: - if (!writer.writeCollection(msg.doubleArrayList, doubleArrayListCollDesc)) + if (!writer.writeCollection(msg.doubleArrayList, doubleArrayListCollDesc, ctx)) return false; writer.incrementState(); case 8: - if (!writer.writeCollection(msg.stringList, stringListCollDesc)) + if (!writer.writeCollection(msg.stringList, stringListCollDesc, ctx)) return false; writer.incrementState(); case 9: - if (!writer.writeCollection(msg.uuidList, uuidListCollDesc)) + if (!writer.writeCollection(msg.uuidList, uuidListCollDesc, ctx)) return false; writer.incrementState(); case 10: - if (!writer.writeCollection(msg.bitSetList, bitSetListCollDesc)) + if (!writer.writeCollection(msg.bitSetList, bitSetListCollDesc, ctx)) return false; writer.incrementState(); case 11: - if (!writer.writeCollection(msg.igniteUuidList, igniteUuidListCollDesc)) + if (!writer.writeCollection(msg.igniteUuidList, igniteUuidListCollDesc, ctx)) return false; writer.incrementState(); case 12: - if (!writer.writeCollection(msg.affTopVersionList, affTopVersionListCollDesc)) + if (!writer.writeCollection(msg.affTopVersionList, affTopVersionListCollDesc, ctx)) return false; writer.incrementState(); case 13: - if (!writer.writeCollection(msg.boxedBooleanList, boxedBooleanListCollDesc)) + if (!writer.writeCollection(msg.boxedBooleanList, boxedBooleanListCollDesc, ctx)) return false; writer.incrementState(); case 14: - if (!writer.writeCollection(msg.boxedByteList, boxedByteListCollDesc)) + if (!writer.writeCollection(msg.boxedByteList, boxedByteListCollDesc, ctx)) return false; writer.incrementState(); case 15: - if (!writer.writeCollection(msg.boxedShortList, boxedShortListCollDesc)) + if (!writer.writeCollection(msg.boxedShortList, boxedShortListCollDesc, ctx)) return false; writer.incrementState(); case 16: - if (!writer.writeCollection(msg.boxedIntList, boxedIntListCollDesc)) + if (!writer.writeCollection(msg.boxedIntList, boxedIntListCollDesc, ctx)) return false; writer.incrementState(); case 17: - if (!writer.writeCollection(msg.boxedLongList, boxedLongListCollDesc)) + if (!writer.writeCollection(msg.boxedLongList, boxedLongListCollDesc, ctx)) return false; writer.incrementState(); case 18: - if (!writer.writeCollection(msg.boxedCharList, boxedCharListCollDesc)) + if (!writer.writeCollection(msg.boxedCharList, boxedCharListCollDesc, ctx)) return false; writer.incrementState(); case 19: - if (!writer.writeCollection(msg.boxedFloatList, boxedFloatListCollDesc)) + if (!writer.writeCollection(msg.boxedFloatList, boxedFloatListCollDesc, ctx)) return false; writer.incrementState(); case 20: - if (!writer.writeCollection(msg.boxedDoubleList, boxedDoubleListCollDesc)) + if (!writer.writeCollection(msg.boxedDoubleList, boxedDoubleListCollDesc, ctx)) return false; writer.incrementState(); case 21: - if (!writer.writeCollection(msg.messageList, messageListCollDesc)) + if (!writer.writeCollection(msg.messageList, messageListCollDesc, ctx)) return false; writer.incrementState(); case 22: - if (!writer.writeCollection(msg.gridLongListList, gridLongListListCollDesc)) + if (!writer.writeCollection(msg.gridLongListList, gridLongListListCollDesc, ctx)) return false; writer.incrementState(); case 23: - if (!writer.writeCollection(msg.boxedIntegerSet, boxedIntegerSetCollDesc)) + if (!writer.writeCollection(msg.boxedIntegerSet, boxedIntegerSetCollDesc, ctx)) return false; writer.incrementState(); case 24: - if (!writer.writeCollection(msg.bitSetSet, bitSetSetCollDesc)) + if (!writer.writeCollection(msg.bitSetSet, bitSetSetCollDesc, ctx)) return false; writer.incrementState(); case 25: - if (!writer.writeCollection(msg.cacheObjectSet, cacheObjectSetCollDesc)) + if (!writer.writeCollection(msg.cacheObjectSet, cacheObjectSetCollDesc, ctx)) return false; writer.incrementState(); @@ -256,10 +257,10 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer } /** */ - @Override public final boolean readFrom(TestCollectionsMessage msg, MessageReader reader) { + @Override public final boolean readFrom(TestCollectionsMessage msg, MessageReader reader, MessageSerializationContext ctx) { switch (reader.state()) { case 0: - msg.booleanArrayList = reader.readCollection(booleanArrayListCollDesc); + msg.booleanArrayList = reader.readCollection(booleanArrayListCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -267,7 +268,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 1: - msg.byteArrayList = reader.readCollection(byteArrayListCollDesc); + msg.byteArrayList = reader.readCollection(byteArrayListCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -275,7 +276,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 2: - msg.shortArrayList = reader.readCollection(shortArrayListCollDesc); + msg.shortArrayList = reader.readCollection(shortArrayListCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -283,7 +284,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 3: - msg.intArrayList = reader.readCollection(intArrayListCollDesc); + msg.intArrayList = reader.readCollection(intArrayListCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -291,7 +292,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 4: - msg.longArrayList = reader.readCollection(longArrayListCollDesc); + msg.longArrayList = reader.readCollection(longArrayListCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -299,7 +300,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 5: - msg.charArrayList = reader.readCollection(charArrayListCollDesc); + msg.charArrayList = reader.readCollection(charArrayListCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -307,7 +308,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 6: - msg.floatArrayList = reader.readCollection(floatArrayListCollDesc); + msg.floatArrayList = reader.readCollection(floatArrayListCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -315,7 +316,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 7: - msg.doubleArrayList = reader.readCollection(doubleArrayListCollDesc); + msg.doubleArrayList = reader.readCollection(doubleArrayListCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -323,7 +324,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 8: - msg.stringList = reader.readCollection(stringListCollDesc); + msg.stringList = reader.readCollection(stringListCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -331,7 +332,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 9: - msg.uuidList = reader.readCollection(uuidListCollDesc); + msg.uuidList = reader.readCollection(uuidListCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -339,7 +340,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 10: - msg.bitSetList = reader.readCollection(bitSetListCollDesc); + msg.bitSetList = reader.readCollection(bitSetListCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -347,7 +348,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 11: - msg.igniteUuidList = reader.readCollection(igniteUuidListCollDesc); + msg.igniteUuidList = reader.readCollection(igniteUuidListCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -355,7 +356,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 12: - msg.affTopVersionList = reader.readCollection(affTopVersionListCollDesc); + msg.affTopVersionList = reader.readCollection(affTopVersionListCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -363,7 +364,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 13: - msg.boxedBooleanList = reader.readCollection(boxedBooleanListCollDesc); + msg.boxedBooleanList = reader.readCollection(boxedBooleanListCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -371,7 +372,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 14: - msg.boxedByteList = reader.readCollection(boxedByteListCollDesc); + msg.boxedByteList = reader.readCollection(boxedByteListCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -379,7 +380,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 15: - msg.boxedShortList = reader.readCollection(boxedShortListCollDesc); + msg.boxedShortList = reader.readCollection(boxedShortListCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -387,7 +388,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 16: - msg.boxedIntList = reader.readCollection(boxedIntListCollDesc); + msg.boxedIntList = reader.readCollection(boxedIntListCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -395,7 +396,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 17: - msg.boxedLongList = reader.readCollection(boxedLongListCollDesc); + msg.boxedLongList = reader.readCollection(boxedLongListCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -403,7 +404,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 18: - msg.boxedCharList = reader.readCollection(boxedCharListCollDesc); + msg.boxedCharList = reader.readCollection(boxedCharListCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -411,7 +412,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 19: - msg.boxedFloatList = reader.readCollection(boxedFloatListCollDesc); + msg.boxedFloatList = reader.readCollection(boxedFloatListCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -419,7 +420,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 20: - msg.boxedDoubleList = reader.readCollection(boxedDoubleListCollDesc); + msg.boxedDoubleList = reader.readCollection(boxedDoubleListCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -427,7 +428,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 21: - msg.messageList = reader.readCollection(messageListCollDesc); + msg.messageList = reader.readCollection(messageListCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -435,7 +436,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 22: - msg.gridLongListList = reader.readCollection(gridLongListListCollDesc); + msg.gridLongListList = reader.readCollection(gridLongListListCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -443,7 +444,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 23: - msg.boxedIntegerSet = reader.readCollection(boxedIntegerSetCollDesc); + msg.boxedIntegerSet = reader.readCollection(boxedIntegerSetCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -451,7 +452,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 24: - msg.bitSetSet = reader.readCollection(bitSetSetCollDesc); + msg.bitSetSet = reader.readCollection(bitSetSetCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -459,7 +460,7 @@ public final class TestCollectionsMessageSerializer implements MessageSerializer reader.incrementState(); case 25: - msg.cacheObjectSet = reader.readCollection(cacheObjectSetCollDesc); + msg.cacheObjectSet = reader.readCollection(cacheObjectSetCollDesc, ctx); if (!reader.isLastRead()) return false; diff --git a/modules/core/src/test/resources/codegen/TestEnumSetMessageSerializer.java b/modules/core/src/test/resources/codegen/TestEnumSetMessageSerializer.java index fb0afa111fa6f..d5cc64a6abde1 100644 --- a/modules/core/src/test/resources/codegen/TestEnumSetMessageSerializer.java +++ b/modules/core/src/test/resources/codegen/TestEnumSetMessageSerializer.java @@ -17,6 +17,7 @@ package org.apache.ignite.internal; +import org.apache.ignite.internal.MessageSerializationContext; import org.apache.ignite.internal.TestEnumSetMessage; import org.apache.ignite.plugin.extensions.communication.CollectionImplementationType; import org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType; @@ -46,7 +47,7 @@ public final class TestEnumSetMessageSerializer implements MessageSerializer(TransactionIsolation.class, DefaultEnumMapper.INSTANCE::encode, b -> DefaultEnumMapper.INSTANCE.decode(transactionIsolationVals, b)), CollectionImplementationType.ENUM_SET), false); /** */ - @Override public final boolean writeTo(TestEnumSetMessage msg, MessageWriter writer) { + @Override public final boolean writeTo(TestEnumSetMessage msg, MessageWriter writer, MessageSerializationContext ctx) { if (!writer.isHeaderWritten()) { if (!writer.writeHeader(msg.directType())) return false; @@ -56,19 +57,19 @@ public final class TestEnumSetMessageSerializer implements MessageSerializer { /** */ - @Override public final boolean writeTo(TestMarshallableMessage msg, MessageWriter writer) { + @Override public final boolean writeTo(TestMarshallableMessage msg, MessageWriter writer, MessageSerializationContext ctx) { if (!writer.isHeaderWritten()) { if (!writer.writeHeader(msg.directType())) return false; @@ -61,7 +62,7 @@ public final class TestMarshallableMessageSerializer implements MessageSerialize } /** */ - @Override public final boolean readFrom(TestMarshallableMessage msg, MessageReader reader) { + @Override public final boolean readFrom(TestMarshallableMessage msg, MessageReader reader, MessageSerializationContext ctx) { switch (reader.state()) { case 0: msg.iv = reader.readInt(); diff --git a/modules/core/src/test/resources/codegen/TestMarshalledArrayMapMessageSerializer.java b/modules/core/src/test/resources/codegen/TestMarshalledArrayMapMessageSerializer.java index 4f3a7c0e51fc9..52f8785c633e4 100644 --- a/modules/core/src/test/resources/codegen/TestMarshalledArrayMapMessageSerializer.java +++ b/modules/core/src/test/resources/codegen/TestMarshalledArrayMapMessageSerializer.java @@ -19,6 +19,7 @@ import java.util.List; import org.apache.ignite.internal.GridTopicMessage; +import org.apache.ignite.internal.MessageSerializationContext; import org.apache.ignite.internal.TestMarshalledArrayMapMessage; import org.apache.ignite.plugin.extensions.communication.CollectionImplementationType; import org.apache.ignite.plugin.extensions.communication.MessageArrayType; @@ -45,7 +46,7 @@ public final class TestMarshalledArrayMapMessageSerializer implements MessageSer private static final MessageArrayType mapValsCollDesc = new MessageArrayType(new MessageCollectionType(new MessageItemType(MessageCollectionItemType.MSG), CollectionImplementationType.ARRAY_LIST), List.class); /** */ - @Override public final boolean writeTo(TestMarshalledArrayMapMessage msg, MessageWriter writer) { + @Override public final boolean writeTo(TestMarshalledArrayMapMessage msg, MessageWriter writer, MessageSerializationContext ctx) { if (!writer.isHeaderWritten()) { if (!writer.writeHeader(msg.directType())) return false; @@ -55,25 +56,25 @@ public final class TestMarshalledArrayMapMessageSerializer implements MessageSer switch (writer.state()) { case 0: - if (!writer.writeObjectArray(msg.mapKeys, mapKeysCollDesc)) + if (!writer.writeObjectArray(msg.mapKeys, mapKeysCollDesc, ctx)) return false; writer.incrementState(); case 1: - if (!writer.writeObjectArray(msg.mapVals, mapValsCollDesc)) + if (!writer.writeObjectArray(msg.mapVals, mapValsCollDesc, ctx)) return false; writer.incrementState(); case 2: - if (!writer.writeObjectArray(msg.fixedMapKeys, fixedMapKeysCollDesc)) + if (!writer.writeObjectArray(msg.fixedMapKeys, fixedMapKeysCollDesc, ctx)) return false; writer.incrementState(); case 3: - if (!writer.writeObjectArray(msg.fixedMapVals, fixedMapValsCollDesc)) + if (!writer.writeObjectArray(msg.fixedMapVals, fixedMapValsCollDesc, ctx)) return false; writer.incrementState(); @@ -83,10 +84,10 @@ public final class TestMarshalledArrayMapMessageSerializer implements MessageSer } /** */ - @Override public final boolean readFrom(TestMarshalledArrayMapMessage msg, MessageReader reader) { + @Override public final boolean readFrom(TestMarshalledArrayMapMessage msg, MessageReader reader, MessageSerializationContext ctx) { switch (reader.state()) { case 0: - msg.mapKeys = reader.readObjectArray(mapKeysCollDesc); + msg.mapKeys = reader.readObjectArray(mapKeysCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -94,7 +95,7 @@ public final class TestMarshalledArrayMapMessageSerializer implements MessageSer reader.incrementState(); case 1: - msg.mapVals = reader.readObjectArray(mapValsCollDesc); + msg.mapVals = reader.readObjectArray(mapValsCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -102,7 +103,7 @@ public final class TestMarshalledArrayMapMessageSerializer implements MessageSer reader.incrementState(); case 2: - msg.fixedMapKeys = reader.readObjectArray(fixedMapKeysCollDesc); + msg.fixedMapKeys = reader.readObjectArray(fixedMapKeysCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -110,7 +111,7 @@ public final class TestMarshalledArrayMapMessageSerializer implements MessageSer reader.incrementState(); case 3: - msg.fixedMapVals = reader.readObjectArray(fixedMapValsCollDesc); + msg.fixedMapVals = reader.readObjectArray(fixedMapValsCollDesc, ctx); if (!reader.isLastRead()) return false; diff --git a/modules/core/src/test/resources/codegen/TestMarshalledCollectionMessageSerializer.java b/modules/core/src/test/resources/codegen/TestMarshalledCollectionMessageSerializer.java index 43f7bf2f2e996..7b831f8ec04e8 100644 --- a/modules/core/src/test/resources/codegen/TestMarshalledCollectionMessageSerializer.java +++ b/modules/core/src/test/resources/codegen/TestMarshalledCollectionMessageSerializer.java @@ -17,6 +17,7 @@ package org.apache.ignite.internal; +import org.apache.ignite.internal.MessageSerializationContext; import org.apache.ignite.internal.TestMarshalledCollectionMessage; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.plugin.extensions.communication.MessageArrayType; @@ -36,7 +37,7 @@ public final class TestMarshalledCollectionMessageSerializer implements MessageS private static final MessageArrayType keysArrCollDesc = new MessageArrayType(new MessageItemType(MessageCollectionItemType.GRID_CACHE_VERSION), GridCacheVersion.class); /** */ - @Override public final boolean writeTo(TestMarshalledCollectionMessage msg, MessageWriter writer) { + @Override public final boolean writeTo(TestMarshalledCollectionMessage msg, MessageWriter writer, MessageSerializationContext ctx) { if (!writer.isHeaderWritten()) { if (!writer.writeHeader(msg.directType())) return false; @@ -46,7 +47,7 @@ public final class TestMarshalledCollectionMessageSerializer implements MessageS switch (writer.state()) { case 0: - if (!writer.writeObjectArray(msg.keysArr, keysArrCollDesc)) + if (!writer.writeObjectArray(msg.keysArr, keysArrCollDesc, ctx)) return false; writer.incrementState(); @@ -56,10 +57,10 @@ public final class TestMarshalledCollectionMessageSerializer implements MessageS } /** */ - @Override public final boolean readFrom(TestMarshalledCollectionMessage msg, MessageReader reader) { + @Override public final boolean readFrom(TestMarshalledCollectionMessage msg, MessageReader reader, MessageSerializationContext ctx) { switch (reader.state()) { case 0: - msg.keysArr = reader.readObjectArray(keysArrCollDesc); + msg.keysArr = reader.readObjectArray(keysArrCollDesc, ctx); if (!reader.isLastRead()) return false; diff --git a/modules/core/src/test/resources/codegen/TestMarshalledMapMessageSerializer.java b/modules/core/src/test/resources/codegen/TestMarshalledMapMessageSerializer.java index dd0fcb2253364..e3aca2bf684f3 100644 --- a/modules/core/src/test/resources/codegen/TestMarshalledMapMessageSerializer.java +++ b/modules/core/src/test/resources/codegen/TestMarshalledMapMessageSerializer.java @@ -17,6 +17,7 @@ package org.apache.ignite.internal; +import org.apache.ignite.internal.MessageSerializationContext; import org.apache.ignite.internal.TestMarshalledMapMessage; import org.apache.ignite.plugin.extensions.communication.CollectionImplementationType; import org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType; @@ -38,7 +39,7 @@ public final class TestMarshalledMapMessageSerializer implements MessageSerializ private static final MessageCollectionType mapValsCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.GRID_CACHE_VERSION), CollectionImplementationType.ARRAY_LIST); /** */ - @Override public final boolean writeTo(TestMarshalledMapMessage msg, MessageWriter writer) { + @Override public final boolean writeTo(TestMarshalledMapMessage msg, MessageWriter writer, MessageSerializationContext ctx) { if (!writer.isHeaderWritten()) { if (!writer.writeHeader(msg.directType())) return false; @@ -48,13 +49,13 @@ public final class TestMarshalledMapMessageSerializer implements MessageSerializ switch (writer.state()) { case 0: - if (!writer.writeCollection(msg.mapKeys, mapKeysCollDesc)) + if (!writer.writeCollection(msg.mapKeys, mapKeysCollDesc, ctx)) return false; writer.incrementState(); case 1: - if (!writer.writeCollection(msg.mapVals, mapValsCollDesc)) + if (!writer.writeCollection(msg.mapVals, mapValsCollDesc, ctx)) return false; writer.incrementState(); @@ -64,10 +65,10 @@ public final class TestMarshalledMapMessageSerializer implements MessageSerializ } /** */ - @Override public final boolean readFrom(TestMarshalledMapMessage msg, MessageReader reader) { + @Override public final boolean readFrom(TestMarshalledMapMessage msg, MessageReader reader, MessageSerializationContext ctx) { switch (reader.state()) { case 0: - msg.mapKeys = reader.readCollection(mapKeysCollDesc); + msg.mapKeys = reader.readCollection(mapKeysCollDesc, ctx); if (!reader.isLastRead()) return false; @@ -75,7 +76,7 @@ public final class TestMarshalledMapMessageSerializer implements MessageSerializ reader.incrementState(); case 1: - msg.mapVals = reader.readCollection(mapValsCollDesc); + msg.mapVals = reader.readCollection(mapValsCollDesc, ctx); if (!reader.isLastRead()) return false; diff --git a/modules/core/src/test/resources/codegen/TestMarshalledMessageSerializer.java b/modules/core/src/test/resources/codegen/TestMarshalledMessageSerializer.java index fa81057b60403..b924687a0d06f 100644 --- a/modules/core/src/test/resources/codegen/TestMarshalledMessageSerializer.java +++ b/modules/core/src/test/resources/codegen/TestMarshalledMessageSerializer.java @@ -17,6 +17,7 @@ package org.apache.ignite.internal; +import org.apache.ignite.internal.MessageSerializationContext; import org.apache.ignite.internal.TestMarshalledMessage; import org.apache.ignite.plugin.extensions.communication.MessageReader; import org.apache.ignite.plugin.extensions.communication.MessageSerializer; @@ -29,7 +30,7 @@ */ public final class TestMarshalledMessageSerializer implements MessageSerializer { /** */ - @Override public final boolean writeTo(TestMarshalledMessage msg, MessageWriter writer) { + @Override public final boolean writeTo(TestMarshalledMessage msg, MessageWriter writer, MessageSerializationContext ctx) { if (!writer.isHeaderWritten()) { if (!writer.writeHeader(msg.directType())) return false; @@ -49,7 +50,7 @@ public final class TestMarshalledMessageSerializer implements MessageSerializer< } /** */ - @Override public final boolean readFrom(TestMarshalledMessage msg, MessageReader reader) { + @Override public final boolean readFrom(TestMarshalledMessage msg, MessageReader reader, MessageSerializationContext ctx) { switch (reader.state()) { case 0: msg.dataBytes = reader.readByteArray(); diff --git a/modules/core/src/test/resources/codegen/TestMarshalledObjectsMessageSerializer.java b/modules/core/src/test/resources/codegen/TestMarshalledObjectsMessageSerializer.java index b68578b06a615..68d62d8879123 100644 --- a/modules/core/src/test/resources/codegen/TestMarshalledObjectsMessageSerializer.java +++ b/modules/core/src/test/resources/codegen/TestMarshalledObjectsMessageSerializer.java @@ -17,6 +17,7 @@ package org.apache.ignite.internal; +import org.apache.ignite.internal.MessageSerializationContext; import org.apache.ignite.internal.TestMarshalledObjectsMessage; import org.apache.ignite.plugin.extensions.communication.CollectionImplementationType; import org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType; @@ -36,7 +37,7 @@ public final class TestMarshalledObjectsMessageSerializer implements MessageSeri private static final MessageCollectionType dataBytesCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.BYTE_ARR), CollectionImplementationType.ARRAY_LIST); /** */ - @Override public final boolean writeTo(TestMarshalledObjectsMessage msg, MessageWriter writer) { + @Override public final boolean writeTo(TestMarshalledObjectsMessage msg, MessageWriter writer, MessageSerializationContext ctx) { if (!writer.isHeaderWritten()) { if (!writer.writeHeader(msg.directType())) return false; @@ -46,7 +47,7 @@ public final class TestMarshalledObjectsMessageSerializer implements MessageSeri switch (writer.state()) { case 0: - if (!writer.writeCollection(msg.dataBytes, dataBytesCollDesc)) + if (!writer.writeCollection(msg.dataBytes, dataBytesCollDesc, ctx)) return false; writer.incrementState(); @@ -56,10 +57,10 @@ public final class TestMarshalledObjectsMessageSerializer implements MessageSeri } /** */ - @Override public final boolean readFrom(TestMarshalledObjectsMessage msg, MessageReader reader) { + @Override public final boolean readFrom(TestMarshalledObjectsMessage msg, MessageReader reader, MessageSerializationContext ctx) { switch (reader.state()) { case 0: - msg.dataBytes = reader.readCollection(dataBytesCollDesc); + msg.dataBytes = reader.readCollection(dataBytesCollDesc, ctx); if (!reader.isLastRead()) return false; diff --git a/modules/core/src/test/resources/codegen/TestMessageSerializer.java b/modules/core/src/test/resources/codegen/TestMessageSerializer.java index 7aa0a054471aa..1811c09f59037 100644 --- a/modules/core/src/test/resources/codegen/TestMessageSerializer.java +++ b/modules/core/src/test/resources/codegen/TestMessageSerializer.java @@ -17,6 +17,7 @@ package org.apache.ignite.internal; +import org.apache.ignite.internal.MessageSerializationContext; import org.apache.ignite.internal.TestMessage; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.plugin.extensions.communication.MessageArrayType; @@ -40,7 +41,7 @@ public final class TestMessageSerializer implements MessageSerializer { + /** */ + @Override public final boolean writeTo(TestRollingUpgradeAwareMessage msg, MessageWriter writer, MessageSerializationContext ctx) { + if (!writer.isHeaderWritten()) { + if (!writer.writeHeader(msg.directType())) + return false; + + writer.onHeaderWritten(); + } + + switch (writer.state()) { + case 0: + if (!writer.writeInt(msg.plain)) + return false; + + writer.incrementState(); + + case 1: + if (ctx.includeFieldDeprecatedBy(TestFeatureRegistry.FIRST_FEATURE)) { + if (!writer.writeString(msg.oldFld)) + return false; + } + + writer.incrementState(); + + case 2: + if (ctx.includeFieldIntroducedBy(TestFeatureRegistry.FIRST_FEATURE)) { + if (!writer.writeString(msg.newFld)) + return false; + } + + writer.incrementState(); + + case 3: + if (ctx.includeFieldIntroducedBy(TestFeatureRegistry.FIRST_FEATURE) && ctx.includeFieldDeprecatedBy(TestFeatureRegistry.SECOND_FEATURE)) { + if (!writer.writeLong(msg.windowed)) + return false; + } + + writer.incrementState(); + + } + + return true; + } + + /** */ + @Override public final boolean readFrom(TestRollingUpgradeAwareMessage msg, MessageReader reader, MessageSerializationContext ctx) { + switch (reader.state()) { + case 0: + msg.plain = reader.readInt(); + + if (!reader.isLastRead()) + return false; + + reader.incrementState(); + + case 1: + if (ctx.includeFieldDeprecatedBy(TestFeatureRegistry.FIRST_FEATURE)) { + msg.oldFld = reader.readString(); + + if (!reader.isLastRead()) + return false; + } + + reader.incrementState(); + + case 2: + if (ctx.includeFieldIntroducedBy(TestFeatureRegistry.FIRST_FEATURE)) { + msg.newFld = reader.readString(); + + if (!reader.isLastRead()) + return false; + } + + reader.incrementState(); + + case 3: + if (ctx.includeFieldIntroducedBy(TestFeatureRegistry.FIRST_FEATURE) && ctx.includeFieldDeprecatedBy(TestFeatureRegistry.SECOND_FEATURE)) { + msg.windowed = reader.readLong(); + + if (!reader.isLastRead()) + return false; + } + + reader.incrementState(); + + } + + return true; + } + + /** {@inheritDoc} */ + @Override public final TestRollingUpgradeAwareMessage createMessage() { + return new TestRollingUpgradeAwareMessage(); + } +} diff --git a/modules/core/src/test/resources/codegen/TestUnknownFeatureMessage.java b/modules/core/src/test/resources/codegen/TestUnknownFeatureMessage.java new file mode 100644 index 0000000000000..7e1db62bb29e7 --- /dev/null +++ b/modules/core/src/test/resources/codegen/TestUnknownFeatureMessage.java @@ -0,0 +1,27 @@ +/* + * 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.plugin.extensions.communication.Message; + +/** */ +public class TestUnknownFeatureMessage implements Message { + /** */ + @Order(value = 0, introducedBy = "NO_SUCH_FEATURE") + int fld; +} diff --git a/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/GridDirectParser.java b/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/GridDirectParser.java index f30fbc5cfc0ea..43f89a6ab11c8 100644 --- a/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/GridDirectParser.java +++ b/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/GridDirectParser.java @@ -29,6 +29,7 @@ import org.jetbrains.annotations.Nullable; import static org.apache.ignite.internal.util.CommonUtils.makeMessageType; +import static org.apache.ignite.internal.util.nio.MessageSerialization.resolveSerializationContext; /** * Parser for direct messages. @@ -86,7 +87,7 @@ public GridDirectParser(IgniteLogger log, MessageFactory msgFactory, GridNioMess if (msg != null && buf.hasRemaining()) { reader.setBuffer(buf); - finished = MessageSerialization.readFrom(msgFactory, msg, reader); + finished = MessageSerialization.readFrom(msgFactory, msg, reader, resolveSerializationContext(ses)); } if (finished) { diff --git a/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/GridNioServer.java b/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/GridNioServer.java index a067277648d35..09926571b29e1 100644 --- a/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/GridNioServer.java +++ b/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/GridNioServer.java @@ -54,6 +54,7 @@ import org.apache.ignite.IgniteLogger; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.IgniteInterruptedCheckedException; +import org.apache.ignite.internal.MessageSerializationContext; import org.apache.ignite.internal.processors.odbc.ClientMessage; import org.apache.ignite.internal.util.CommonUtils; import org.apache.ignite.internal.util.GridConcurrentHashSet; @@ -85,6 +86,7 @@ import static org.apache.ignite.failure.FailureType.SYSTEM_WORKER_TERMINATION; import static org.apache.ignite.internal.util.nio.GridNioSessionMetaKey.MSG_WRITER; import static org.apache.ignite.internal.util.nio.GridNioSessionMetaKey.NIO_OPERATION; +import static org.apache.ignite.internal.util.nio.MessageSerialization.resolveSerializationContext; /** * TCP NIO server. Due to asynchronous nature of connections processing @@ -1443,6 +1445,8 @@ private void processWriteSsl(SelectionKey key) throws IOException { MessageWriter writer = messageWriter(ses); + MessageSerializationContext serCtx = resolveSerializationContext(ses); + boolean handshakeFinished = sslFilter.lock(ses); try { @@ -1506,7 +1510,7 @@ private void processWriteSsl(SelectionKey key) throws IOException { List pendingRequests = new ArrayList<>(2); if (req != null) - finished = writeToBuffer(writer, buf, req, pendingRequests); + finished = writeToBuffer(writer, buf, req, pendingRequests, serCtx); // Fill up as many messages as possible to write buffer. while (finished) { @@ -1518,7 +1522,7 @@ private void processWriteSsl(SelectionKey key) throws IOException { if (req == null) break; - finished = writeToBuffer(writer, buf, req, pendingRequests); + finished = writeToBuffer(writer, buf, req, pendingRequests, serCtx); } int sesBufLimit = buf.limit(); @@ -1592,13 +1596,15 @@ private void processWriteSsl(SelectionKey key) throws IOException { * @param buf Buffer to write. * @param req Source of data. * @param pendingRequests List of requests which was successfully written. + * @param serCtx Serialization context of the session. * @return {@code true} if message successfully written to buffer and {@code false} otherwise. */ private boolean writeToBuffer( MessageWriter writer, ByteBuffer buf, SessionWriteRequest req, - List pendingRequests + List pendingRequests, + MessageSerializationContext serCtx ) { Message msg; boolean finished; @@ -1614,7 +1620,7 @@ private boolean writeToBuffer( else { writer.setBuffer(buf); - finished = MessageSerialization.writeTo(messageFactory(), msg, writer); + finished = MessageSerialization.writeTo(messageFactory(), msg, writer, serCtx); } if (finished) { @@ -1692,6 +1698,8 @@ private void processWrite0(SelectionKey key) throws IOException { MessageWriter writer = messageWriter(ses); + MessageSerializationContext serCtx = resolveSerializationContext(ses); + if (req == null) { req = systemMessage(ses); @@ -1709,7 +1717,7 @@ private void processWrite0(SelectionKey key) throws IOException { boolean finished = false; if (req != null) - finished = writeToBuffer(ses, buf, req, writer); + finished = writeToBuffer(ses, buf, req, writer, serCtx); // Fill up as many messages as possible to write buffer. while (finished) { @@ -1723,7 +1731,7 @@ private void processWrite0(SelectionKey key) throws IOException { if (req == null) break; - finished = writeToBuffer(ses, buf, req, writer); + finished = writeToBuffer(ses, buf, req, writer, serCtx); } buf.flip(); @@ -1781,14 +1789,20 @@ private void processWrite0(SelectionKey key) throws IOException { } /** - * @param writer Customizer of writing. + * @param ses Session the message is written to. * @param buf Buffer to write. * @param req Source of data. - * @param ses Session for notification about writting. + * @param writer Customizer of writing. + * @param serCtx Serialization context of the session. * @return {@code true} if message successfully written to buffer and {@code false} otherwise. */ - private boolean writeToBuffer(GridSelectorNioSessionImpl ses, ByteBuffer buf, SessionWriteRequest req, - MessageWriter writer) { + private boolean writeToBuffer( + GridSelectorNioSessionImpl ses, + ByteBuffer buf, + SessionWriteRequest req, + MessageWriter writer, + MessageSerializationContext serCtx + ) { Message msg; boolean finished; msg = (Message)req.message(); @@ -1803,7 +1817,7 @@ private boolean writeToBuffer(GridSelectorNioSessionImpl ses, ByteBuffer buf, Se else { writer.setBuffer(buf); - finished = MessageSerialization.writeTo(msgFactory, msg, writer); + finished = MessageSerialization.writeTo(msgFactory, msg, writer, serCtx); } if (finished) { diff --git a/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/GridNioSessionMetaKey.java b/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/GridNioSessionMetaKey.java index fbdcc6d5d34f9..9a5836d14cc4c 100644 --- a/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/GridNioSessionMetaKey.java +++ b/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/GridNioSessionMetaKey.java @@ -42,7 +42,10 @@ public enum GridNioSessionMetaKey { MARSHALLER_ID, /** Message writer. */ - MSG_WRITER; + MSG_WRITER, + + /** Message serialization context. */ + MSG_SER_CTX; /** Maximum count of NIO session keys in system. */ public static final int MAX_KEYS_CNT = 64; diff --git a/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/MessageSerialization.java b/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/MessageSerialization.java index b436edb764d49..ee47ffd3c779e 100644 --- a/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/MessageSerialization.java +++ b/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/MessageSerialization.java @@ -17,11 +17,13 @@ package org.apache.ignite.internal.util.nio; +import org.apache.ignite.internal.MessageSerializationContext; import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.plugin.extensions.communication.MessageFactory; import org.apache.ignite.plugin.extensions.communication.MessageReader; import org.apache.ignite.plugin.extensions.communication.MessageSerializer; import org.apache.ignite.plugin.extensions.communication.MessageWriter; +import org.jetbrains.annotations.Nullable; /** * Resolve-and-dispatch entry points for {@link MessageSerializer}: each looks up the serializer registered for the @@ -40,11 +42,19 @@ private MessageSerialization() { * @param factory Message factory. * @param msg Message instance. * @param writer Writer. + * @param ctx Serialization context. * @param Message type. * @return Whether message was fully written. */ - public static boolean writeTo(MessageFactory factory, M msg, MessageWriter writer) { - return resolve(factory, msg).writeTo(msg, writer); + public static boolean writeTo( + MessageFactory factory, + M msg, + MessageWriter writer, + MessageSerializationContext ctx + ) { + assert ctx != null : "Message is serialized without a serialization context [msg=" + msg.getClass().getName() + ']'; + + return resolveMessageserializer(factory, msg).writeTo(msg, writer, ctx); } /** @@ -53,16 +63,29 @@ public static boolean writeTo(MessageFactory factory, M msg, * @param factory Message factory. * @param msg Message instance. * @param reader Reader. + * @param ctx Serialization context. * @param Message type. * @return Whether message was fully read. */ - public static boolean readFrom(MessageFactory factory, M msg, MessageReader reader) { - return resolve(factory, msg).readFrom(msg, reader); + public static boolean readFrom( + MessageFactory factory, + M msg, + MessageReader reader, + MessageSerializationContext ctx + ) { + assert ctx != null : "Message is deserialized without a serialization context [msg=" + msg.getClass().getName() + ']'; + + return resolveMessageserializer(factory, msg).readFrom(msg, reader, ctx); + } + + /** */ + public static @Nullable MessageSerializationContext resolveSerializationContext(GridNioSession ses) { + return ses.meta(GridNioSessionMetaKey.MSG_SER_CTX.ordinal()); } /** @return the serializer registered for {@code msg}'s direct type. */ @SuppressWarnings("unchecked") - private static MessageSerializer resolve(MessageFactory factory, M msg) { + private static MessageSerializer resolveMessageserializer(MessageFactory factory, M msg) { return (MessageSerializer)factory.serializer(msg.directType()); } } diff --git a/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageReader.java b/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageReader.java index 796acc40a191d..faf50669796dd 100644 --- a/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageReader.java +++ b/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageReader.java @@ -22,6 +22,7 @@ import java.util.Collection; import java.util.Map; import java.util.UUID; +import org.apache.ignite.internal.MessageSerializationContext; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.CacheObject; import org.apache.ignite.internal.processors.cache.KeyCacheObject; @@ -196,21 +197,23 @@ public default void setBuffer(ByteBuffer buf) { /** * Reads nested message. * + * @param ctx Serialization context. * @param Type of the message. * @return Message. */ - public default T readMessage() { - return readMessage(false); + public default T readMessage(MessageSerializationContext ctx) { + return readMessage(false, ctx); } /** * Reads nested message. * * @param compress Whether message should be decompressed. + * @param ctx Serialization context. * @param Type of the message. * @return Message. */ - public T readMessage(boolean compress); + public T readMessage(boolean compress, MessageSerializationContext ctx); /** * Reads {@link CacheObject}. @@ -237,29 +240,32 @@ public default T readMessage() { * Reads array of objects. * * @param type Array component type. + * @param ctx Serialization context. * @param Type of the read object. * @return Array of objects. */ - public T[] readObjectArray(MessageArrayType type); + public T[] readObjectArray(MessageArrayType type, MessageSerializationContext ctx); /** * Reads any collection. * * @param type Collection item type. + * @param ctx Serialization context. * @param Type of the read collection. * @return Collection. */ - public > C readCollection(MessageCollectionType type); + public > C readCollection(MessageCollectionType type, MessageSerializationContext ctx); /** * Reads map. * * @param type Map type. + * @param ctx Serialization context. * @param Type of the read map. * @return Map. */ - public default > M readMap(MessageMapType type) { - return readMap(type, false); + public default > M readMap(MessageMapType type, MessageSerializationContext ctx) { + return readMap(type, false, ctx); } /** @@ -267,10 +273,11 @@ public default T readMessage() { * * @param type Map type. * @param compress Whether map should be compressed. + * @param ctx Serialization context. * @param Type of the read map. * @return Map. */ - public > M readMap(MessageMapType type, boolean compress); + public > M readMap(MessageMapType type, boolean compress, MessageSerializationContext ctx); /** @return Ignite product version. */ IgniteProductVersion readIgniteProductVersion(); diff --git a/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageSerializer.java b/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageSerializer.java index 86ce0d170a09f..ab66f296ed6b0 100644 --- a/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageSerializer.java +++ b/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageSerializer.java @@ -17,6 +17,8 @@ package org.apache.ignite.plugin.extensions.communication; +import org.apache.ignite.internal.MessageSerializationContext; + /** * Interface for message serialization logic. Resolve-and-dispatch entry points that look the serializer up from the * message factory live in {@code MessageSerialization}. @@ -27,18 +29,20 @@ public interface MessageSerializer { * * @param msg Message instance. * @param writer Writer. + * @param ctx Serialization context. * @return Whether message was fully written. */ - public boolean writeTo(M msg, MessageWriter writer); + public boolean writeTo(M msg, MessageWriter writer, MessageSerializationContext ctx); /** * Reads this message from provided byte buffer. * * @param msg Message instance. * @param reader Reader. + * @param ctx Serialization context. * @return Whether message was fully read. */ - public boolean readFrom(M msg, MessageReader reader); + public boolean readFrom(M msg, MessageReader reader, MessageSerializationContext ctx); /** * @return New instance of message. diff --git a/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageWriter.java b/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageWriter.java index 019bab8fa9db9..4f281cec3a86a 100644 --- a/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageWriter.java +++ b/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageWriter.java @@ -22,6 +22,7 @@ import java.util.Collection; import java.util.Map; import java.util.UUID; +import org.apache.ignite.internal.MessageSerializationContext; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.CacheObject; import org.apache.ignite.internal.processors.cache.KeyCacheObject; @@ -246,10 +247,11 @@ public default void setBuffer(ByteBuffer buf) { * Writes nested message. * * @param val Message. + * @param ctx Serialization context. * @return Whether value was fully written. */ - public default boolean writeMessage(Message val) { - return writeMessage(val, false); + public default boolean writeMessage(Message val, MessageSerializationContext ctx) { + return writeMessage(val, false, ctx); } /** @@ -257,9 +259,10 @@ public default boolean writeMessage(Message val) { * * @param val Message. * @param compress Whether message should be compressed. + * @param ctx Serialization context. * @return Whether value was fully written. */ - public boolean writeMessage(Message val, boolean compress); + public boolean writeMessage(Message val, boolean compress, MessageSerializationContext ctx); /** * Writes {@link CacheObject}. @@ -290,32 +293,35 @@ public default boolean writeMessage(Message val) { * * @param arr Array of objects. * @param type Array component type. + * @param ctx Serialization context. * @param Type of the objects that array contains. * @return Whether array was fully written. */ - public boolean writeObjectArray(T[] arr, MessageArrayType type); + public boolean writeObjectArray(T[] arr, MessageArrayType type, MessageSerializationContext ctx); /** * Writes collection with its elements order. * * @param col Collection. * @param type Collection item type. + * @param ctx Serialization context. * @param Type of the objects that collection contains. * @return Whether value was fully written. */ - public boolean writeCollection(Collection col, MessageCollectionType type); + public boolean writeCollection(Collection col, MessageCollectionType type, MessageSerializationContext ctx); /** * Writes map. * * @param map Map. * @param type Map type. + * @param ctx Serialization context. * @param Initial key types of the map to write. * @param Initial value types of the map to write. * @return Whether value was fully written. */ - public default boolean writeMap(Map map, MessageMapType type) { - return writeMap(map, type, false); + public default boolean writeMap(Map map, MessageMapType type, MessageSerializationContext ctx) { + return writeMap(map, type, false, ctx); } /** @@ -324,11 +330,12 @@ public default boolean writeMap(Map map, MessageMapType type) { * @param map Map. * @param type Map type. * @param compress Whether map should be compressed. + * @param ctx Serialization context. * @param Initial key types of the map to write. * @param Initial value types of the map to write. * @return Whether value was fully written. */ - public boolean writeMap(Map map, MessageMapType type, boolean compress); + public boolean writeMap(Map map, MessageMapType type, boolean compress, MessageSerializationContext ctx); /** * Writes ignite product version. diff --git a/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/DiscoveryMessageParser.java b/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/DiscoveryMessageParser.java index aeb7c1be8851b..06a14735271a2 100644 --- a/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/DiscoveryMessageParser.java +++ b/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/DiscoveryMessageParser.java @@ -37,6 +37,8 @@ import org.apache.ignite.plugin.extensions.communication.MessageSerializer; import org.apache.ignite.spi.IgniteSpiException; +import static org.apache.ignite.internal.MessageSerializationContext.LATEST_SCHEMA; + /** * Class is responsible for serializing discovery messages using RU-ready {@link MessageSerializer} mechanism. */ @@ -105,7 +107,7 @@ private void serializeMessage(Message m, OutputStream out) throws IOException { do { msgBuf.clear(); - finished = MessageSerialization.writeTo(msgFactory, m, msgWriter); + finished = MessageSerialization.writeTo(msgFactory, m, msgWriter, LATEST_SCHEMA); out.write(msgBuf.array(), 0, msgBuf.position()); } @@ -131,7 +133,7 @@ private T deserializeMessage(InputStream in) throws IOExcept msgBuf.rewind(); } - finished = MessageSerialization.readFrom(msgFactory, msg, msgReader); + finished = MessageSerialization.readFrom(msgFactory, msg, msgReader, LATEST_SCHEMA); assert read != -1 || finished : "Stream closed before message was fully read.";