conditions = new ArrayList<>();
+
+ if (!ann.introducedBy().isEmpty())
+ conditions.add("ctx.includeFieldIntroducedBy(" + buildFeatureArgument(ann.introducedBy(), regCls) + ")");
+
+ if (!ann.deprecatedBy().isEmpty())
+ conditions.add("ctx.includeFieldDeprecatedBy(" + buildFeatureArgument(ann.deprecatedBy(), regCls) + ")");
+
+ return String.join(" && ", conditions);
+ }
+
+ /** */
+ private String buildFeatureArgument(String featureName, String registryCls) {
+ imports.add(registryCls);
+
+ return registryCls.substring(registryCls.lastIndexOf('.') + 1) + "." + featureName;
+ }
+
+ /** */
+ static String resolveFeatureRegistry(Element declaringCls) {
+ FeatureRegistry ann = declaringCls.getAnnotation(FeatureRegistry.class);
+
+ if (ann == null)
+ return DFLT_FEATURE_REG_CLS;
+
+ try {
+ return ann.value().getName();
+ }
+ catch (MirroredTypeException e) {
+ return qualifiedClassName(e.getTypeMirror());
+ }
+ }
+
/**
* Generate code for processing write of single field:
*
@@ -301,13 +354,27 @@ 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++;
+ String featureCondition = buildFeatureCondition(field);
+
+ if (featureCondition != null) {
+ write.add(indentedLine("if (%s) {", featureCondition));
+
+ indent++;
+ }
+
returnFalseIf(write, "!" + writeExpr);
+ if (featureCondition != null) {
+ indent--;
+
+ write.add(indentedLine("}"));
+ }
+
write.add(EMPTY);
write.add(indentedLine("writer.incrementState();"));
write.add(EMPTY);
@@ -335,11 +402,25 @@ private void readField(VariableElement field, int opt, String readExpr) {
indent++;
+ String featureCondition = buildFeatureCondition(field);
+
+ if (featureCondition != null) {
+ read.add(indentedLine("if (%s) {", featureCondition));
+
+ indent++;
+ }
+
read.add(indentedLine("%s = %s;", fieldRef(field), readExpr));
read.add(EMPTY);
returnFalseIf(read, "!reader.isLastRead()");
+ if (featureCondition != null) {
+ indent--;
+
+ read.add(indentedLine("}"));
+ }
+
read.add(EMPTY);
read.add(indentedLine("reader.incrementState();"));
read.add(EMPTY);
@@ -360,13 +441,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 +456,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 +837,14 @@ private static final class FieldCall {
private final boolean compress;
/** */
- private FieldCall(String mtd, @Nullable String collDesc, boolean compress) {
+ private final boolean requiresCtx;
+
+ /** */
+ private FieldCall(String mtd, @Nullable String collDesc, boolean compress, boolean requiresCtx) {
this.mtd = mtd;
this.collDesc = collDesc;
this.compress = compress;
+ this.requiresCtx = requiresCtx;
}
/** @return Full call expression; {@code valArg}, when given, is passed as the first argument (write side). */
@@ -775,8 +860,26 @@ private String expr(String mtdPrefix, @Nullable String valArg) {
if (compress)
args.add("true");
+ if (requiresCtx)
+ 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..af6bd589e87d0 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 FeatureRegistry
*/
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.FIELD)
public @interface Order {
/** @return Order of the field. */
int value();
+
+ /**
+ * Marks a newly introduced message field. Introducing a new field requires introducing a new
+ * {@link IgniteFeature} to which this element must be linked.
+ *
+ *
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 guarded.
+ */
+ String introducedBy() default "";
+
+ /**
+ * Marks a message field that is planned for removal in a future release. Removing the field requires introducing
+ * a new {@link IgniteFeature} to which this element must be linked.
+ *
+ * An annotated field is excluded from message serialization 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 guarded.
+ */
+ 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..3d53ffca4d302
--- /dev/null
+++ b/modules/commons/src/main/java/org/apache/ignite/internal/MessageSerializationContext.java
@@ -0,0 +1,93 @@
+/*
+ * 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;
+import org.apache.ignite.lang.IgniteFuture;
+
+/**
+ * Represents context that determines how data transmitted between nodes is serialized and deserialized.
+ */
+public interface MessageSerializationContext {
+ /**
+ * @param feature Feature that deprecated the field.
+ * @return {@code true} if the message field should be included during 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 serialization or deserialization.
+ */
+ boolean includeFieldIntroducedBy(IgniteFeature feature);
+
+ /**
+ * {@link MessageSerializationContext} implementation that ignores Rolling Upgrade compatibility during
+ * message serialization.
+ *
+ * Using this context instructs the serialization framework to always serialize the actual message state: all
+ * newly introduced fields are included, and all deprecated fields are excluded.
+ */
+ MessageSerializationContext IGNORED = 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 [IGNORED]";
+ }
+ };
+
+ /**
+ * Stub {@link MessageSerializationContext} implementation used when the serialization context has not yet been determined.
+ *
+ * The serialization context is unavailable between connection establishment and serialization protocol negotiation.
+ * Messages sent during this period cannot rely on the {@link IgniteFuture} mechanism to adjust the message serialization
+ * in an RU-compatible way.
+ */
+ MessageSerializationContext UNNEGOTIATED = 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 [UNNEGOTIATED]";
+ }
+
+ /** */
+ private IllegalStateException buildError(IgniteFeature feature) {
+ return new IllegalStateException(
+ "A feature-guarded 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..816f0344c6326
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/direct/IgniteMessageSerializationContext.java
@@ -0,0 +1,252 @@
+/*
+ * 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.IgniteEx;
+import org.apache.ignite.internal.MessageSerializationContext;
+import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException;
+import org.apache.ignite.internal.managers.discovery.IgniteClusterNode;
+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.spi.discovery.tcp.internal.UnsupportedNodeVersionException;
+import org.jetbrains.annotations.Nullable;
+
+/** */
+public class IgniteMessageSerializationContext implements MessageSerializationContext {
+ /** */
+ private final Map ctxByComponent;
+
+ /** */
+ private IgniteMessageSerializationContext(Map ctxByComponent) {
+ this.ctxByComponent = ctxByComponent;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean includeFieldIntroducedBy(IgniteFeature feature) {
+ return componentContext(feature).includeFieldIntroducedBy(feature.id());
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean includeFieldDeprecatedBy(IgniteFeature feature) {
+ return componentContext(feature).includeFieldDeprecatedBy(feature.id());
+ }
+
+ /** */
+ private ComponentMessageSerializationContext componentContext(IgniteFeature feature) {
+ ComponentMessageSerializationContext cmpCtx = ctxByComponent.get(feature.componentName());
+
+ if (cmpCtx == null) {
+ throw new IllegalStateException(
+ "A field is guarded by a feature of an undeclared component. The component must register its messages " +
+ "and feature set [feature=" + feature + ", component=" + feature.componentName() +
+ ", declaredComponents=" + ctxByComponent.keySet() + ']'
+ );
+ }
+
+ return cmpCtx;
+ }
+
+ /** */
+ public static IgniteMessageSerializationContext buildForPeers(
+ Ignite loc,
+ ClusterNode rmt
+ ) throws UnsupportedNodeVersionException, ClusterTopologyCheckedException {
+ assert rmt instanceof IgniteClusterNode : rmt;
+
+ return buildForPeers(loc, resolveRemoteFeatures((IgniteEx)loc, (IgniteClusterNode)rmt));
+ }
+
+ /** */
+ public static IgniteMessageSerializationContext buildForPeers(
+ Ignite loc,
+ IgniteNodeFeatureSet rmt
+ ) throws UnsupportedNodeVersionException {
+ return buildForPeers(((IgniteEx)loc).context().localNodeFeatures(), 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 @Nullable IgniteNodeFeatureSet resolveRemoteFeatures(
+ IgniteEx loc,
+ IgniteClusterNode rmt
+ ) throws ClusterTopologyCheckedException {
+ IgniteNodeFeatureSet features = rmt.features();
+
+ if (features != null)
+ return features;
+
+ // Node features are unavailable when the node instance was created by Java deserialization
+ // (see {@link GridAffinityAssignment}). In this case, resolve the node again from the
+ // local discovery cache by its ID.
+ ClusterNode cachedNode = loc.context().discovery().node(rmt.id());
+
+ if (cachedNode == null) {
+ throw new ClusterTopologyCheckedException(
+ "Failed to resolve the remote node by ID because it has left the cluster [nodeId=" + rmt.id() + ']');
+ }
+
+ assert cachedNode instanceof IgniteClusterNode : cachedNode;
+
+ return ((IgniteClusterNode)cachedNode).features();
+ }
+
+ /** */
+ private static ComponentMessageSerializationContext resolveComponentSerializationContext(
+ String cmpName,
+ @Nullable IgniteComponentFeatureSet locCmpFeatures,
+ @Nullable IgniteComponentFeatureSet rmtCmpFeatures
+ ) throws UnsupportedNodeVersionException {
+ assert locCmpFeatures != null || rmtCmpFeatures != null;
+
+ 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());
+
+ 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 + ']');
+ }
+
+ return new ComponentMessageSerializationContext(src.features(), src.features());
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return "IgniteMessageSerializationContext " + ctxByComponent;
+ }
+
+ /** {@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 {
+ /** */
+ @Nullable private final IgniteFeatureSet excludedDeprecatedFields;
+
+ /** */
+ @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 "ComponentContext [introduced=" + includedIntroducedFields + ", deprecated=" + excludedDeprecatedFields + ']';
+ }
+ }
+}
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 c0752343b5441..965bf5d930f04 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
@@ -33,6 +33,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.managers.communication.CompressedMessage;
import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
import org.apache.ignite.internal.processors.cache.CacheObject;
@@ -926,11 +927,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;
}
@@ -942,8 +944,10 @@ 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;
@@ -960,7 +964,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;
@@ -978,11 +982,13 @@ 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());
@@ -997,7 +1003,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;
@@ -1016,8 +1022,10 @@ public void writeCollection(Collection col, MessageCollectionType type, M
* @param list List.
* @param type Type.
* @param writer Writer.
+ * @param ctx Serialization context.
*/
- private void writeRandomAccessList(List list, MessageCollectionType type, MessageWriter writer) {
+ private void writeRandomAccessList(List list, MessageCollectionType type, MessageWriter writer,
+ MessageSerializationContext ctx) {
assert list instanceof RandomAccess;
int size = list.size();
@@ -1035,7 +1043,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;
@@ -1050,8 +1058,10 @@ 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());
@@ -1071,7 +1081,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;
@@ -1079,7 +1089,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;
@@ -1555,9 +1565,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;
@@ -1576,7 +1587,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);
@@ -1600,9 +1611,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();
@@ -1617,7 +1629,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;
@@ -1644,9 +1656,11 @@ 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();
@@ -1661,7 +1675,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;
@@ -1696,9 +1710,11 @@ 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();
@@ -1714,7 +1730,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;
@@ -1723,7 +1739,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;
@@ -2003,8 +2019,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);
@@ -2132,17 +2149,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;
@@ -2152,7 +2169,7 @@ protected void write(MessageType type, Object val, MessageWriter writer)
break;
case MSG:
- writeMessage((Message)val, writer);
+ writeMessage((Message)val, writer, ctx);
break;
@@ -2176,9 +2193,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();
@@ -2256,19 +2274,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 sendJoinRequest(boolean recon,
+ @Nullable private T2 sendJoinRequest(boolean recon,
InetSocketAddress addr) throws InterruptedException {
assert addr != null;
@@ -696,18 +695,16 @@ private static void sleepEx(long millis, Runnable before, Runnable after) throws
DiscoveryDataPacket discoveryData = null;
while (true) {
- boolean openSock = false;
+ boolean openSes = false;
- Socket sock = null;
+ TcpDiscoveryIoSession ses = null;
try {
long tsNanos = System.nanoTime();
- sock = spi.openSocket(addr, timeoutHelper);
+ ses = spi.openSession(addr, timeoutHelper);
- openSock = true;
-
- TcpDiscoveryIoSession ses = createSession(sock);
+ openSes = true;
TcpDiscoveryHandshakeRequest req = new TcpDiscoveryHandshakeRequest(locNodeId, locNode.features());
@@ -718,20 +715,20 @@ private static void sleepEx(long millis, Runnable before, Runnable after) throws
TcpDiscoveryHandshakeResponse res = spi.readHandshakeResponse(ses, ackTimeout0);
- spi.validateRemoteFeatures(res.nodeFeatures());
+ ses.rebuildMessageSerializationContext(res.nodeFeatures());
// Convert the addresses once.
Collection redirectAddrs = res.redirectAddresses();
if (redirectAddrs != null) {
- U.closeQuiet(sock);
+ U.closeQuiet(ses);
- openSock = false;
+ openSes = false;
if (log.isInfoEnabled())
log.info("Reconnecting to the addresses of a proper DC [addrs=" + redirectAddrs + ']');
- T2> redirectedRes = sendJoinRequests(recon, redirectAddrs);
+ T2> redirectedRes = sendJoinRequests(recon, redirectAddrs);
return redirectedRes.get2();
}
@@ -783,10 +780,10 @@ private static void sleepEx(long millis, Runnable before, Runnable after) throws
log.debug("Message has been sent to address [msg=" + msg + ", addr=" + addr +
", rmtNodeId=" + rmtNodeId + ']');
- return new T2<>(new SocketStream(sock, ses), spi.readReceipt(sock, timeoutHelper.nextTimeoutChunk(ackTimeout0)));
+ return new T2<>(ses, spi.readReceipt(ses, timeoutHelper.nextTimeoutChunk(ackTimeout0)));
}
catch (IOException | IgniteCheckedException e) {
- U.closeQuiet(sock);
+ U.closeQuiet(ses);
if (log.isDebugEnabled())
log.error("Exception on joining: " + e.getMessage(), e);
@@ -836,7 +833,7 @@ private static void sleepEx(long millis, Runnable before, Runnable after) throws
if (!spi.failureDetectionTimeoutEnabled() && ++reconCnt == spi.getReconnectCount())
break;
- if (!openSock) {
+ if (!openSes) {
// Reconnect for the second time, if connection is not established.
if (connectAttempts < 2) {
connectAttempts++;
@@ -968,10 +965,10 @@ private NavigableSet allVisibleNodes() {
/** {@inheritDoc} */
@Override public void brakeConnection() {
- SocketStream sockStream = msgWorker.currSock;
+ TcpDiscoveryIoSession ses = msgWorker.currSes;
- if (sockStream != null)
- U.closeQuiet(sockStream.socket());
+ if (ses != null)
+ U.closeQuiet(ses);
}
/** {@inheritDoc} */
@@ -1093,7 +1090,7 @@ private class SocketReader extends IgniteSpiThread {
private final Object mux = new Object();
/** */
- private SocketStream sockStream;
+ private TcpDiscoveryIoSession ses;
/** */
private UUID rmtNodeId;
@@ -1108,12 +1105,12 @@ private class SocketReader extends IgniteSpiThread {
}
/**
- * @param sockStream Socket.
+ * @param ses IO session.
* @param rmtNodeId Rmt node id.
*/
- void setSocket(SocketStream sockStream, UUID rmtNodeId) {
+ void onRemoteSessionReady(TcpDiscoveryIoSession ses, UUID rmtNodeId) {
synchronized (mux) {
- this.sockStream = sockStream;
+ this.ses = ses;
this.rmtNodeId = rmtNodeId;
@@ -1128,16 +1125,14 @@ private void forceStopRead() throws InterruptedException {
CountDownLatch stopReadLatch;
synchronized (mux) {
- SocketStream stream = sockStream;
-
- if (stream == null)
+ if (ses == null)
return;
this.stopReadLatch = stopReadLatch = new CountDownLatch(1);
- U.closeQuiet(stream.socket());
+ U.closeQuiet(ses);
- this.sockStream = null;
+ this.ses = null;
this.rmtNodeId = null;
mux.notifyAll();
@@ -1149,7 +1144,7 @@ private void forceStopRead() throws InterruptedException {
/** {@inheritDoc} */
@Override protected void body() throws InterruptedException {
while (!isInterrupted()) {
- SocketStream sockStream;
+ TcpDiscoveryIoSession ses;
UUID rmtNodeId;
// Disconnected from router node.
@@ -1162,38 +1157,35 @@ private void forceStopRead() throws InterruptedException {
stopReadLatch = null;
}
- if (this.sockStream == null) {
+ if (this.ses == null) {
mux.wait();
continue;
}
- sockStream = this.sockStream;
+ ses = this.ses;
rmtNodeId = this.rmtNodeId;
}
- Socket sock = sockStream.socket();
-
U.enhanceThreadName(U.id8(rmtNodeId)
- + ' ' + sockStream.sock.getInetAddress().getHostAddress()
- + ":" + sockStream.sock.getPort());
+ + ' ' + ses.socket().getInetAddress().getHostAddress()
+ + ":" + ses.socket().getPort());
try {
- TcpDiscoveryIoSession ses = sockStream.session();
-
- assert sock.getKeepAlive() && sock.getTcpNoDelay() : "Socket wasn't configured properly:" +
- " KeepAlive " + sock.getKeepAlive() +
- " TcpNoDelay " + sock.getTcpNoDelay();
+ assert ses.socket().getKeepAlive() && ses.socket().getTcpNoDelay() :
+ "Socket wasn't configured properly:" +
+ " KeepAlive " + ses.socket().getKeepAlive() +
+ " TcpNoDelay " + ses.socket().getTcpNoDelay();
while (!isInterrupted()) {
TcpDiscoveryAbstractMessage msg;
try {
- msg = spi.readMessage(ses, sock.getSoTimeout());
+ msg = spi.readMessage(ses, ses.socket().getSoTimeout());
}
catch (IgniteCheckedException e) {
if (log.isDebugEnabled())
- U.error(log, "Failed to read message [sock=" + sock + ", " +
+ U.error(log, "Failed to read message [ses=" + ses + ", " +
"locNodeId=" + getLocalNodeId() + ", rmtNodeId=" + rmtNodeId + ']', e);
// Exists possibility that exception raised on interruption.
@@ -1213,7 +1205,7 @@ private void forceStopRead() throws InterruptedException {
"(make sure same versions of all classes are available on all nodes) " +
"[rmtNodeId=" + rmtNodeId + ", err=" + clsNotFoundEx.getMessage() + ']');
else
- LT.error(log, e, "Failed to read message [sock=" + sock + ", locNodeId=" +
+ LT.error(log, e, "Failed to read message [ses=" + ses + ", locNodeId=" +
getLocalNodeId() + ", rmtNodeId=" + rmtNodeId + ']');
continue;
@@ -1237,17 +1229,17 @@ private void forceStopRead() throws InterruptedException {
}
}
catch (IOException e) {
- msgWorker.addMessage(new SocketClosedMessage(sockStream));
+ msgWorker.addMessage(new SessionClosedMessage(ses));
if (log.isDebugEnabled())
- U.error(log, "Connection failed [sock=" + sock + ", locNodeId=" + getLocalNodeId() + ']', e);
+ U.error(log, "Connection failed [ses=" + ses + ", locNodeId=" + getLocalNodeId() + ']', e);
}
finally {
- U.closeQuiet(sock);
+ U.closeQuiet(ses);
synchronized (mux) {
- if (this.sockStream == sockStream) {
- this.sockStream = null;
+ if (this.ses == ses) {
+ this.ses = null;
this.rmtNodeId = null;
}
}
@@ -1263,9 +1255,6 @@ private class SocketWriter extends IgniteSpiThread {
/** */
private final Object mux = new Object();
- /** */
- private Socket sock;
-
/** */
private TcpDiscoveryIoSession ses;
@@ -1314,7 +1303,7 @@ private void forceLeave() throws InterruptedException {
synchronized (mux) {
// If writer was stopped.
- if (sock == null)
+ if (ses == null)
return;
this.forceLeaveLatch = forceLeaveLatch = new CountDownLatch(1);
@@ -1327,14 +1316,10 @@ private void forceLeave() throws InterruptedException {
forceLeaveLatch.await();
}
- /**
- * @param sock Socket.
- */
- private void setSocket(Socket sock) {
+ /** */
+ private void onRemoteSessionReady(TcpDiscoveryIoSession ses) {
synchronized (mux) {
- this.sock = sock;
-
- ses = createSession(sock);
+ this.ses = ses;
unackedMsg = null;
@@ -1347,7 +1332,7 @@ private void setSocket(Socket sock) {
*/
public boolean isOnline() {
synchronized (mux) {
- return sock != null;
+ return ses != null;
}
}
@@ -1371,12 +1356,12 @@ void ackReceived(TcpDiscoveryClientAckResponse res) {
TcpDiscoveryAbstractMessage msg = null;
while (!Thread.currentThread().isInterrupted()) {
- Socket sock;
+ TcpDiscoveryIoSession ses;
synchronized (mux) {
- sock = this.sock;
+ ses = this.ses;
- if (sock == null) {
+ if (ses == null) {
mux.wait();
continue;
@@ -1397,9 +1382,9 @@ void ackReceived(TcpDiscoveryClientAckResponse res) {
}
}
- U.closeQuiet(sock);
+ U.closeQuiet(ses);
- this.sock = null;
+ this.ses = null;
clear();
@@ -1490,11 +1475,11 @@ void ackReceived(TcpDiscoveryClientAckResponse res) {
else
U.error(log, "Failed to send message: " + msg, e);
- U.closeQuiet(sock);
+ U.closeQuiet(ses);
synchronized (mux) {
- if (sock == this.sock)
- this.sock = null; // Connection has dead.
+ if (ses == this.ses)
+ this.ses = null; // Connection has dead.
clear();
}
@@ -1526,7 +1511,7 @@ private void clear() {
*/
private class Reconnector extends IgniteSpiThread {
/** */
- private volatile SocketStream sockStream;
+ private volatile TcpDiscoveryIoSession ses;
/** */
private final boolean join;
@@ -1551,10 +1536,9 @@ protected Reconnector(boolean join, InetSocketAddress prevAddr) {
public void cancel() {
interrupt();
- SocketStream sockStream = this.sockStream;
+ TcpDiscoveryIoSession ses = this.ses;
- if (sockStream != null)
- U.closeQuiet(sockStream.socket());
+ U.closeQuiet(ses);
}
/** {@inheritDoc} */
@@ -1572,9 +1556,9 @@ public void cancel() {
try {
while (true) {
- SocketStream joinRes = joinTopology(prevAddr, timeout, null, null);
+ TcpDiscoveryIoSession ses = joinTopology(prevAddr, timeout, null, null);
- if (joinRes == null) {
+ if (ses == null) {
if (join) {
joinError(new IgniteSpiException("Join process timed out, connection failed and " +
"failed to reconnect (consider increasing 'joinTimeout' configuration property) " +
@@ -1587,29 +1571,21 @@ public void cancel() {
return;
}
- sockStream = joinRes;
-
- Socket sock = sockStream.socket();
- TcpDiscoveryIoSession ses = sockStream.session();
+ this.ses = ses;
if (isInterrupted())
throw new InterruptedException();
- int oldTimeout = 0;
-
try {
- oldTimeout = sock.getSoTimeout();
-
- sock.setSoTimeout((int)spi.netTimeout);
-
- assert sock.getKeepAlive() && sock.getTcpNoDelay() : "Socket wasn't configured properly:" +
- " KeepAlive " + sock.getKeepAlive() +
- " TcpNoDelay " + sock.getTcpNoDelay();
+ assert ses.socket().getKeepAlive() && ses.socket().getTcpNoDelay() :
+ "Socket wasn't configured properly:" +
+ " KeepAlive " + ses.socket().getKeepAlive() +
+ " TcpNoDelay " + ses.socket().getTcpNoDelay();
List msgs = null;
while (!isInterrupted()) {
- TcpDiscoveryAbstractMessage msg = spi.readMessage(ses, sock.getSoTimeout());
+ TcpDiscoveryAbstractMessage msg = spi.readMessage(ses, spi.netTimeout);
if (msg instanceof TcpDiscoveryClientReconnectMessage) {
TcpDiscoveryClientReconnectMessage res = (TcpDiscoveryClientReconnectMessage)msg;
@@ -1644,7 +1620,7 @@ else if (spi.ensured(msg)) {
}
}
catch (IOException | IgniteCheckedException e) {
- U.closeQuiet(sock);
+ U.closeQuiet(ses);
if (log.isDebugEnabled())
log.error("Reconnect error [join=" + join + ", timeout=" + timeout + ']', e);
@@ -1662,10 +1638,6 @@ else if (spi.ensured(msg)) {
else
U.warn(log, "Failed to reconnect to cluster (will retry): " + e);
}
- finally {
- if (success)
- sock.setSoTimeout(oldTimeout);
- }
}
}
catch (IOException | IgniteCheckedException e) {
@@ -1677,10 +1649,9 @@ else if (spi.ensured(msg)) {
}
finally {
if (!success) {
- SocketStream sockStream = this.sockStream;
+ TcpDiscoveryIoSession ses = this.ses;
- if (sockStream != null)
- U.closeQuiet(sockStream.socket());
+ U.closeQuiet(ses);
if (join)
joinError(new IgniteSpiException("Failed to connect to cluster, connection failed and failed " +
@@ -1700,7 +1671,7 @@ protected class MessageWorker extends GridWorker {
private final BlockingDeque queue = new LinkedBlockingDeque<>();
/** */
- private SocketStream currSock;
+ private TcpDiscoveryIoSession currSes;
/** */
private Reconnector reconnector;
@@ -1751,7 +1722,7 @@ private MessageWorker(IgniteLogger log) {
if (state == STARTING) {
joinError(new IgniteSpiException("Join process timed out, did not receive response for " +
"join request (consider increasing 'joinTimeout' configuration property) " +
- "[joinTimeout=" + spi.joinTimeout + ", sock=" + currSock + ']'));
+ "[joinTimeout=" + spi.joinTimeout + ", ses=" + currSes + ']'));
break;
}
@@ -1774,7 +1745,7 @@ else if (msg == SPI_STOP) {
assert spi.getSpiContext().isStopping();
- if (connected && currSock != null) {
+ if (connected && currSes != null) {
TcpDiscoveryNodeLeftMessage leftMsg = new TcpDiscoveryNodeLeftMessage(getLocalNodeId());
leftMsg.client(true);
@@ -1796,7 +1767,7 @@ else if (msg == SPI_RECONNECT) {
sockWriter.forceLeave();
sockReader.forceStopRead();
- currSock = null;
+ currSes = null;
queue.clear();
@@ -1824,13 +1795,13 @@ else if (msg instanceof TcpDiscoveryNodeFailedMessage &&
forceFailMsg = msg0;
}
- else if (msg instanceof SocketClosedMessage) {
- if (((SocketClosedMessage)msg).sock == currSock) {
- Socket sock = currSock.sock;
-
- InetSocketAddress prevAddr = new InetSocketAddress(sock.getInetAddress(), sock.getPort());
+ else if (msg instanceof SessionClosedMessage sesClosedMsg) {
+ if (sesClosedMsg.ses == currSes) {
+ InetSocketAddress prevAddr = new InetSocketAddress(
+ currSes.socket().getInetAddress(),
+ currSes.socket().getPort());
- currSock = null;
+ currSes = null;
boolean join = joinLatch.getCount() > 0;
@@ -1990,10 +1961,10 @@ else if (discoMsg instanceof TcpDiscoveryCheckFailedMessage)
((IgniteEx)spi.ignite()).context().failure().process(new FailureContext(CRITICAL_ERROR, t));
}
finally {
- SocketStream currSock = this.currSock;
+ TcpDiscoveryIoSession ses = this.currSes;
- if (currSock != null)
- U.closeQuiet(currSock.socket());
+ if (ses != null)
+ U.closeQuiet(ses);
if (joinLatch.getCount() > 0)
joinError(new IgniteSpiException("Some error in join process.")); // This should not occur.
@@ -2072,10 +2043,10 @@ private void tryJoin() throws InterruptedException {
joinCnt++;
- SocketStream joinRes;
+ TcpDiscoveryIoSession ses;
try {
- joinRes = joinTopology(null, spi.joinTimeout,
+ ses = joinTopology(null, spi.joinTimeout,
new Runnable() {
@Override public void run() {
blockingSectionBegin();
@@ -2093,7 +2064,7 @@ private void tryJoin() throws InterruptedException {
return;
}
- if (joinRes == null) {
+ if (ses == null) {
if (join)
joinError(new IgniteSpiException("Join process timed out (timeout = " + spi.joinTimeout + ")."));
else {
@@ -2105,9 +2076,9 @@ private void tryJoin() throws InterruptedException {
return;
}
- currSock = joinRes;
+ currSes = ses;
- sockWriter.setSocket(joinRes.socket());
+ sockWriter.onRemoteSessionReady(ses);
if (spi.joinTimeout > 0) {
final int joinCnt0 = joinCnt;
@@ -2117,7 +2088,7 @@ private void tryJoin() throws InterruptedException {
}, spi.joinTimeout, MILLISECONDS);
}
- sockReader.setSocket(joinRes, locNode.clientRouterNodeId());
+ sockReader.onRemoteSessionReady(ses, locNode.clientRouterNodeId());
}
/** */
@@ -2519,11 +2490,12 @@ private void processClientReconnectMessage(TcpDiscoveryClientReconnectMessage ms
if (getLocalNodeId().equals(msg.creatorNodeId())) {
if (reconnector != null) {
assert msg.success() : msg;
+ assert reconnector.ses != null : msg;
- currSock = reconnector.sockStream;
+ currSes = reconnector.ses;
- sockWriter.setSocket(currSock.socket());
- sockReader.setSocket(currSock, locNode.clientRouterNodeId());
+ sockWriter.onRemoteSessionReady(currSes);
+ sockReader.onRemoteSessionReady(currSes, locNode.clientRouterNodeId());
reconnector = null;
@@ -2707,62 +2679,14 @@ private JoinTimeout(int joinCnt) {
/**
*
*/
- private static class SocketClosedMessage {
- /** */
- private final SocketStream sock;
-
- /**
- * @param sock Socket.
- */
- private SocketClosedMessage(SocketStream sock) {
- this.sock = sock;
- }
- }
-
- /**
- *
- */
- private static class SocketStream {
+ private static class SessionClosedMessage {
/** */
- private final Socket sock;
-
- /**
- * The only session ever used to read messages from the socket. Shared by all socket users
- * ({@link Reconnector}, {@link SocketReader}), otherwise messages buffered by one session's
- * read-ahead would be lost when another session takes the socket over.
- */
private final TcpDiscoveryIoSession ses;
- /**
- * @param sock Socket.
- * @param ses Session bound to the socket.
- */
- SocketStream(Socket sock, TcpDiscoveryIoSession ses) {
- assert sock != null;
- assert ses != null;
-
- this.sock = sock;
+ /** */
+ private SessionClosedMessage(TcpDiscoveryIoSession ses) {
this.ses = ses;
}
-
- /**
- * @return Socket.
- */
- Socket socket() {
- return sock;
- }
-
- /**
- * @return Session bound to the socket.
- */
- TcpDiscoveryIoSession session() {
- return ses;
- }
-
- /** {@inheritDoc} */
- @Override public String toString() {
- return sock.toString();
- }
}
/**
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java
index fe86a1c789b42..8ca5cd0c1d746 100644
--- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java
@@ -100,7 +100,6 @@
import org.apache.ignite.internal.util.typedef.C1;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.P1;
-import org.apache.ignite.internal.util.typedef.T2;
import org.apache.ignite.internal.util.typedef.X;
import org.apache.ignite.internal.util.typedef.internal.LT;
import org.apache.ignite.internal.util.typedef.internal.S;
@@ -124,8 +123,10 @@
import org.apache.ignite.spi.discovery.DiscoverySpiCustomMessage;
import org.apache.ignite.spi.discovery.DiscoverySpiListener;
import org.apache.ignite.spi.discovery.IgniteDiscoveryThread;
+import org.apache.ignite.spi.discovery.tcp.internal.ClientMessageHolder;
import org.apache.ignite.spi.discovery.tcp.internal.DiscoveryDataPacket;
import org.apache.ignite.spi.discovery.tcp.internal.FutureTask;
+import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoveryMessageSerializer;
import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoveryNode;
import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoveryNodesRing;
import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoverySpiState;
@@ -950,9 +951,7 @@ private boolean pingNode(TcpDiscoveryNode node) {
fut.sock = sock;
- sock = spi.openSocket(sock, addr, timeoutHelper);
-
- TcpDiscoveryIoSession ses = createSession(sock);
+ TcpDiscoveryIoSession ses = spi.openSession(sock, addr, timeoutHelper);
spi.writeMessage(ses, new TcpDiscoveryPingRequest(locNodeId, clientNodeId),
timeoutHelper.nextTimeoutChunk(spi.getSocketTimeout()));
@@ -1497,13 +1496,12 @@ else if (U.millisSinceNanos(joinStartNanos) > spi.joinTimeout)
boolean openSock = false;
- Socket sock = null;
+ TcpDiscoveryIoSession ses = null;
try {
long tsNanos = System.nanoTime();
- sock = spi.openSocket(addr, timeoutHelper);
- TcpDiscoveryIoSession ses = createSession(sock);
+ ses = spi.openSession(addr, timeoutHelper);
openSock = true;
@@ -1514,7 +1512,7 @@ else if (U.millisSinceNanos(joinStartNanos) > spi.joinTimeout)
TcpDiscoveryHandshakeResponse res = spi.readHandshakeResponse(ses, timeoutHelper.nextTimeoutChunk(ackTimeout0));
- spi.validateRemoteFeatures(res.nodeFeatures());
+ ses.rebuildMessageSerializationContext(res.nodeFeatures());
if (msg instanceof TcpDiscoveryJoinRequestMessage) {
boolean ignore = false;
@@ -1564,7 +1562,7 @@ else if (U.millisSinceNanos(joinStartNanos) > spi.joinTimeout)
// E.g. due to class not found issue.
joinReqSent = msg instanceof TcpDiscoveryJoinRequestMessage;
- int receipt = spi.readReceipt(sock, timeoutHelper.nextTimeoutChunk(ackTimeout0));
+ int receipt = spi.readReceipt(ses, timeoutHelper.nextTimeoutChunk(ackTimeout0));
spi.stats.onMessageSent(msg, U.nanosToMillis(tsNanos0 - tsNanos));
@@ -1652,7 +1650,7 @@ else if (U.millisSinceNanos(joinStartNanos) > spi.joinTimeout)
}
}
finally {
- U.closeQuiet(sock);
+ U.closeQuiet(ses);
}
}
@@ -1993,10 +1991,7 @@ private void clearNodeAddedMessage(TcpDiscoveryAbstractMessage msg) {
/** {@inheritDoc} */
@Override public void brakeConnection() {
- Socket sock = msgWorker.sock;
-
- if (sock != null)
- U.closeQuiet(sock);
+ U.closeQuiet(msgWorker.ses);
}
/** {@inheritDoc} */
@@ -2864,9 +2859,6 @@ protected class RingMessageWorker extends MessageWorker connLsnr : spi.incomeConnLsnrs)
connLsnr.apply(sock);
- byte[] buf = new byte[4];
- int read = 0;
-
- while (read < buf.length) {
- int r = sock.getInputStream().read(buf, read, buf.length - read);
-
- if (r >= 0)
- read += r;
- else {
- if (log.isDebugEnabled())
- log.debug("Failed to read magic header (too few bytes received) " +
- "[rmtAddr=" + rmtAddr +
- ", locAddr=" + sock.getLocalSocketAddress() + ']');
-
- LT.warn(log, "Failed to read magic header (too few bytes received) [rmtAddr=" +
- rmtAddr + ", locAddr=" + sock.getLocalSocketAddress() + ']');
-
- return;
- }
- }
-
- if (!Arrays.equals(buf, U.IGNITE_HEADER)) {
- if (log.isDebugEnabled())
- log.debug("Unknown connection detected (possible reasons: an incompatible Ignite node or " +
- "other software connecting to this Ignite port" +
- (!spi.isSslEnabled() ? ", or missing SSL configuration on remote node" : "") +
- ") [rmtAddr=" + rmtAddr +
- ", locAddr=" + sock.getLocalSocketAddress() +
- ", rcvdHdr=" + U.byteArray2HexString(buf) + ']');
-
- LT.warn(log, "Unknown connection detected (possible reasons: an incompatible Ignite node or " +
- "other software connecting to this Ignite port" +
- (!spi.isSslEnabled() ? ", or missing SSL configuration on remote node" : "") +
- ") [rmtAddr=" + sock.getInetAddress() + ", rcvdHdr=" + U.byteArray2HexString(buf) + ']', true);
-
+ if (!spi.readMagicHeader(ses, spi.netTimeout))
return;
- }
-
- // Restore timeout.
- sock.setSoTimeout(timeout);
TcpDiscoveryAbstractMessage msg = spi.readMessage(ses, spi.netTimeout);
@@ -6717,7 +6664,7 @@ else if (log.isInfoEnabled()) {
spi.writeMessage(ses, res, spi.getEffectiveSocketTimeout(srvSock));
- spi.validateRemoteFeatures(req.nodeFeatures());
+ ses.rebuildMessageSerializationContext(req.nodeFeatures());
// It can happen if a remote node is stopped and it has a loopback address in the list of addresses,
// the local node sends a handshake request message on the loopback address, so we get here.
@@ -6731,7 +6678,7 @@ else if (log.isInfoEnabled()) {
}
if (req.client()) {
- ClientMessageWorker clientMsgWrk0 = new ClientMessageWorker(sock, nodeId, log);
+ ClientMessageWorker clientMsgWrk0 = new ClientMessageWorker(ses, nodeId, log);
while (true) {
ClientMessageWorker old = clientMsgWorkers.putIfAbsent(nodeId, clientMsgWrk0);
@@ -6757,7 +6704,7 @@ else if (log.isInfoEnabled()) {
log.debug("Already have client message worker, closing connection " +
"[locNodeId=" + locNodeId +
", rmtNodeId=" + nodeId +
- ", workerSock=" + old.sock +
+ ", workerSes=" + old.ses +
", sock=" + sock + ']');
return;
@@ -6861,7 +6808,7 @@ else if (e.hasCause(ObjectStreamException.class) || (!sock.isClosed() && !e.hasC
if (msg instanceof TcpDiscoveryConnectionCheckMessage) {
ringMessageReceived();
- spi.writeToSocket(sock, RES_OK, sockTimeout);
+ spi.writeReceipt(ses, RES_OK, sockTimeout);
continue;
}
@@ -6887,7 +6834,7 @@ else if (msg instanceof TcpDiscoveryClientReconnectMessage) {
TcpDiscoverySpiState state = spiStateCopy();
if (state == CONNECTED) {
- spi.writeToSocket(sock, RES_OK, sockTimeout);
+ spi.writeReceipt(ses, RES_OK, sockTimeout);
if (clientMsgWrk != null && clientMsgWrk.runner() == null && !clientMsgWrk.isDone())
new MessageWorkerThreadWithCleanup<>(clientMsgWrk, log).start();
@@ -6901,21 +6848,21 @@ else if (msg instanceof TcpDiscoveryClientReconnectMessage) {
// If message is received from previous node and node is connecting forward to next node.
if (!getLocalNodeId().equals(msg0.routerNodeId()) && state == CONNECTING) {
- spi.writeToSocket(sock, RES_OK, sockTimeout);
+ spi.writeReceipt(ses, RES_OK, sockTimeout);
msgWorker.addMessage(msg);
continue;
}
- spi.writeToSocket(sock, RES_CONTINUE_JOIN, sockTimeout);
+ spi.writeReceipt(ses, RES_CONTINUE_JOIN, sockTimeout);
break;
}
}
else if (msg instanceof TcpDiscoveryDuplicateIdMessage) {
// Send receipt back.
- spi.writeToSocket(sock, RES_OK, sockTimeout);
+ spi.writeReceipt(ses, RES_OK, sockTimeout);
boolean ignored = false;
@@ -6944,7 +6891,7 @@ else if (msg instanceof TcpDiscoveryDuplicateIdMessage) {
}
else if (msg instanceof TcpDiscoveryAuthFailedMessage) {
// Send receipt back.
- spi.writeToSocket(sock, RES_OK, sockTimeout);
+ spi.writeReceipt(ses, RES_OK, sockTimeout);
synchronized (mux) {
if (spiState == CONNECTING) {
@@ -6972,7 +6919,7 @@ else if (msg instanceof TcpDiscoveryAuthFailedMessage) {
}
else if (msg instanceof TcpDiscoveryCheckFailedMessage) {
// Send receipt back.
- spi.writeToSocket(sock, RES_OK, sockTimeout);
+ spi.writeReceipt(ses, RES_OK, sockTimeout);
boolean ignored = false;
@@ -7015,7 +6962,7 @@ else if (msg instanceof TcpDiscoveryCheckFailedMessage) {
}
else if (msg instanceof TcpDiscoveryLoopbackProblemMessage) {
// Send receipt back.
- spi.writeToSocket(sock, RES_OK, sockTimeout);
+ spi.writeReceipt(ses, RES_OK, sockTimeout);
boolean ignored = false;
@@ -7080,7 +7027,7 @@ else if (msg instanceof TcpDiscoveryRingLatencyCheckMessage) {
clientMsgWrk.addMessage(ack);
}
else
- spi.writeToSocket(sock, RES_OK, sockTimeout);
+ spi.writeReceipt(ses, RES_OK, sockTimeout);
if (metricsUpdateMsg != null)
processClientMetricsUpdateMessage(metricsUpdateMsg);
@@ -7155,7 +7102,7 @@ else if (msg instanceof TcpDiscoveryRingLatencyCheckMessage) {
U.interrupt(clientMsgWrk.runner());
}
- U.close(sock, log);
+ ses.close(log);
if (log.isInfoEnabled()) {
log.info("Finished serving remote node connection [rmtAddr=" + rmtAddr +
@@ -7398,13 +7345,13 @@ private boolean processJoinRequestMessage(
// Check that joining node can accept incoming connections.
if (node.clientRouterNodeId() == null) {
if (!pingJoiningNode(node)) {
- spi.writeToSocket(sock, RES_JOIN_IMPOSSIBLE, sockTimeout);
+ spi.writeReceipt(ses, RES_JOIN_IMPOSSIBLE, sockTimeout);
return false;
}
}
- spi.writeToSocket(sock, RES_OK, sockTimeout);
+ spi.writeReceipt(ses, RES_OK, sockTimeout);
if (log.isDebugEnabled())
log.debug("Responded to join request message [msg=" + msg + ", res=" + RES_OK + ']');
@@ -7441,7 +7388,7 @@ private boolean processJoinRequestMessage(
// Local node is stopping. Remote node should try next one.
res = RES_CONTINUE_JOIN;
- spi.writeToSocket(sock, res, sockTimeout);
+ spi.writeReceipt(ses, res, sockTimeout);
if (log.isDebugEnabled())
log.debug("Responded to join request message [msg=" + msg + ", res=" + res + ']');
@@ -7486,14 +7433,14 @@ private boolean pingJoiningNode(TcpDiscoveryNode node) {
@Override public void interrupt() {
super.interrupt();
- U.closeQuiet(sock);
+ U.closeQuiet(ses);
}
/** {@inheritDoc} */
@Override protected void cleanup() {
super.cleanup();
- U.closeQuiet(sock);
+ U.closeQuiet(ses);
synchronized (mux) {
readers.remove(this);
@@ -7538,23 +7485,12 @@ private class StatisticsPrinter extends IgniteSpiThread {
}
/** */
- private class ClientMessageWorker extends MessageWorker> {
+ private class ClientMessageWorker extends MessageWorker {
/** Node ID. */
private final UUID clientNodeId;
- // The code responsible for sending and receiving messages to and from client nodes represents a special case in ServerImpl,
- // as it is split into two separate components.
- // One part, ClientMessageWorker, handles only message sending to clients and does not process responses.
- // The other part, which reads messages from clients, is implemented in SocketReader.
- // Due to this separation, we don't require a full TcpDiscoveryIoSession here
- // and can instead extract just the message-writing functionality.
- // At the same time, we aim to keep both reading and writing logic encapsulated within TcpDiscoveryIoSession.
- // As a result, we need to copy some code from TcpDiscoveryIoSession into the new class, TcpDiscoveryMessageSerializer.
- /** */
- private final TcpDiscoveryMessageSerializer clientMsgSer;
-
- /** Socket. */
- private final Socket sock;
+ /** Session shared with the socket reader serving the same client connection. */
+ private final TcpDiscoveryIoSession ses;
/** Current client metrics. */
private volatile ClusterMetrics metrics;
@@ -7569,29 +7505,32 @@ private class ClientMessageWorker extends MessageWorker()
);
- this.sock = sock;
+ this.ses = ses;
this.clientNodeId = clientNodeId;
- clientMsgSer = new TcpDiscoveryMessageSerializer(spi);
-
lastMetricsUpdateMsgTimeNanos = System.nanoTime();
}
+ /** */
+ TcpDiscoveryIoSession session() {
+ return ses;
+ }
+
/**
* @param clientVer Client version.
*/
@@ -7615,24 +7554,19 @@ void metrics(ClusterMetrics metrics) {
this.metrics = metrics;
}
- /**
- * @param msg Message.
- */
+ /** @param msg Discovery Message. */
void addMessage(TcpDiscoveryAbstractMessage msg) {
- addMessage(msg, null);
+ addMessage(new ClientMessageHolder(msg));
}
- /**
- * @param msg Message.
- * @param msgBytes Optional message bytes.
- */
- void addMessage(TcpDiscoveryAbstractMessage msg, @Nullable byte[] msgBytes) {
- T2 t = new T2<>(msg, msgBytes);
+ /** @param msgHolder Holder of a Discovery Message to send to the client. */
+ void addMessage(ClientMessageHolder msgHolder) {
+ TcpDiscoveryAbstractMessage msg = msgHolder.message();
if (msg.highPriority())
- queue.addFirst(t);
+ queue.addFirst(msgHolder);
else
- queue.add(t);
+ queue.add(msgHolder);
DebugLogger log = messageLogger(msg);
@@ -7641,10 +7575,10 @@ void addMessage(TcpDiscoveryAbstractMessage msg, @Nullable byte[] msgBytes) {
}
/** {@inheritDoc} */
- @Override protected void processMessage(T2 msgT) {
+ @Override protected void processMessage(ClientMessageHolder msgHolder) {
boolean success = false;
- TcpDiscoveryAbstractMessage msg = msgT.get1();
+ TcpDiscoveryAbstractMessage msg = msgHolder.message();
try {
assert msg.verified() : msg;
@@ -7659,30 +7593,31 @@ void addMessage(TcpDiscoveryAbstractMessage msg, @Nullable byte[] msgBytes) {
clientVer = IgniteUtils.productVersion(node);
else if (msgLog.isDebugEnabled()) {
msgLog.debug("Skip sending message ack to client, fail to get client node " +
- "[sock=" + sock + ", locNodeId=" + getLocalNodeId() +
+ "[ses=" + ses + ", locNodeId=" + getLocalNodeId() +
", rmtNodeId=" + clientNodeId + ", msg=" + msg + ']');
}
}
if (clientVer != null) {
if (msgLog.isDebugEnabled()) {
- msgLog.debug("Sending message ack to client [sock=" + sock + ", locNodeId="
+ msgLog.debug("Sending message ack to client [ses=" + ses + ", locNodeId="
+ getLocalNodeId() + ", rmtNodeId=" + clientNodeId + ", msg=" + msg + ']');
}
- writeToSocket(msgT, spi.failureDetectionTimeoutEnabled() ? spi.clientFailureDetectionTimeout() :
- spi.getSocketTimeout());
+ long timeout = spi.failureDetectionTimeoutEnabled() ? spi.clientFailureDetectionTimeout() : spi.getSocketTimeout();
+
+ writeMessage(msgHolder, timeout);
}
}
else {
if (msgLog.isDebugEnabled()) {
- msgLog.debug("Redirecting message to client [sock=" + sock + ", locNodeId="
+ msgLog.debug("Redirecting message to client [ses=" + ses + ", locNodeId="
+ getLocalNodeId() + ", rmtNodeId=" + clientNodeId + ", msg=" + msg + ']');
}
assert topologyInitialized(msg) : msg;
- writeToSocket(msgT, spi.getEffectiveSocketTimeout(false));
+ writeMessage(msgHolder, spi.getEffectiveSocketTimeout(false));
}
boolean clientFailed = msg instanceof TcpDiscoveryNodeFailedMessage &&
@@ -7694,10 +7629,10 @@ else if (msgLog.isDebugEnabled()) {
}
catch (IgniteCheckedException | IOException e) {
if (log.isDebugEnabled())
- U.error(log, "Client connection failed [sock=" + sock + ", locNodeId="
+ U.error(log, "Client connection failed [ses=" + ses + ", locNodeId="
+ getLocalNodeId() + ", rmtNodeId=" + clientNodeId + ", msg=" + msg + ']', e);
- onException("Client connection failed [sock=" + sock + ", locNodeId="
+ onException("Client connection failed [ses=" + ses + ", locNodeId="
+ getLocalNodeId() + ", rmtNodeId=" + clientNodeId + ", msg=" + msg + ']', e);
}
finally {
@@ -7706,20 +7641,22 @@ else if (msgLog.isDebugEnabled()) {
U.interrupt(runner());
- U.close(sock, log);
+ ses.close(log);
}
}
}
/**
- * @param msgT Message tuple.
+ * @param msgHolder Message holder.
* @param timeout Timeout.
*/
- private void writeToSocket(T2 msgT, long timeout)
- throws IgniteCheckedException, IOException {
- byte[] msgBytes = msgT.get2() == null ? clientMsgSer.serializeMessage(msgT.get1()) : msgT.get2();
+ private void writeMessage(ClientMessageHolder msgHolder, long timeout) throws IgniteCheckedException, IOException {
+ byte[] msgBytes = msgHolder.messageBytes(ses.serializationContext());
- spi.writeToSocket(sock, msgBytes, timeout);
+ if (msgBytes != null)
+ spi.write(ses, msgBytes, timeout);
+ else
+ spi.writeMessage(ses, msgHolder.message(), timeout);
}
/**
@@ -7799,7 +7736,7 @@ public boolean ping(IgniteSpiOperationTimeoutHelper timeoutHelper) throws Interr
@Override protected void tearDown() {
pingResult(false);
- U.closeQuiet(sock);
+ U.closeQuiet(ses);
}
/** {@inheritDoc} */
@@ -8007,24 +7944,6 @@ private static class GridPingFutureAdapter extends GridFutureAdapter {
GridPingFutureAdapter(@Nullable UUID nodeId) {
this.nodeId = nodeId;
}
-
- /**
- * Returns socket associated with this ping future.
- *
- * @return Socket or {@code null} if no socket associated.
- */
- public Socket sock() {
- return sock;
- }
-
- /**
- * Associates socket with this ping future.
- *
- * @param sock Socket.
- */
- public void sock(Socket sock) {
- this.sock = sock;
- }
}
/**
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryIoSession.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryIoSession.java
index 3749f3b4234fe..a9d7a069bae4d 100644
--- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryIoSession.java
+++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryIoSession.java
@@ -26,18 +26,23 @@
import java.io.OutputStream;
import java.io.StreamCorruptedException;
import java.net.Socket;
+import java.net.SocketException;
import java.nio.ByteBuffer;
import java.security.cert.Certificate;
+import java.util.concurrent.locks.ReentrantLock;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSocket;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteException;
+import org.apache.ignite.IgniteLogger;
import org.apache.ignite.internal.GridKernalContext;
import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.MessageSerializationContext;
import org.apache.ignite.internal.direct.DirectMessageReader;
-import org.apache.ignite.internal.direct.DirectMessageWriter;
+import org.apache.ignite.internal.direct.IgniteMessageSerializationContext;
import org.apache.ignite.internal.managers.communication.DiscoveryMarshalling;
import org.apache.ignite.internal.managers.communication.UnknownMessageException;
+import org.apache.ignite.internal.processors.rollingupgrade.feature.IgniteNodeFeatureSet;
import org.apache.ignite.internal.util.CommonUtils;
import org.apache.ignite.internal.util.nio.MessageSerialization;
import org.apache.ignite.internal.util.typedef.X;
@@ -45,6 +50,8 @@
import org.apache.ignite.marshaller.jdk.JdkMarshaller;
import org.apache.ignite.plugin.extensions.communication.Message;
import org.apache.ignite.plugin.extensions.communication.MessageSerializer;
+import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoveryMessageSerializer;
+import org.apache.ignite.spi.discovery.tcp.internal.UnsupportedNodeVersionException;
import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryAbstractMessage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -60,33 +67,39 @@
*
* A leading byte is used to distinguish between the modes. The byte will be removed in future.
*/
-public class TcpDiscoveryIoSession {
+public class TcpDiscoveryIoSession implements AutoCloseable {
/** Default size of buffer used for buffering socket in/out. */
private static final int DFLT_SOCK_BUFFER_SIZE = 8192;
- /** Size for an intermediate buffer for serializing discovery messages. */
- private static final int MSG_BUFFER_SIZE = 100;
+ /** Size of the intermediate buffer a message is deserialized through. */
+ private static final int READ_BUFFER_SIZE = 100;
/** */
- final TcpDiscoverySpi spi;
+ private final TcpDiscoverySpi spi;
/** */
private final Socket sock;
/** */
- private final DirectMessageWriter msgWriter;
+ private final TcpDiscoveryMessageSerializer msgSer;
/** */
private final DirectMessageReader msgReader;
+ /** */
+ private final ByteBuffer readBuf;
+
/** Buffered socket output stream. */
private final OutputStream out;
/** Buffered socket input stream. */
private final CompositeInputStream in;
- /** Intermediate buffer for serializing discovery messages. */
- private final ByteBuffer msgBuf;
+ /** */
+ private final ReentrantLock sesWriteLock = new ReentrantLock();
+
+ /** */
+ private volatile MessageSerializationContext serCtx = MessageSerializationContext.UNNEGOTIATED;
/**
* Creates a new discovery I/O session bound to the given socket.
@@ -99,11 +112,11 @@ public class TcpDiscoveryIoSession {
this.sock = sock;
this.spi = spi;
- msgBuf = ByteBuffer.allocate(MSG_BUFFER_SIZE);
-
- msgWriter = new DirectMessageWriter(spi.messageFactory());
+ readBuf = ByteBuffer.allocate(READ_BUFFER_SIZE);
msgReader = new DirectMessageReader(spi.messageFactory(), null);
+ this.msgSer = new TcpDiscoveryMessageSerializer(spi);
+
try {
int sendBufSize = sock.getSendBufferSize() > 0 ? sock.getSendBufferSize() : DFLT_SOCK_BUFFER_SIZE;
int rcvBufSize = sock.getReceiveBufferSize() > 0 ? sock.getReceiveBufferSize() : DFLT_SOCK_BUFFER_SIZE;
@@ -116,6 +129,16 @@ public class TcpDiscoveryIoSession {
}
}
+ /** */
+ void rebuildMessageSerializationContext(@Nullable IgniteNodeFeatureSet rmtFeatures) throws UnsupportedNodeVersionException {
+ serCtx = IgniteMessageSerializationContext.buildForPeers(spi.ignite(), rmtFeatures);
+ }
+
+ /** @return Serialization context the two nodes of this session agreed on. */
+ public MessageSerializationContext serializationContext() {
+ return serCtx;
+ }
+
/**
* Writes a discovery message to the underlying socket output stream.
*
@@ -123,8 +146,10 @@ public class TcpDiscoveryIoSession {
* @throws IgniteCheckedException If serialization fails.
*/
void writeMessage(TcpDiscoveryAbstractMessage msg) throws IgniteCheckedException, IOException {
+ sesWriteLock.lock();
+
try {
- serializeMessage((Message)msg, out);
+ msgSer.writeTo(msg, out, serCtx);
out.flush();
}
@@ -139,6 +164,23 @@ void writeMessage(TcpDiscoveryAbstractMessage msg) throws IgniteCheckedException
throw new IgniteCheckedException(e);
}
+ finally {
+ sesWriteLock.unlock();
+ }
+ }
+
+ /**
+ * Reads the next discovery message from the socket input stream limiting read time.
+ *
+ * @param timeout Socket read timeout for this operation, {@code 0} means infinite.
+ * @param Type of the expected message.
+ * @return Deserialized message instance.
+ * @throws IgniteCheckedException If deserialization fails.
+ */
+ T readMessage(long timeout) throws IgniteCheckedException, IOException {
+ try (SocketTimeoutScope ignored = withTimeout(timeout)) {
+ return readMessage();
+ }
}
/**
@@ -161,37 +203,37 @@ T readMessage() throws IgniteCheckedException, IOException {
msg = spi.messageFactory().create(msgType);
}
catch (IgniteException e) {
- detectSslAlert(b0, b1, in);
+ detectSslAlert(b0, b1);
// 'Invalid message type' should not be lost.
throw e;
}
msgReader.reset();
- msgReader.setBuffer(msgBuf);
+ msgReader.setBuffer(readBuf);
boolean finished;
do {
- msgBuf.clear();
+ readBuf.clear();
- int read = in.read(msgBuf.array(), msgBuf.position(), msgBuf.remaining());
+ int read = in.read(readBuf.array(), readBuf.position(), readBuf.remaining());
if (read == -1)
throw new EOFException("Connection closed before message was fully read.");
- msgBuf.limit(read);
+ readBuf.limit(read);
- finished = MessageSerialization.readFrom(spi.messageFactory(), msg, msgReader);
+ finished = MessageSerialization.readFrom(spi.messageFactory(), 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
// the previous message. But it is not guaranteed with Client Discovery where messages aren't acknowledged.
// Thus, we have to keep the uprocessed bytes read from the socket. It won't return them again.
- if (msgBuf.hasRemaining()) {
- byte[] unprocessedReadTail = new byte[msgBuf.remaining()];
+ if (readBuf.hasRemaining()) {
+ byte[] unprocessedReadTail = new byte[readBuf.remaining()];
- msgBuf.get(unprocessedReadTail, 0, msgBuf.remaining());
+ readBuf.get(unprocessedReadTail, 0, readBuf.remaining());
in.attachByteArray(unprocessedReadTail);
}
@@ -237,39 +279,108 @@ public Socket socket() {
}
/**
- * Serializes a discovery message into given output stream.
+ * Writes raw data to the underlying socket output stream.
*
- * @param m Discovery message to serialize.
- * @param out Output stream to write serialized message.
- * @throws IOException If serialization fails.
+ * @param data Raw data to write.
+ * @throws IOException If failed.
*/
- void serializeMessage(Message m, OutputStream out) throws IOException, IgniteCheckedException {
- GridKernalContext kctx = ((IgniteEx)spi.ignite()).context();
+ void write(byte[] data) throws IOException {
+ sesWriteLock.lock();
+
+ try {
+ out.write(data);
- DiscoveryMarshalling.marshal(m, kctx, null);
+ out.flush();
+ }
+ finally {
+ sesWriteLock.unlock();
+ }
+ }
- msgWriter.reset();
- msgWriter.setBuffer(msgBuf);
+ /**
+ * Writes a single byte response to the underlying socket output stream.
+ *
+ * @param b Integer response.
+ * @throws IOException If failed.
+ */
+ void write(int b) throws IOException {
+ sesWriteLock.lock();
+
+ try {
+ out.write(b);
+
+ out.flush();
+ }
+ finally {
+ sesWriteLock.unlock();
+ }
+ }
- boolean finished;
+ /**
+ * Reads a single byte from the underlying socket input stream limiting read time.
+ *
+ * @param timeout Socket read timeout for this operation, {@code 0} means infinite.
+ * @return Receipt.
+ * @throws IOException If failed.
+ * @throws EOFException If the connection has been closed.
+ */
+ int read(long timeout) throws IOException {
+ try (SocketTimeoutScope ignored = withTimeout(timeout)) {
+ int res = in.read();
- do {
- // Should be cleared before first operation.
- msgBuf.clear();
+ if (res == -1)
+ throw new EOFException();
- finished = MessageSerialization.writeTo(spi.messageFactory(), m, msgWriter);
+ return res;
+ }
+ }
- out.write(msgBuf.array(), 0, msgBuf.position());
+ /**
+ * Reads {@code data.length} bytes from the underlying socket stream into the given array limiting
+ * read time.
+ *
+ * @param data Array to read the data into.
+ * @param timeout Socket read timeout for this operation, {@code 0} means infinite.
+ * @return Number of bytes read, less than {@code data.length} only if the connection has been closed.
+ * @throws IOException If failed.
+ */
+ int read(byte[] data, long timeout) throws IOException {
+ try (SocketTimeoutScope ignored = withTimeout(timeout)) {
+ return in.readNBytes(data, 0, data.length);
}
- while (!finished);
}
/**
- * Checks wheter input stream contains SSL alert.
+ * Applies the given read timeout to the session socket until the returned scope is closed.
+ *
+ * @param timeout Socket read timeout, {@code 0} means infinite.
+ * @return Scope restoring the previous socket read timeout when closed.
+ * @throws SocketException If the timeout can not be applied.
+ */
+ private SocketTimeoutScope withTimeout(long timeout) throws SocketException {
+ SocketTimeoutScope scope = new SocketTimeoutScope(sock.getSoTimeout());
+
+ sock.setSoTimeout((int)timeout);
+
+ return scope;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void close() {
+ U.closeQuiet(sock);
+ }
+
+ /** */
+ void close(IgniteLogger log) {
+ U.close(sock, log);
+ }
+
+ /**
+ * Checks whether input stream contains SSL alert.
* See handling {@code StreamCorruptedException} in {@link #readMessage()}.
* Keeps logic similar to {@link java.io.ObjectInputStream#readStreamHeader}.
*/
- private void detectSslAlert(byte b0, byte b1, InputStream in) throws IOException {
+ private void detectSslAlert(byte b0, byte b1) throws IOException {
byte[] hdr = new byte[4];
hdr[0] = b0;
hdr[1] = b1;
@@ -284,6 +395,32 @@ private void detectSslAlert(byte b0, byte b1, InputStream in) throws IOException
throw new StreamCorruptedException("invalid stream header: " + hex);
}
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return "TcpDiscoveryIoSession [sock=" + sock + ']';
+ }
+
+ /** Restores the socket read timeout changed for the duration of a single operation. */
+ private final class SocketTimeoutScope implements AutoCloseable {
+ /** */
+ private final int oldTimeout;
+
+ /** */
+ private SocketTimeoutScope(int oldTimeout) {
+ this.oldTimeout = oldTimeout;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void close() {
+ try {
+ sock.setSoTimeout(oldTimeout);
+ }
+ catch (SocketException ignored) {
+ // No-op.
+ }
+ }
+ }
+
/**
* Input stream implementation that combines a byte array and a regular InputStream allowing to read bytes
* from the array first and then proceed with reading from InputStream.
@@ -327,7 +464,13 @@ private void attachByteArray(byte[] prefixData) {
if (len0 == len)
return len0;
- return len0 + super.read(b, off + len0, len - len0);
+ int read = super.read(b, off + len0, len - len0);
+
+ // Do not report the bytes already taken from the prefix buffer as an end of the stream.
+ if (read < 0)
+ return len0 > 0 ? len0 : read;
+
+ return len0 + read;
}
/** {@inheritDoc} */
@@ -339,7 +482,9 @@ private void attachByteArray(byte[] prefixData) {
@Override public int readNBytes(byte[] b, int off, int len) throws IOException {
int len0 = readPrefixBuffer(b, off, len);
- return super.readNBytes(b, off + len0, len - len0);
+ assert len0 <= len;
+
+ return len0 + super.readNBytes(b, off + len0, len - len0);
}
/** {@inheritDoc} */
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryMessageSerializer.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryMessageSerializer.java
deleted file mode 100644
index 8c871f9e2eb46..0000000000000
--- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryMessageSerializer.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ignite.spi.discovery.tcp;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.Socket;
-import org.apache.ignite.IgniteCheckedException;
-import org.apache.ignite.plugin.extensions.communication.Message;
-import org.apache.ignite.plugin.extensions.communication.MessageSerializer;
-import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryAbstractMessage;
-
-/**
- * Class is responsible for serializing discovery messages using RU-ready {@link MessageSerializer} mechanism.
- *
- * It is used in a special case: when server wants to send discovery messages to clients, it may not have a {@link TcpDiscoveryIoSession}
- * to serialize the messages.
- * This class enables server to serialize discovery messages anyway, duplicating serialization code from {@link TcpDiscoveryIoSession}.
- */
-class TcpDiscoveryMessageSerializer extends TcpDiscoveryIoSession {
- /**
- * @param spi Discovery SPI instance.
- */
- public TcpDiscoveryMessageSerializer(TcpDiscoverySpi spi) {
- super(new Socket() {
- @Override public OutputStream getOutputStream() throws IOException {
- return null;
- }
-
- @Override public InputStream getInputStream() throws IOException {
- return null;
- }
- }, spi);
- }
-
- /**
- * Serializes a discovery message into a byte array.
- *
- * @param msg Discovery message to serialize.
- * @return Serialized byte array containing the message data.
- * @throws IgniteCheckedException If serialization fails.
- * @throws IOException If serialization fails.
- */
- byte[] serializeMessage(TcpDiscoveryAbstractMessage msg) throws IgniteCheckedException, IOException {
- try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
- serializeMessage((Message)msg, out);
-
- return out.toByteArray();
- }
- }
-}
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 a20ac2d7f01b1..ade01b61e6f0b 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
@@ -17,9 +17,7 @@
package org.apache.ignite.spi.discovery.tcp;
-import java.io.EOFException;
import java.io.IOException;
-import java.io.OutputStream;
import java.io.Serializable;
import java.io.StreamCorruptedException;
import java.net.InetAddress;
@@ -61,8 +59,6 @@
import org.apache.ignite.internal.managers.discovery.IgniteDiscoverySpi;
import org.apache.ignite.internal.processors.failure.FailureProcessor;
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;
@@ -102,7 +98,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;
@@ -1575,58 +1570,62 @@ public long getCoordinatorSinceTimestamp() {
}
/**
- * @param sockAddr Remote address.
+ * @param rmtAddr Remote address.
* @param timeoutHelper Timeout helper.
- * @return Opened socket.
+ * @return Session bound to the connected socket.
* @throws IOException If failed.
* @throws IgniteSpiOperationTimeoutException In case of timeout.
* @throws IgniteCheckedException If node is not yet initialized or is stopping.
*/
- protected Socket openSocket(
- InetSocketAddress sockAddr,
+ protected TcpDiscoveryIoSession openSession(
+ InetSocketAddress rmtAddr,
IgniteSpiOperationTimeoutHelper timeoutHelper
) throws IOException, IgniteSpiOperationTimeoutException, IgniteCheckedException {
- return openSocket(createSocket(), sockAddr, timeoutHelper);
+ Socket sock = createSocket();
+
+ try {
+ return openSession(sock, rmtAddr, timeoutHelper);
+ }
+ catch (IOException | IgniteCheckedException | IgniteException e) {
+ U.closeQuiet(sock);
+
+ throw e;
+ }
}
/**
* Connects to remote address sending {@code U.IGNITE_HEADER} when connection is established.
*
- * @param sock Socket bound to a local host address.
+ * @param sock Socket bound to a local host address, not connected yet.
* @param remAddr Remote address.
* @param timeoutHelper Timeout helper.
- * @return Connected socket.
+ * @return Session bound to the connected socket.
* @throws IOException If failed.
* @throws IgniteSpiOperationTimeoutException In case of timeout.
* @throws IgniteCheckedException If node is not yet initialized or is stopping.
*/
- protected Socket openSocket(
+ protected TcpDiscoveryIoSession openSession(
Socket sock,
InetSocketAddress remAddr,
IgniteSpiOperationTimeoutHelper timeoutHelper
) throws IOException, IgniteSpiOperationTimeoutException, IgniteCheckedException {
+ assert sock != null;
assert remAddr != null;
- try {
- InetSocketAddress resolved = remAddr.isUnresolved() ?
- new InetSocketAddress(InetAddress.getByName(remAddr.getHostName()), remAddr.getPort()) : remAddr;
+ InetSocketAddress resolved = remAddr.isUnresolved() ?
+ new InetSocketAddress(InetAddress.getByName(remAddr.getHostName()), remAddr.getPort()) : remAddr;
- InetAddress addr = resolved.getAddress();
+ InetAddress addr = resolved.getAddress();
- assert addr != null;
+ assert addr != null;
- sock.connect(resolved, (int)timeoutHelper.nextTimeoutChunk(sockTimeout));
+ sock.connect(resolved, (int)timeoutHelper.nextTimeoutChunk(sockTimeout));
- writeToSocket(sock, U.IGNITE_HEADER, timeoutHelper.nextTimeoutChunk(sockTimeout));
+ TcpDiscoveryIoSession ses = new TcpDiscoveryIoSession(sock, this);
- return sock;
- }
- catch (IOException | IgniteCheckedException e) {
- if (sock != null)
- U.closeQuiet(sock);
+ write(ses, U.IGNITE_HEADER, timeoutHelper.nextTimeoutChunk(sockTimeout));
- throw e;
- }
+ return ses;
}
/**
@@ -1634,11 +1633,11 @@ protected Socket openSocket(
* before, on SSL handshake, and doesn't accept new messages. In a such case it's possible to check the original error
* by reading the socket input stream.
*
- * @param sock Socket to check.
+ * @param ses Session to check.
* @param writeErr Error on writing a message to the socket.
* @return {@code SSLException} in case of SSL error, or {@code null} otherwise.
*/
- private @Nullable SSLException checkSslException(Socket sock, Exception writeErr) {
+ private @Nullable SSLException checkSslException(TcpDiscoveryIoSession ses, Exception writeErr) {
if (!sslEnable)
return null;
@@ -1650,7 +1649,7 @@ protected Socket openSocket(
try {
// Set timeout to 1ms, in this case of closed socket it should return fast.
if (X.hasCause(writeErr, SocketException.class))
- readReceipt(sock, 1);
+ readReceipt(ses, 1);
}
catch (SSLException sslErr) {
return sslErr;
@@ -1691,62 +1690,27 @@ 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 socket.
+ * Writes raw data to the session socket.
*
- * @param sock Socket.
+ * @param ses IO session.
* @param data Raw data to write.
* @param timeout Socket write timeout.
* @throws IOException If IO failed or write timed out.
* @throws IgniteCheckedException If node is not yet initialized or is stopping.
*/
- protected void writeToSocket(
- Socket sock,
+ protected void write(
+ TcpDiscoveryIoSession ses,
byte[] data,
long timeout
) throws IOException, IgniteCheckedException {
- assert sock != null;
assert data != null;
- try (SocketTimeoutObject ignored = startTimer(sock, timeout)) {
- OutputStream out = sock.getOutputStream();
-
- out.write(data);
-
- out.flush();
+ try (SocketTimeoutObject ignored = startTimer(ses, timeout)) {
+ ses.write(data);
}
catch (IOException e) {
- SSLException sslEx = checkSslException(sock, e);
+ SSLException sslEx = checkSslException(ses, e);
throw sslEx == null ? e : sslEx;
}
@@ -1788,46 +1752,37 @@ protected void writeMessage(
TcpDiscoveryAbstractMessage msg,
long timeout
) throws IOException, IgniteCheckedException {
- Socket sock = ses.socket();
-
- assert sock != null;
assert msg != null;
- try (SocketTimeoutObject ignored = startTimer(sock, timeout)) {
+ try (SocketTimeoutObject ignored = startTimer(ses, timeout)) {
ses.writeMessage(msg);
}
catch (IgniteCheckedException e) {
- SSLException sslEx = checkSslException(sock, e);
+ SSLException sslEx = checkSslException(ses, e);
throw sslEx == null ? e : new IgniteCheckedException(sslEx);
}
}
/**
- * Writes response to the socket.
+ * Writes response to the session socket.
*
- * @param sock Socket.
+ * @param ses IO session.
* @param res Integer response.
* @param timeout Socket timeout.
* @throws IOException If IO failed or write timed out.
* @throws IgniteCheckedException If node is not yet initialized or is stopping.
*/
- protected void writeToSocket(
- Socket sock,
+ protected void writeReceipt(
+ TcpDiscoveryIoSession ses,
int res,
long timeout
) throws IOException, IgniteCheckedException {
- assert sock != null;
-
- try (SocketTimeoutObject ignored = startTimer(sock, timeout)) {
- OutputStream out = sock.getOutputStream();
-
- out.write(res);
-
- out.flush();
+ try (SocketTimeoutObject ignored = startTimer(ses, timeout)) {
+ ses.write(res);
}
catch (IOException e) {
- SSLException sslEx = checkSslException(sock, e);
+ SSLException sslEx = checkSslException(ses, e);
throw (sslEx == null) ? e : sslEx;
}
@@ -1843,22 +1798,15 @@ protected void writeToSocket(
* @throws IgniteCheckedException If unmarshalling failed.
*/
protected T readMessage(TcpDiscoveryIoSession ses, long timeout) throws IOException, IgniteCheckedException {
- Socket sock = ses.socket();
-
- assert sock != null;
-
- int oldTimeout = sock.getSoTimeout();
-
try {
- sock.setSoTimeout((int)timeout);
-
- return ses.readMessage();
+ return ses.readMessage(timeout);
}
catch (IOException | IgniteCheckedException e) {
if (X.hasCause(e, SocketTimeoutException.class))
LT.warn(log, "Timed out waiting for message to be read (most probably, the reason is " +
"long GC pauses on remote node) [curTimeout=" + timeout +
- ", rmtAddr=" + sock.getRemoteSocketAddress() + ", rmtPort=" + sock.getPort() + ']');
+ ", rmtAddr=" + ses.socket().getRemoteSocketAddress() +
+ ", rmtPort=" + ses.socket().getPort() + ']');
StreamCorruptedException streamCorruptedCause = X.cause(e, StreamCorruptedException.class);
@@ -1880,7 +1828,7 @@ protected T readMessage(TcpDiscoveryIoSession ses, long time
if (X.hasCause(e, ClassNotFoundException.class)) {
LT.error(log, e, "Failed to read message due to an unknown class to unmarshal received. Unable to " +
"process the Discovery protocol. Stopping the Discovery SPI and invoking the failure handler. " +
- "RmtAddr=" + sock.getRemoteSocketAddress() + ", rmtPort=" + sock.getPort() + ']');
+ "RmtAddr=" + ses.socket().getRemoteSocketAddress() + ", rmtPort=" + ses.socket().getPort() + ']');
ignite.context().failure().process(new FailureContext(FailureType.CRITICAL_ERROR, e));
@@ -1890,58 +1838,64 @@ protected T readMessage(TcpDiscoveryIoSession ses, long time
throw e;
}
- finally {
- // Quietly restore timeout.
- try {
- sock.setSoTimeout(oldTimeout);
- }
- catch (SocketException ignored) {
- // No-op.
- }
- }
}
/**
- * Reads message delivery receipt from the socket.
+ * Reads and verifies the {@code U.IGNITE_HEADER} an incoming connection is expected to start with.
+ * See {@link #openSession(Socket, InetSocketAddress, IgniteSpiOperationTimeoutHelper)} writing this prefix.
*
- * @param sock Socket.
- * @param timeout Socket timeout for this operation.
- * @return Receipt.
+ * @param ses IO session.
+ * @param timeout Operation timeout.
+ * @return {@code true} if the Ignite header was successfully read during the specified timeout,
+ * {@code false} otherwise.
* @throws IOException If IO failed or read timed out.
*/
- protected int readReceipt(Socket sock, long timeout) throws IOException {
- assert sock != null;
+ protected boolean readMagicHeader(TcpDiscoveryIoSession ses, long timeout) throws IOException {
+ byte[] buf = new byte[U.IGNITE_HEADER.length];
- int oldTimeout = sock.getSoTimeout();
+ if (ses.read(buf, timeout) < buf.length) {
+ LT.warn(log, "Failed to read magic header (too few bytes received) " +
+ "[rmtAddr=" + ses.socket().getRemoteSocketAddress() +
+ ", locAddr=" + ses.socket().getLocalSocketAddress() + ']');
- try {
- sock.setSoTimeout((int)timeout);
+ return false;
+ }
- int res = sock.getInputStream().read();
+ if (!Arrays.equals(buf, U.IGNITE_HEADER)) {
+ LT.warn(log, "Unknown connection detected (possible reasons: an incompatible Ignite node or " +
+ "other software connecting to this Ignite port" +
+ (!isSslEnabled() ? ", or missing SSL configuration on remote node" : "") +
+ ") [rmtAddr=" + ses.socket().getRemoteSocketAddress() +
+ ", locAddr=" + ses.socket().getLocalSocketAddress() +
+ ", rcvdHdr=" + U.byteArray2HexString(buf) + ']', true);
+
+ return false;
+ }
- if (res == -1)
- throw new EOFException();
+ return true;
+ }
- return res;
+ /**
+ * Reads message delivery receipt from the session socket.
+ *
+ * @param ses IO session.
+ * @param timeout Socket timeout for this operation.
+ * @return Receipt.
+ * @throws IOException If IO failed or read timed out.
+ */
+ protected int readReceipt(TcpDiscoveryIoSession ses, long timeout) throws IOException {
+ try {
+ return ses.read(timeout);
}
catch (SocketTimeoutException e) {
LT.warn(log, "Timed out waiting for message delivery receipt (most probably, the reason is " +
"in long GC pauses on remote node; consider tuning GC and increasing 'ackTimeout' " +
"configuration property). Will retry to send message with increased timeout " +
- "[currentTimeout=" + timeout + ", rmtAddr=" + sock.getRemoteSocketAddress() +
- ", rmtPort=" + sock.getPort() + ']');
+ "[currentTimeout=" + timeout + ", rmtAddr=" + ses.socket().getRemoteSocketAddress() +
+ ", rmtPort=" + ses.socket().getPort() + ']');
throw e;
}
- finally {
- // Quietly restore timeout.
- try {
- sock.setSoTimeout(oldTimeout);
- }
- catch (SocketException ignored) {
- // No-op.
- }
- }
}
/**
@@ -2503,9 +2457,9 @@ TcpDiscoveryHandshakeResponse readHandshakeResponse(
}
/** Starts a timer for a socket operation. */
- private SocketTimeoutObject startTimer(Socket sock, long timeout) throws IgniteCheckedException {
+ private SocketTimeoutObject startTimer(TcpDiscoveryIoSession ses, long timeout) throws IgniteCheckedException {
try {
- SocketTimeoutObject obj = new SocketTimeoutObject(sock, U.currentTimeMillis() + timeout);
+ SocketTimeoutObject obj = new SocketTimeoutObject(ses, U.currentTimeMillis() + timeout);
addTimeoutObject(obj);
@@ -2533,7 +2487,7 @@ private class SocketTimeoutObject implements IgniteSpiTimeoutObject, AutoCloseab
private final IgniteUuid id = IgniteUuid.randomUuid();
/** */
- private final Socket sock;
+ private final TcpDiscoveryIoSession ses;
/** */
private final long endTime;
@@ -2542,14 +2496,14 @@ private class SocketTimeoutObject implements IgniteSpiTimeoutObject, AutoCloseab
private final AtomicBoolean done = new AtomicBoolean();
/**
- * @param sock Socket.
+ * @param ses IO session.
* @param endTime End time.
*/
- SocketTimeoutObject(Socket sock, long endTime) {
- assert sock != null;
+ SocketTimeoutObject(TcpDiscoveryIoSession ses, long endTime) {
+ assert ses != null;
assert endTime > 0;
- this.sock = sock;
+ this.ses = ses;
this.endTime = endTime;
}
@@ -2563,15 +2517,16 @@ boolean cancel() {
/** {@inheritDoc} */
@Override public void onTimeout() {
if (done.compareAndSet(false, true)) {
- // Close socket - timeout occurred.
- U.closeQuiet(sock);
+ // Close session - timeout occurred.
+ ses.close();
LT.warn(log, "Socket write has timed out (consider increasing " +
(failureDetectionTimeoutEnabled() ?
"'IgniteConfiguration.failureDetectionTimeout' configuration property) [" +
"failureDetectionTimeout=" + failureDetectionTimeout() :
"'sockTimeout' configuration property) [sockTimeout=" + sockTimeout) +
- ", rmtAddr=" + sock.getRemoteSocketAddress() + ", rmtPort=" + sock.getPort() +
+ ", rmtAddr=" + ses.socket().getRemoteSocketAddress() +
+ ", rmtPort=" + ses.socket().getPort() +
", sockTimeout=" + sockTimeout + ']');
}
}
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
new file mode 100644
index 0000000000000..e663ab47795fc
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/ClientMessageHolder.java
@@ -0,0 +1,62 @@
+/*
+ * 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.spi.discovery.tcp.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+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;
+
+/** */
+public class ClientMessageHolder {
+ /** */
+ private final TcpDiscoveryAbstractMessage msg;
+
+ /** */
+ private final Map bytesByCtx = new HashMap<>(1);
+
+ /** */
+ public ClientMessageHolder(TcpDiscoveryAbstractMessage msg) {
+ assert msg != null;
+
+ this.msg = msg;
+ }
+
+ /** */
+ public TcpDiscoveryAbstractMessage message() {
+ return msg;
+ }
+
+ /** */
+ public synchronized byte @Nullable [] messageBytes(MessageSerializationContext ctx) {
+ return bytesByCtx.get(ctx);
+ }
+
+ /** */
+ public synchronized void serialize(TcpDiscoveryMessageSerializer ser, MessageSerializationContext ctx) throws IgniteCheckedException {
+ if (!bytesByCtx.containsKey(ctx))
+ bytesByCtx.put(ctx, ser.serialize(msg, ctx));
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return msg.toString();
+ }
+}
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
new file mode 100644
index 0000000000000..2e83c7618c851
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/TcpDiscoveryMessageSerializer.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.spi.discovery.tcp.internal;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.IgniteEx;
+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;
+import org.apache.ignite.internal.util.nio.MessageSerialization;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryAbstractMessage;
+
+/** */
+public class TcpDiscoveryMessageSerializer {
+ /** Size of the intermediate buffer a message is serialized through. */
+ private static final int BUFFER_SIZE = 100;
+
+ /** */
+ private final TcpDiscoverySpi spi;
+
+ /** */
+ private final DirectMessageWriter writer;
+
+ /** */
+ private final ByteBuffer buf = ByteBuffer.allocate(BUFFER_SIZE);
+
+ /** @param spi Discovery SPI whose messages this serializer writes. */
+ public TcpDiscoveryMessageSerializer(TcpDiscoverySpi spi) {
+ this.spi = spi;
+
+ writer = new DirectMessageWriter(spi.messageFactory());
+ }
+
+ /**
+ * Serializes a discovery message into given output stream.
+ *
+ * @param msg Discovery message to serialize.
+ * @param out Output stream to write serialized message.
+ * @param ctx Serialization context the recipient agreed on.
+ * @throws IgniteCheckedException If serialization fails.
+ * @throws IOException If serialization fails.
+ */
+ public void writeTo(
+ TcpDiscoveryAbstractMessage msg,
+ OutputStream out,
+ MessageSerializationContext ctx
+ ) throws IgniteCheckedException, IOException {
+ DiscoveryMarshalling.marshal(msg, ((IgniteEx)spi.ignite()).context(), null);
+
+ writer.reset();
+ writer.setBuffer(buf);
+
+ boolean finished;
+
+ do {
+ // Should be cleared before first operation.
+ buf.clear();
+
+ finished = MessageSerialization.writeTo(spi.messageFactory(), msg, writer, ctx);
+
+ out.write(buf.array(), 0, buf.position());
+ }
+ while (!finished);
+ }
+
+ /**
+ * Serializes a discovery message into a byte array.
+ *
+ * @param msg Discovery message to serialize.
+ * @param ctx Serialization context the recipient agreed on.
+ * @return Serialized byte array containing the message data.
+ * @throws IgniteCheckedException If serialization fails.
+ */
+ public byte[] serialize(TcpDiscoveryAbstractMessage msg, MessageSerializationContext ctx) throws IgniteCheckedException {
+ try (GridByteArrayOutputStream out = new GridByteArrayOutputStream()) {
+ writeTo(msg, out, ctx);
+
+ return out.toByteArray();
+ }
+ catch (IOException e) {
+ throw new IgniteCheckedException("Failed to serialize a discovery message: " + msg, e);
+ }
+ }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/IgniteClientRejoinTest.java b/modules/core/src/test/java/org/apache/ignite/internal/IgniteClientRejoinTest.java
index 23be4f0f8b0a7..e059f8e87a446 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/IgniteClientRejoinTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/IgniteClientRejoinTest.java
@@ -353,15 +353,15 @@ private class TcpCommunicationSpi extends org.apache.ignite.spi.communication.tc
*/
private class DiscoverySpi extends TcpDiscoverySpi {
/** {@inheritDoc} */
- @Override protected void writeToSocket(
- Socket sock,
+ @Override protected void write(
+ TcpDiscoveryIoSession ses,
byte[] data,
long timeout
) throws IOException, IgniteCheckedException {
- if (blockAll || block && sock.getPort() == 47500)
+ if (blockAll || block && ses.socket().getPort() == 47500)
throw new SocketException("Test discovery exception");
- super.writeToSocket(sock, data, timeout);
+ super.write(ses, data, timeout);
}
/** {@inheritDoc} */
@@ -377,27 +377,27 @@ private class DiscoverySpi extends TcpDiscoverySpi {
}
/** {@inheritDoc} */
- @Override protected void writeToSocket(
- Socket sock,
+ @Override protected void writeReceipt(
+ TcpDiscoveryIoSession ses,
int res,
long timeout
) throws IOException, IgniteCheckedException {
- if (blockAll || block && sock.getPort() == 47500)
+ if (blockAll || block && ses.socket().getPort() == 47500)
throw new SocketException("Test discovery exception");
- super.writeToSocket(sock, res, timeout);
+ super.writeReceipt(ses, res, timeout);
}
/** {@inheritDoc} */
- @Override protected Socket openSocket(
+ @Override protected TcpDiscoveryIoSession openSession(
Socket sock,
InetSocketAddress remAddr,
IgniteSpiOperationTimeoutHelper timeoutHelper
) throws IOException, IgniteCheckedException {
- if (blockAll || block && sock.getPort() == 47500)
+ if (blockAll || block && remAddr.getPort() == 47500)
throw new SocketException("Test discovery exception");
- return super.openSocket(sock, remAddr, timeoutHelper);
+ return super.openSession(sock, remAddr, timeoutHelper);
}
}
}
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/IgniteDiscoveryMassiveNodeFailTest.java b/modules/core/src/test/java/org/apache/ignite/internal/IgniteDiscoveryMassiveNodeFailTest.java
index 2ddece5dc923c..a12b701809d5d 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/IgniteDiscoveryMassiveNodeFailTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/IgniteDiscoveryMassiveNodeFailTest.java
@@ -302,17 +302,17 @@ public void testRecoveryOnDisconnect() throws Exception {
*/
private class FailDiscoverySpi extends TcpDiscoverySpi {
/** {@inheritDoc} */
- @Override protected void writeToSocket(
- Socket sock,
+ @Override protected void write(
+ TcpDiscoveryIoSession ses,
byte[] data,
long timeout
) throws IOException, IgniteCheckedException {
- assertNotFailedNode(sock);
+ assertNotFailedNode(ses.socket());
if (isDrop())
return;
- super.writeToSocket(sock, data, timeout);
+ super.write(ses, data, timeout);
}
/** {@inheritDoc} */
@@ -335,17 +335,17 @@ private boolean isDrop() {
}
/** {@inheritDoc} */
- @Override protected void writeToSocket(
- Socket sock,
+ @Override protected void writeReceipt(
+ TcpDiscoveryIoSession ses,
int res,
long timeout
) throws IOException, IgniteCheckedException {
- assertNotFailedNode(sock);
+ assertNotFailedNode(ses.socket());
if (isDrop())
return;
- super.writeToSocket(sock, res, timeout);
+ super.writeReceipt(ses, res, timeout);
}
/**
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..37f25a885acc8 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,45 @@ 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 [featureName=NO_SUCH_FEATURE");
+ }
+
+ /** */
+ @Test
+ public void testSameFeatureInBothGuardsRejected() {
+ 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 [registry=");
+ }
+
/** */
@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..a3e66c91819bd 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.IGNORED;
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, IGNORED);
chunk.flip();
@@ -168,7 +169,7 @@ private T doMarshalUnmarshalChunked(T srcMsg) {
reader.setBuffer(chunk);
- resMsg = reader.readMessage(false);
+ resMsg = reader.readMessage(false, IGNORED);
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..48e861cc6c98a 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.IGNORED;
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, IGNORED)) {
// No-op.
}
msg = msgFactory.create(msgType);
- while (!MessageSerialization.readFrom(msgFactory, msg, reader)) {
+ while (!MessageSerialization.readFrom(msgFactory, msg, reader, IGNORED)) {
// 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..28c5b23e347be 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.IGNORED;
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, IGNORED);
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, IGNORED);
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, IGNORED),
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, IGNORED),
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, IGNORED));
tmpBuf.flip();
@@ -231,7 +232,7 @@ public void testReadFailsOnTruncatedPayload() {
wireWriter.setBuffer(wire);
- assertTrue(wireWriter.writeMessage(compressedMsg, false));
+ assertTrue(wireWriter.writeMessage(compressedMsg, false, IGNORED));
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, IGNORED), 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
@@ -122,7 +124,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, IGNORED));
assertTrue(msgWritter.getBuffer().hasRemaining());
@@ -134,7 +136,7 @@ public void testCacheSize() throws Exception {
TcpDiscoveryMetricsUpdateMessage msg2 = new TcpDiscoveryMetricsUpdateMessage();
- assertTrue(MessageSerialization.readFrom(msgFactory, msg2, msgReader));
+ assertTrue(MessageSerialization.readFrom(msgFactory, msg2, msgReader, IGNORED));
Map cacheMetrics2 = msg2.serversFullMetricsMessages().values().iterator().next()
.cachesMetricsMessages();
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheTopologySplitAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheTopologySplitAbstractTest.java
index f85acbd4a42da..a29986bfa2674 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheTopologySplitAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheTopologySplitAbstractTest.java
@@ -207,25 +207,25 @@ protected void checkSegmented(InetSocketAddress sockAddr, long timeout) throws S
}
/** {@inheritDoc} */
- @Override protected Socket openSocket(
+ @Override protected TcpDiscoveryIoSession openSession(
Socket sock,
InetSocketAddress remAddr,
IgniteSpiOperationTimeoutHelper timeoutHelper
) throws IOException, IgniteCheckedException {
checkSegmented(remAddr, timeoutHelper.nextTimeoutChunk(getSocketTimeout()));
- return super.openSocket(sock, remAddr, timeoutHelper);
+ return super.openSession(sock, remAddr, timeoutHelper);
}
/** {@inheritDoc} */
- @Override protected void writeToSocket(
- Socket sock,
+ @Override protected void write(
+ TcpDiscoveryIoSession ses,
byte[] data,
long timeout
) throws IOException, IgniteCheckedException {
- checkSegmented((InetSocketAddress)sock.getRemoteSocketAddress(), timeout);
+ checkSegmented((InetSocketAddress)ses.socket().getRemoteSocketAddress(), timeout);
- super.writeToSocket(sock, data, timeout);
+ super.write(ses, data, timeout);
}
/** {@inheritDoc} */
@@ -238,14 +238,14 @@ protected void checkSegmented(InetSocketAddress sockAddr, long timeout) throws S
}
/** {@inheritDoc} */
- @Override protected void writeToSocket(
- Socket sock,
+ @Override protected void writeReceipt(
+ TcpDiscoveryIoSession ses,
int res,
long timeout
) throws IOException, IgniteCheckedException {
- checkSegmented((InetSocketAddress)sock.getRemoteSocketAddress(), timeout);
+ checkSegmented((InetSocketAddress)ses.socket().getRemoteSocketAddress(), timeout);
- super.writeToSocket(sock, res, timeout);
+ super.writeReceipt(ses, res, timeout);
}
}
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..4f6851c31a6e6 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.IGNORED;
/**
*
@@ -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, IGNORED);
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, IGNORED);
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..60d05ca3feddf 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.IGNORED;
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, IGNORED));
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, IGNORED));
assertEquals("Reads" + ERROR_SUFFIX,
expReadsWritesCnt, reader.state());
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/rest/RestProcessorHangTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/rest/RestProcessorHangTest.java
index b473603babcac..04e228110470c 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/rest/RestProcessorHangTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/rest/RestProcessorHangTest.java
@@ -18,7 +18,6 @@
package org.apache.ignite.internal.processors.rest;
import java.io.IOException;
-import java.net.Socket;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
@@ -30,6 +29,7 @@
import org.apache.ignite.internal.IgniteKernal;
import org.apache.ignite.internal.IgnitionEx;
import org.apache.ignite.internal.processors.rest.request.GridRestCacheRequest;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoveryIoSession;
import org.apache.ignite.spi.discovery.tcp.TestTcpDiscoverySpi;
import org.apache.ignite.testframework.GridTestUtils;
import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
@@ -71,8 +71,8 @@ public void testNodeStopOnDiscoverySpiFailTest() throws Exception {
// Discovery spi that never allows connecting.
TestTcpDiscoverySpi discoSpi = new TestTcpDiscoverySpi() {
- @Override protected void writeToSocket(
- Socket sock,
+ @Override protected void writeReceipt(
+ TcpDiscoveryIoSession ses,
int res,
long timeout
) throws IOException, IgniteCheckedException {
@@ -84,7 +84,7 @@ public void testNodeStopOnDiscoverySpiFailTest() throws Exception {
// No-op.
}
- super.writeToSocket(sock, 255, timeout);
+ super.writeReceipt(ses, 255, timeout);
}
};
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..4258e93cc6a8a
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/message/RollingUpgradeMessageSerializationTest.java
@@ -0,0 +1,592 @@
+/*
+ * 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.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 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.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 testDiscoveryNewerClient() throws Exception {
+ IgniteEx srv = startGrid(0, "2.19.0");
+
+ ru(srv).enableVersionUpgrade();
+
+ IgniteEx client = startClientGrid(1, "2.20.0");
+
+ TestCoreMessage receivedMsg = sendOverDiscovery(srv, TestCoreMessage.build()).get(client.name());
+
+ assertFields(B, null, null, null, receivedMsg);
+ }
+
+ /** */
+ @Test
+ public void testDiscoveryClientOriginated() throws Exception {
+ IgniteEx srv = startGrid(0, "2.19.0");
+
+ ru(srv).enableVersionUpgrade();
+
+ IgniteEx cli1 = startClientGrid(1, "2.20.0");
+ IgniteEx cli2 = startClientGrid(2, "2.19.0");
+
+ Map receivedMsgs = sendOverDiscovery(cli1, TestCoreMessage.build());
+
+ assertFields(B, null, null, null, receivedMsgs.get(cli2.name()));
+ assertFields(B, null, null, null, receivedMsgs.get(srv.name()));
+ }
+
+ /** */
+ @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(B, D, E, null, receivedMsgs.get(newVerCli.name()));
+ assertFields(B, null, null, null, receivedMsgs.get(oldVerCli.name()));
+ }
+
+ /** */
+ @Test
+ public void testDiscoveryClientsOnOneVersion() throws Exception {
+ IgniteEx srv = startGrid(0, "2.20.0");
+
+ startClientGrid(1, "2.20.0");
+ startClientGrid(2, "2.20.0");
+
+ Map receivedMsgs = sendOverDiscovery(srv, TestCoreMessage.build());
+
+ for (TestCoreMessage msg : receivedMsgs.values())
+ assertFields(B, D, E, null, msg);
+ }
+
+ /** */
+ @Test
+ public void testCommunicationWithClient() throws Exception {
+ IgniteEx srv = startGrid(0, "2.19.0");
+
+ ru(srv).enableVersionUpgrade();
+
+ IgniteEx client = startClientGrid(1, "2.20.0");
+
+ TestCoreMessage receivedMsg = send(srv, client, TestCoreMessage.build());
+
+ assertFields(B, null, null, null, receivedMsg);
+
+ receivedMsg = send(client, srv, TestCoreMessage.build());
+
+ assertFields(B, null, null, null, receivedMsg);
+ }
+
+ /** */
+ @Test
+ public void testDefaultRegistrySameOldVersion() throws Exception {
+ startPair("2.19.0", "2.19.0");
+
+ assertFields(B, D, null, null, send(grid(0), grid(1), TestDefaultRegistryMessage.build()));
+ }
+
+ /** */
+ @Test
+ public void testDefaultRegistryMixedPair() throws Exception {
+ startPair("2.19.0", "2.20.0");
+
+ assertFields(null, D, null, null, send(grid(1), grid(0), TestDefaultRegistryMessage.build()));
+
+ assertFields(null, D, null, null, send(grid(0), grid(1), TestDefaultRegistryMessage.build()));
+ }
+
+ /** */
+ @Test
+ public void testDefaultRegistrySameNewVersion() throws Exception {
+ startPair("2.20.0", "2.20.0");
+
+ assertFields(B, D, null, null, send(grid(0), grid(1), TestDefaultRegistryMessage.build()));
+ }
+
+ /** */
+ @Test
+ public void testCommunicationSameOldVersion() throws Exception {
+ startPair("2.19.0", "2.19.0");
+
+ TestCoreMessage receivedMsg = send(grid(0), grid(1), TestCoreMessage.build());
+
+ assertFields(B, null, null, null, receivedMsg);
+ }
+
+ /** */
+ @Test
+ public void testCommunicationNewerSender() throws Exception {
+ startPair("2.19.0", "2.20.0");
+
+ TestCoreMessage receivedMsg = send(grid(1), grid(0), TestCoreMessage.build());
+
+ assertFields(B, null, null, null, receivedMsg);
+ }
+
+ /** */
+ @Test
+ public void testCommunicationOlderSender() throws Exception {
+ startPair("2.19.0", "2.20.0");
+
+ TestCoreMessage receivedMsg = send(grid(0), grid(1), TestCoreMessage.build());
+
+ assertFields(B, null, null, null, receivedMsg);
+ }
+
+ /** */
+ @Test
+ public void testCommunicationSameNewVersion() throws Exception {
+ startPair("2.20.0", "2.20.0");
+
+ TestCoreMessage receivedMsg = send(grid(0), grid(1), TestCoreMessage.build());
+
+ assertFields(B, D, E, null, receivedMsg);
+ }
+
+ /** */
+ @Test
+ public void testDiscoverySameOldVersion() throws Exception {
+ startPair("2.19.0", "2.19.0");
+
+ for (TestCoreMessage msg : sendOverDiscovery(grid(1), TestCoreMessage.build()).values())
+ assertFields(B, null, null, null, msg);
+ }
+
+ /** */
+ @Test
+ public void testDiscoveryMixedPair() throws Exception {
+ startPair("2.19.0", "2.20.0");
+
+ for (TestCoreMessage msg : sendOverDiscovery(grid(1), TestCoreMessage.build()).values())
+ assertFields(B, null, null, null, msg);
+ }
+
+ /** */
+ @Test
+ public void testDiscoveryUniformRing() throws Exception {
+ startGrid(0, "2.20.0");
+ startGrid(1, "2.20.0");
+ startGrid(2, "2.20.0");
+
+ Map receivedMsgs = sendOverDiscovery(grid(1), TestCoreMessage.build());
+
+ for (TestCoreMessage msg : receivedMsgs.values())
+ assertFields(B, D, E, null, msg);
+ }
+
+ /** */
+ @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");
+
+ Map receivedMsgs = sendOverDiscovery(grid(1), TestCoreMessage.build());
+
+ for (TestCoreMessage msg : receivedMsgs.values())
+ assertFields(B, null, null, null, msg);
+ }
+
+
+ /** */
+ @Test
+ public void testCommunicationWindowOpenSameVersion() throws Exception {
+ startPair("2.19.2", "2.19.2");
+
+ TestCoreMessage receivedMsg = send(grid(0), grid(1), TestCoreMessage.build());
+
+ assertFields(B, D, null, null, receivedMsg);
+ }
+
+ /** */
+ @Test
+ public void testCommunicationWindowOpenNewerSender() throws Exception {
+ startPair("2.19.2", "2.20.0");
+
+ TestCoreMessage receivedMsg = send(grid(1), grid(0), TestCoreMessage.build());
+
+ assertFields(B, D, null, null, receivedMsg);
+ }
+
+ /** */
+ @Test
+ public void testCommunicationWindowOpenOlderSender() throws Exception {
+ startPair("2.19.2", "2.20.0");
+
+ TestCoreMessage receivedMsg = send(grid(0), grid(1), TestCoreMessage.build());
+
+ assertFields(B, D, null, null, receivedMsg);
+ }
+
+
+ /** */
+ @Test
+ public void testCommunicationWindowClosed() throws Exception {
+ startPair("2.20.0", "2.20.1");
+
+ TestCoreMessage receivedMsg = send(grid(1), grid(0), TestCoreMessage.build());
+
+ assertFields(null, null, E, null, receivedMsg);
+ }
+
+ /** */
+ @Test
+ public void testCommunicationUpgradeOpensWindow() throws Exception {
+ startGrid(0, "2.19.0");
+ startGrid(1, "2.19.0");
+
+ TestCoreMessage receivedMsg = send(grid(0), grid(1), TestCoreMessage.build());
+
+ assertFields(B, null, null, null, receivedMsg);
+
+ ru(1).enableVersionUpgrade();
+
+ upgradeNodeVersion(0, "2.19.2");
+ upgradeNodeVersion(1, "2.19.2");
+
+ receivedMsg = send(grid(0), grid(1), TestCoreMessage.build());
+
+ assertFields(B, D, null, null, receivedMsg);
+ }
+
+ /** */
+ @Test
+ public void testCommunicationUpgradeAgreesNewFeature() throws Exception {
+ startGrid(0, "2.19.2");
+ startGrid(1, "2.19.2");
+
+ TestCoreMessage receivedMsg = send(grid(0), grid(1), TestCoreMessage.build());
+
+ assertFields(B, D, null, null, receivedMsg);
+
+ ru(1).enableVersionUpgrade();
+
+ upgradeNodeVersion(0, "2.19.2", "2.20.0");
+
+ receivedMsg = send(grid(0), grid(1), TestCoreMessage.build());
+
+ assertFields(B, D, null, null, receivedMsg);
+
+ upgradeNodeVersion(1, "2.19.2", "2.20.0");
+
+ receivedMsg = send(grid(0), grid(1), TestCoreMessage.build());
+
+ assertFields(B, D, E, null, receivedMsg);
+ }
+
+ /** */
+ @Test
+ public void testPluginDiffersCoreMatches() throws Exception {
+ startPair("2.20.0 | 1.0.0", "2.20.0 | 2.0.0");
+
+ checkPluginDiffersCoreMatches(grid(1), grid(0));
+
+ checkPluginDiffersCoreMatches(grid(1), grid(0));
+ }
+
+ /** */
+ @Test
+ public void testPluginSameVersion() throws Exception {
+ startPair("2.20.0 | 2.0.0", "2.20.0 | 2.0.0");
+
+ TestCoreMessage receivedCoreMsg = send(grid(0), grid(1), TestCoreMessage.build());
+
+ assertFields(B, D, E, null, receivedCoreMsg);
+
+ TestPluginMessage receivedPluginMsg = send(grid(0), grid(1), TestPluginMessage.build());
+
+ assertFields(B, D, E, null, receivedPluginMsg);
+ }
+
+ /** */
+ @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");
+
+ checkPluginMissingOnClient(srv, cli);
+
+ checkPluginMissingOnClient(cli, srv);
+ }
+
+ /** */
+ @Test
+ public void testWholeUpgradeProcess() throws Exception {
+ startGrid(0, "2.19.0");
+ startGrid(1, "2.19.0");
+ startClientGrid(2, "2.19.0");
+
+ checkMessagesTransmissionBetweenAllNodes(B, null, null, null);
+
+ ru(1).enableVersionUpgrade();
+
+ checkMessagesTransmissionBetweenAllNodes(B, null, null, null);
+
+ upgradeNodeVersion(0, "2.19.0", "2.19.2");
+
+ checkMessagesTransmissionBetweenAllNodes(B, null, null, null);
+
+ upgradeNodeVersion(1, "2.19.0", "2.19.2");
+
+ checkMutualMessageTransmission(grid(0), grid(1), B, D, null, null);
+ checkMutualMessageTransmission(grid(0), grid(2), B, null, null, null);
+ checkMutualMessageTransmission(grid(1), grid(2), B, null, null, null);
+
+ upgradeNodeVersion(2, "2.19.0", "2.19.2");
+
+ checkMessagesTransmissionBetweenAllNodes(B, D, null, null);
+
+ finalizeClusterVersion(0, "2.19.2");
+
+ checkMessagesTransmissionBetweenAllNodes(B, D, null, null);
+
+ ru(1).enableVersionUpgrade();
+
+ upgradeNodeVersion(0, "2.19.2", "2.20.0");
+
+ checkMessagesTransmissionBetweenAllNodes(B, D, null, null);
+
+ upgradeNodeVersion(1, "2.19.2", "2.20.0");
+
+ checkMutualMessageTransmission(grid(0), grid(1), B, D, E, null);
+ checkMutualMessageTransmission(grid(0), grid(2), B, D, null, null);
+ checkMutualMessageTransmission(grid(1), grid(2), B, D, null, null);
+
+ upgradeNodeVersion(2, "2.19.2", "2.20.0");
+
+ checkMessagesTransmissionBetweenAllNodes(B, D, E, null);
+
+ finalizeClusterVersion(0, "2.20.0");
+
+ checkMessagesTransmissionBetweenAllNodes(B, D, E, null);
+
+ ru(1).enableVersionUpgrade();
+
+ upgradeNodeVersion(0, "2.20.0", "2.20.1");
+
+ checkMutualMessageTransmission(grid(0), grid(1), null, null, E, null);
+ checkMutualMessageTransmission(grid(0), grid(2), null, null, E, null);
+ checkMutualMessageTransmission(grid(1), grid(2), B, D, E, null);
+
+ upgradeNodeVersion(1, "2.20.0", "2.20.1");
+
+ checkMutualMessageTransmission(grid(0), grid(1), B, D, E, F);
+ checkMutualMessageTransmission(grid(0), grid(2), null, null, E, null);
+ checkMutualMessageTransmission(grid(1), grid(2), null, null, E, null);
+
+ upgradeNodeVersion(2, "2.20.0", "2.20.1");
+
+ checkMessagesTransmissionBetweenAllNodes(B, D, E, F);
+
+ finalizeClusterVersion(0, "2.20.1");
+
+ checkMessagesTransmissionBetweenAllNodes(B, D, E, F);
+ }
+
+ /** */
+ private void checkMessagesTransmissionBetweenAllNodes(String expB, 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++) {
+ checkMutualMessageTransmission(
+ (IgniteEx)clusterNodes.get(i), (IgniteEx)clusterNodes.get(j), expB, expD, expE, expF);
+ }
+ }
+ }
+
+ /** */
+ private void checkMutualMessageTransmission(
+ IgniteEx first,
+ IgniteEx second,
+ String expB,
+ String expD,
+ String expE,
+ String expF
+ ) throws Exception {
+ checkMessageTransmission(first, second, expB, expD, expE, expF);
+ checkMessageTransmission(second, first, expB, expD, expE, expF);
+ }
+
+ /** */
+ private void checkMessageTransmission(
+ IgniteEx from,
+ IgniteEx to,
+ String expB,
+ String expD,
+ String expE,
+ String expF
+ ) throws Exception {
+ TestCoreMessage receivedCommunicationMsg = send(from, to, TestCoreMessage.build());
+
+ assertFields(expB, expD, expE, expF, receivedCommunicationMsg);
+
+ TestCoreMessage receivedDiscoveryMsg = sendOverDiscovery(from, TestCoreMessage.build()).get(to.name());
+
+ assertFields(expB, expD, expE, expF, receivedDiscoveryMsg);
+ }
+
+ /** */
+ private void checkPluginDiffersCoreMatches(IgniteEx snd, IgniteEx rcv) throws Exception {
+ TestCoreMessage receivedCoreMsg = send(snd, rcv, TestCoreMessage.build());
+
+ assertFields(B, D, E, null, receivedCoreMsg);
+
+ TestPluginMessage receivedPluginMsg = send(snd, rcv, TestPluginMessage.build());
+
+ assertFields(B, D, null, null, receivedPluginMsg);
+ }
+
+ /** */
+ private void checkPluginMissingOnClient(IgniteEx snd, IgniteEx rcv) throws Exception {
+ TestPluginMessage receivedPluginMsg = send(snd, rcv, TestPluginMessage.build());
+
+ assertFields(B, null, null, null, receivedPluginMsg);
+
+ TestCoreMessage receivedCoreMsg = send(snd, rcv, TestCoreMessage.build());
+
+ assertFields(B, D, E, null, receivedCoreMsg);
+ }
+
+ /** */
+ 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,
+ TestCoreMessage 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(TestCoreMessage.class,
+ (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 startPair(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 expB, String expD, String expE, String expF, TestMessage msg) {
+ assertEquals(A, msg.fldA());
+ assertEquals(C, msg.fldC());
+ assertEquals(expB, msg.fldB());
+ 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..843c928ad1ca0
--- /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.FeatureRegistry;
+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;
+
+/** */
+@FeatureRegistry(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..718cf35a19b86
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/message/TestDefaultRegistryMessage.java
@@ -0,0 +1,82 @@
+/*
+ * 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.plugin.extensions.communication.Message;
+
+/** */
+public class TestDefaultRegistryMessage implements Message, TestMessage {
+ /** */
+ @Order(0)
+ String fldA;
+
+ /** */
+ @Order(value = 1, deprecatedBy = "ROLLING_UPGRADE_FEATURE")
+ String fldB;
+
+ /** */
+ @Order(2)
+ String fldC;
+
+ /** */
+ @Order(value = 3, introducedBy = "ROLLING_UPGRADE_FEATURE")
+ String fldD;
+
+ /** */
+ public static TestDefaultRegistryMessage build() {
+ TestDefaultRegistryMessage msg = new TestDefaultRegistryMessage();
+
+ msg.fldA = A;
+ msg.fldB = B;
+ msg.fldC = C;
+ msg.fldD = D;
+
+ 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 null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String fldF() {
+ return null;
+ }
+}
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..e26968266f147
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/rollingupgrade/message/TestPluginMessage.java
@@ -0,0 +1,102 @@
+/*
+ * 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.FeatureRegistry;
+import org.apache.ignite.internal.Order;
+import org.apache.ignite.internal.processors.rollingupgrade.feature.TestPluginReleaseFeatures_2_1_0;
+import org.apache.ignite.plugin.extensions.communication.Message;
+
+/**
+ * Carries fields guarded by features of two components at once: the core one and the test plugin's.
+ *
+ * Only exchanged between nodes that declare the plugin component. A field guarded by a feature of a
+ * component neither node declares has no answer - see {@code IgniteMessageSerializationContext#component} -
+ * so this message and the core-only {@link TestCoreMessage} are kept apart rather than
+ * folded into one that every test would have to declare the plugin for.
+ */
+@FeatureRegistry(TestPluginReleaseFeatures_2_1_0.class)
+public class TestPluginMessage implements Message, 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 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..a978a506abb89 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.IGNORED;
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, IGNORED));
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, IGNORED));
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, IGNORED));
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, IGNORED));
return res;
}
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/IgniteTcpCommunicationConnectOnInitTest.java b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/IgniteTcpCommunicationConnectOnInitTest.java
index ba7507bfb64d5..ff83530400195 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/IgniteTcpCommunicationConnectOnInitTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/IgniteTcpCommunicationConnectOnInitTest.java
@@ -179,35 +179,25 @@ private GridNioServer> startServer() throws Exception {
*/
private class TestDiscoverySpi extends TcpDiscoverySpi {
/** {@inheritDoc} */
- @Override protected Socket openSocket(
- InetSocketAddress sockAddr,
- IgniteSpiOperationTimeoutHelper timeoutHelper
- ) throws IOException, IgniteCheckedException {
- awaitLatch();
-
- return super.openSocket(sockAddr, timeoutHelper);
- }
-
- /** {@inheritDoc} */
- @Override protected Socket openSocket(
+ @Override protected TcpDiscoveryIoSession openSession(
Socket sock,
- InetSocketAddress remAddr,
+ InetSocketAddress sockAddr,
IgniteSpiOperationTimeoutHelper timeoutHelper
) throws IOException, IgniteCheckedException {
awaitLatch();
- return super.openSocket(sock, remAddr, timeoutHelper);
+ return super.openSession(sock, sockAddr, timeoutHelper);
}
/** {@inheritDoc} */
- @Override protected void writeToSocket(
- Socket sock,
+ @Override protected void write(
+ TcpDiscoveryIoSession ses,
byte[] data,
long timeout
) throws IOException, IgniteCheckedException {
awaitLatch();
- super.writeToSocket(sock, data, timeout);
+ super.write(ses, data, timeout);
}
/** {@inheritDoc} */
@@ -222,14 +212,14 @@ private class TestDiscoverySpi extends TcpDiscoverySpi {
}
/** {@inheritDoc} */
- @Override protected void writeToSocket(
- Socket sock,
+ @Override protected void writeReceipt(
+ TcpDiscoveryIoSession ses,
int res,
long timeout
) throws IOException, IgniteCheckedException {
awaitLatch();
- super.writeToSocket(sock, res, timeout);
+ super.writeReceipt(ses, res, timeout);
}
/**
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/spi/discovery/tcp/IgniteMetricsOverflowTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/IgniteMetricsOverflowTest.java
index b6c7d58225217..c041a9bc6085f 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/IgniteMetricsOverflowTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/IgniteMetricsOverflowTest.java
@@ -18,7 +18,6 @@
package org.apache.ignite.spi.discovery.tcp;
import java.io.IOException;
-import java.net.Socket;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.apache.ignite.Ignite;
@@ -47,7 +46,7 @@ public class IgniteMetricsOverflowTest extends GridCommonAbstractTest {
private CountDownLatch slowDownLatch;
/**
- * Period of time, for which {@link TcpDiscoverySpi#readReceipt(Socket, long)} execution is delayed on the node
+ * Period of time, for which {@link TcpDiscoverySpi#readReceipt(TcpDiscoveryIoSession, long)} execution is delayed on the node
* with a slow {@link DiscoverySpi}.
*/
private volatile int readReceiptDelay;
@@ -153,7 +152,7 @@ public void testMetricOverflow() throws Exception {
/** */
private class TestTcpDiscoverySpi extends TcpDiscoverySpi {
/** {@inheritDoc} */
- @Override protected int readReceipt(Socket sock, long timeout) throws IOException {
+ @Override protected int readReceipt(TcpDiscoveryIoSession ses, long timeout) throws IOException {
if (readReceiptDelay > 0) {
slowDownLatch.countDown();
@@ -165,7 +164,7 @@ private class TestTcpDiscoverySpi extends TcpDiscoverySpi {
}
}
- return super.readReceipt(sock, timeout);
+ return super.readReceipt(ses, timeout);
}
}
}
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/MultiDataCenterSplitTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/MultiDataCenterSplitTest.java
index 96bff0e22b004..b429c35ba17c2 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/MultiDataCenterSplitTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/MultiDataCenterSplitTest.java
@@ -351,10 +351,10 @@ private TestTcpDiscoverySpi(
}
/** {@inheritDoc} */
- @Override protected void writeToSocket(Socket sock, byte[] data, long timeout) throws IOException, IgniteCheckedException {
- tryToBlock(sock, data, timeout);
+ @Override protected void write(TcpDiscoveryIoSession ses, byte[] data, long timeout) throws IOException, IgniteCheckedException {
+ tryToBlock(ses.socket(), data, timeout);
- super.writeToSocket(sock, data, timeout);
+ super.write(ses, data, timeout);
}
/** */
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/ReceivedMessagesTracker.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/ReceivedMessagesTracker.java
index f7b93eba19f03..fea9c7528023d 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/ReceivedMessagesTracker.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/ReceivedMessagesTracker.java
@@ -17,7 +17,6 @@
package org.apache.ignite.spi.discovery.tcp;
-import java.net.Socket;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
@@ -28,18 +27,18 @@
/** */
public class ReceivedMessagesTracker {
/** */
- private final Map msgs = Collections.synchronizedMap(new WeakHashMap<>());
+ private final Map msgs = Collections.synchronizedMap(new WeakHashMap<>());
/** */
public T track(TcpDiscoveryIoSession ses, T msg) {
if (msg instanceof TcpDiscoveryAbstractMessage)
- msgs.put(ses.socket(), (TcpDiscoveryAbstractMessage)msg);
+ msgs.put(ses, (TcpDiscoveryAbstractMessage)msg);
return msg;
}
/** */
- public @Nullable TcpDiscoveryAbstractMessage lastFor(Socket sock) {
- return msgs.get(sock);
+ public @Nullable TcpDiscoveryAbstractMessage lastFor(TcpDiscoveryIoSession ses) {
+ return msgs.get(ses);
}
}
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoverySpiFailureTimeoutSelfTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoverySpiFailureTimeoutSelfTest.java
index 3fd9b589bc919..9efb3b52809dc 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoverySpiFailureTimeoutSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoverySpiFailureTimeoutSelfTest.java
@@ -18,7 +18,6 @@
package org.apache.ignite.spi.discovery.tcp;
import java.io.IOException;
-import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.Collections;
@@ -445,8 +444,8 @@ private static class TestTcpDiscoverySpi2 extends TcpDiscoverySpi {
private Exception err;
/** */
- @Override protected void writeToSocket(
- Socket sock,
+ @Override protected void write(
+ TcpDiscoveryIoSession ses,
byte[] data,
long timeout
) throws IOException, IgniteCheckedException {
@@ -461,8 +460,8 @@ private static class TestTcpDiscoverySpi2 extends TcpDiscoverySpi {
}
}
- if (sock.getSoTimeout() >= writeToSocketDelay)
- super.writeToSocket(sock, data, timeout);
+ if (ses.socket().getSoTimeout() >= writeToSocketDelay)
+ super.write(ses, data, timeout);
else
throw new SocketTimeoutException("Write to socket delay timeout exception.");
}
@@ -491,8 +490,8 @@ private static class TestTcpDiscoverySpi2 extends TcpDiscoverySpi {
}
/** */
- @Override protected void writeToSocket(
- Socket sock,
+ @Override protected void writeReceipt(
+ TcpDiscoveryIoSession ses,
int res,
long timeout
) throws IOException, IgniteCheckedException {
@@ -507,8 +506,8 @@ private static class TestTcpDiscoverySpi2 extends TcpDiscoverySpi {
}
}
- if (sock.getSoTimeout() >= writeToSocketDelay)
- super.writeToSocket(sock, res, timeout);
+ if (ses.socket().getSoTimeout() >= writeToSocketDelay)
+ super.writeReceipt(ses, res, timeout);
else
throw new SocketTimeoutException("Write to socket delay timeout exception.");
}
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoverySpiSelfTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoverySpiSelfTest.java
index f8a0410bcfa61..ca96f33f159cf 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoverySpiSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoverySpiSelfTest.java
@@ -2591,11 +2591,13 @@ private void pauseResumeOperation(boolean isPause, AtomicBoolean... locks) {
}
/** {@inheritDoc} */
- @Override protected void writeToSocket(
- Socket sock,
+ @Override protected void write(
+ TcpDiscoveryIoSession ses,
byte[] data,
long timeout
) throws IOException, IgniteCheckedException {
+ Socket sock = ses.socket();
+
waitFor(writeLock);
TcpDiscoveryAbstractMessage msg = decodeMessage(this, data);
@@ -2603,7 +2605,7 @@ private void pauseResumeOperation(boolean isPause, AtomicBoolean... locks) {
if (msg != null && !onMessage(sock, msg))
return;
- super.writeToSocket(sock, data, timeout);
+ super.write(ses, data, timeout);
if (msg != null && afterWrite != null)
afterWrite.apply(msg, sock);
@@ -2642,13 +2644,14 @@ else if (msg instanceof TcpDiscoveryClientReconnectMessage)
}
/** {@inheritDoc} */
- @Override protected Socket openSocket(
+ @Override protected TcpDiscoveryIoSession openSession(
+ Socket sock,
InetSocketAddress sockAddr,
IgniteSpiOperationTimeoutHelper timeoutHelper
) throws IOException, IgniteCheckedException {
waitFor(openSockLock);
- return super.openSocket(sockAddr, timeoutHelper);
+ return super.openSession(sock, sockAddr, timeoutHelper);
}
/**
@@ -2689,12 +2692,14 @@ public void resumeAll() {
}
/** {@inheritDoc} */
- @Override protected void writeToSocket(
- Socket sock,
+ @Override protected void writeReceipt(
+ TcpDiscoveryIoSession ses,
int res,
long timeout
) throws IOException, IgniteCheckedException {
- TcpDiscoveryAbstractMessage msg = msgTracker.lastFor(sock);
+ Socket sock = ses.socket();
+
+ TcpDiscoveryAbstractMessage msg = msgTracker.lastFor(ses);
if (delayJoinAckFor != null && msg instanceof TcpDiscoveryJoinRequestMessage) {
TcpDiscoveryJoinRequestMessage msg0 = (TcpDiscoveryJoinRequestMessage)msg;
@@ -2713,12 +2718,12 @@ public void resumeAll() {
}
}
- super.writeToSocket(sock, res, timeout);
+ super.writeReceipt(ses, res, timeout);
}
/** {@inheritDoc} */
- @Override protected int readReceipt(Socket sock, long timeout) throws IOException {
- int res = super.readReceipt(sock, timeout);
+ @Override protected int readReceipt(TcpDiscoveryIoSession ses, long timeout) throws IOException {
+ int res = super.readReceipt(ses, timeout);
if (res != TcpDiscoveryImpl.RES_OK) {
invalidRes = true;
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoveryUnresolvedHostTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoveryUnresolvedHostTest.java
index de4dd6f7b0a71..a613b758997ea 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoveryUnresolvedHostTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoveryUnresolvedHostTest.java
@@ -66,7 +66,10 @@ public void test() throws Exception {
//Ignore.
}
- assertEquals(0, spi.getSockets().size());
+ assertFalse(spi.getSockets().isEmpty());
+
+ for (Socket sock : spi.getSockets())
+ assertTrue(sock.isClosed());
}
/**
@@ -77,33 +80,23 @@ private static class TestTcpDiscoverySpi extends TcpDiscoverySpi {
Set sockets = new HashSet<>();
/** {@inheritDoc} */
- @Override Socket createSocket() throws IOException {
- Socket sock = super.createSocket();
-
- sockets.add(sock);
-
- return sock;
- }
-
- /** {@inheritDoc} */
- @Override protected Socket openSocket(
+ @Override protected TcpDiscoveryIoSession openSession(
Socket sock,
InetSocketAddress remAddr,
IgniteSpiOperationTimeoutHelper timeoutHelper
) throws IOException, IgniteCheckedException {
try {
- return super.openSocket(sock, remAddr, timeoutHelper);
+ return super.openSession(sock, remAddr, timeoutHelper);
}
catch (IgniteSpiOperationTimeoutException | IOException e) {
- if (sock.isClosed())
- sockets.remove(sock);
+ sockets.add(sock);
throw e;
}
}
/**
- * Gets list of sockets opened by this discovery spi.
+ * Gets sockets of the failed connection attempts.
*
* @return List of sockets.
*/
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryCoordinatorFailureTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryCoordinatorFailureTest.java
index 43633ef547436..dad5c4c8fd891 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryCoordinatorFailureTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryCoordinatorFailureTest.java
@@ -148,7 +148,7 @@ public void testClusterFailedNewCoordinatorInitialized() throws Exception {
stallSpi.startStall();
- // At this point startGrid(3) cannot proceed as well because openSocket() is blocked.
+ // At this point startGrid(3) cannot proceed as well because openSession() is blocked.
assertFalse(fut3.isDone());
fut4.get();
@@ -205,24 +205,14 @@ private static class StallingJoinDiscoverySpi extends TcpDiscoverySpi {
private volatile CountDownLatch stallLatch;
/** {@inheritDoc} */
- @Override protected Socket openSocket(
- InetSocketAddress sockAddr,
- IgniteSpiOperationTimeoutHelper timeoutHelper
- ) throws IOException, IgniteCheckedException {
- checkStall();
-
- return super.openSocket(sockAddr, timeoutHelper);
- }
-
- /** {@inheritDoc} */
- @Override protected Socket openSocket(
+ @Override protected TcpDiscoveryIoSession openSession(
Socket sock,
- InetSocketAddress remAddr,
+ InetSocketAddress sockAddr,
IgniteSpiOperationTimeoutHelper timeoutHelper
) throws IOException, IgniteCheckedException {
checkStall();
- return super.openSocket(sock, remAddr, timeoutHelper);
+ return super.openSession(sock, sockAddr, timeoutHelper);
}
/**
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryFailedJoinTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryFailedJoinTest.java
index 0b5eb6891e794..a53a814b6da3f 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryFailedJoinTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryFailedJoinTest.java
@@ -167,26 +167,15 @@ private void assertStartFailed(final String name) {
*/
private static class FailTcpDiscoverySpi extends TcpDiscoverySpi {
/** {@inheritDoc} */
- @Override protected Socket openSocket(
+ @Override protected TcpDiscoveryIoSession openSession(
+ Socket sock,
InetSocketAddress sockAddr,
IgniteSpiOperationTimeoutHelper timeoutHelper
) throws IOException, IgniteCheckedException {
if (sockAddr.getPort() == FAIL_PORT)
throw new SocketException("Connection refused");
- return super.openSocket(sockAddr, timeoutHelper);
- }
-
- /** {@inheritDoc} */
- @Override protected Socket openSocket(
- Socket sock,
- InetSocketAddress remAddr,
- IgniteSpiOperationTimeoutHelper timeoutHelper
- ) throws IOException, IgniteCheckedException {
- if (remAddr.getPort() == FAIL_PORT)
- throw new SocketException("Connection refused");
-
- return super.openSocket(sock, remAddr, timeoutHelper);
+ return super.openSession(sock, sockAddr, timeoutHelper);
}
}
@@ -195,13 +184,13 @@ private static class FailTcpDiscoverySpi extends TcpDiscoverySpi {
*/
private static class DropTcpDiscoverySpi extends TcpDiscoverySpi {
/** {@inheritDoc} */
- @Override protected void writeToSocket(
- Socket sock,
+ @Override protected void write(
+ TcpDiscoveryIoSession ses,
byte[] data,
long timeout
) throws IOException, IgniteCheckedException {
- if (sock.getPort() != FAIL_PORT)
- super.writeToSocket(sock, data, timeout);
+ if (ses.socket().getPort() != FAIL_PORT)
+ super.write(ses, data, timeout);
}
/** {@inheritDoc} */
@@ -212,13 +201,13 @@ private static class DropTcpDiscoverySpi extends TcpDiscoverySpi {
}
/** {@inheritDoc} */
- @Override protected void writeToSocket(
- Socket sock,
+ @Override protected void writeReceipt(
+ TcpDiscoveryIoSession ses,
int res,
long timeout
) throws IOException, IgniteCheckedException {
- if (sock.getPort() != FAIL_PORT)
- super.writeToSocket(sock, res, timeout);
+ if (ses.socket().getPort() != FAIL_PORT)
+ super.writeReceipt(ses, res, timeout);
}
}
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryNetworkIssuesTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryNetworkIssuesTest.java
index 37496f5d3b209..43996bbd6c438 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryNetworkIssuesTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryNetworkIssuesTest.java
@@ -191,21 +191,22 @@ public void testServerGetsSegmentedOnBecomeDangling() throws Exception {
IgniteEx ig1 = startGrid(NODE_1_NAME);
specialSpi = new TcpDiscoverySpi() {
- @Override protected int readReceipt(Socket sock, long timeout) throws IOException {
- if (netBroken.get() && sock.getPort() == NODE_3_PORT)
+ @Override protected int readReceipt(TcpDiscoveryIoSession ses, long timeout) throws IOException {
+ if (netBroken.get() && ses.socket().getPort() == NODE_3_PORT)
throw new SocketTimeoutException("Read timed out");
- return super.readReceipt(sock, timeout);
+ return super.readReceipt(ses, timeout);
}
- @Override protected Socket openSocket(
+ @Override protected TcpDiscoveryIoSession openSession(
+ Socket sock,
InetSocketAddress sockAddr,
IgniteSpiOperationTimeoutHelper timeoutHelper
) throws IOException, IgniteCheckedException {
if (netBroken.get() && sockAddr.getPort() == NODE_4_PORT)
throw new SocketTimeoutException("connect timed out");
- return super.openSocket(sockAddr, timeoutHelper);
+ return super.openSession(sock, sockAddr, timeoutHelper);
}
};
@@ -615,15 +616,15 @@ private boolean dropMsg(Socket sock) {
}
/** {@inheritDoc} */
- @Override protected void writeToSocket(
- Socket sock,
+ @Override protected void writeReceipt(
+ TcpDiscoveryIoSession ses,
int res,
long timeout
) throws IOException, IgniteCheckedException {
- if (dropMsg(sock))
+ if (dropMsg(ses.socket()))
return;
- super.writeToSocket(sock, res, timeout);
+ super.writeReceipt(ses, res, timeout);
}
/** {@inheritDoc} */
@@ -645,15 +646,15 @@ private boolean dropMsg(Socket sock) {
}
/** {@inheritDoc} */
- @Override protected void writeToSocket(
- Socket sock,
+ @Override protected void write(
+ TcpDiscoveryIoSession ses,
byte[] data,
long timeout
) throws IOException, IgniteCheckedException {
- if (dropMsg(sock))
+ if (dropMsg(ses.socket()))
return;
- super.writeToSocket(sock, data, timeout);
+ super.write(ses, data, timeout);
}
/**
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryPendingMessageDeliveryTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryPendingMessageDeliveryTest.java
index ec2f0c30ab2c1..4fabd12223492 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryPendingMessageDeliveryTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryPendingMessageDeliveryTest.java
@@ -18,7 +18,6 @@
package org.apache.ignite.spi.discovery.tcp;
import java.io.IOException;
-import java.net.Socket;
import java.util.Set;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCheckedException;
@@ -268,13 +267,13 @@ private class DyingThreadDiscoverySpi extends NoRingClosingTcpDiscoverySpi {
*/
private class DyingDiscoverySpi extends NoRingClosingTcpDiscoverySpi {
/** {@inheritDoc} */
- @Override protected void writeToSocket(
- Socket sock,
+ @Override protected void write(
+ TcpDiscoveryIoSession ses,
byte[] data,
long timeout
) throws IOException, IgniteCheckedException {
if (!blockMsgs)
- super.writeToSocket(sock, data, timeout);
+ super.write(ses, data, timeout);
}
/** {@inheritDoc} */
@@ -285,13 +284,13 @@ private class DyingDiscoverySpi extends NoRingClosingTcpDiscoverySpi {
}
/** {@inheritDoc} */
- @Override protected void writeToSocket(
- Socket sock,
+ @Override protected void writeReceipt(
+ TcpDiscoveryIoSession ses,
int res,
long timeout
) throws IOException, IgniteCheckedException {
if (!blockMsgs)
- super.writeToSocket(sock, res, timeout);
+ super.writeReceipt(ses, res, timeout);
}
}
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpiFailureTimeoutSelfTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpiFailureTimeoutSelfTest.java
index c71c26b054063..e7fccc4e86347 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpiFailureTimeoutSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpiFailureTimeoutSelfTest.java
@@ -263,7 +263,7 @@ private static class TestTcpDiscoverySpi extends TcpDiscoverySpi {
private volatile IgniteSpiOperationTimeoutException err;
/** {@inheritDoc} */
- @Override protected Socket openSocket(
+ @Override protected TcpDiscoveryIoSession openSession(
Socket sock,
InetSocketAddress sockAddr,
IgniteSpiOperationTimeoutHelper timeoutHelper
@@ -291,7 +291,7 @@ else if (openSockTimeoutWait) {
}
}
- super.openSocket(sock, sockAddr, timeoutHelper);
+ TcpDiscoveryIoSession ses = super.openSession(sock, sockAddr, timeoutHelper);
try {
Thread.sleep(1500);
@@ -300,7 +300,7 @@ else if (openSockTimeoutWait) {
// No-op.
}
- return sock;
+ return ses;
}
/** {@inheritDoc} */
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpiReconnectDelayTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpiReconnectDelayTest.java
index 21c7207c6b04e..0b3f253bc4cc3 100644
--- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpiReconnectDelayTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpiReconnectDelayTest.java
@@ -421,15 +421,15 @@ private static class FailingTcpDiscoverySpi extends TcpDiscoverySpi {
}
/** {@inheritDoc} */
- @Override protected void writeToSocket(
- Socket sock,
+ @Override protected void writeReceipt(
+ TcpDiscoveryIoSession ses,
int res,
long timeout
) throws IOException, IgniteCheckedException {
- if (msgTracker.lastFor(sock) instanceof TcpDiscoveryJoinRequestMessage && failJoinReqRes.getAndDecrement() > 0)
+ if (msgTracker.lastFor(ses) instanceof TcpDiscoveryJoinRequestMessage && failJoinReqRes.getAndDecrement() > 0)
res = RES_WAIT;
- super.writeToSocket(sock, res, timeout);
+ super.writeReceipt(ses, res, timeout);
}
/**
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 55e53c7d44cb1..4767e5fdc587d 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
@@ -1414,7 +1414,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);
@@ -1465,7 +1465,7 @@ protected List evictingPartitionsAfterJoin(Ignite ign, IgniteCache, ?
GridTestNode fakeNode = new GridTestNode(UUID.randomUUID(), null);
- fakeNode.consistentId(getTestIgniteInstanceName(nodes.size()));
+ fakeNode.setConsistentId(getTestIgniteInstanceName(nodes.size()));
nodes.add(fakeNode);
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java
index c8ff74b6ced33..e8a54f1c0d41f 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java
@@ -67,6 +67,7 @@
import org.apache.ignite.internal.processors.rollingupgrade.PluginVersionRollingUpgradeTest;
import org.apache.ignite.internal.processors.rollingupgrade.feature.IgniteFeatureSetTest;
import org.apache.ignite.internal.processors.rollingupgrade.feature.ManagementApiVersionValidationTest;
+import org.apache.ignite.internal.processors.rollingupgrade.message.RollingUpgradeMessageSerializationTest;
import org.apache.ignite.internal.product.GridProductVersionSelfTest;
import org.apache.ignite.internal.util.ErrorMessageSelfTest;
import org.apache.ignite.internal.util.nio.IgniteExceptionInNioWorkerSelfTest;
@@ -112,6 +113,7 @@
CoreVersionRollingUpgradeTest.class,
PluginVersionRollingUpgradeTest.class,
+ RollingUpgradeMessageSerializationTest.class,
ManagementApiVersionValidationTest.class,
GridProductVersionSelfTest.class,
GridAffinityAssignmentV2Test.class,
diff --git a/modules/core/src/test/resources/codegen/ChildMessageSerializer.java b/modules/core/src/test/resources/codegen/ChildMessageSerializer.java
index 8f77e193422f7..1dd438554f9a0 100644
--- a/modules/core/src/test/resources/codegen/ChildMessageSerializer.java
+++ b/modules/core/src/test/resources/codegen/ChildMessageSerializer.java
@@ -19,6 +19,7 @@
import org.apache.ignite.internal.AbstractMessage;
import org.apache.ignite.internal.ChildMessage;
+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;
@@ -30,7 +31,7 @@
*/
public final class ChildMessageSerializer implements MessageSerializer {
/** */
- @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..4461ca0bea9c1 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
@@ -85,6 +85,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
@@ -1506,7 +1507,7 @@ private void processWriteSsl(SelectionKey key) throws IOException {
List pendingRequests = new ArrayList<>(2);
if (req != null)
- finished = writeToBuffer(writer, buf, req, pendingRequests);
+ finished = writeToBuffer(ses, writer, buf, req, pendingRequests);
// Fill up as many messages as possible to write buffer.
while (finished) {
@@ -1518,7 +1519,7 @@ private void processWriteSsl(SelectionKey key) throws IOException {
if (req == null)
break;
- finished = writeToBuffer(writer, buf, req, pendingRequests);
+ finished = writeToBuffer(ses, writer, buf, req, pendingRequests);
}
int sesBufLimit = buf.limit();
@@ -1588,6 +1589,7 @@ private void processWriteSsl(SelectionKey key) throws IOException {
}
/**
+ * @param ses Session the message is written to.
* @param writer Customizer of writing.
* @param buf Buffer to write.
* @param req Source of data.
@@ -1595,6 +1597,7 @@ private void processWriteSsl(SelectionKey key) throws IOException {
* @return {@code true} if message successfully written to buffer and {@code false} otherwise.
*/
private boolean writeToBuffer(
+ GridSelectorNioSessionImpl ses,
MessageWriter writer,
ByteBuffer buf,
SessionWriteRequest req,
@@ -1614,7 +1617,7 @@ private boolean writeToBuffer(
else {
writer.setBuffer(buf);
- finished = MessageSerialization.writeTo(messageFactory(), msg, writer);
+ finished = MessageSerialization.writeTo(messageFactory(), msg, writer, resolveSerializationContext(ses));
}
if (finished) {
@@ -1781,14 +1784,18 @@ 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.
* @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
+ ) {
Message msg;
boolean finished;
msg = (Message)req.message();
@@ -1803,7 +1810,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, resolveSerializationContext(ses));
}
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..5f888f042ad3a 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,6 +17,7 @@
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;
@@ -40,11 +41,17 @@ 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
+ ) {
+ return resolveMessageserializer(factory, msg).writeTo(msg, writer, ctx);
}
/**
@@ -53,16 +60,31 @@ 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
+ ) {
+ return resolveMessageserializer(factory, msg).readFrom(msg, reader, ctx);
+ }
+
+ /** */
+ public static MessageSerializationContext resolveSerializationContext(GridNioSession ses) {
+ MessageSerializationContext ctx = ses.meta(GridNioSessionMetaKey.MSG_SER_CTX.ordinal());
+
+ assert ctx != null : "Session has no serialization context: " + ses;
+
+ return ctx;
}
/** @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..d5439362129ea 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,13 @@ 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..451fe3d66efb9 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.IGNORED;
+
/**
* 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, IGNORED);
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, IGNORED);
assert read != -1 || finished : "Stream closed before message was fully read.";