Skip to content

Commit

Permalink
Adds cluster version and node-cluster version validation.
Browse files Browse the repository at this point in the history
  • Loading branch information
vbekiaris committed Nov 15, 2016
1 parent 6860693 commit 0e8e885
Show file tree
Hide file tree
Showing 61 changed files with 1,962 additions and 311 deletions.
Expand Up @@ -22,6 +22,7 @@
import com.hazelcast.core.Member;
import com.hazelcast.core.MembershipListener;
import com.hazelcast.transaction.TransactionOptions;
import com.hazelcast.version.Version;

import java.util.Collection;
import java.util.LinkedHashSet;
Expand Down Expand Up @@ -74,6 +75,11 @@ public void changeClusterState(ClusterState newState) {
throw new UnsupportedOperationException();
}

@Override
public Version getClusterVersion() {
throw new UnsupportedOperationException();
}

@Override
public void changeClusterState(ClusterState newState, TransactionOptions transactionOptions) {
throw new UnsupportedOperationException();
Expand Down
Expand Up @@ -42,6 +42,7 @@
import com.hazelcast.topic.impl.reliable.ReliableMessageListenerAdapter;
import com.hazelcast.topic.impl.reliable.ReliableTopicMessage;
import com.hazelcast.util.UuidUtil;
import com.hazelcast.version.Version;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
Expand Down Expand Up @@ -259,7 +260,7 @@ private void process(ReliableTopicMessage message) throws Throwable {
private Message<E> toMessage(ReliableTopicMessage m) {
Member member = null;
if (m.getPublisherAddress() != null) {
member = new com.hazelcast.client.impl.MemberImpl(m.getPublisherAddress());
member = new com.hazelcast.client.impl.MemberImpl(m.getPublisherAddress(), Version.UNKNOWN);
}
E payload = serializationService.toObject(m.getPayload());
return new Message<E>(name, payload, m.getPublishTime(), member);
Expand Down
15 changes: 10 additions & 5 deletions hazelcast/src/main/java/com/hazelcast/client/impl/MemberImpl.java
Expand Up @@ -21,6 +21,7 @@
import com.hazelcast.logging.ILogger;
import com.hazelcast.nio.Address;
import com.hazelcast.nio.serialization.impl.BinaryInterface;
import com.hazelcast.version.Version;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

import java.util.Map;
Expand All @@ -37,16 +38,20 @@ public final class MemberImpl extends AbstractMember implements Member {
public MemberImpl() {
}

public MemberImpl(Address address) {
super(address);
public MemberImpl(Address address, Version version) {
super(address, version);
}

public MemberImpl(Address address, String uuid) {
super(address, uuid);
public MemberImpl(Address address, Version version, String uuid) {
super(address, version, uuid);
}

public MemberImpl(Address address, String uuid, Map<String, Object> attributes, boolean liteMember) {
super(address, uuid, attributes, liteMember);
super(address, Version.UNKNOWN, uuid, attributes, liteMember);
}

public MemberImpl(Address address, Version version, String uuid, Map<String, Object> attributes, boolean liteMember) {
super(address, version, uuid, attributes, liteMember);
}

public MemberImpl(AbstractMember member) {
Expand Down
26 changes: 26 additions & 0 deletions hazelcast/src/main/java/com/hazelcast/core/Cluster.java
Expand Up @@ -20,6 +20,7 @@
import com.hazelcast.spi.properties.GroupProperty;
import com.hazelcast.transaction.TransactionException;
import com.hazelcast.transaction.TransactionOptions;
import com.hazelcast.version.Version;

import java.util.Set;

Expand Down Expand Up @@ -168,6 +169,31 @@ public interface Cluster {
*/
void changeClusterState(ClusterState newState, TransactionOptions transactionOptions);

/**
* The cluster version indicates the operating version of the cluster. It is separate from each node's codebase version,
* as it may be acceptable for a node to operate at a different compatibility version than its codebase version. This method
* may return {@code null} if invoked after the ClusterService is constructed and before the node forms a cluster, either
* by joining existing members or becoming master of its standalone cluster if it is the first node on the cluster.
* Importantly, this is the time during which a lifecycle event with state
* {@link com.hazelcast.core.LifecycleEvent.LifecycleState#STARTING} is triggered.
*
* For example, consider a cluster comprised of nodes running on {@code hazelcast-3.8.jar}. Each node's codebase version
* is 3.8.0 and on startup the cluster version is also 3.8.0. After a while, another node joins, running on
* {@code hazelcast-3.9.jar}; this node's codebase version is 3.9.0. If deemed compatible, it is allowed to join the cluster.
* At this point, the cluster version is still 3.8.0, the 3.9.0 member should be able to adapt its behaviour to be compatible
* with other the 3.8.0 members. Once all 3.8.0 members have been shutdown and replaced by other members on codebase
* version 3.9.0, still the cluster version will be 3.8.0. At this point, it is possible to update the cluster version to
* 3.9.0, since all cluster members will be compatible with the new cluster version. Once cluster version
* is updated to 3.9.0, further communication among members will take place in 3.9.0 and all new features and functionality
* of version 3.9.0 will be available.
*
* @return the version at which this cluster operates.
* @see com.hazelcast.internal.cluster.ClusterService#changeClusterVersion(Version)
* @see com.hazelcast.internal.cluster.ClusterService#changeClusterVersion(Version, TransactionOptions)
* @since 3.8
*/
Version getClusterVersion();

/**
* Changes state of the cluster to the {@link ClusterState#PASSIVE} transactionally,
* then triggers the shutdown process on each node. Transaction will be {@code TWO_PHASE}
Expand Down
13 changes: 13 additions & 0 deletions hazelcast/src/main/java/com/hazelcast/core/Member.java
Expand Up @@ -16,8 +16,10 @@

package com.hazelcast.core;

import com.hazelcast.internal.cluster.ClusterService;
import com.hazelcast.nio.Address;
import com.hazelcast.nio.serialization.DataSerializable;
import com.hazelcast.version.Version;

import java.net.InetSocketAddress;
import java.util.Map;
Expand Down Expand Up @@ -258,4 +260,15 @@ public interface Member extends DataSerializable, Endpoint {
*/
void removeAttribute(String key);

/**
* Returns the Hazelcast codebase version of this member; this may or may not be different from the version reported by
* {@link ClusterService#getClusterVersion()}, for example when a node with a different codebase version is added to an
* existing cluster. See the documentation for {@link ClusterService#getClusterVersion()} for a more thorough discussion
* of {@code Cluster} and {@code Member} / {@code Node} version.
*
* @return the {@link Version} of this member.
* @since 3.8
*/
Version getVersion();

}
Expand Up @@ -19,6 +19,7 @@
import com.hazelcast.instance.MemberImpl;
import com.hazelcast.nio.Address;
import com.hazelcast.spi.exception.RetryableException;
import com.hazelcast.version.Version;

import java.io.IOException;
import java.io.ObjectInputStream;
Expand Down Expand Up @@ -57,13 +58,14 @@ private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();

Address address = member.getAddress();
String host = address.getHost();
String host = address.getHost();
int port = address.getPort();

out.writeUTF(member.getUuid());
out.writeUTF(host);
out.writeInt(port);
out.writeBoolean(member.isLiteMember());
out.writeObject(member.getVersion());
}

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
Expand All @@ -73,7 +75,8 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE
String host = in.readUTF();
int port = in.readInt();
boolean liteMember = in.readBoolean();
Version version = (Version) in.readObject();

member = new MemberImpl(new Address(host, port), false, uuid, null, null, liteMember);
member = new MemberImpl(new Address(host, port), version, false, uuid, null, null, liteMember);
}
}
27 changes: 19 additions & 8 deletions hazelcast/src/main/java/com/hazelcast/instance/AbstractMember.java
Expand Up @@ -16,15 +16,16 @@

package com.hazelcast.instance;

import com.hazelcast.nio.serialization.impl.BinaryInterface;
import com.hazelcast.cluster.MemberAttributeOperationType;
import com.hazelcast.core.Member;
import com.hazelcast.logging.ILogger;
import com.hazelcast.nio.Address;
import com.hazelcast.nio.IOUtil;
import com.hazelcast.nio.ObjectDataInput;
import com.hazelcast.nio.ObjectDataOutput;
import com.hazelcast.nio.serialization.impl.BinaryInterface;
import com.hazelcast.spi.annotation.PrivateApi;
import com.hazelcast.version.Version;

import java.io.IOException;
import java.net.InetAddress;
Expand All @@ -43,24 +44,26 @@ public abstract class AbstractMember implements Member {
protected Address address;
protected String uuid;
protected boolean liteMember;
protected Version version;

protected AbstractMember() {
}

protected AbstractMember(Address address) {
this(address, null, null);
protected AbstractMember(Address address, Version version) {
this(address, version, null, null);
}

protected AbstractMember(Address address, String uuid) {
this(address, uuid, null);
protected AbstractMember(Address address, Version version, String uuid) {
this(address, version, uuid, null);
}

protected AbstractMember(Address address, String uuid, Map<String, Object> attributes) {
this(address, uuid, attributes, false);
protected AbstractMember(Address address, Version version, String uuid, Map<String, Object> attributes) {
this(address, version, uuid, attributes, false);
}

protected AbstractMember(Address address, String uuid, Map<String, Object> attributes, boolean liteMember) {
protected AbstractMember(Address address, Version version, String uuid, Map<String, Object> attributes, boolean liteMember) {
this.address = address;
this.version = version;
this.uuid = uuid;
if (attributes != null) {
this.attributes.putAll(attributes);
Expand All @@ -70,6 +73,7 @@ protected AbstractMember(Address address, String uuid, Map<String, Object> attri

protected AbstractMember(AbstractMember member) {
this.address = member.address;
this.version = member.version;
this.uuid = member.uuid;
this.attributes.putAll(member.attributes);
this.liteMember = member.liteMember;
Expand Down Expand Up @@ -149,12 +153,18 @@ protected Object getAttribute(String key) {
return attributes.get(key);
}

@Override
public Version getVersion() {
return version;
}

@Override
public void readData(ObjectDataInput in) throws IOException {
address = new Address();
address.readData(in);
uuid = in.readUTF();
liteMember = in.readBoolean();
version = in.readObject();
int size = in.readInt();
for (int i = 0; i < size; i++) {
String key = in.readUTF();
Expand All @@ -168,6 +178,7 @@ public void writeData(ObjectDataOutput out) throws IOException {
address.writeData(out);
out.writeUTF(uuid);
out.writeBoolean(liteMember);
out.writeObject(version);
Map<String, Object> attributes = new HashMap<String, Object>(this.attributes);
out.writeInt(attributes.size());
for (Map.Entry<String, Object> entry : attributes.entrySet()) {
Expand Down
Expand Up @@ -28,9 +28,22 @@
*/
public final class BuildInfoProvider {

/**
* Use this in production code to obtain the BuildInfo already parsed when this class was first loaded.
* Its properties will not change at runtime.
*/
public static final BuildInfo BUILD_INFO = getBuildInfo();

private BuildInfoProvider() {
}

/**
* Parses {@code hazelcast-runtime.properties} for {@code BuildInfo}; also checks for overrides in System.properties.
* Use this method to obtain and cache a {@code BuildInfo} object or from test code that needs to re-parse properties
* on each invocation.
*
* @return the parsed BuildInfo
*/
public static BuildInfo getBuildInfo() {
final InputStream inRuntimeProperties =
BuildInfoProvider.class.getClassLoader().getResourceAsStream("hazelcast-runtime.properties");
Expand Down Expand Up @@ -63,6 +76,12 @@ public static BuildInfo getBuildInfo() {
}
int buildNumber = Integer.parseInt(build);

// override version with a system property
String overridingVersion = System.getProperty("hazelcast.version");
if (overridingVersion != null) {
version = overridingVersion;
}

String sv = runtimeProperties.getProperty("hazelcast.serialization.version");
byte serialVersion = Byte.parseByte(sv);
return new BuildInfo(version, build, revision, buildNumber, enterprise, serialVersion);
Expand Down

0 comments on commit 0e8e885

Please sign in to comment.