/* * 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 org.apache.geode.DataSerializer; import org.apache.geode.distributed.DurableClientAttributes; import org.apache.geode.distributed.internal.DistributionConfig; 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.Version; import org.apache.geode.internal.i18n.LocalizedStrings; import org.jgroups.util.UUID; import java.io.DataInput; import java.io.DataOutput; import java.io.EOFException; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; /** * 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 { // whether to show UUID info in toString() private final static boolean SHOW_UUIDS = Boolean.getBoolean(DistributionConfig.GEMFIRE_PREFIX + "show_UUIDs"); 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() {} public MemberAttributes getAttributes() { return new MemberAttributes(directPort, processId, vmKind, vmViewId, name, groups, durableClientAttributes); } 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; } public int getPort() { return this.udpPort; } public boolean isMulticastAddress() { return false; // ipAddr.isMulticastAddress(); } public boolean preferredForCoordinator() { return this.preferredForCoordinator; } public void setPreferredForCoordinator(boolean preferred) { this.preferredForCoordinator = preferred; } public InetAddress getInetAddress() { return this.inetAddr; } 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. */ public int compareTo(NetMember o) { if (o == this) { return 0; } // obligatory type check if (o == null || !(o instanceof GMSMember)) { throw new ClassCastException( LocalizedStrings.Member_MEMBERCOMPARETO_COMPARISON_BETWEEN_DIFFERENT_CLASSES .toLocalizedString()); } 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 = SHOW_UUIDS ? (";uuid=" + getUUID().toStringLong()) : ((this.uuidLSBs == 0 && this.uuidMSBs == 0) ? "; no uuid" : "; uuid set"); sb.append("GMSMember[addr=").append(inetAddr).append(";port=").append(udpPort) .append(";processId=").append(processId).append(";name=").append(name).append(uuid) .append("]"); return sb.toString(); } public int getUdpPort() { return udpPort; } public boolean isNetworkPartitionDetectionEnabled() { return networkPartitionDetectionEnabled; } public byte getMemberWeight() { return memberWeight; } public InetAddress getInetAddr() { return inetAddr; } public int getProcessId() { return processId; } public byte getVmKind() { return vmKind; } public int getVmViewId() { return vmViewId; } @Override public void setVmViewId(int id) { this.vmViewId = id; } public int getDirectPort() { return directPort; } public String getName() { return name; } public DurableClientAttributes getDurableClientAttributes() { return durableClientAttributes; } public String[] getRoles() { return groups; } public void setUdpPort(int udpPort) { this.udpPort = udpPort; } public void setNetworkPartitionDetectionEnabled(boolean networkPartitionDetectionEnabled) { this.networkPartitionDetectionEnabled = networkPartitionDetectionEnabled; } public void setMemberWeight(byte memberWeight) { this.memberWeight = memberWeight; } public void setInetAddr(InetAddress inetAddr) { this.inetAddr = inetAddr; } public void setProcessId(int processId) { this.processId = processId; } public void setVmKind(int vmKind) { this.vmKind = (byte) vmKind; } public void setVersion(Version v) { this.versionOrdinal = v.ordinal(); } public void setBirthViewId(int birthViewId) { this.vmViewId = birthViewId; } public void setDirectPort(int directPort) { this.directPort = directPort; } public void setName(String name) { this.name = name; } public void setDurableClientAttributes(DurableClientAttributes durableClientAttributes) { this.durableClientAttributes = durableClientAttributes; } @Override public String[] getGroups() { return groups; } public void setGroups(String[] groups) { this.groups = groups; } 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); } @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(); } @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 } } }