public static void handleGetDecision(List<String> msgs) throws Exception { List<String> toBeRemoved = new ArrayList<String>(); for (String msg : msgs) { Message m = ThreePhaseCommitUtility.deserializeMessage(msg); if (GET_DECISION.equals(m.getMessage())) { handleGetDecision(m); toBeRemoved.add(msg); } } msgs.removeAll(toBeRemoved); }
public static void main(String args[]) { if (args.length < 3) { throw new IllegalArgumentException( "please provide intial co-ordinator id and current process id"); } try { String t = null; if (args.length == 4) t = args[3]; delay = Integer.parseInt(args[2]); COORDINATOR_TIME_OUT_IN_SECONDS += delay * NUM_PARTICIPANTS; PARTICIPANT_TIME_OUT_IN_SECONDS += delay * NUM_PARTICIPANTS; GET_DECISION_TIME_OUT_IN_SECONDS += delay * NUM_PARTICIPANTS; netController = new NetController( new Config("bin/com/tpc/util/" + "config_" + args[1] + ".txt"), new FaultModel(t), delay * 1000); processId = Integer.parseInt(args[1]); coordinatorId = -1; String myVote = YES; activeProcesses = ThreePhaseCommitUtility.getActiveProcess(processId); System.out.println("active processes list obtained from log is" + activeProcesses); playList = ThreePhaseCommitUtility.fetchLocalState(processId); // read the recent log record for any change of state LogRecord recentLog = ThreePhaseCommitUtility.fetchMessageFromDTLog(processId); if (recentLog != null) { System.out.println("Process " + processId + " has the recentLog of " + recentLog); if (recentLog.getMessage().equals(YES) || recentLog.getMessage().equals(START_3PC)) { boolean gotDecision = false; while (!gotDecision) { List<Integer> participants = new ArrayList<Integer>(activeProcesses); participants.remove((Object) new Integer(processId)); Message getDecision = new Message(); getDecision.setProcessId(processId); getDecision.setMessage(GET_DECISION); getDecision.setTransactionId(recentLog.getTransactionId()); for (Integer partcipant : participants) { netController.sendMsg( partcipant, ThreePhaseCommitUtility.serializeMessage(getDecision)); } System.out.println( "Process " + processId + " has sent a GET_DECISION message to " + activeProcesses); List<String> receivedMsgs = new ArrayList<String>(); Timer getDecisionTimer = new Timer(GET_DECISION_TIME_OUT_IN_SECONDS); getDecisionTimer.start(); while (receivedMsgs.isEmpty() && !getDecisionTimer.hasTimedOut()) { receivedMsgs.addAll(netController.getReceivedMsgs()); } System.out.println("Received messages while waiting for decision:" + receivedMsgs); for (String message : receivedMsgs) { Message msg = ThreePhaseCommitUtility.deserializeMessage(message); if (msg.getTransactionId() == recentLog.getTransactionId() && (msg.getMessage().equals(COMMIT) || msg.getMessage().equals(ABORT))) { ThreePhaseCommitUtility.writeMessageToDTLog( processId, new LogRecord( msg.getTransactionId(), msg.getMessage(), msg.getPlaylistCommand())); gotDecision = true; if (msg.getMessage().equals(COMMIT)) { executeCommand(msg.getPlaylistCommand()); } } } } } else { canParticipate = true; } } else { coordinatorId = Integer.parseInt(args[0]); canParticipate = true; } int cnt = 0; // current process is the initial co-ordinator while (true) { if (processId == coordinatorId) { while (ThreePhaseCommitUtility.getPlaylistCommand() != null && ThreePhaseCommitUtility.getPlaylistCommand().getAction() != null) { currentCommand = ThreePhaseCommitUtility.getPlaylistCommand(); cnt++; Thread.sleep(5000); System.out.println("current cnt:" + cnt); currTrans++; List<Integer> totalParticipants = new ArrayList<Integer>(); System.out.println("reinitializing active processes"); for (int i = 0; i <= NUM_PARTICIPANTS; i++) { if (i != processId) totalParticipants.add(i); activeProcesses.add(i); } ThreePhaseCommitUtility.saveActiveProcess(processId, activeProcesses); Message message = new Message( processId, currTrans, VOTE_REQ, ThreePhaseCommitUtility.getPlaylistCommand()); ThreePhaseCommitUtility.writeMessageToDTLog( processId, new LogRecord(currTrans, START_3PC, message.getPlaylistCommand())); List<Integer> participants = new ArrayList<Integer>(totalParticipants); System.out.println("starting new transaction!"); participants.remove((Object) new Integer(processId)); // Send VOTE REQ to all participants System.out.println("sending vote requests!"); for (Integer participant : participants) { boolean sendStatus = netController.sendMsg( participant, ThreePhaseCommitUtility.serializeMessage(message)); if (!sendStatus) { log.log(Level.INFO, "send to process" + participant + " failed"); } } // Get VOTE responses from participants. Timer timer = new Timer(COORDINATOR_TIME_OUT_IN_SECONDS); timer.start(); List<String> reportMessages = new ArrayList<String>(); while (reportMessages.size() < totalParticipants.size() && !timer.hasTimedOut()) { List<String> recMsgs = netController.getReceivedMsgs(); handleGetDecision(recMsgs); reportMessages.addAll(recMsgs); } // some process timed out. aborting if (timer.hasTimedOut()) { System.out.println("a few processes timedout. Hence aborting the transaction"); System.out.println("received messages:" + reportMessages); ThreePhaseCommitUtility.writeMessageToDTLog( processId, new LogRecord(currTrans, ABORT, currentCommand)); for (String rawMessage : reportMessages) { Message msg = ThreePhaseCommitUtility.deserializeMessage(rawMessage); if (msg.getMessage().equals(YES)) { netController.sendMsg( msg.getProcessId(), ThreePhaseCommitUtility.serializeMessage( new Message(processId, currTrans, ABORT, currentCommand))); } } continue; } // abort if some process sends no. boolean abortFlag = false; List<Message> forMessages = new ArrayList<Message>(); List<Message> againstMessages = new ArrayList<Message>(); for (String reportMessage : reportMessages) { Message msg = ThreePhaseCommitUtility.deserializeMessage(reportMessage); if (msg.getMessage().equals(NO)) { System.out.println("process " + msg.getProcessId() + "has decided abort"); abortFlag = true; } else if (msg.getMessage().equals(YES)) { System.out.println("process " + msg.getProcessId() + "is ok with commiting"); forMessages.add(msg); } } // some processes have decided to abort. ABORT if (abortFlag || !myVote.equals(YES)) { System.out.println("coordinator has decided to abort"); ThreePhaseCommitUtility.writeMessageToDTLog( processId, new LogRecord(currTrans, ABORT, currentCommand)); for (Message msg : forMessages) { Message abortMessage = new Message(processId, currTrans, ABORT, currentCommand); netController.sendMsg( msg.getProcessId(), ThreePhaseCommitUtility.serializeMessage(abortMessage)); } } // all processes have sent yes! COMMIT away if (!abortFlag && myVote.equals(YES)) { System.out.println("everyone has sent yes. sending PRE COMMIT"); Message preCommitMessage = new Message(processId, currTrans, PRE_COMMIT); for (Integer parts : participants) { netController.sendMsg( parts, ThreePhaseCommitUtility.serializeMessage(preCommitMessage)); } List<String> ackMessages = new ArrayList<String>(); Timer ackTimer = new Timer(COORDINATOR_TIME_OUT_IN_SECONDS); ackTimer.start(); while (ackMessages.size() < activeProcesses.size() - 1 && !ackTimer.hasTimedOut()) { List<String> recMsgs = netController.getReceivedMsgs(); handleGetDecision(recMsgs); ackMessages.addAll(recMsgs); } // just a simple check. Ideally should never happen. for (String ackMessage : ackMessages) { Message ackMsg = ThreePhaseCommitUtility.deserializeMessage(ackMessage); if (!ackMsg.getMessage().equals("ACK")) { throw new IllegalStateException("din receive ack"); } } // write commit to DT log ThreePhaseCommitUtility.writeMessageToDTLog( processId, new LogRecord(currTrans, COMMIT, currentCommand)); executeCommand(currentCommand); // send COMMIT to everyone System.out.println("sending commit to everyone!"); for (Integer parts : participants) { netController.sendMsg( parts, ThreePhaseCommitUtility.serializeMessage( new Message(processId, currTrans, COMMIT, currentCommand))); } ThreePhaseCommitUtility.removeTopPlaylistCommand(); } } } else { // current process is a participant. List<String> receivedMsgs = new ArrayList<String>(); while (processId != coordinatorId) { Timer timer = new Timer(PARTICIPANT_TIME_OUT_IN_SECONDS); timer.start(); System.out.println("Process " + processId + " is waiting for some message"); while (receivedMsgs.isEmpty() && !timer.hasTimedOut()) { receivedMsgs.addAll(netController.getReceivedMsgs()); } // if time-out has happened if (timer.hasTimedOut() && (participant_waiting_for.equals(COMMIT) || participant_waiting_for.equals(PRE_COMMIT) || participant_waiting_for.equals(ABORT))) { System.out.println( "Process " + processId + " has encountered a time out and the participant is waiting for " + participant_waiting_for); initiateElection(); System.out.println("active processes" + activeProcesses); List<Integer> currentActiveParticipants = new ArrayList<Integer>(activeProcesses); if (coordinatorId == processId) { // invoke co-ordinator's termination protocol currentActiveParticipants.remove((Object) new Integer(processId)); coordinatorTerminationProtocol(currentActiveParticipants); break; } } // if there is some message received System.out.println("Received messages :" + receivedMsgs); for (String message : receivedMsgs) { Message msg = ThreePhaseCommitUtility.deserializeMessage(message); if (msg.getMessage().equals(VOTE_REQ)) { // set this as the new co-ordinator if (msg.getProcessId() != coordinatorId) { coordinatorId = msg.getProcessId(); } System.out.println("Process " + processId + " received a vote request"); currTrans = msg.getTransactionId(); currentCommand = msg.getPlaylistCommand(); Message voteYes = new Message(); voteYes.setProcessId(processId); voteYes.setMessage(YES); ThreePhaseCommitUtility.writeMessageToDTLog( processId, new LogRecord(msg.getTransactionId(), YES)); netController.sendMsg( coordinatorId, ThreePhaseCommitUtility.serializeMessage(voteYes)); System.out.println("Process " + processId + " waiting for a pre_commit"); participant_waiting_for = PRE_COMMIT; canParticipate = true; my_current_state = YES; } else if (canParticipate && msg.getProcessId() == coordinatorId && msg.getMessage().equals(ABORT) && currTrans == msg.getTransactionId()) { ThreePhaseCommitUtility.writeMessageToDTLog( processId, new LogRecord(msg.getTransactionId(), ABORT, msg.getPlaylistCommand())); System.out.println("Process " + processId + " received an abort"); participant_waiting_for = VOTE_REQ; my_current_state = ABORT; } else if (canParticipate && msg.getProcessId() == coordinatorId && msg.getMessage().equals(COMMIT) && currTrans == msg.getTransactionId()) { executeCommand(msg.getPlaylistCommand()); ThreePhaseCommitUtility.writeMessageToDTLog( processId, new LogRecord(msg.getTransactionId(), COMMIT, msg.getPlaylistCommand())); System.out.println("Process " + processId + " received a commit"); participant_waiting_for = VOTE_REQ; my_current_state = COMMIT; } else if (canParticipate && msg.getProcessId() == coordinatorId && msg.getMessage().equals(PRE_COMMIT) && currTrans == msg.getTransactionId()) { System.out.println("Process " + processId + " received a pre-commit"); Message ack = new Message(); ack.setProcessId(processId); ack.setMessage(ACK); ack.setTransactionId(currTrans); netController.sendMsg(coordinatorId, ThreePhaseCommitUtility.serializeMessage(ack)); participant_waiting_for = COMMIT; my_current_state = PRE_COMMIT; System.out.println( "Process " + processId + " voted with an ACK and waiting for " + participant_waiting_for); // ThreePhaseCommitUtility.writeMessageToDTLog(processId, COMMIT); } else if (canParticipate && msg.getMessage().equals(NEW_CO_OD)) { System.out.println( "Process " + processId + " got a NEW_CO_OD from process " + msg.getProcessId()); if (!hasElectionHappened) { System.out.println("removing processes " + coordinatorId); System.out.println("active processes " + activeProcesses); activeProcesses.remove((Object) new Integer(coordinatorId)); System.out.println("active processes " + activeProcesses); ThreePhaseCommitUtility.saveActiveProcess(processId, activeProcesses); hasElectionHappened = false; } coordinatorId = msg.getProcessId(); participantTerminationProtocol(); } else if (canParticipate && msg.getMessage().equals(GET_DECISION)) { System.out.println( "Process " + processId + " got a GET_DECISION from process " + msg.getProcessId()); activeProcesses.add(msg.getProcessId()); ThreePhaseCommitUtility.saveActiveProcess(coordinatorId, activeProcesses); handleGetDecision(msg); } } receivedMsgs.clear(); } } } } catch (Exception e) { e.printStackTrace(); System.exit(1); } }
public static void coordinatorTerminationProtocol(List<Integer> participants) throws Exception { int totalParticipants = participants.size(); // send STATE_REQ to all processes. System.out.println("Starting termination protocol. Co-ordinator is" + processId); System.out.println("sending state request to" + participants); for (Integer participant : participants) { System.out.println("sending state req to :" + participant + "for trans" + currTrans); netController.sendMsg( participant, ThreePhaseCommitUtility.serializeMessage( new Message(coordinatorId, currTrans, STATE_REQ))); } // Wait for all responses or until timeout Timer stateReqTimer = new Timer(COORDINATOR_TIME_OUT_IN_SECONDS); stateReqTimer.start(); List<String> stateReqresponses = new ArrayList<String>(); while (stateReqresponses.size() < totalParticipants && !stateReqTimer.hasTimedOut()) { stateReqresponses.addAll(netController.getReceivedMsgs()); } // get co-ordinators state. LogRecord recentLogRecord = ThreePhaseCommitUtility.fetchMessageFromDTLog(processId); String state = recentLogRecord.getMessage(); boolean abortFlag, uncertainFlag, commitFlag, commitableFlag; abortFlag = uncertainFlag = commitFlag = false; abortFlag = state.equals(ABORT); commitFlag = state.equals(COMMIT); commitableFlag = my_current_state.equals(PRE_COMMIT); uncertainFlag = abortFlag == false && commitFlag == false; System.out.println("parsing participant states..." + stateReqresponses); // get participant state List<Integer> uncertainProcesses = new ArrayList<Integer>(); if (!abortFlag && !commitFlag) { for (String resp : stateReqresponses) { Message msg = ThreePhaseCommitUtility.deserializeMessage(resp); if (msg.getMessage().equals(ABORTED)) { abortFlag = true; break; } else if (msg.getMessage().equals(COMMITTED)) { commitFlag = true; break; } else if (msg.getMessage().equals(COMMITTABLE)) { commitableFlag = true; } else if (msg.getMessage().equals(UNCERTAIN)) { uncertainFlag = true; uncertainProcesses.add(msg.getProcessId()); } } } if (abortFlag) { System.out.println("deciding to abort!"); if (!state.equals(ABORT)) { ThreePhaseCommitUtility.writeMessageToDTLog( processId, new LogRecord(currTrans, ABORT, currentCommand)); } for (Integer participant : participants) { netController.sendMsg( participant, ThreePhaseCommitUtility.serializeMessage( new Message(processId, currTrans, ABORT, currentCommand))); } } else if (commitFlag) { System.out.println("deciding to commit!"); if (!state.equals(COMMIT)) { ThreePhaseCommitUtility.writeMessageToDTLog( processId, new LogRecord(currTrans, COMMIT, currentCommand)); executeCommand(currentCommand); } for (Integer participant : participants) { netController.sendMsg( participant, ThreePhaseCommitUtility.serializeMessage( new Message(processId, currTrans, COMMIT, currentCommand))); } ThreePhaseCommitUtility.removeTopPlaylistCommand(); } else if (commitableFlag || COMMIT.equals(participant_waiting_for)) { System.out.println("commitable, sending pre commit to uncertain processes."); for (Integer participant : uncertainProcesses) { netController.sendMsg( participant, ThreePhaseCommitUtility.serializeMessage( new Message(processId, currTrans, PRE_COMMIT))); } Timer ackTimer = new Timer(COORDINATOR_TIME_OUT_IN_SECONDS); ackTimer.start(); List<String> ackMsgs = new ArrayList<String>(); while (ackMsgs.size() != uncertainProcesses.size() || !ackTimer.hasTimedOut()) { ackMsgs.addAll(netController.getReceivedMsgs()); } System.out.println("sending commit to all processes"); ThreePhaseCommitUtility.writeMessageToDTLog( processId, new LogRecord(currTrans, COMMIT, currentCommand)); ThreePhaseCommitUtility.removeTopPlaylistCommand(); executeCommand(currentCommand); for (Integer participant : participants) { netController.sendMsg( participant, ThreePhaseCommitUtility.serializeMessage( new Message(processId, currTrans, COMMIT, currentCommand))); } System.out.println("sent commit to all processes"); } else { System.out.println("all of em are uncertain. aborting transaction"); if (!state.equals(ABORT)) { ThreePhaseCommitUtility.writeMessageToDTLog( processId, new LogRecord(currTrans, ABORT, currentCommand)); } System.out.println("sending abort to" + participants); for (Integer participant : participants) { netController.sendMsg( participant, ThreePhaseCommitUtility.serializeMessage( new Message(processId, currTrans, ABORT, currentCommand))); } } System.out.println("completing termination protocol"); }
public static void participantTerminationProtocol() throws Exception { System.out.println("Process " + processId + " is initiating participant termination protocol"); List<String> receivedMsgs = new ArrayList<String>(); boolean notCommitted = true; System.out.println("Process " + processId + " is waiting for STATE_REQ"); while (notCommitted && processId != coordinatorId) { Timer timer = new Timer(PARTICIPANT_TIME_OUT_IN_SECONDS); timer.start(); while (receivedMsgs.isEmpty() && !timer.hasTimedOut()) { receivedMsgs.addAll(netController.getReceivedMsgs()); } // if time-out has happened if (timer.hasTimedOut() && (participant_waiting_for.equals(STATE_RESP))) { System.out.println( "Process " + processId + " has timed out while waiting for response from co-ordinator"); initiateElection(); if (coordinatorId == processId) { // invoke co-ordinator's termination protocol List<Integer> participants = new ArrayList<Integer>(activeProcesses); System.out.println("active processes!" + activeProcesses); participants.remove((Object) new Integer(processId)); coordinatorTerminationProtocol(participants); } } for (String message : receivedMsgs) { Message msg = ThreePhaseCommitUtility.deserializeMessage(message); if (msg.getProcessId() == coordinatorId && msg.getMessage().equals(STATE_REQ)) { Message state = new Message(); state.setProcessId(processId); state.setTransactionId(msg.getTransactionId()); System.out.println("msg of process " + processId + " is " + msg); if (my_current_state.equals(ABORTED)) { state.setMessage(ABORTED); } else if (my_current_state.equals(COMMIT)) { state.setMessage(COMMITTED); } else if (my_current_state.equals(PRE_COMMIT)) { state.setMessage(COMMITTABLE); } else { state.setMessage(UNCERTAIN); } netController.sendMsg(coordinatorId, ThreePhaseCommitUtility.serializeMessage(state)); participant_waiting_for = STATE_RESP; System.out.println( "Process " + processId + " sends its current state " + state.getMessage()); } else if (msg.getProcessId() == coordinatorId && msg.getMessage().equals(ABORT)) { LogRecord myState = ThreePhaseCommitUtility.fetchRecordForTransaction(processId, msg.getTransactionId()); if (!myState.getMessage().equals(ABORT)) ThreePhaseCommitUtility.writeMessageToDTLog( processId, new LogRecord(msg.getTransactionId(), ABORT, msg.getPlaylistCommand())); System.out.println( "Process " + processId + " received abort during the termination protocol"); participant_waiting_for = ""; notCommitted = false; my_current_state = ABORTED; } else if (msg.getProcessId() == coordinatorId && msg.getMessage().equals(COMMIT)) { LogRecord myState = ThreePhaseCommitUtility.fetchRecordForTransaction(processId, msg.getTransactionId()); if (!myState.getMessage().equals(COMMIT)) { ThreePhaseCommitUtility.writeMessageToDTLog( processId, new LogRecord(msg.getTransactionId(), COMMIT, msg.getPlaylistCommand())); executeCommand(msg.getPlaylistCommand()); } participant_waiting_for = ""; my_current_state = COMMIT; System.out.println( "Process " + processId + " received commit during the termination protocol"); notCommitted = false; } else if (msg.getMessage().equals(GET_DECISION)) { System.out.println( "Process " + processId + " got a GET_DECISION from process " + msg.getProcessId()); handleGetDecision(msg); } else if (msg.getMessage().equals(PRE_COMMIT)) { my_current_state = PRE_COMMIT; Message ack = new Message(); ack.setProcessId(processId); ack.setMessage(ACK); netController.sendMsg(coordinatorId, ThreePhaseCommitUtility.serializeMessage(ack)); System.out.println( "Process " + processId + " received pre_commit during the termination protocol and has sent ACK"); } } receivedMsgs.clear(); } System.out.println("Process " + processId + " has completed participant termination protocol"); }