package org.infinispan.xsite.statetransfer;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import org.infinispan.commons.marshall.MarshallUtil;
import org.infinispan.util.ByteString;
import org.infinispan.util.concurrent.CompletableFutures;
import org.infinispan.xsite.BackupReceiver;
import org.infinispan.xsite.XSiteReplicateCommand;
/**
* Command used to control the state transfer between sites.
*
* @author Pedro Ruivo
* @since 7.0
*/
public class XSiteStateTransferControlCommand extends XSiteReplicateCommand {
public static final int COMMAND_ID = 28;
private StateTransferControl control;
private XSiteStateProvider provider;
private XSiteStateConsumer consumer;
private XSiteStateTransferManager stateTransferManager;
private String siteName;
private boolean statusOk;
private int topologyId;
public XSiteStateTransferControlCommand(ByteString cacheName, StateTransferControl control, String siteName) {
super(cacheName);
this.control = control;
this.siteName = siteName;
}
public XSiteStateTransferControlCommand(ByteString cacheName) {
super(cacheName);
}
public XSiteStateTransferControlCommand() {
super(null);
}
@Override
public Object performInLocalSite(BackupReceiver receiver) throws Throwable {
receiver.handleStateTransferControl(this);
return null;
}
public final void initialize(XSiteStateProvider provider, XSiteStateConsumer consumer,
XSiteStateTransferManager stateTransferManager) {
this.provider = provider;
this.consumer = consumer;
this.stateTransferManager = stateTransferManager;
}
@Override
public CompletableFuture<Object> invokeAsync() throws Throwable {
switch (control) {
case START_SEND:
provider.startStateTransfer(siteName, getOrigin(), topologyId);
break;
case START_RECEIVE:
consumer.startStateTransfer(siteName);
break;
case FINISH_RECEIVE:
consumer.endStateTransfer(siteName);
break;
case FINISH_SEND:
stateTransferManager.notifyStatePushFinished(siteName, getOrigin(), statusOk);
break;
case CANCEL_SEND:
provider.cancelStateTransfer(siteName);
break;
case RESTART_SEND:
provider.cancelStateTransfer(siteName);
provider.startStateTransfer(siteName, getOrigin(), topologyId);
break;
case STATUS_REQUEST:
return CompletableFuture.completedFuture(stateTransferManager.getStatus());
case CLEAR_STATUS:
stateTransferManager.clearStatus();
break;
default:
throw new IllegalStateException("Unknown control command: " + control);
}
return CompletableFutures.completedNull();
}
@Override
public byte getCommandId() {
return COMMAND_ID;
}
@Override
public void writeTo(ObjectOutput output) throws IOException {
MarshallUtil.marshallEnum(control, output);
switch (control) {
case START_SEND:
case RESTART_SEND:
output.writeUTF(siteName);
output.writeInt(topologyId);
return;
case CANCEL_SEND:
output.writeUTF(siteName);
return;
case FINISH_SEND:
output.writeUTF(siteName);
output.writeBoolean(statusOk);
return;
case START_RECEIVE:
case FINISH_RECEIVE:
MarshallUtil.marshallString(siteName, output);
return;
case STATUS_REQUEST:
case CLEAR_STATUS:
return;
default:
throw new IllegalStateException("Unknown control command: " + control);
}
}
@Override
public void readFrom(ObjectInput input) throws IOException, ClassNotFoundException {
control = Objects.requireNonNull(MarshallUtil.unmarshallEnum(input, StateTransferControl::valueOf));
switch (control) {
case START_SEND:
case RESTART_SEND:
siteName = input.readUTF();
topologyId = input.readInt();
return;
case CANCEL_SEND:
siteName = input.readUTF();
return;
case FINISH_SEND:
siteName = input.readUTF();
statusOk = input.readBoolean();
return;
case START_RECEIVE:
case FINISH_RECEIVE:
siteName = MarshallUtil.unmarshallString(input);
return;
case STATUS_REQUEST:
case CLEAR_STATUS:
return;
default:
throw new IllegalStateException("Unknown control command: " + control);
}
}
@Override
public boolean isReturnValueExpected() {
return this.control == StateTransferControl.STATUS_REQUEST;
}
public void setStatusOk(boolean statusOk) {
this.statusOk = statusOk;
}
public void setSiteName(String siteName) {
this.siteName = siteName;
}
public String getSiteName() {
return siteName;
}
public void setTopologyId(int topologyId) {
this.topologyId = topologyId;
}
public XSiteStateTransferControlCommand copyForCache(ByteString cacheName) {
//cache name is final. we need to copy the command.
XSiteStateTransferControlCommand copy = new XSiteStateTransferControlCommand(cacheName);
copy.control = this.control;
copy.provider = this.provider;
copy.consumer = this.consumer;
copy.stateTransferManager = this.stateTransferManager;
copy.siteName = this.siteName;
copy.statusOk = this.statusOk;
copy.topologyId = this.topologyId;
copy.setOriginSite(this.getOriginSite());
copy.setOrigin(this.getOrigin());
return copy;
}
public enum StateTransferControl {
START_SEND,
START_RECEIVE,
FINISH_SEND,
FINISH_RECEIVE,
CANCEL_SEND,
RESTART_SEND,
STATUS_REQUEST,
CLEAR_STATUS;
private static final StateTransferControl[] CACHED_VALUES = values();
private static StateTransferControl valueOf(int index) {
return CACHED_VALUES[index];
}
}
@Override
public String toString() {
return "XSiteStateTransferControlCommand{" +
"control=" + control +
", siteName='" + siteName + '\'' +
", statusOk=" + statusOk +
", cacheName='" + cacheName + '\'' +
'}';
}
}