package org.corfudb.runtime.clients;
import com.google.common.collect.ImmutableSet;
import io.netty.channel.ChannelHandlerContext;
import lombok.Getter;
import lombok.Setter;
import org.corfudb.protocols.wireprotocol.CorfuMsg;
import org.corfudb.protocols.wireprotocol.CorfuMsgType;
import org.corfudb.protocols.wireprotocol.CorfuPayloadMsg;
import org.corfudb.protocols.wireprotocol.FailureDetectorMsg;
import org.corfudb.runtime.exceptions.AlreadyBootstrappedException;
import org.corfudb.runtime.exceptions.NoBootstrapException;
import org.corfudb.runtime.view.Layout;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
/**
* A client to the Management Server.
* <p>
* Failure Detection:
* This client allows a client to trigger failures handlers with relevant failures.
* <p>
* Created by zlokhandwala on 11/4/16.
*/
public class ManagementClient implements IClient {
/**
* The messages this client should handle.
*/
@Getter
public final Set<CorfuMsgType> HandledTypes =
new ImmutableSet.Builder<CorfuMsgType>()
.add(CorfuMsgType.MANAGEMENT_BOOTSTRAP_REQUEST)
.add(CorfuMsgType.MANAGEMENT_NOBOOTSTRAP_ERROR)
.add(CorfuMsgType.MANAGEMENT_ALREADY_BOOTSTRAP_ERROR)
.add(CorfuMsgType.MANAGEMENT_FAILURE_DETECTED)
.add(CorfuMsgType.MANAGEMENT_START_FAILURE_HANDLER)
.add(CorfuMsgType.HEARTBEAT_REQUEST)
.add(CorfuMsgType.HEARTBEAT_RESPONSE)
.build();
@Setter
@Getter
IClientRouter router;
/**
* Handle a incoming message on the channel
*
* @param msg The incoming message
* @param ctx The channel handler context
*/
@Override
public void handleMessage(CorfuMsg msg, ChannelHandlerContext ctx) {
switch (msg.getMsgType()) {
case MANAGEMENT_NOBOOTSTRAP_ERROR:
router.completeExceptionally(msg.getRequestID(), new NoBootstrapException());
break;
case MANAGEMENT_ALREADY_BOOTSTRAP_ERROR:
router.completeExceptionally(msg.getRequestID(), new AlreadyBootstrappedException());
break;
case HEARTBEAT_RESPONSE:
router.completeRequest(msg.getRequestID(), ((CorfuPayloadMsg<byte[]>)msg).getPayload());
break;
}
}
/**
* Bootstraps a management server.
*
* @param l The layout to bootstrap with.
* @return A completable future which will return TRUE if the
* bootstrap was successful, false otherwise.
*/
public CompletableFuture<Boolean> bootstrapManagement(Layout l) {
return router.sendMessageAndGetCompletable(CorfuMsgType.MANAGEMENT_BOOTSTRAP_REQUEST.payloadMsg(l));
}
/**
* Sends the failure detected to the relevant management server.
*
* @param nodes The failed nodes map to be handled.
* @return A future which will be return TRUE if completed successfully else returns FALSE.
*/
public CompletableFuture<Boolean> handleFailure(Set nodes) {
return router.sendMessageAndGetCompletable(CorfuMsgType.MANAGEMENT_FAILURE_DETECTED.payloadMsg(new FailureDetectorMsg(nodes)));
}
/**
* Initiates failure handling in the Management Server.
*
* @return A future which returns TRUE if failure handler triggered successfully.
*/
public CompletableFuture<Boolean> initiateFailureHandler() {
return router.sendMessageAndGetCompletable(CorfuMsgType.MANAGEMENT_START_FAILURE_HANDLER.msg());
}
/**
* Requests for a heartbeat message containing the node status.
*
* @return A future which will return the node health metrics of
* the node which was requested for the heartbeat.
*/
public CompletableFuture<byte[]> sendHeartbeatRequest() {
return router.sendMessageAndGetCompletable(CorfuMsgType.HEARTBEAT_REQUEST.msg());
}
}