Goal is a communication protocol that able to work between nodes with different Ignite versions.
It is proposed to work between versions that differ by 1 minor version, for example 2.20.X between 2.19.X (but not between 2.20.X and 2.18.X).
Communication protocol consist of 2 parts:
Message classes, including ser/des algorithm.Messages to remote node.Message - is base class for all messages transported between nodes. Proposed changes:
Message#writeTo consumes IgniteProductVersion of destination node and use it for serializing data for this version (mostly, for ignoring some fields).Message#readFrom consumes IgniteProductVersion of source node and use it for deserializing data (mostly, for setting default values of new fields).
public interface Message {
public boolean writeTo(ByteBuffer buf, MessageWriter writer, IgniteProductVersion destVer);
public boolean readFrom(ByteBuffer buf, MessageReader reader, IgniteProductVersion srcVer);
public short directType();
} |
@Since and @Until for Message classes and Message fields, to use it for generating code for Message#writeTo and Message#readFrom:@Since(version = "2.19.0")
public class MyMessage {
private int id;
@Until(version = "2.20.0")
private String rmFld;
@Since(version = "2.20.0")
private String newFld;
@Override public boolean writeTo(ByteBuffer buf, MessageWriter writer, IgniteProductVersion destVer) {
if (destVer.lessThan(2, 19, 0))
throw new IgniteException("Must not send the message to destination node");
if (!writer.writeString(id))
return false;
if (destVer.lessThan(2, 20, 0)) {
if (!writer.writeString(rmFld))
return false;
}
if (destVer.greaterThanEqual(2, 20, 0)) {
if (!writer.writeString(newFld))
return false;
}
return true;
}
@Override public boolean readFrom(ByteBuffer buf, MessageReader reader, IgniteProductVersion srcVer) {
id = reader.readString();
if (srcVer.greaterThanEqual(2, 20, 0))
newFld = reader.readString();
else
newFld = null;
return true;
}
} |
Introduce Communication Protocol Version (ProtoVer) that depends on changes in the parts:
Message. Version is updated along with a commit that introduce a change.Message).Rules to support compatibility:
Messages. Only adding new fields is allowed.FeatureTable).@since Ignite version.(@since - 1) version. @since version and notify release manager to drop support of old versions.ProtoVer is fixed for Ignite release version. Nodes exchange theirs ProtoVer, FeatureMask on joining node on discovery:
ProtoVer.Major is different then FeatureMask is validated. Let the cluster version V, the joining node version V+2. If the joining node mask contains features since V + 1, then this node must not be join the cluster.ProtoVer.Minor is differrent then enable Rolling upgrade mode for communication protocol between nodes with different versions.Stable mode.Handshake algorithm is extended on new step - validating TcpCommunicationConfiguration consistency. Settings that affects both communicating nodes must be same:
In Stable mode logic of exchanging messages is not changed. Between nodes open channel, messages are written to the channel one by one as byte stream. There is no delimeters between messages, each message starts with direct type. Reader knows reads full message with Message#readFrom logic.
| Message header | Message |
|---|---|
2 bytes: direct type | fields |
In Rolling upgrade mode logic is different, because node can't know whether it reads full message - Message#readFrom can't guarantee that.
Message#readFrom returns true or fields count is achieved. Then the message is processed.| Frame header | Message header | Message | |||
|---|---|---|---|---|---|
1 byte: 1bit - continuation bit 2-7bit - reserved | 2 bytes: unsigned frame size (frame size limit 64Kb) | 2 bytes: direct type | 1 byte: fields count (max 255 fields) | fields | trailing zeros |