com.gemstone.org.jgroups.protocols.Discovery 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$
**/
package com.gemstone.org.jgroups.protocols;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Properties;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicBoolean;
import com.gemstone.org.jgroups.Address;
import com.gemstone.org.jgroups.Event;
import com.gemstone.org.jgroups.Message;
import com.gemstone.org.jgroups.View;
import com.gemstone.org.jgroups.ViewId;
import com.gemstone.org.jgroups.stack.Protocol;
import com.gemstone.org.jgroups.util.ExternalStrings;
/**
* The Discovery protocol layer retrieves the initial membership (used by the GMS when started
* by sending event FIND_INITIAL_MBRS down the stack). We do this by specific subclasses, e.g. by mcasting PING
* requests to an IP MCAST address or, if gossiping is enabled, by contacting the GossipServer.
* The responses should allow us to determine the coordinator whom we have to
* contact, e.g. in case we want to join the group. When we are a server (after having
* received the BECOME_SERVER event), we'll respond to PING requests with a PING
* response. The FIND_INITIAL_MBRS event will eventually be answered with a
* FIND_INITIAL_MBRS_OK event up the stack.
* The following properties are available
*
* - timeout - the timeout (ms) to wait for the initial members, default is 3000=3 secs
*
- num_initial_members - the minimum number of initial members for a FIND_INITAL_MBRS, default is 2
*
- num_ping_requests - the number of GET_MBRS_REQ messages to be sent (min=1), distributed over timeout ms
*
* @author Bela Ban
* @version $Id: Discovery.java,v 1.14 2005/12/16 16:02:43 belaban Exp $
*/
public abstract class Discovery extends Protocol {
final Vector members=new Vector(11);
Address local_addr=null;
String group_addr=null;
long timeout=3000;
int num_initial_members=2;
boolean is_server=false;
PingWaiter ping_waiter;
/** Number of GET_MBRS_REQ messages to be sent (min=1), distributed over timeout ms */
int num_ping_requests=2;
int num_discovery_requests=0;
// start GemStoneAddition
@Override // GemStoneAddition
public int getProtocolEnum() {
return com.gemstone.org.jgroups.stack.Protocol.enumDISCOVERY;
}
// end GemStone addition
/** Called after local_addr was set */
public void localAddressSet(Address addr) {
}
// GemStoneAddition - parameters
public abstract void sendGetMembersRequest(AtomicBoolean waiter_sync);
/** Called when CONNECT_OK has been received */
public void handleConnectOK() {
}
public void handleDisconnect() {
}
public void handleConnect() {
}
public long getTimeout() {
return timeout;
}
public void setTimeout(long timeout) {
this.timeout=timeout;
if(ping_waiter != null)
ping_waiter.setTimeout(timeout);
}
public int getNumInitialMembers() {
return num_initial_members;
}
public void setNumInitialMembers(int num_initial_members) {
this.num_initial_members=num_initial_members;
if(ping_waiter != null)
ping_waiter.setNumRsps(num_initial_members);
}
public int getNumPingRequests() {
return num_ping_requests;
}
public void setNumPingRequests(int num_ping_requests) {
this.num_ping_requests=num_ping_requests;
}
public int getNumberOfDiscoveryRequestsSent() {
return num_discovery_requests;
}
@Override // GemStoneAddition
public Vector providedUpServices() {
Vector ret=new Vector(1);
ret.addElement(Integer.valueOf(Event.FIND_INITIAL_MBRS));
return ret;
}
/**
* sets the properties of the PING protocol.
* The following properties are available
* property: timeout - the timeout (ms) to wait for the initial members, default is 3000=3 secs
* property: num_initial_members - the minimum number of initial members for a FIND_INITAL_MBRS, default is 2
* @param props - a property set
* @return returns true if all properties were parsed properly
* returns false if there are unrecnogized properties in the property set
*/
@Override // GemStoneAddition
public boolean setProperties(Properties props) {
String str;
super.setProperties(props);
str=props.getProperty("timeout"); // max time to wait for initial members
if(str != null) {
timeout=Long.parseLong(str);
if(timeout <= 0) {
if(log.isErrorEnabled()) log.error(ExternalStrings.Discovery_TIMEOUT_MUST_BE__0);
return false;
}
props.remove("timeout");
}
str=props.getProperty("num_initial_members"); // wait for at most n members
if(str != null) {
num_initial_members=Integer.parseInt(str);
props.remove("num_initial_members");
}
str=props.getProperty("num_ping_requests"); // number of GET_MBRS_REQ messages
if(str != null) {
num_ping_requests=Integer.parseInt(str);
props.remove("num_ping_requests");
if(num_ping_requests < 1)
num_ping_requests=1;
}
if(props.size() > 0) {
StringBuffer sb=new StringBuffer();
for(Enumeration e=props.propertyNames(); e.hasMoreElements();) {
sb.append(e.nextElement().toString());
if(e.hasMoreElements()) {
sb.append(", ");
}
}
if(log.isErrorEnabled()) log.error(ExternalStrings.Discovery_THE_FOLLOWING_PROPERTIES_ARE_NOT_RECOGNIZED__0, sb);
return false;
}
return true;
}
@Override // GemStoneAddition
public void resetStats() {
super.resetStats();
num_discovery_requests=0;
}
@Override // GemStoneAddition
public void start() throws Exception {
super.start();
PingSender ping_sender=new PingSender(timeout, num_ping_requests, this);
if(ping_waiter == null)
ping_waiter=new PingWaiter(timeout, num_initial_members, this, ping_sender);
}
/** GemStoneAddition - tell the waiter it can start its countdown now */
public final void wakeWaiter(AtomicBoolean waiter_sync) {
synchronized(waiter_sync) {
waiter_sync.set(true);
waiter_sync.notifyAll();
}
}
@Override // GemStoneAddition
public void stop() {
is_server=false;
if(ping_waiter != null)
ping_waiter.stop();
}
/**
* Finds the initial membership
* @return Vector of PingRsp
*/
public Vector findInitialMembers() {
return ping_waiter != null? ping_waiter.findInitialMembers() : null;
}
public String findInitialMembersAsString() {
Vector results=findInitialMembers();
if(results == null || results.size() == 0) return "";
PingRsp rsp;
StringBuffer sb=new StringBuffer();
for(Iterator it=results.iterator(); it.hasNext();) {
rsp=(PingRsp)it.next();
sb.append(rsp).append("\n");
}
return sb.toString();
}
/**
* An event was received from the layer below. Usually the current layer will want to examine
* the event type and - depending on its type - perform some computation
* (e.g. removing headers from a MSG event type, or updating the internal membership list
* when receiving a VIEW_CHANGE event).
* Finally the event is either a) discarded, or b) an event is sent down
* the stack using PassDown
or c) the event (or another event) is sent up
* the stack using PassUp
.
*
* For the PING protocol, the Up operation does the following things.
* 1. If the event is a Event.MSG then PING will inspect the message header.
* If the header is null, PING simply passes up the event
* If the header is PingHeader.GET_MBRS_REQ then the PING protocol
* will PassDown a PingRequest message
* If the header is PingHeader.GET_MBRS_RSP we will add the message to the initial members
* vector and wake up any waiting threads.
* 2. If the event is Event.SET_LOCAL_ADDR we will simple set the local address of this protocol
* 3. For all other messages we simple pass it up to the protocol above
*
* @param evt - the event that has been sent from the layer below
*/
@Override // GemStoneAddition
public void up(Event evt) {
Message msg, rsp_msg;
// Object obj; GemStoneAddition
PingHeader hdr, rsp_hdr;
PingRsp rsp;
Address coord = null;
switch(evt.getType()) {
case Event.MSG:
msg=(Message)evt.getArg();
// obj=msg.getHeader(getName()); GemStoneAddition - do null check after removeHeader instead
// if(obj == null || !(obj instanceof PingHeader)) {
// passUp(evt);
// return;
// }
hdr=(PingHeader)msg.removeHeader(getName());
if (hdr == null) {
passUp(evt);
return;
}
switch(hdr.type) {
case PingHeader.GET_MBRS_REQ: // return Rsp(local_addr, coord)
if(local_addr != null && msg.getSrc() != null && local_addr.equals(msg.getSrc())) {
if(trace)
log.trace("discarded my own discovery request");
return;
}
// GemStoneAddition - don't respond if not done with initial discovery and we're
// using a gossip server
// if (getName().equals("TCPGOSSIP") && !is_server) { deadcoded for Fraser release - caused concurrent startup split-brain in locators
// return;
// }
synchronized(members) {
// coord=members.size() > 0 ? (Address)members.firstElement() : local_addr;
// GemStoneAddition - if no membership set, get a likely
// candidate from the ping waiter. if that fails, use the
// local address
if (members.size() > 0) {
// GemStoneAddition - split brain detection
for (int i=0; i 0) {
// if (members.get(0).equals(local_addr)) {
// PingRsp ping_rsp=new PingRsp(local_addr, local_addr, true);
// Message rsp_msg=new Message(null, null, null);
// Header rsp_hdr=new PingHeader(PingHeader.GET_MBRS_RSP, ping_rsp);
// rsp_msg.putHeader(getName(), rsp_hdr);
// rsp_msg.bundleable = false; // GemStoneAddition
// if(trace)
// log.trace("multicasting decision to become coordinator");
// passDown(new Event(Event.MSG, rsp_msg));
// }
// }
// }
/* -------------------------- Private methods ---------------------------- */
protected View makeView(Vector mbrs) {
Address coord;
long id;
ViewId view_id=new ViewId(local_addr);
coord=view_id.getCoordAddress();
id=view_id.getId();
return new View(coord, id, mbrs);
}
}