Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package org.jgroups.protocols.pbcast;
import org.jgroups.*;
import org.jgroups.annotations.MBean;
import org.jgroups.annotations.ManagedAttribute;
import org.jgroups.annotations.ManagedOperation;
import org.jgroups.stack.Protocol;
import org.jgroups.stack.StateTransferInfo;
import org.jgroups.util.Digest;
import org.jgroups.util.ProcessingQueue;
import org.jgroups.util.StateTransferResult;
import org.jgroups.util.Util;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.EOFException;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.Supplier;
import static org.jgroups.conf.AttributeType.BYTES;
import static org.jgroups.conf.AttributeType.SCALAR;
/**
* STATE_TRANSFER protocol based on byte array transfer. A state request is sent
* to a chosen member (coordinator if null). That member makes a copy D of its
* current digest and asks the application for a copy of its current state S.
* Then the member returns both S and D to the requester. The requester first
* sets its digest to D and then returns the state to the application.
* @author Bela Ban
* @see STATE
* @see STATE_SOCK
*/
@MBean(description="State transfer protocol based on byte array transfer")
public class STATE_TRANSFER extends Protocol implements ProcessingQueue.Handler {
protected long start, stop; // to measure state transfer time
@ManagedAttribute(description="The number of state requests",type=SCALAR)
protected final LongAdder num_state_reqs=new LongAdder();
@ManagedAttribute(description="The number of bytes sent (total state)",type=BYTES)
protected final LongAdder num_bytes_sent=new LongAdder();
@ManagedAttribute(description="The average state size (in bytes)",type=BYTES)
protected double avg_state_size;
protected volatile View view;
protected final List members=new ArrayList<>();
/** List of members requesting state */
protected final ProcessingQueue state_requesters=new ProcessingQueue().setHandler(this);
/** set to true while waiting for a STATE_RSP */
protected volatile boolean waiting_for_state_response=false;
protected boolean flushProtocolInStack=false;
/** Don't remove! https://issues.redhat.com/browse/JGRP-2814 */
@ManagedAttribute(type=SCALAR) @Deprecated
public long getNumberOfStateRequests() {return num_state_reqs.sum();}
/** Don't remove! https://issues.redhat.com/browse/JGRP-2814 */
@ManagedAttribute(type=SCALAR) @Deprecated
public long getNumberOfStateBytesSent() {return num_bytes_sent.sum();}
/** Don't remove! https://issues.redhat.com/browse/JGRP-2814 */
@ManagedAttribute(type=SCALAR) @Deprecated
public double getAverageStateSize() {return avg_state_size;}
public List requiredDownServices() {
return Arrays.asList(Event.GET_DIGEST, Event.OVERWRITE_DIGEST);
}
public void resetStats() {
super.resetStats();
num_state_reqs.reset();
num_bytes_sent.reset();
avg_state_size=0;
}
public void start() throws Exception {
Map map=new HashMap<>();
map.put("state_transfer", Boolean.TRUE);
map.put("protocol_class", getClass().getName());
up_prot.up(new Event(Event.CONFIG, map));
}
public void stop() {
super.stop();
waiting_for_state_response=false;
}
@ManagedOperation(description="Closes BARRIER and suspends STABLE")
public void closeBarrierAndSuspendStable() {
if(!isDigestNeeded())
return;
log.trace("%s: sending down CLOSE_BARRIER and SUSPEND_STABLE", local_addr);
down_prot.down(new Event(Event.CLOSE_BARRIER));
down_prot.down(new Event(Event.SUSPEND_STABLE));
}
@ManagedOperation(description="Opens BARRIER and resumes STABLE")
public void openBarrierAndResumeStable() {
if(!isDigestNeeded())
return;
log.trace("%s: sending down OPEN_BARRIER and RESUME_STABLE", local_addr);
down_prot.down(new Event(Event.OPEN_BARRIER));
down_prot.down(new Event(Event.RESUME_STABLE));
}
public void openBarrier() {
if(!isDigestNeeded())
return;
log.trace("%s: sending down OPEN_BARRIER", local_addr);
down_prot.down(new Event(Event.OPEN_BARRIER));
}
public void resumeStable() {
log.trace("%s: sending down RESUME_STABLE", local_addr);
down_prot.down(new Event(Event.RESUME_STABLE));
}
public Object up(Event evt) {
switch(evt.getType()) {
case Event.TMP_VIEW:
case Event.VIEW_CHANGE:
handleViewChange(evt.getArg());
break;
case Event.CONFIG:
Map config=evt.getArg();
if(config != null && config.containsKey("state_transfer"))
log.error(Util.getMessage("ProtocolStackCannotContainTwoStateTransferProtocolsRemoveEitherOneOfThem"));
break;
}
return up_prot.up(evt);
}
public Object up(Message msg) {
StateHeader hdr=msg.getHeader(this.id);
if(hdr == null)
return up_prot.up(msg);
switch(hdr.type) {
case StateHeader.STATE_REQ:
state_requesters.add(msg.getSrc());
break;
case StateHeader.STATE_RSP:
handleStateRsp(hdr.getDigest(), msg.getSrc(), msg.getArray());
break;
case StateHeader.STATE_EX:
closeHoleFor(msg.getSrc());
try {
handleException(Util.exceptionFromBuffer(msg.getArray(), msg.getOffset(), msg.getLength()));
}
catch(Throwable t) {
log.error("failed deserializaing state exception", t);
}
break;
default:
log.error("%s: type %s not known in StateHeader", local_addr, hdr.type);
break;
}
return null;
}
public Object down(Event evt) {
switch(evt.getType()) {
case Event.TMP_VIEW:
case Event.VIEW_CHANGE:
handleViewChange(evt.getArg());
break;
case Event.GET_STATE:
Address target;
StateTransferInfo info=evt.getArg();
if(info.target == null) {
target=determineCoordinator();
}
else {
target=info.target;
if(target.equals(local_addr)) {
log.error("%s: cannot fetch state from myself", local_addr);
target=null;
}
}
if(target == null) {
log.debug("%s: first member (no state)", local_addr);
up_prot.up(new Event(Event.GET_STATE_OK, new StateTransferInfo()));
}
else {
Message state_req=new EmptyMessage(target).putHeader(this.id, new StateHeader(StateHeader.STATE_REQ))
.setFlag(Message.Flag.DONT_BUNDLE, Message.Flag.OOB, Message.Flag.SKIP_BARRIER);
log.debug("%s: asking %s for state", local_addr, target);
// suspend sending and handling of message garbage collection gossip messages,
// fixes bugs #943480 and #938584). Wake up when state has been received
/*if(log.isDebugEnabled())
log.debug("passing down a SUSPEND_STABLE event");
down_prot.down(new Event(Event.SUSPEND_STABLE, new Long(info.timeout)));*/
waiting_for_state_response=true;
start=System.currentTimeMillis();
down_prot.down(state_req);
}
return null; // don't pass down any further !
case Event.CONFIG:
Map config=evt.getArg();
if(config != null && config.containsKey("flush_supported")) {
flushProtocolInStack=true;
}
break;
}
return down_prot.down(evt); // pass on to the layer below us
}
/* --------------------------- Private Methods -------------------------------- */
/**
* When FLUSH is used we do not need to pass digests between members
*
* see JGroups/doc/design/PartialStateTransfer.txt see
* JGroups/doc/design/FLUSH.txt
*
* @return true if use of digests is required, false otherwise
*/
protected boolean isDigestNeeded() {
return !flushProtocolInStack;
}
protected void punchHoleFor(Address member) {
down_prot.down(new Event(Event.PUNCH_HOLE, member));
}
protected void closeHoleFor(Address member) {
down_prot.down(new Event(Event.CLOSE_HOLE, member));
}
/**
* Return the first element of members which is not me. Otherwise return null.
*/
protected Address determineCoordinator() {
synchronized(members) {
for(Address member:members)
if(!local_addr.equals(member))
return member;
}
return null;
}
protected void handleViewChange(View v) {
Address old_coord;
List new_members=v.getMembers();
boolean send_up_exception=false;
this.view=v;
synchronized(members) {
old_coord=(!members.isEmpty()? members.get(0) : null);
members.clear();
members.addAll(new_members);
// this handles the case where a coord dies during a state transfer; prevents clients from hanging forever
// Note this only takes a coordinator crash into account, a getState(target, timeout), where target is not
// null is not handled ! (Usually we get the state from the coordinator)
// https://issues.redhat.com/browse/JGRP-148
if(waiting_for_state_response && old_coord != null && !members.contains(old_coord))
send_up_exception=true;
}
if(send_up_exception) {
log.warn("%s: discovered that the state provider (%s) left", local_addr, old_coord);
waiting_for_state_response=false;
Exception ex=new EOFException("state provider " + old_coord + " left");
up_prot.up(new Event(Event.GET_STATE_OK, new StateTransferResult(ex)));
openBarrierAndResumeStable();
}
// remove non members from list of members requesting state
state_requesters.retainAll(new_members);
}
protected void handleException(Throwable exception) {
if(isDigestNeeded())
openBarrierAndResumeStable();
up_prot.up(new Event(Event.GET_STATE_OK, new StateTransferResult(exception)));
}
public void handle(Address state_requester) {
handleStateReq(state_requester);
}
protected void handleStateReq(Address requester) {
if(requester == null)
return;
log.debug("%s: received state request from %s", local_addr, requester);
Digest digest=null;
if(isDigestNeeded()) {
try {
punchHoleFor(requester);
closeBarrierAndSuspendStable();
digest=(Digest)down_prot.down(Event.GET_DIGEST_EVT);
}
catch(Throwable t) {
sendException(requester, t);
resumeStable();
closeHoleFor(requester);
return;
}
finally {
openBarrier();
}
}
// moved after reopening BARRIER (JGRP-1742)
try {
getStateFromApplication(requester, digest);
}
catch(Throwable t) {
sendException(requester, t);
}
finally {
if(isDigestNeeded()) {
closeHoleFor(requester);
resumeStable();
}
}
}
protected void getStateFromApplication(Address requester, Digest digest) {
StateTransferInfo rsp=(StateTransferInfo)up_prot.up(new Event(Event.GET_APPLSTATE));
byte[] state=rsp.state;
if(stats) {
num_state_reqs.increment();
if(state != null)
num_bytes_sent.add(state.length);
avg_state_size=num_bytes_sent.doubleValue() / num_state_reqs.doubleValue();
}
Message state_rsp=new BytesMessage(requester, state).putHeader(this.id, new StateHeader(StateHeader.STATE_RSP, digest));
log.trace("%s: sending state to %s (size=%s)", local_addr, state_rsp.getDest(), Util.printBytes(state != null? state.length : 0));
down_prot.down(state_rsp);
}
protected void sendException(Address requester, Throwable exception) {
try {
Message ex_msg=new BytesMessage(requester).setArray(Util.exceptionToBuffer(exception))
.putHeader(getId(), new StateHeader(StateHeader.STATE_EX));
down(ex_msg);
}
catch(Throwable t) {
log.error("%s: failed sending exception %s to %s", local_addr, exception, requester);
}
}
/** Set the digest and the send the state up to the application */
protected void handleStateRsp(final Digest digest, Address sender, byte[] state) {
try {
if(isDigestNeeded()) {
punchHoleFor(sender);
closeBarrierAndSuspendStable(); // fix for https://issues.redhat.com/browse/JGRP-1013
if(digest != null)
down_prot.down(new Event(Event.OVERWRITE_DIGEST, digest)); // set the digest (e.g. in NAKACK)
}
waiting_for_state_response=false;
stop=System.currentTimeMillis();
log.debug("%s: received state, size=%s, time=%d milliseconds", local_addr,
(state == null? "0" : Util.printBytes(state.length)), stop - start);
StateTransferResult result=new StateTransferResult(state);
up_prot.up(new Event(Event.GET_STATE_OK, result));
down_prot.down(new Event(Event.GET_VIEW_FROM_COORD)); // https://issues.redhat.com/browse/JGRP-1751
}
catch(Throwable t) {
handleException(t);
}
finally {
if(isDigestNeeded()) {
closeHoleFor(sender);
openBarrierAndResumeStable();
}
}
}
/* ------------------------ End of Private Methods ------------------------------ */
/**
* Wraps data for a state request/response. Note that for a state response
* the actual state will not create() {
return StateHeader::new;
}
public int getType() {
return type;
}
public Digest getDigest() {
return my_digest;
}
public String toString() {
StringBuilder sb=new StringBuilder();
sb.append("type=").append(type2Str(type));
if(my_digest != null)
sb.append(", digest=").append(my_digest);
return sb.toString();
}
static String type2Str(int t) {
switch(t) {
case STATE_REQ: return "STATE_REQ";
case STATE_RSP: return "STATE_RSP";
case STATE_EX: return "STATE_EX";
default: return "";
}
}
@Override
public void writeTo(DataOutput out) throws IOException {
out.writeByte(type);
Util.writeStreamable(my_digest, out);
}
@Override
public void readFrom(DataInput in) throws IOException, ClassNotFoundException {
type=in.readByte();
my_digest=Util.readStreamable(Digest::new, in);
}
@Override
public int serializedSize() {
int retval=Global.BYTE_SIZE; // type
retval+=Global.BYTE_SIZE; // presence byte for my_digest
if(my_digest != null)
retval+=my_digest.serializedSize(true);
return retval;
}
}
}