@Override public HighAvailabilityMemberState masterIsAvailable( HighAvailabilityMemberContext context, InstanceId masterId, URI masterHaURI) { if (masterId.equals(context.getMyId())) { throw new RuntimeException( "i (" + context.getMyId() + ") am trying to become a slave but " + "someone said i am available as master"); } if (masterId.equals(context.getElectedMasterId())) { // A member joined and we all got the same event return this; } throw new RuntimeException( "my (" + context.getMyId() + ") current master is " + context.getAvailableHaMaster() + " (elected as " + context.getElectedMasterId() + " but i got a " + "masterIsAvailable event for " + masterHaURI); }
@Override public HighAvailabilityMemberState masterIsElected( HighAvailabilityMemberContext context, InstanceId masterId) { if (masterId.equals(context.getMyId())) { return TO_MASTER; } if (masterId.equals(context.getElectedMasterId())) { return this; } return PENDING; }
@Override public HighAvailabilityMemberState masterIsElected( HighAvailabilityMemberContext context, InstanceId masterId) { if (masterId.equals(context.getElectedMasterId())) { // A member joined and we all got the same event return this; } if (masterId.equals(context.getMyId())) { return TO_MASTER; } // This may mean the master changed from the time we transitioned here return PENDING; }
@Override public HighAvailabilityMemberState masterIsAvailable( HighAvailabilityMemberContext context, InstanceId masterId, URI masterHaURI) { if (masterId.equals(context.getMyId())) { throw new RuntimeException("Cannot transition to MASTER directly from SLAVE state"); } else if (masterId.equals(context.getElectedMasterId())) { // this is just someone else that joined the cluster return this; } throw new RuntimeException( "Received a MasterIsAvailable event for " + masterId + " which is different from the current master (" + context.getElectedMasterId() + ") while in the SLAVE state (probably missed a MasterIsElected event)"); }
@Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } MemberIsAvailable that = (MemberIsAvailable) o; if (!clusterUri.equals(that.clusterUri)) { return false; } if (!instanceId.equals(that.instanceId)) { return false; } if (!role.equals(that.role)) { return false; } if (!roleUri.equals(that.roleUri)) { return false; } return true; }
@Override public HighAvailabilityMemberState slaveIsAvailable( HighAvailabilityMemberContext context, InstanceId slaveId, URI slaveUri) { if (slaveId.equals(context.getMyId())) { throw new RuntimeException("Cannot go from pending to slave"); } return this; }
@Override public HighAvailabilityMemberState slaveIsAvailable( HighAvailabilityMemberContext context, InstanceId slaveId, URI slaveUri) { if (slaveId.equals(context.getMyId())) { throw new RuntimeException("Cannot be master and transition to slave at the same time"); } return this; }
@Override public HighAvailabilityMemberState slaveIsAvailable( HighAvailabilityMemberContext context, InstanceId slaveId, URI slaveUri) { if (slaveId.equals(context.getMyId())) { return SLAVE; } return this; }
@Override public HighAvailabilityMemberState masterIsElected( HighAvailabilityMemberContext context, InstanceId masterId) { assert context.getAvailableHaMaster() == null; if (masterId.equals(context.getMyId()) && !context.isSlaveOnly()) { return TO_MASTER; } return PENDING; }
@Override public HighAvailabilityMemberState masterIsElected( HighAvailabilityMemberContext context, InstanceId masterId) { assert context.getAvailableHaMaster() == null; if (masterId.equals(context.getMyId())) { return this; } return PENDING; // everything still goes }
@Override public HighAvailabilityMemberState masterIsAvailable( HighAvailabilityMemberContext context, InstanceId masterId, URI masterHaURI) { // assert context.getAvailableMaster() == null; if (masterId.equals(context.getMyId())) { throw new RuntimeException( "Received a MasterIsAvailable event for my InstanceId while in" + " PENDING state"); } return TO_SLAVE; }
@Override public HighAvailabilityMemberState masterIsElected( HighAvailabilityMemberContext context, InstanceId masterId) { if (masterId.equals(context.getMyId())) { return this; } // This means we (probably) were disconnected and got back in the cluster // and we find out that we are not the master anymore. return PENDING; }
@Override public HighAvailabilityMemberState masterIsAvailable( HighAvailabilityMemberContext context, InstanceId masterId, URI masterHaURI) { if (masterId.equals(context.getMyId())) { return MASTER; } throw new RuntimeException( "Received a MasterIsAvailable event for instance " + masterId + " while in TO_MASTER state"); }
@Override public HighAvailabilityMemberState masterIsAvailable( HighAvailabilityMemberContext context, InstanceId masterId, URI masterHaURI) { if (masterId.equals(context.getMyId())) { return this; } throw new RuntimeException( "I, " + context.getMyId() + " got a masterIsAvailable for " + masterHaURI + " (id is " + masterId + " ) while in MASTER state. Probably missed a " + "MasterIsElected event."); }
@Override public HeartbeatState handle( HeartbeatContext context, Message<HeartbeatMessage> message, MessageHolder outgoing) throws Throwable { switch (message.getMessageType()) { case i_am_alive: { HeartbeatMessage.IAmAliveState state = message.getPayload(); if (context.getClusterContext().isMe(state.getServer())) { break; } context.getClusterContext().getLogger(HeartbeatState.class).debug("Received " + state); if (state.getServer() == null) { break; } if (context.alive(state.getServer())) { // Send suspicions messages to all non-failed servers for (InstanceId aliveServer : context.getAlive()) { if (!aliveServer.equals(context.getClusterContext().getMyId())) { URI aliveServerUri = context.getClusterContext().configuration.getUriForId(aliveServer); outgoing.offer( Message.to( HeartbeatMessage.suspicions, aliveServerUri, new HeartbeatMessage.SuspicionsState( context.getSuspicionsFor(context.getClusterContext().getMyId())))); } } } context .getClusterContext() .timeouts .cancelTimeout(HeartbeatMessage.i_am_alive + "-" + state.getServer()); context .getClusterContext() .timeouts .setTimeout( HeartbeatMessage.i_am_alive + "-" + state.getServer(), timeout(HeartbeatMessage.timed_out, message, state.getServer())); // Check if this server knows something that we don't if (message.hasHeader("last-learned")) { long lastLearned = Long.parseLong(message.getHeader("last-learned")); if (lastLearned > context.getLearnerContext().getLastKnownLearnedInstanceInCluster()) { outgoing.offer(internal(LearnerMessage.catchUp, lastLearned)); } } break; } case timed_out: { InstanceId server = message.getPayload(); context .getClusterContext() .getLogger(HeartbeatState.class) .debug("Received timed out for server " + server); // Check if this node is no longer a part of the cluster if (context.getClusterContext().getConfiguration().getMembers().containsKey(server)) { context.suspect(server); context .getClusterContext() .timeouts .setTimeout( HeartbeatMessage.i_am_alive + "-" + server, timeout(HeartbeatMessage.timed_out, message, server)); // Send suspicions messages to all non-failed servers for (InstanceId aliveServer : context.getAlive()) { if (!aliveServer.equals(context.getClusterContext().getMyId())) { URI sendTo = context.getClusterContext().getConfiguration().getUriForId(aliveServer); outgoing.offer( Message.to( HeartbeatMessage.suspicions, sendTo, new HeartbeatMessage.SuspicionsState( context.getSuspicionsFor(context.getClusterContext().getMyId())))); } } } else { // If no longer part of cluster, then don't bother context.serverLeftCluster(server); } break; } case sendHeartbeat: { InstanceId to = message.getPayload(); // Check if this node is no longer a part of the cluster if (!context.getClusterContext().isMe(to) && context.getClusterContext().getConfiguration().getMembers().containsKey(to)) { URI toSendTo = context.getClusterContext().getConfiguration().getUriForId(to); // Send heartbeat message to given server outgoing.offer( to( HeartbeatMessage.i_am_alive, toSendTo, new HeartbeatMessage.IAmAliveState(context.getClusterContext().getMyId())) .setHeader( "last-learned", context.getLearnerContext().getLastLearnedInstanceId() + "")); // Set new timeout to send heartbeat to this host context .getClusterContext() .timeouts .setTimeout( HeartbeatMessage.sendHeartbeat + "-" + to, timeout(HeartbeatMessage.sendHeartbeat, message, to)); } break; } case reset_send_heartbeat: { InstanceId to = message.getPayload(); if (!context.getClusterContext().isMe(to)) { String timeoutName = HeartbeatMessage.sendHeartbeat + "-" + to; context.getClusterContext().timeouts.cancelTimeout(timeoutName); context .getClusterContext() .timeouts .setTimeout(timeoutName, timeout(HeartbeatMessage.sendHeartbeat, message, to)); } break; } case suspicions: { HeartbeatMessage.SuspicionsState suspicions = message.getPayload(); context .getClusterContext() .getLogger(HeartbeatState.class) .debug("Received suspicions as " + suspicions); URI from = new URI(message.getHeader(Message.FROM)); InstanceId fromId = context.getClusterContext().getConfiguration().getServerId(from); /* * Remove ourselves from the suspicions received - we just received a message, * it's not normal to be considered failed. Whatever it was, it was transient and now it has * passed. */ suspicions.getSuspicions().remove(context.getClusterContext().getMyId()); context.suspicions(fromId, suspicions.getSuspicions()); break; } case leave: { context.getClusterContext().getLogger(HeartbeatState.class).debug("Received leave"); return start; } case addHeartbeatListener: { context.addHeartbeatListener((HeartbeatListener) message.getPayload()); break; } case removeHeartbeatListener: { context.removeHeartbeatListener((HeartbeatListener) message.getPayload()); break; } } return this; }