package ibis.ipl.registry.gossip; import ibis.ipl.impl.IbisIdentifier; import ibis.util.TypedProperties; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.HashSet; import java.util.Set; import java.util.UUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; class Member { private static final Logger logger = LoggerFactory.getLogger(Member.class); private final IbisIdentifier identifier; private final TypedProperties properties; private long lastSeen; // ibisses who claim this member is no more // cleared upon succesful contact private Set<UUID> witnesses; // member can be declared dead after the timeout has expired AND at least // N witnesses have not been able to contact the peer. // witnesses and timeout cleared whenever a peer is able to contact the node private boolean dead; private boolean left; Member(IbisIdentifier identifier, TypedProperties properties) { this.properties = properties; this.identifier = identifier; lastSeen = System.currentTimeMillis(); witnesses = new HashSet<UUID>(); dead = false; left = false; } Member(DataInputStream in, TypedProperties properties) throws IOException { this.properties = properties; identifier = new IbisIdentifier(in); //assume there was no transfer time. Good enough //for this timeout long notSeenFor = in.readLong(); lastSeen = System.currentTimeMillis() - notSeenFor; int nrOfWittnesses = in.readInt(); if (nrOfWittnesses < 0) { throw new IOException("negative list value"); } witnesses = new HashSet<UUID>(); for (int i = 0; i < nrOfWittnesses; i++) { witnesses.add(new UUID(in.readLong(), in.readLong())); } dead = in.readBoolean(); left = in.readBoolean(); } synchronized void writeTo(DataOutputStream out) throws IOException { identifier.writeTo(out); //send value independant of our clock long notSeenFor = System.currentTimeMillis() - lastSeen; out.writeLong(notSeenFor); out.writeInt(witnesses.size()); for(UUID witness: witnesses) { out.writeLong(witness.getMostSignificantBits()); out.writeLong(witness.getLeastSignificantBits()); } out.writeBoolean(dead); out.writeBoolean(left); } synchronized public void merge(Member other) { logger.debug("merging " + this + " with " + other); if (other.lastSeen > lastSeen) { lastSeen = other.lastSeen; } for(UUID witness: other.witnesses) { witnesses.add(witness); } if (other.dead) { dead = true; } if (other.left) { left = true; } if (dead || left) { witnesses.clear(); } //check if this member is now dead int witnessesRequired = properties.getIntProperty(RegistryProperties.WITNESSES_REQUIRED); if (timedout() && witnesses.size() > witnessesRequired) { logger.debug("member dead after merge: " + witnesses.size()); dead = true; witnesses.clear(); } logger.debug("merge result = " + this); } synchronized IbisIdentifier getIdentifier() { return identifier; } synchronized UUID getUUID() { return UUID.fromString(identifier.getID()); } synchronized void setLeft() { left = true; } public synchronized void declareDead() { dead = true; witnesses.clear(); } synchronized boolean isDead() { return dead; } synchronized boolean hasLeft() { return left; } synchronized boolean timedout() { long timeout = properties.getIntProperty(RegistryProperties.PEER_DEAD_TIMEOUT) * 1000; return System.currentTimeMillis() > (lastSeen + timeout); } synchronized void seen() { if (dead) { logger.warn("contacted dead member: " + this); return; } lastSeen = System.currentTimeMillis(); witnesses.clear(); } synchronized void suspectDead(IbisIdentifier witness) { if (dead) { // already dead return; } witnesses.add(UUID.fromString(witness.getID())); int witnessesRequired = properties.getIntProperty(RegistryProperties.WITNESSES_REQUIRED); if (timedout() && witnesses.size() > witnessesRequired) { dead = true; witnesses.clear(); } } synchronized boolean isSuspect() { if (dead || left) { return false; } return timedout(); } public synchronized String toString() { long age = System.currentTimeMillis() - lastSeen; return String.format("%s last seen %d milliseconds ago, witnesses: %d, timeout = %b, left = %b, dead = %b", identifier, age, witnesses.size(), timedout(), hasLeft(), isDead()); } public synchronized int nrOfWitnesses() { return witnesses.size(); } }