com.gemstone.org.jgroups.protocols.pbcast.FD Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gemfire-jgroups Show documentation
Show all versions of gemfire-jgroups Show documentation
SnappyData store based off Pivotal GemFireXD
/** Notice of modification as required by the LGPL
* This file was modified by Gemstone Systems Inc. on
* $Date$
**/
// $Id: FD.java,v 1.9 2005/08/11 12:43:46 belaban Exp $
package com.gemstone.org.jgroups.protocols.pbcast;
import com.gemstone.org.jgroups.Address;
import com.gemstone.org.jgroups.Event;
import com.gemstone.org.jgroups.Message;
import com.gemstone.org.jgroups.SuspectMember;
import com.gemstone.org.jgroups.View;
import com.gemstone.org.jgroups.stack.Protocol;
import com.gemstone.org.jgroups.util.ExternalStrings;
import com.gemstone.org.jgroups.util.Util;
import com.gemstone.org.jgroups.util.GemFireTracer;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Vector;
/**
* Passive failure detection protocol. It assumes a pbcast protocol, which uses rounds of gossiping for
* reliable message delivery. Gossip protocols typically involve all the members sending gossips in regular
* intervals. This protocol therefore works as follows: it allocates a timestamp for each member and updates
* the timestamp whenever it receives a message from a sender P. Any type of message is accepted from P. For
* example, PBCAST regularly sends the following messages:
*
* - regular mcast message from P
*
- regular ucast message from P
*
- gossip from P
*
- retransmit request from P
*
- retransmit response from P
*
*
* @author Bela Ban
*/
public class FD extends Protocol implements Runnable {
Address local_addr=null;
// GemStoneAddition must be accessed synchronized on checker_lock
Thread checker=null; // checks timestamps for timeout, generates SUSPECT event
final Object checker_lock=new Object();
long timeout=6000; // number of millisecs to wait for a member to be suspected
// (should be higher than the gossip_interval value in PBCAST
final Hashtable members=new Hashtable(11); // keys=Addresses (members), vals=Entries (timestamp)
final Vector suspected_mbrs=new Vector(11); // currently suspected members (dynamically updated)
static class Entry {
long timestamp;
Entry(long timestamp) {
this.timestamp=timestamp;
}
@Override // GemStoneAddition
public String toString() {
return Long.toString(timestamp);
}
}
@Override // GemStoneAddition
public String getName() {
return "FD";
}
@Override // GemStoneAddition
public boolean setProperties(Properties props) {
String str;
super.setProperties(props);
str=props.getProperty("timeout");
if(str != null) {
timeout=Long.parseLong(str);
props.remove("timeout");
}
if(props.size() > 0) {
log.error(ExternalStrings.FD_FDSETPROPERTIES_THE_FOLLOWING_PROPERTIES_ARE_NOT_RECOGNIZED__0, props);
return false;
}
return true;
}
@Override // GemStoneAddition
public void stop() {
stopChecker();
}
@Override // GemStoneAddition
public void up(Event evt) {
Message msg;
Address sender;
switch(evt.getType()) {
case Event.SET_LOCAL_ADDRESS:
local_addr=(Address)evt.getArg();
break;
case Event.MSG:
msg=(Message)evt.getArg();
sender=msg.getSrc();
updateSender(sender);
break;
}
passUp(evt); // pass up to the layer above us
}
@Override // GemStoneAddition
public void down(Event evt) {
View v;
Vector mbrs;
Address mbr;
switch(evt.getType()) {
case Event.VIEW_CHANGE:
v=(View)evt.getArg();
mbrs=v.getMembers();
passDown(evt);
synchronized (members) { // GemStoneAddition
for(Enumeration e=members.keys(); e.hasMoreElements();) {
mbr=(Address)e.nextElement();
if(!mbrs.contains(mbr)) {
members.remove(mbr);
}
}
members.remove(local_addr);
if(members.size() > 0 /* && checker == null GemStoneAddition */)
startChecker();
}
return;
// generated by PBCAST, contains list of members a gossip has visited. we can safely reset their counter
case Event.HEARD_FROM:
updateSenders((Vector)evt.getArg());
return; // don't pass down
}
passDown(evt);
}
public void run() {
Address mbr;
long timestamp, diff;
for (;;) { // GemStoneAddition -- remove coding anti-pattern
if (Thread.currentThread().isInterrupted()) break; // GemStoneAddition
synchronized (members) { // GemStoneAddition
if (members.size() == 0) // GemStoneAddition
break;
for(Enumeration e=members.keys(); e.hasMoreElements();) {
mbr=(Address)e.nextElement();
timestamp=((Entry)members.get(mbr)).timestamp;
diff=System.currentTimeMillis() - timestamp;
if(diff >= timeout) {
if(log.isInfoEnabled()) log.info(ExternalStrings.FD_SUSPECTING__0, mbr);
passUp(new Event(Event.SUSPECT, new SuspectMember(local_addr, mbr)));
if(!suspected_mbrs.contains(mbr))
suspected_mbrs.addElement(mbr);
}
} // for
} // synchronized
try { // GemStoneAddition
Util.sleep(timeout);
}
catch (InterruptedException e) {
break; // exit loop and thread
}
}
synchronized (checker_lock) { // GemStoneAddition
checker=null;
}
}
void startChecker() {
synchronized(checker_lock) {
if(checker == null) {
checker=new Thread(GemFireTracer.GROUP, this, "FD.CheckerThread");
checker.setDaemon(true);
checker.start();
}
}
}
void stopChecker() {
Thread tmp;
synchronized(checker_lock) {
if(checker != null && checker.isAlive()) {
tmp=checker;
checker=null;
tmp.interrupt();
try {
tmp.join(timeout);
}
catch(InterruptedException ex) {
Thread.currentThread().interrupt(); // GemStoneAddition
// propagate to caller
}
if(tmp.isAlive())
if(warn) log.warn("interrupted checker thread is still alive !");
}
checker=null;
}
}
void updateSender(Address mbr) {
Entry entry;
long curr_time;
if(mbr == null) {
if(log.isDebugEnabled()) log.debug("member " + mbr + " not found");
return;
}
if(suspected_mbrs.size() > 0 && suspected_mbrs.contains(mbr)) {
passUp(new Event(Event.UNSUSPECT, mbr));
suspected_mbrs.remove(mbr);
}
if(mbr.equals(local_addr))
return;
curr_time=System.currentTimeMillis();
synchronized (members) { // GemStoneAddition
entry=(Entry)members.get(mbr);
if(entry != null)
entry.timestamp=curr_time;
else
members.put(mbr, new Entry(curr_time));
}
}
void updateSenders(Vector v) {
Address mbr;
if(v == null) return;
for(int i=0; i < v.size(); i++) {
mbr=(Address)v.elementAt(i);
updateSender(mbr);
}
}
String printTimestamps() {
StringBuffer sb=new StringBuffer();
Address mbr;
synchronized(members) {
for(Enumeration e=members.keys(); e.hasMoreElements();) {
mbr=(Address)e.nextElement();
sb.append("\n" + mbr + ": " + (System.currentTimeMillis() - ((Entry)members.get(mbr)).timestamp));
}
}
return sb.toString();
}
}