blob: 4b97b86bc3aca0c624a4c1331835d30a183579a4 [file] [log] [blame]
/*
* 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.geode.distributed.internal.membership;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.EOFException;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import org.apache.geode.DataSerializer;
import org.apache.geode.InternalGemFireError;
import org.apache.geode.annotations.Immutable;
import org.apache.geode.annotations.VisibleForTesting;
import org.apache.geode.annotations.internal.MutableForTesting;
import org.apache.geode.cache.client.ServerConnectivityException;
import org.apache.geode.distributed.DistributedMember;
import org.apache.geode.distributed.DurableClientAttributes;
import org.apache.geode.distributed.Role;
import org.apache.geode.distributed.internal.ClusterDistributionManager;
import org.apache.geode.distributed.internal.DistributionAdvisor.ProfileId;
import org.apache.geode.distributed.internal.ServerLocation;
import org.apache.geode.distributed.internal.membership.gms.api.MemberData;
import org.apache.geode.distributed.internal.membership.gms.api.MemberDataBuilder;
import org.apache.geode.distributed.internal.membership.gms.api.MemberIdentifier;
import org.apache.geode.internal.Assert;
import org.apache.geode.internal.InternalDataSerializer;
import org.apache.geode.internal.OSProcess;
import org.apache.geode.internal.cache.versions.VersionSource;
import org.apache.geode.internal.net.SocketCreator;
import org.apache.geode.internal.serialization.DataSerializableFixedID;
import org.apache.geode.internal.serialization.DeserializationContext;
import org.apache.geode.internal.serialization.SerializationContext;
import org.apache.geode.internal.serialization.UnsupportedSerializationVersionException;
import org.apache.geode.internal.serialization.Version;
/**
* This is the fundamental representation of a member of a GemFire distributed system.
*/
public class InternalDistributedMember
implements DistributedMember, MemberIdentifier, Externalizable,
DataSerializableFixedID, ProfileId, VersionSource<DistributedMember> {
private static final long serialVersionUID = -2785249969777296507L;
private MemberData memberData; // the underlying member object
/**
* whether this is a partial member ID (without roles, durable attributes). We use partial IDs in
* EventID objects to reduce their size. It would be better to use canonical IDs but there is
* currently no central mechanism that would allow that for both server and client identifiers
*/
private boolean isPartial;
/**
* The roles, if any, of this member. Lazily created first time getRoles() is called.
*/
private volatile Set<Role> rolesSet = null;
/** lock object used when getting/setting roles/rolesSet fields */
private final Object rolesLock = new Object();
/**
* Unique tag (such as randomly generated bytes) to help enforce uniqueness. Note: this should be
* displayable.
*/
private String uniqueTag = null;
/** serialization bit flag */
private static final int NPD_ENABLED_BIT = 0x1;
/** serialization bit flag */
private static final int COORD_ENABLED_BIT = 0x2;
/** partial ID bit flag */
private static final int PARTIAL_ID_BIT = 0x4;
/** product version bit flag */
private static final int VERSION_BIT = 0x8;
public int getVmPid() {
return memberData.getProcessId();
}
@Override
public int compareTo(DistributedMember o) {
return compareTo(o, false, true);
}
public void setDurableTimeout(int newValue) {
memberData.setDurableTimeout(newValue);
}
public void setDurableId(String id) {
memberData.setDurableId(id);
}
@FunctionalInterface
public interface HostnameResolver {
InetAddress getInetAddress(ServerLocation location) throws UnknownHostException;
}
public static void setHostnameResolver(final HostnameResolver hostnameResolver) {
InternalDistributedMember.hostnameResolver = hostnameResolver;
}
/** Retrieves an InetAddress given the provided hostname */
@MutableForTesting
private static HostnameResolver hostnameResolver =
(location) -> InetAddress.getByName(location.getHostName());
private transient Version versionObj = Version.CURRENT;
/** The versions in which this message was modified */
@Immutable
private static final Version[] dsfidVersions = new Version[] {
Version.GFE_71, Version.GFE_90};
private void defaultToCurrentHost() {
memberData.setProcessId(OSProcess.getId());
try {
if (SocketCreator.resolve_dns) {
memberData.setHostName(SocketCreator.getHostName(SocketCreator.getLocalHost()));
} else {
memberData.setHostName(SocketCreator.getLocalHost().getHostAddress());
}
} catch (UnknownHostException ee) {
throw new InternalGemFireError(ee);
}
}
// Used only by deserialization
public InternalDistributedMember() {}
/**
* Construct a InternalDistributedMember
* <p>
*
* This, and the following constructor are the only valid ways to create an ID for a distributed
* member for use in the P2P cache. Use of other constructors can break
* network-partition-detection.
*
* @param i the inet address
* @param membershipPort the membership port
* @param splitBrainEnabled whether this feature is enabled for the member
* @param canBeCoordinator whether the member is eligible to be the membership coordinator
*/
public InternalDistributedMember(InetAddress i, int membershipPort, boolean splitBrainEnabled,
boolean canBeCoordinator) {
String hostName = SocketCreator.resolve_dns ? SocketCreator.getHostName(i) : i.getHostAddress();
this.memberData = MemberDataBuilder.newBuilder(i, hostName)
.setMembershipPort(membershipPort)
.setNetworkPartitionDetectionEnabled(splitBrainEnabled)
.setPreferredForCoordinator(canBeCoordinator)
.build();
this.versionObj = Version.CURRENT;
}
/**
* Construct a InternalDistributedMember based on the given member data.
*
*/
public InternalDistributedMember(MemberData m) {
memberData = m;
if (memberData.getHostName() == null || memberData.isPartial()) {
String hostName = SocketCreator.resolve_dns ? SocketCreator.getHostName(m.getInetAddress())
: m.getInetAddress().getHostAddress();
memberData.setHostName(hostName);
}
short version = m.getVersionOrdinal();
try {
this.versionObj = Version.fromOrdinal(version);
} catch (UnsupportedSerializationVersionException e) {
this.versionObj = Version.CURRENT;
}
cachedToString = null;
this.isPartial = m.isPartial();
}
/**
* Replace the current member data with the given member data. This can be used to fill out an
* InternalDistributedMember that was created from a partial data created by
* readEssentialData.
*
* @param m the replacement member data
*/
public void setMemberData(MemberData m) {
this.memberData = m;
}
/**
* Create a InternalDistributedMember referring to the current host (as defined by the given
* string).
* <p>
*
* <b> THIS METHOD IS FOR TESTING ONLY. DO NOT USE IT TO CREATE IDs FOR USE IN THE PRODUCT. IT
* DOES NOT PROPERLY INITIALIZE ATTRIBUTES NEEDED FOR P2P FUNCTIONALITY. </b>
*
*
* @param i the hostname, stored in the member ID but not resolved - local host inet addr is used
* @param p the membership listening port
* @throws RuntimeException if the given hostname cannot be resolved
*/
@VisibleForTesting
public InternalDistributedMember(String i, int p) {
this(MemberDataBuilder.newBuilderForLocalHost(i)
.setMembershipPort(p)
.build());
}
/**
* Creates a new InternalDistributedMember for use in notifying listeners in client
* caches. The version information in the ID is set to Version.CURRENT.
*
* @param location the coordinates of the server
*/
public InternalDistributedMember(ServerLocation location) {
final InetAddress addr;
try {
addr = hostnameResolver.getInetAddress(location);
} catch (UnknownHostException e) {
throw new ServerConnectivityException("Unable to resolve server location " + location, e);
}
memberData = MemberDataBuilder.newBuilder(addr, location.getHostName())
.setMembershipPort(location.getPort())
.setNetworkPartitionDetectionEnabled(false)
.setPreferredForCoordinator(true)
.build();
versionObj = Version.CURRENT;
}
/**
* Create a InternalDistributedMember referring to the current host (as defined by the given
* string) with additional info including optional connection name and an optional unique string.
* Currently these two optional fields (and this constructor) are only used by the
* LonerDistributionManager.
* <p>
*
* < b> DO NOT USE THIS METHOD TO CREATE ANYTHING OTHER THAN A LONER ID. IT DOES NOT PROPERLY
* INITIALIZE THE ID. </b>
*
* @param host the hostname, must be for the current host
* @param p the membership port
* @param n member name
* @param u unique string used make the member more unique
* @param vmKind the dmType
* @param groups the server groups / roles
* @param attr durable client attributes, if any
*
* @throws UnknownHostException if the given hostname cannot be resolved
*/
public InternalDistributedMember(String host, int p, String n, String u, int vmKind,
String[] groups, DurableClientAttributes attr) throws UnknownHostException {
InetAddress addr = SocketCreator.toInetAddress(host);
MemberDataBuilder builder = MemberDataBuilder.newBuilder(addr, host)
.setName(n)
.setMembershipPort(p)
.setDirectChannelPort(p)
.setPreferredForCoordinator(false)
.setNetworkPartitionDetectionEnabled(true)
.setVmKind(vmKind)
.setGroups(groups);
if (attr != null) {
builder.setDurableId(attr.getId())
.setDurableTimeout(attr.getTimeout());
}
memberData = builder.build();
defaultToCurrentHost();
this.uniqueTag = u;
}
/**
* Create a InternalDistributedMember
* <p>
*
* <b> THIS METHOD IS FOR TESTING ONLY. DO NOT USE IT TO CREATE IDs FOR USE IN THE PRODUCT. IT
* DOES NOT PROPERLY INITIALIZE ATTRIBUTES NEEDED FOR P2P FUNCTIONALITY. </b>
*
*
* @param i the host address
* @param p the membership listening port
*/
public InternalDistributedMember(InetAddress i, int p) {
memberData = MemberDataBuilder.newBuilder(i, "localhost")
.setMembershipPort(p)
.build();
defaultToCurrentHost();
}
/**
* Create a InternalDistributedMember as defined by the given address.
* <p>
*
* <b> THIS METHOD IS FOR TESTING ONLY. DO NOT USE IT TO CREATE IDs FOR USE IN THE PRODUCT. IT
* DOES NOT PROPERLY INITIALIZE ATTRIBUTES NEEDED FOR P2P FUNCTIONALITY. </b>
*
* @param addr address of the server
* @param p the listening port of the server
* @param isCurrentHost true if the given host refers to the current host (bridge and gateway use
* false to create a temporary id for the OTHER side of a connection)
*/
public InternalDistributedMember(InetAddress addr, int p, boolean isCurrentHost) {
memberData = MemberDataBuilder.newBuilder(addr, "localhost")
.setMembershipPort(p).build();
if (isCurrentHost) {
defaultToCurrentHost();
}
}
/**
* Return the underlying host address
*
* @return the underlying host address
*/
public InetAddress getInetAddress() {
return memberData.getInetAddress();
}
/**
* Return the underlying port (membership port)
*
* @return the underlying membership port
*/
public int getMembershipPort() {
return memberData.getMembershipPort();
}
@Override
public short getVersionOrdinal() {
return versionObj == null ? memberData.getVersionOrdinal() : versionObj.ordinal();
}
/**
* Returns the port on which the direct channel runs
*/
public int getDirectChannelPort() {
assert !this.isPartial;
return memberData.getDirectChannelPort();
}
/**
* [GemStone] Returns the kind of VM that hosts the distribution manager with this address.
*
* @see ClusterDistributionManager#getDMType()
* @see ClusterDistributionManager#NORMAL_DM_TYPE
*/
public int getVmKind() {
return memberData.getVmKind();
}
@Override
public int getMemberWeight() {
return memberData.getMemberWeight();
}
/**
* Returns the membership view ID that this member was born in. For backward compatibility reasons
* this is limited to 16 bits.
*/
public int getVmViewId() {
return memberData.getVmViewId();
}
@Override
public boolean preferredForCoordinator() {
return memberData.isPreferredForCoordinator();
}
/**
* Returns an unmodifiable Set of this member's Roles.
*/
@Override
public Set<Role> getRoles() {
Set<Role> tmpRolesSet = this.rolesSet;
if (tmpRolesSet != null) {
return tmpRolesSet;
}
assert !this.isPartial;
synchronized (this.rolesLock) {
tmpRolesSet = this.rolesSet;
if (tmpRolesSet == null) {
final String[] tmpRoles = memberData.getGroups();
// convert array of string role names to array of Roles...
if (tmpRoles == null || tmpRoles.length == 0) {
tmpRolesSet = Collections.emptySet();
} else {
tmpRolesSet = new HashSet<Role>(tmpRoles.length);
for (int i = 0; i < tmpRoles.length; i++) {
tmpRolesSet.add(InternalRole.getRole(tmpRoles[i]));
}
tmpRolesSet = Collections.unmodifiableSet(tmpRolesSet);
}
this.rolesSet = tmpRolesSet;
}
}
Assert.assertTrue(tmpRolesSet != null);
return tmpRolesSet;
}
@Override
public List<String> getGroups() {
return Collections.unmodifiableList(Arrays.asList(memberData.getGroups()));
}
public void setGroups(String[] newGroups) {
assert !this.isPartial;
assert newGroups != null;
synchronized (this.rolesLock) {
memberData.setGroups(newGroups);
this.rolesSet = null;
this.cachedToString = null;
}
}
@Override
public void setVmViewId(int p) {
memberData.setVmViewId(p);
cachedToString = null;
}
@Override
public void setPreferredForCoordinator(boolean preferred) {
memberData.setPreferredForCoordinator(preferred);
cachedToString = null;
}
@Override
public void setDirectChannelPort(int dcPort) {
memberData.setDirectChannelPort(dcPort);
cachedToString = null;
}
@Override
public void setVmKind(int dmType) {
memberData.setVmKind(dmType);
cachedToString = null;
}
/**
* Returns the name of this member's distributed system connection or null if no name was
* specified.
*/
@Override
public String getName() {
String result = memberData.getName();
if (result == null) {
result = "";
}
return result;
}
/**
* Returns this client member's durable attributes or null if no durable attributes were created.
*/
@Override
public DurableClientAttributes getDurableClientAttributes() {
assert !this.isPartial;
String durableId = memberData.getDurableId();
if (durableId == null || durableId.isEmpty()) {
return new DurableClientAttributes("", 300);
}
return new DurableClientAttributes(durableId, memberData.getDurableTimeout());
}
public int compareTo(DistributedMember o, boolean compareMemberData, boolean compareViewIds) {
if (this == o) {
return 0;
}
// obligatory type check
if (!(o instanceof InternalDistributedMember))
throw new ClassCastException(
"InternalDistributedMember.compareTo(): comparison between different classes");
InternalDistributedMember other = (InternalDistributedMember) o;
int myPort = getMembershipPort();
int otherPort = other.getMembershipPort();
if (myPort < otherPort)
return -1;
if (myPort > otherPort)
return 1;
InetAddress myAddr = getInetAddress();
InetAddress otherAddr = other.getInetAddress();
// Discard null cases
if (myAddr == null && otherAddr == null) {
return 0;
} else if (myAddr == null) {
return -1;
} else if (otherAddr == null)
return 1;
byte[] myBytes = myAddr.getAddress();
byte[] otherBytes = otherAddr.getAddress();
if (myBytes != otherBytes) {
for (int i = 0; i < myBytes.length; i++) {
if (i >= otherBytes.length)
return -1; // same as far as they go, but shorter...
if (myBytes[i] < otherBytes[i])
return -1;
if (myBytes[i] > otherBytes[i])
return 1;
}
if (myBytes.length > otherBytes.length)
return 1; // same as far as they go, but longer...
}
String myName = getName();
String otherName = other.getName();
if (!(other.isPartial || this.isPartial)) {
if (myName == null && otherName == null) {
// do nothing
} else if (myName == null) {
return -1;
} else if (otherName == null) {
return 1;
} else {
int i = myName.compareTo(otherName);
if (i != 0) {
return i;
}
}
}
if (this.uniqueTag == null && other.uniqueTag == null) {
if (compareViewIds) {
// not loners, so look at P2P view ID
int thisViewId = getVmViewId();
int otherViewId = other.getVmViewId();
if (thisViewId >= 0 && otherViewId >= 0) {
if (thisViewId < otherViewId) {
return -1;
} else if (thisViewId > otherViewId) {
return 1;
} // else they're the same, so continue
}
}
} else if (this.uniqueTag == null) {
return -1;
} else if (other.uniqueTag == null) {
return 1;
} else {
int i = this.uniqueTag.compareTo(other.uniqueTag);
if (i != 0) {
return i;
}
}
if (compareMemberData && this.memberData != null && other.memberData != null) {
return this.memberData.compareAdditionalData(other.memberData);
} else {
return 0;
}
}
/**
* An InternalDistributedMember created for a test or via readEssentialData will be a Partial ID,
* possibly not having ancillary info like "name".
*
* @return true if this is a partial ID
*/
public boolean isPartial() {
return isPartial;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
// GemStone fix for 29125
if (!(obj instanceof InternalDistributedMember)) {
return false;
}
InternalDistributedMember other = (InternalDistributedMember) obj;
int myPort = getMembershipPort();
int otherPort = other.getMembershipPort();
if (myPort != otherPort) {
return false;
}
InetAddress myAddr = getInetAddress();
InetAddress otherAddr = other.getInetAddress();
if (myAddr == null && otherAddr == null) {
return true;
} else if (!Objects.equals(myAddr, otherAddr)) {
return false;
}
if (!isPartial() && !other.isPartial()) {
if (!Objects.equals(getName(), other.getName())) {
return false;
}
}
if (this.uniqueTag == null && other.uniqueTag == null) {
// not loners, so look at P2P view ID
int thisViewId = getVmViewId();
int otherViewId = other.getVmViewId();
if (thisViewId >= 0 && otherViewId >= 0) {
if (thisViewId != otherViewId) {
return false;
} // else they're the same, so continue
}
} else if (!Objects.equals(this.uniqueTag, other.uniqueTag)) {
return false;
}
if (this.memberData != null && other.memberData != null) {
if (0 != this.memberData.compareAdditionalData(other.memberData)) {
return false;
}
}
// purposely avoid checking roles
// @todo Add durableClientAttributes to equals
return true;
}
@Override
public int hashCode() {
int result = 0;
result = result + memberData.getInetAddress().hashCode();
result = result + getMembershipPort();
return result;
}
private String shortName(String hostname) {
if (hostname == null)
return "<null inet_addr hostname>";
int index = hostname.indexOf('.');
if (index > 0 && !Character.isDigit(hostname.charAt(0)))
return hostname.substring(0, index);
else
return hostname;
}
/** the cached string description of this object */
private transient String cachedToString;
@Override
public String toString() {
String result = cachedToString;
if (result == null) {
final StringBuilder sb = new StringBuilder();
addFixedToString(sb);
// add version if not current
short version = memberData.getVersionOrdinal();
if (version != Version.CURRENT.ordinal()) {
sb.append("(version:").append(Version.toString(version)).append(')');
}
// leave out Roles on purpose
result = sb.toString();
cachedToString = result;
}
return result;
}
public void addFixedToString(StringBuilder sb) {
// Note: This method is used to generate the HARegion name. If it is changed, memory and GII
// issues will occur in the case of clients with subscriptions during rolling upgrade.
String host;
InetAddress add = getInetAddress();
if (add.isMulticastAddress())
host = add.getHostAddress();
else {
String hostName = memberData.getHostName();
host = SocketCreator.resolve_dns ? shortName(hostName) : hostName;
}
sb.append(host);
String myName = getName();
int vmPid = memberData.getProcessId();
int vmKind = memberData.getVmKind();
if (vmPid > 0 || vmKind != ClusterDistributionManager.NORMAL_DM_TYPE || !"".equals(myName)) {
sb.append("(");
if (!"".equals(myName)) {
sb.append(myName);
if (vmPid > 0) {
sb.append(':');
}
}
if (vmPid > 0)
sb.append(vmPid);
String vmStr = "";
switch (vmKind) {
case ClusterDistributionManager.NORMAL_DM_TYPE:
// vmStr = ":local"; // let this be silent
break;
case ClusterDistributionManager.LOCATOR_DM_TYPE:
vmStr = ":locator";
break;
case ClusterDistributionManager.ADMIN_ONLY_DM_TYPE:
vmStr = ":admin";
break;
case ClusterDistributionManager.LONER_DM_TYPE:
vmStr = ":loner";
break;
default:
vmStr = ":<unknown:" + vmKind + ">";
break;
}
sb.append(vmStr);
sb.append(")");
}
if (vmKind != ClusterDistributionManager.LONER_DM_TYPE
&& memberData.isPreferredForCoordinator()) {
sb.append("<ec>");
}
int vmViewId = getVmViewId();
if (vmViewId >= 0) {
sb.append("<v" + vmViewId + ">");
}
sb.append(":");
sb.append(getMembershipPort());
if (vmKind == ClusterDistributionManager.LONER_DM_TYPE) {
// add some more info that was added in 4.2.1 for loner bridge clients
// impact on non-bridge loners is ok
if (this.uniqueTag != null && this.uniqueTag.length() != 0) {
sb.append(":").append(this.uniqueTag);
}
String name = getName();
if (name.length() != 0) {
sb.append(":").append(name);
}
}
}
private short readVersion(int flags, DataInput in) throws IOException {
if ((flags & VERSION_BIT) != 0) {
short version = Version.readOrdinal(in);
this.versionObj = Version.fromOrdinalNoThrow(version, false);
return version;
} else {
// prior to 7.1 member IDs did not serialize their version information
Version v = InternalDataSerializer.getVersionForDataStreamOrNull(in);
if (v != null) {
this.versionObj = v;
return v.ordinal();
}
return Version.CURRENT_ORDINAL;
}
}
/**
* For Externalizable
*
* @see Externalizable
*/
@Override
public void writeExternal(ObjectOutput out) throws IOException {
Assert.assertTrue(memberData.getVmKind() > 0);
// do it the way we like
byte[] address = getInetAddress().getAddress();
out.writeInt(address.length); // IPv6 compatible
out.write(address);
out.writeInt(getMembershipPort());
DataSerializer.writeString(memberData.getHostName(), out);
int flags = 0;
if (memberData.isNetworkPartitionDetectionEnabled())
flags |= NPD_ENABLED_BIT;
if (memberData.isPreferredForCoordinator())
flags |= COORD_ENABLED_BIT;
if (this.isPartial)
flags |= PARTIAL_ID_BIT;
// always write product version but enable reading from older versions
// that do not have it
flags |= VERSION_BIT;
out.writeByte((byte) (flags & 0xff));
out.writeInt(memberData.getDirectChannelPort());
out.writeInt(memberData.getProcessId());
out.writeInt(memberData.getVmKind());
out.writeInt(memberData.getVmViewId());
DataSerializer.writeStringArray(memberData.getGroups(), out);
DataSerializer.writeString(memberData.getName(), out);
DataSerializer.writeString(this.uniqueTag, out);
String durableId = memberData.getDurableId();
DataSerializer.writeString(durableId == null ? "" : durableId, out);
DataSerializer.writeInteger(
Integer.valueOf(durableId == null ? 300 : memberData.getDurableTimeout()),
out);
Version.writeOrdinal(out, memberData.getVersionOrdinal(), true);
memberData.writeAdditionalData(out);
}
/**
* For Externalizable
*
* @see Externalizable
*/
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
int len = in.readInt(); // IPv6 compatible
byte addr[] = new byte[len];
in.readFully(addr);
InetAddress inetAddr = InetAddress.getByAddress(addr);
int port = in.readInt();
String hostName = DataSerializer.readString(in);
int flags = in.readUnsignedByte();
boolean sbEnabled = (flags & NPD_ENABLED_BIT) != 0;
boolean elCoord = (flags & COORD_ENABLED_BIT) != 0;
this.isPartial = (flags & PARTIAL_ID_BIT) != 0;
int dcPort = in.readInt();
int vmPid = in.readInt();
int vmKind = in.readInt();
int vmViewId = in.readInt();
String[] groups = DataSerializer.readStringArray(in);
String name = DataSerializer.readString(in);
this.uniqueTag = DataSerializer.readString(in);
String durableId = DataSerializer.readString(in);
int durableTimeout = in.readInt();
short version = readVersion(flags, in);
memberData = MemberDataBuilder.newBuilder(inetAddr, hostName)
.setMembershipPort(port)
.setDirectChannelPort(dcPort)
.setName(name)
.setNetworkPartitionDetectionEnabled(sbEnabled)
.setPreferredForCoordinator(elCoord)
.setVersionOrdinal(version)
.setVmPid(vmPid)
.setVmKind(vmKind)
.setVmViewId(vmViewId)
.setGroups(groups)
.setDurableId(durableId)
.setDurableTimeout(durableTimeout)
.build();
if (version >= Version.GFE_90.ordinal()) {
try {
memberData.readAdditionalData(in);
} catch (java.io.EOFException e) {
// old version
}
}
Assert.assertTrue(memberData.getVmKind() > 0);
}
@Override
public int getDSFID() {
return DISTRIBUTED_MEMBER;
}
@Override
public void toData(DataOutput out,
SerializationContext context) throws IOException {
toDataPre_GFE_9_0_0_0(out, context);
if (memberData.getVersionOrdinal() >= Version.GFE_90.ordinal()) {
getMemberData().writeAdditionalData(out);
}
}
public void toDataPre_GFE_9_0_0_0(DataOutput out, SerializationContext context)
throws IOException {
// Assert.assertTrue(vmKind > 0);
// NOTE: If you change the serialized format of this class
// then bump Connection.HANDSHAKE_VERSION since an
// instance of this class is sent during Connection handshake.
DataSerializer.writeInetAddress(getInetAddress(), out);
out.writeInt(getMembershipPort());
DataSerializer.writeString(memberData.getHostName(), out);
int flags = 0;
if (memberData.isNetworkPartitionDetectionEnabled())
flags |= NPD_ENABLED_BIT;
if (memberData.isPreferredForCoordinator())
flags |= COORD_ENABLED_BIT;
if (this.isPartial)
flags |= PARTIAL_ID_BIT;
// always write product version but enable reading from older versions
// that do not have it
flags |= VERSION_BIT;
out.writeByte((byte) (flags & 0xff));
out.writeInt(memberData.getDirectChannelPort());
out.writeInt(memberData.getProcessId());
int vmKind = memberData.getVmKind();
out.writeByte(vmKind);
DataSerializer.writeStringArray(memberData.getGroups(), out);
DataSerializer.writeString(memberData.getName(), out);
if (vmKind == ClusterDistributionManager.LONER_DM_TYPE) {
DataSerializer.writeString(this.uniqueTag, out);
} else { // added in 6.5 for unique identifiers in P2P
DataSerializer.writeString(String.valueOf(memberData.getVmViewId()), out);
}
String durableId = memberData.getDurableId();
DataSerializer.writeString(durableId == null ? "" : durableId, out);
DataSerializer.writeInteger(
Integer.valueOf(durableId == null ? 300 : memberData.getDurableTimeout()),
out);
short version = memberData.getVersionOrdinal();
Version.writeOrdinal(out, version, true);
}
public void toDataPre_GFE_7_1_0_0(DataOutput out, SerializationContext context)
throws IOException {
Assert.assertTrue(memberData.getVmKind() > 0);
// disabled to allow post-connect setting of the port for loner systems
// Assert.assertTrue(getPort() > 0);
// if (this.getPort() == 0) {
// InternalDistributedSystem.getLogger().warning(String.format("%s",
// "Serializing ID with zero port", new Exception("Stack trace")));
// }
// NOTE: If you change the serialized format of this class
// then bump Connection.HANDSHAKE_VERSION since an
// instance of this class is sent during Connection handshake.
DataSerializer.writeInetAddress(getInetAddress(), out);
out.writeInt(getMembershipPort());
DataSerializer.writeString(memberData.getHostName(), out);
int flags = 0;
if (memberData.isNetworkPartitionDetectionEnabled())
flags |= NPD_ENABLED_BIT;
if (memberData.isPreferredForCoordinator())
flags |= COORD_ENABLED_BIT;
if (this.isPartial)
flags |= PARTIAL_ID_BIT;
out.writeByte((byte) (flags & 0xff));
out.writeInt(memberData.getDirectChannelPort());
out.writeInt(memberData.getProcessId());
out.writeByte(memberData.getVmKind());
DataSerializer.writeStringArray(memberData.getGroups(), out);
DataSerializer.writeString(memberData.getName(), out);
int vmKind = memberData.getVmKind();
if (vmKind == ClusterDistributionManager.LONER_DM_TYPE) {
DataSerializer.writeString(this.uniqueTag, out);
} else { // added in 6.5 for unique identifiers in P2P
DataSerializer.writeString(String.valueOf(memberData.getVmViewId()), out);
}
String durableId = memberData.getDurableId();
DataSerializer.writeString(durableId == null ? "" : durableId, out);
DataSerializer.writeInteger(
Integer.valueOf(durableId == null ? 300 : memberData.getDurableTimeout()),
out);
}
@Override
public void fromData(DataInput in,
DeserializationContext context) throws IOException, ClassNotFoundException {
fromDataPre_GFE_9_0_0_0(in, context);
// just in case this is just a non-versioned read
// from a file we ought to check the version
if (getMemberData().getVersionOrdinal() >= Version.GFE_90.ordinal()) {
try {
memberData.readAdditionalData(in);
} catch (EOFException e) {
// nope - it's from a pre-GEODE client or WAN site
}
}
}
public void fromDataPre_GFE_9_0_0_0(DataInput in, DeserializationContext context)
throws IOException, ClassNotFoundException {
InetAddress inetAddr = DataSerializer.readInetAddress(in);
int port = in.readInt();
String hostName = DataSerializer.readString(in);
hostName = SocketCreator.resolve_dns
? SocketCreator.getCanonicalHostName(inetAddr, hostName) : inetAddr.getHostAddress();
int flags = in.readUnsignedByte();
boolean sbEnabled = (flags & NPD_ENABLED_BIT) != 0;
boolean elCoord = (flags & COORD_ENABLED_BIT) != 0;
this.isPartial = (flags & PARTIAL_ID_BIT) != 0;
int dcPort = in.readInt();
int vmPid = in.readInt();
int vmKind = in.readUnsignedByte();
String[] groups = DataSerializer.readStringArray(in);
int vmViewId = -1;
String name = DataSerializer.readString(in);
if (vmKind == ClusterDistributionManager.LONER_DM_TYPE) {
this.uniqueTag = DataSerializer.readString(in);
} else {
String str = DataSerializer.readString(in);
if (str != null) { // backward compatibility from earlier than 6.5
vmViewId = Integer.parseInt(str);
}
}
String durableId = DataSerializer.readString(in);
int durableTimeout = in.readInt();
short version = readVersion(flags, in);
memberData = MemberDataBuilder.newBuilder(inetAddr, hostName)
.setMembershipPort(port)
.setDirectChannelPort(dcPort)
.setName(name)
.setNetworkPartitionDetectionEnabled(sbEnabled)
.setPreferredForCoordinator(elCoord)
.setVersionOrdinal(version)
.setVmPid(vmPid)
.setVmKind(vmKind)
.setVmViewId(vmViewId)
.setGroups(groups)
.setDurableId(durableId)
.setDurableTimeout(durableTimeout)
.build();
Assert.assertTrue(memberData.getVmKind() > 0);
// Assert.assertTrue(getPort() > 0);
}
public void fromDataPre_GFE_7_1_0_0(DataInput in, DeserializationContext context)
throws IOException, ClassNotFoundException {
InetAddress inetAddr = DataSerializer.readInetAddress(in);
int port = in.readInt();
String hostName = DataSerializer.readString(in);
hostName = SocketCreator.resolve_dns
? SocketCreator.getCanonicalHostName(inetAddr, hostName) : inetAddr.getHostAddress();
int flags = in.readUnsignedByte();
boolean sbEnabled = (flags & NPD_ENABLED_BIT) != 0;
boolean elCoord = (flags & COORD_ENABLED_BIT) != 0;
this.isPartial = (flags & PARTIAL_ID_BIT) != 0;
int dcPort = in.readInt();
int vmPid = in.readInt();
int vmKind = in.readUnsignedByte();
String[] groups = DataSerializer.readStringArray(in);
int vmViewId = -1;
String name = DataSerializer.readString(in);
if (vmKind == ClusterDistributionManager.LONER_DM_TYPE) {
this.uniqueTag = DataSerializer.readString(in);
} else {
String str = DataSerializer.readString(in);
if (str != null) { // backward compatibility from earlier than 6.5
vmViewId = Integer.parseInt(str);
}
}
String durableId = DataSerializer.readString(in);
int durableTimeout = in.readInt();
short version = readVersion(flags, in);
memberData = MemberDataBuilder.newBuilder(inetAddr, hostName)
.setMembershipPort(port)
.setDirectChannelPort(dcPort)
.setName(name)
.setNetworkPartitionDetectionEnabled(sbEnabled)
.setPreferredForCoordinator(elCoord)
.setVersionOrdinal(version)
.setVmPid(vmPid)
.setVmKind(vmKind)
.setVmViewId(vmViewId)
.setGroups(groups)
.setDurableId(durableId)
.setDurableTimeout(durableTimeout)
.build();
Assert.assertTrue(memberData.getVmKind() > 0);
}
/** this reads an ID written with writeEssentialData */
public static InternalDistributedMember readEssentialData(DataInput in)
throws IOException, ClassNotFoundException {
final InternalDistributedMember mbr = new InternalDistributedMember();
mbr._readEssentialData(in);
return mbr;
}
private void _readEssentialData(DataInput in) throws IOException, ClassNotFoundException {
this.isPartial = true;
InetAddress inetAddr = DataSerializer.readInetAddress(in);
int port = in.readInt();
String hostName =
SocketCreator.resolve_dns ? SocketCreator.getHostName(inetAddr) : inetAddr.getHostAddress();
int flags = in.readUnsignedByte();
boolean sbEnabled = (flags & NPD_ENABLED_BIT) != 0;
boolean elCoord = (flags & COORD_ENABLED_BIT) != 0;
int vmKind = in.readUnsignedByte();
int vmViewId = -1;
if (vmKind == ClusterDistributionManager.LONER_DM_TYPE) {
this.uniqueTag = DataSerializer.readString(in);
} else {
String str = DataSerializer.readString(in);
if (str != null) { // backward compatibility from earlier than 6.5
vmViewId = Integer.parseInt(str);
}
}
String name = DataSerializer.readString(in);
memberData = MemberDataBuilder.newBuilder(inetAddr, hostName)
.setMembershipPort(port)
.setName(name)
.setNetworkPartitionDetectionEnabled(sbEnabled)
.setPreferredForCoordinator(elCoord)
.setVersionOrdinal(InternalDataSerializer.getVersionForDataStream(in).ordinal())
.setVmKind(vmKind)
.setVmViewId(vmViewId)
.build();
if (InternalDataSerializer.getVersionForDataStream(in).compareTo(Version.GFE_90) == 0) {
memberData.readAdditionalData(in);
}
}
@Override
public void writeEssentialData(DataOutput out) throws IOException {
Assert.assertTrue(memberData.getVmKind() > 0);
DataSerializer.writeInetAddress(getInetAddress(), out);
out.writeInt(getMembershipPort());
int flags = 0;
if (memberData.isNetworkPartitionDetectionEnabled())
flags |= NPD_ENABLED_BIT;
if (memberData.isPreferredForCoordinator())
flags |= COORD_ENABLED_BIT;
flags |= PARTIAL_ID_BIT;
out.writeByte((byte) (flags & 0xff));
// out.writeInt(dcPort);
byte vmKind = memberData.getVmKind();
out.writeByte(vmKind);
if (vmKind == ClusterDistributionManager.LONER_DM_TYPE) {
DataSerializer.writeString(this.uniqueTag, out);
} else { // added in 6.5 for unique identifiers in P2P
DataSerializer.writeString(String.valueOf(memberData.getVmViewId()), out);
}
// write name last to fix bug 45160
DataSerializer.writeString(memberData.getName(), out);
Version outputVersion = InternalDataSerializer.getVersionForDataStream(out);
if (0 <= outputVersion.compareTo(Version.GFE_90)
&& outputVersion.compareTo(Version.GEODE_1_1_0) < 0) {
memberData.writeAdditionalData(out);
}
}
/**
* Set the membership port. This is done in loner systems using client/server connection
* information to help form a unique ID
*/
public void setPort(int p) {
assert memberData.getVmKind() == ClusterDistributionManager.LONER_DM_TYPE;
this.memberData.setPort(p);
cachedToString = null;
}
@Override
public MemberData getMemberData() {
return memberData;
}
@Override
public String getHostName() {
return memberData.getHostName();
}
@Override
public String getHost() {
return this.memberData.getInetAddress().getCanonicalHostName();
}
@Override
public int getProcessId() {
return memberData.getProcessId();
}
@Override
public String getId() {
return toString();
}
@Override
public String getUniqueId() {
StringBuilder sb = new StringBuilder();
addFixedToString(sb);
// add version if not current
short version = memberData.getVersionOrdinal();
if (version != Version.CURRENT.ordinal()) {
sb.append("(version:").append(Version.toString(version)).append(')');
}
return sb.toString();
}
public void setVersionObjectForTest(Version v) {
this.versionObj = v;
memberData.setVersion(v);
}
public Version getVersionObject() {
return this.versionObj;
}
@Override
public Version[] getSerializationVersions() {
return dsfidVersions;
}
@VisibleForTesting
void setUniqueTag(String tag) {
uniqueTag = tag;
}
@VisibleForTesting
public void setIsPartial(boolean value) {
isPartial = value;
}
}