public void messageReceived(IoSession ioSession, Object message) throws Exception { if (message instanceof DefaultPaxosMessage) { PaxosMessage paxosMessage = (DefaultPaxosMessage) message; switch (paxosMessage.getType()) { case PROPOSE: handlePropose(paxosMessage); break; case ACCEPTED: handleAccepted(paxosMessage); break; case PREPARE: handlePrepare( (Integer) paxosMessage.getValue(), paxosMessage.getProposerId()); // PSN and consensus instance dont matter break; case PREPARE_RESP: handlePrepareResponse(paxosMessage); break; case RECOVERY: handleRecovery(paxosMessage); break; case RECOVERY_RESP: handleRecoveryResponse(paxosMessage); break; case PING: if (paxosMessage.getProposerId() == getLeader()) // Leaders HeartBeat leaderLastHeard = new Date(); else if (((Integer) paxosMessage.getValue()) > preparedFor) { // I came alive and the leader is not who I thought. preparedFor = ((Integer) paxosMessage.getValue()); handlePrepare(preparedFor, getLeader()); sendRecovery(); } break; default: throw new Exception( "received PaxosMessage of unknown type" + paxosMessage.getType().name()); } } else if (message instanceof ChatMessage) { // Some client sent or some server forwarded. if (nodeIsLeader()) { propose( new DefaultPaxosMessage( nextInstance, nextPropose, id, PaxosMessageType.PROPOSE, (ChatMessage) message)); nextInstance++; } else { sendToLeader((ChatMessage) message); } } else { throw new Exception("Unknown message type:" + message.getClass().getSimpleName()); } }
private void handleRecoveryResponse(PaxosMessage recoveryResponse) { ArrayList<ChatMessage> newChosen = (ArrayList<ChatMessage>) recoveryResponse.getValue(); ensureSize(chosen, newChosen.size()); for (int i = 0; i < newChosen.size(); i++) { if (chosen.get(i) == null) { chosen.set(i, newChosen.get(i)); } else if (!chosen.get(i).equals(newChosen.get(i))) { System.out.println("We have an error, two servers conflict in their chosen values."); } } }
/** * Work through the chosen messages sending what we have left and stopping once we get to an * unfilled slot or the end of the array. */ private void onChosen(PaxosMessage proposal) { chosen.set(proposal.getInstanceNum(), (ChatMessage) proposal.getValue()); if (proposal.getInstanceNum() >= nextInstance) nextInstance = proposal.getInstanceNum() + 1; while (lastSent + 1 < chosen.size()) { ChatMessage toSend = chosen.get(lastSent + 1); if (toSend != null) { if (nodeIsLeader()) sendToClients(toSend); lastSent++; } else { break; // There is still a missing slot. } } }
@Override public void handlePropose(PaxosMessage proposal) { if (preparedFor > proposal.getProposeNum()) return; ensureSize(accepted, proposal.getInstanceNum() + 1); ensureSize(chosen, proposal.getInstanceNum() + 1); accepted.set(proposal.getInstanceNum(), (ChatMessage) proposal.getValue()); // Send accept to all /* sendAllMessage(new DefaultPaxosMessage(proposal.getInstanceNum(), proposal.getProposeNum(), id, PaxosMessageType.ACCEPTED, proposal.getValue())); */ // Silently accept proposals }
@Override public void handlePrepareResponse(PaxosMessage response) { if (!prepareResponseFrom.contains(response.getProposerId())) prepareResponseFrom.add( response.getProposerId()); // This is a new server accepted our prepare request. List<ChatMessage> remoteAccepted = (List<ChatMessage>) response.getValue(); for (int i = 0; i < remoteAccepted.size(); i++) { if (chosen.size() > i && chosen.get(i) != null) continue; if (remoteAccepted.get(i) != null) { propose( new DefaultPaxosMessage( i, nextPropose, id, PaxosMessageType.PROPOSE, remoteAccepted.get(i))); if (i > nextInstance) nextInstance = i; } } }