| /* |
| * 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.gms; |
| |
| import java.io.DataInput; |
| import java.io.DataOutput; |
| import java.io.EOFException; |
| import java.io.IOException; |
| import java.net.InetAddress; |
| import java.net.UnknownHostException; |
| |
| import org.jgroups.util.UUID; |
| |
| import org.apache.geode.DataSerializer; |
| import org.apache.geode.distributed.DurableClientAttributes; |
| import org.apache.geode.distributed.internal.membership.MemberAttributes; |
| import org.apache.geode.distributed.internal.membership.NetMember; |
| import org.apache.geode.internal.DataSerializableFixedID; |
| import org.apache.geode.internal.InternalDataSerializer; |
| import org.apache.geode.internal.Version; |
| |
| /** |
| * This is the fundamental representation of a member of a GemFire distributed system. |
| * |
| * Unfortunately, this class serves two distinct functions. First, it is the fundamental element of |
| * membership in the GemFire distributed system. As such, it is used in enumerations and properly |
| * responds to hashing and equals() comparisons. |
| * |
| * Second, it is used as a cheap way of representing an address. This is unfortunate, because as a |
| * NetMember, it holds two separate port numbers: the "membership" descriptor as well as a direct |
| * communication channel. |
| * |
| */ |
| public class GMSMember implements NetMember, DataSerializableFixedID { |
| private int udpPort = 0; |
| private boolean preferredForCoordinator; |
| private boolean networkPartitionDetectionEnabled; |
| private byte memberWeight; |
| private InetAddress inetAddr; |
| private int processId; |
| private byte vmKind; |
| private int vmViewId = -1; |
| private int directPort; |
| private String name; |
| private DurableClientAttributes durableClientAttributes; |
| private String[] groups; |
| private short versionOrdinal = Version.CURRENT_ORDINAL; |
| private long uuidLSBs; |
| private long uuidMSBs; |
| |
| |
| |
| // Used only by Externalization |
| public GMSMember() {} |
| |
| @Override |
| public MemberAttributes getAttributes() { |
| return new MemberAttributes(directPort, processId, vmKind, vmViewId, name, groups, |
| durableClientAttributes); |
| } |
| |
| @Override |
| public void setAttributes(MemberAttributes p_attr) { |
| MemberAttributes attr = p_attr; |
| if (attr == null) { |
| attr = MemberAttributes.INVALID; |
| } |
| processId = attr.getVmPid(); |
| vmKind = (byte) attr.getVmKind(); |
| directPort = attr.getPort(); |
| vmViewId = attr.getVmViewId(); |
| name = attr.getName(); |
| groups = attr.getGroups(); |
| durableClientAttributes = attr.getDurableClientAttributes(); |
| } |
| |
| /** |
| * Create a CacheMember referring to the current host (as defined by the given string). |
| * |
| * @param i the hostname, must be for the current host |
| * @param p the membership listening port |
| */ |
| public GMSMember(String i, int p) { |
| udpPort = p; |
| try { |
| inetAddr = InetAddress.getByName(i); |
| } catch (UnknownHostException e) { |
| // oops |
| } |
| } |
| |
| /** |
| * Create a CacheMember referring to the current host (as defined by the given string). |
| * |
| * @param i the hostname, must be for the current host |
| * @param p the membership listening port |
| * @param networkPartitionDetectionEnabled whether the member has network partition detection |
| * enabled |
| * @param preferredForCoordinator whether the member can be group coordinator |
| * @param version the member's version ordinal |
| * @param msbs - most significant bytes of UUID |
| * @param lsbs - least significant bytes of UUID |
| */ |
| public GMSMember(MemberAttributes attr, InetAddress i, int p, |
| boolean networkPartitionDetectionEnabled, boolean preferredForCoordinator, short version, |
| long msbs, long lsbs) { |
| setAttributes(attr); |
| this.inetAddr = i; |
| this.udpPort = p; |
| this.networkPartitionDetectionEnabled = networkPartitionDetectionEnabled; |
| this.preferredForCoordinator = preferredForCoordinator; |
| this.versionOrdinal = version; |
| this.uuidMSBs = msbs; |
| this.uuidLSBs = lsbs; |
| } |
| |
| public GMSMember(InetAddress i, int p, short version, long msbs, long lsbs, int viewId) { |
| this.inetAddr = i; |
| this.udpPort = p; |
| this.versionOrdinal = version; |
| this.uuidMSBs = msbs; |
| this.uuidLSBs = lsbs; |
| this.vmViewId = viewId; |
| } |
| |
| |
| /** |
| * Clone a GMSMember |
| * |
| * @param other the member to create a copy of |
| */ |
| public GMSMember(GMSMember other) { |
| this.udpPort = other.udpPort; |
| this.preferredForCoordinator = other.preferredForCoordinator; |
| this.networkPartitionDetectionEnabled = other.networkPartitionDetectionEnabled; |
| this.memberWeight = other.memberWeight; |
| this.inetAddr = other.inetAddr; |
| this.processId = other.processId; |
| this.vmKind = other.vmKind; |
| this.vmViewId = other.vmViewId; |
| this.directPort = other.directPort; |
| this.name = other.name; |
| this.durableClientAttributes = other.durableClientAttributes; |
| this.groups = other.groups; |
| this.versionOrdinal = other.versionOrdinal; |
| this.uuidLSBs = other.uuidLSBs; |
| this.uuidMSBs = other.uuidMSBs; |
| } |
| |
| @Override |
| public int getPort() { |
| return this.udpPort; |
| } |
| |
| @Override |
| public boolean isMulticastAddress() { |
| return false; |
| } |
| |
| @Override |
| public boolean preferredForCoordinator() { |
| return this.preferredForCoordinator; |
| } |
| |
| @Override |
| public void setPreferredForCoordinator(boolean preferred) { |
| this.preferredForCoordinator = preferred; |
| } |
| |
| @Override |
| public InetAddress getInetAddress() { |
| return this.inetAddr; |
| } |
| |
| @Override |
| public short getVersionOrdinal() { |
| return this.versionOrdinal; |
| } |
| |
| public void setVersionOrdinal(short versionOrdinal) { |
| this.versionOrdinal = versionOrdinal; |
| } |
| |
| public void setUUID(UUID u) { |
| this.uuidLSBs = u.getLeastSignificantBits(); |
| this.uuidMSBs = u.getMostSignificantBits(); |
| } |
| |
| /** |
| * return the jgroups logical address for this member, if it's been established |
| */ |
| public UUID getUUID() { |
| if (this.uuidLSBs == 0 && this.uuidMSBs == 0) { |
| return null; |
| } |
| return new UUID(this.uuidMSBs, this.uuidLSBs); |
| } |
| |
| public long getUuidMSBs() { |
| return this.uuidMSBs; |
| } |
| |
| public long getUuidLSBs() { |
| return this.uuidLSBs; |
| } |
| |
| /* |
| * implements the java.lang.Comparable interface |
| * |
| * @see java.lang.Comparable |
| * |
| * @param o - the Object to be compared |
| * |
| * @return a negative integer, zero, or a positive integer as this object is less than, equal to, |
| * or greater than the specified object. |
| * |
| * @exception java.lang.ClassCastException - if the specified object's type prevents it from being |
| * compared to this Object. |
| */ |
| @Override |
| public int compareTo(NetMember o) { |
| if (o == this) { |
| return 0; |
| } |
| // obligatory type check |
| if (o == null || !(o instanceof GMSMember)) { |
| throw new ClassCastException( |
| "NetMember.compareTo(): comparison between different classes"); |
| } |
| byte[] myAddr = inetAddr.getAddress(); |
| GMSMember his = (GMSMember) o; |
| byte[] hisAddr = his.inetAddr.getAddress(); |
| if (myAddr != hisAddr) { |
| for (int idx = 0; idx < myAddr.length; idx++) { |
| if (idx >= hisAddr.length) { |
| return 1; |
| } else if (myAddr[idx] > hisAddr[idx]) { |
| return 1; |
| } else if (myAddr[idx] < hisAddr[idx]) { |
| return -1; |
| } |
| } |
| // After checking both addresses we have only gone up to myAddr.length, their address could be |
| // longer |
| if (hisAddr.length > myAddr.length) { |
| return -1; |
| } |
| } |
| if (udpPort < his.udpPort) |
| return -1; |
| if (his.udpPort < udpPort) |
| return 1; |
| int result = 0; |
| |
| // bug #41983, address of kill-9'd member is reused |
| // before it can be ejected from membership |
| if (this.vmViewId >= 0 && his.vmViewId >= 0) { |
| if (this.vmViewId < his.vmViewId) { |
| result = -1; |
| } else if (his.vmViewId < this.vmViewId) { |
| result = 1; |
| } |
| } |
| if (result == 0 && this.uuidMSBs != 0 && his.uuidMSBs != 0) { |
| if (this.uuidMSBs < his.uuidMSBs) { |
| result = -1; |
| } else if (his.uuidMSBs < this.uuidMSBs) { |
| result = 1; |
| } else if (this.uuidLSBs < his.uuidLSBs) { |
| result = -1; |
| } else if (his.uuidLSBs < this.uuidLSBs) { |
| result = 1; |
| } |
| } |
| return result; |
| } |
| |
| @Override |
| public int compareAdditionalData(NetMember other) { |
| GMSMember his = (GMSMember) other; |
| int result = 0; |
| if (this.uuidMSBs != 0 && his.uuidMSBs != 0) { |
| if (this.uuidMSBs < his.uuidMSBs) { |
| result = -1; |
| } else if (his.uuidMSBs < this.uuidMSBs) { |
| result = 1; |
| } else if (this.uuidLSBs < his.uuidLSBs) { |
| result = -1; |
| } else if (his.uuidLSBs < this.uuidLSBs) { |
| result = 1; |
| } |
| } |
| return result; |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| // GemStone fix for 29125 |
| if ((obj == null) || !(obj instanceof GMSMember)) { |
| return false; |
| } |
| return compareTo((GMSMember) obj) == 0; |
| } |
| |
| @Override |
| public int hashCode() { |
| if (this.inetAddr == null) { |
| return this.udpPort; |
| } |
| return this.udpPort + inetAddr.hashCode(); |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder sb = new StringBuilder(100); |
| String uuid = formatUUID(); |
| |
| sb.append("GMSMember[addr=").append(inetAddr).append(";port=").append(udpPort) |
| .append(";processId=").append(processId).append(";name=").append(name).append(uuid) |
| .append("]"); |
| return sb.toString(); |
| } |
| |
| @Override |
| public String getUniqueId() { |
| StringBuilder sb = new StringBuilder(100); |
| sb.append("GMSMember[addr=").append(inetAddr); |
| sb.append(";processId=").append(processId); |
| sb.append(";name=").append(name); |
| sb.append(formatUUID()).append("]"); |
| return sb.toString(); |
| } |
| |
| public int getUdpPort() { |
| return udpPort; |
| } |
| |
| @Override |
| public boolean isNetworkPartitionDetectionEnabled() { |
| return networkPartitionDetectionEnabled; |
| } |
| |
| @Override |
| public byte getMemberWeight() { |
| return memberWeight; |
| } |
| |
| public InetAddress getInetAddr() { |
| return inetAddr; |
| } |
| |
| @Override |
| public int getProcessId() { |
| return processId; |
| } |
| |
| @Override |
| public byte getVmKind() { |
| return vmKind; |
| } |
| |
| @Override |
| public int getVmViewId() { |
| return vmViewId; |
| } |
| |
| @Override |
| public void setVmViewId(int id) { |
| this.vmViewId = id; |
| } |
| |
| @Override |
| public int getDirectPort() { |
| return directPort; |
| } |
| |
| @Override |
| public String getName() { |
| return name; |
| } |
| |
| @Override |
| public DurableClientAttributes getDurableClientAttributes() { |
| return durableClientAttributes; |
| } |
| |
| public String[] getRoles() { |
| return groups; |
| } |
| |
| public void setUdpPort(int udpPort) { |
| this.udpPort = udpPort; |
| } |
| |
| @Override |
| public void setNetworkPartitionDetectionEnabled(boolean networkPartitionDetectionEnabled) { |
| this.networkPartitionDetectionEnabled = networkPartitionDetectionEnabled; |
| } |
| |
| public void setMemberWeight(byte memberWeight) { |
| this.memberWeight = memberWeight; |
| } |
| |
| public void setInetAddr(InetAddress inetAddr) { |
| this.inetAddr = inetAddr; |
| } |
| |
| @Override |
| public void setProcessId(int processId) { |
| this.processId = processId; |
| } |
| |
| @Override |
| public void setVmKind(int vmKind) { |
| this.vmKind = (byte) vmKind; |
| } |
| |
| @Override |
| public void setVersion(Version v) { |
| this.versionOrdinal = v.ordinal(); |
| } |
| |
| public void setBirthViewId(int birthViewId) { |
| this.vmViewId = birthViewId; |
| } |
| |
| @Override |
| public void setDirectPort(int directPort) { |
| this.directPort = directPort; |
| } |
| |
| @Override |
| public void setName(String name) { |
| this.name = name; |
| } |
| |
| @Override |
| public void setDurableClientAttributes(DurableClientAttributes durableClientAttributes) { |
| this.durableClientAttributes = durableClientAttributes; |
| } |
| |
| @Override |
| public String[] getGroups() { |
| return groups; |
| } |
| |
| @Override |
| public void setGroups(String[] groups) { |
| this.groups = groups; |
| } |
| |
| @Override |
| public void setPort(int p) { |
| this.udpPort = p; |
| } |
| |
| /** |
| * checks to see if this address has UUID information needed to send messages via JGroups |
| */ |
| public boolean hasUUID() { |
| return !(this.uuidLSBs == 0 && this.uuidMSBs == 0); |
| } |
| |
| @Override |
| public Version[] getSerializationVersions() { |
| return null; |
| } |
| |
| @Override |
| public int getDSFID() { |
| return GMSMEMBER; |
| } |
| |
| static final int NPD_ENABLED_BIT = 0x01; |
| static final int PREFERRED_FOR_COORD_BIT = 0x02; |
| |
| @Override |
| public void toData(DataOutput out) throws IOException { |
| writeEssentialData(out); |
| out.writeInt(directPort); |
| out.writeByte(memberWeight); |
| out.writeByte(vmKind); |
| out.writeInt(processId); |
| |
| DataSerializer.writeString(name, out); |
| DataSerializer.writeStringArray(groups, out); |
| } |
| |
| public void writeEssentialData(DataOutput out) throws IOException { |
| Version.writeOrdinal(out, this.versionOrdinal, true); |
| |
| int flags = 0; |
| if (networkPartitionDetectionEnabled) |
| flags |= NPD_ENABLED_BIT; |
| if (preferredForCoordinator) |
| flags |= PREFERRED_FOR_COORD_BIT; |
| out.writeShort(flags); |
| |
| DataSerializer.writeInetAddress(inetAddr, out); |
| out.writeInt(udpPort); |
| out.writeInt(vmViewId); |
| out.writeLong(uuidMSBs); |
| out.writeLong(uuidLSBs); |
| if (InternalDataSerializer.getVersionForDataStream(out).compareTo(Version.GEODE_1_2_0) >= 0) { |
| out.writeByte(vmKind); |
| } |
| } |
| |
| @Override |
| public void fromData(DataInput in) throws IOException, ClassNotFoundException { |
| readEssentialData(in); |
| this.directPort = in.readInt(); |
| this.memberWeight = in.readByte(); |
| this.vmKind = in.readByte(); |
| this.processId = in.readInt(); |
| |
| this.name = DataSerializer.readString(in); |
| this.groups = DataSerializer.readStringArray(in); |
| } |
| |
| public void readEssentialData(DataInput in) throws IOException, ClassNotFoundException { |
| this.versionOrdinal = Version.readOrdinal(in); |
| |
| int flags = in.readShort(); |
| this.networkPartitionDetectionEnabled = (flags & NPD_ENABLED_BIT) != 0; |
| this.preferredForCoordinator = (flags & PREFERRED_FOR_COORD_BIT) != 0; |
| |
| this.inetAddr = DataSerializer.readInetAddress(in); |
| this.udpPort = in.readInt(); |
| this.vmViewId = in.readInt(); |
| this.uuidMSBs = in.readLong(); |
| this.uuidLSBs = in.readLong(); |
| if (InternalDataSerializer.getVersionForDataStream(in).compareTo(Version.GEODE_1_2_0) >= 0) { |
| this.vmKind = in.readByte(); |
| } |
| } |
| |
| @Override |
| public boolean hasAdditionalData() { |
| return uuidMSBs != 0 || uuidLSBs != 0 || memberWeight != 0; |
| } |
| |
| @Override |
| public void writeAdditionalData(DataOutput out) throws IOException { |
| out.writeLong(uuidMSBs); |
| out.writeLong(uuidLSBs); |
| out.write(memberWeight); |
| } |
| |
| @Override |
| public void readAdditionalData(DataInput in) throws ClassNotFoundException, IOException { |
| try { |
| this.uuidMSBs = in.readLong(); |
| this.uuidLSBs = in.readLong(); |
| memberWeight = (byte) (in.readByte() & 0xFF); |
| } catch (EOFException e) { |
| // some IDs do not have UUID or membership weight information |
| } |
| } |
| |
| private String formatUUID() { |
| return ";uuid=" + getUUID().toStringLong(); |
| } |
| } |