@Override public synchronized boolean handleStartElectionRequest(L2StateMessage msg) { Assert.assertEquals(L2StateMessage.START_ELECTION, msg.getType()); if (state == ELECTION_IN_PROGRESS && (myVote.isANewCandidate() || !msg.getEnrollment().isANewCandidate())) { // Another node is also joining in the election process, Cast its vote and notify my vote // Note : WE dont want to do this for new candidates when we are not new. Enrollment vote = msg.getEnrollment(); Enrollment old = votes.put(vote.getNodeID(), vote); boolean sendResponse = msg.inResponseTo().isNull(); if (old != null && !vote.equals(old)) { logger.warn( "Received duplicate vote : Replacing with new one : " + vote + " old one : " + old); sendResponse = true; } if (sendResponse) { // This is either not a response to this node initiating election or a duplicate vote. // Either case notify this // nodes vote L2StateMessage response = createElectionStartedMessage(msg, myVote); logger.info("Casted vote from " + msg + " My Response : " + response); try { groupManager.sendTo(msg.messageFrom(), response); } catch (GroupException e) { logger.error("Error sending Votes to : " + msg.messageFrom(), e); } } else { logger.info("Casted vote from " + msg); } return true; } else { logger.info("Ignoring Start Election Request : " + msg + " My state = " + state); return false; } }
/** This method is called by the winner of the election to announce to the world */ @Override public synchronized void declareWinner(NodeID myNodeId) { Assert.assertEquals(winner.getNodeID(), myNodeId); L2StateMessage msg = createElectionWonMessage(this.winner); debugInfo("Announcing as winner: " + myNodeId); this.groupManager.sendAll(msg); logger.info("Declared as Winner: Winner is : " + this.winner); reset(winner); }
private synchronized void handleElectionWonMessage(L2StateMessage clusterMsg) { debugInfo("Received election_won or election_already_won msg: " + clusterMsg); Enrollment winningEnrollment = clusterMsg.getEnrollment(); if (state == ACTIVE_COORDINATOR) { // Can't get Election Won from another node : Split brain String error = state + " Received Election Won Msg : " + clusterMsg + ". A Terracotta server tried to join the mirror group as a second ACTIVE"; logger.error(error); if (clusterMsg.getType() == L2StateMessage.ELECTION_WON_ALREADY) { sendNGResponse(clusterMsg.messageFrom(), clusterMsg); } groupManager.zapNode( winningEnrollment.getNodeID(), L2HAZapNodeRequestProcessor.SPLIT_BRAIN, error); } else if (activeNode.isNull() || activeNode.equals(winningEnrollment.getNodeID()) || clusterMsg.getType() == L2StateMessage.ELECTION_WON) { // There is no active server for this node or the other node just detected a failure of ACTIVE // server and ran an // election and is sending the results. This can happen if this node for some reason is not // able to detect that // the active is down but the other node did. Go with the new active. setActiveNodeID(winningEnrollment.getNodeID()); moveToPassiveState(winningEnrollment); if (clusterMsg.getType() == L2StateMessage.ELECTION_WON_ALREADY) { sendOKResponse(clusterMsg.messageFrom(), clusterMsg); } } else { // This is done to solve DEV-1532. Node sent ELECTION_WON_ALREADY message but our ACTIVE is // intact. logger.warn( "Conflicting Election Won Msg : " + clusterMsg + " since I already have a ACTIVE Node : " + activeNode + ". Sending NG response"); // The reason we send a response for ELECTION_WON_ALREADY message is that if we don't agree we // don't want the // other server to send us cluster state messages. sendNGResponse(clusterMsg.messageFrom(), clusterMsg); } }
private synchronized void electionStarted(Enrollment e) { if (this.state == ELECTION_IN_PROGRESS) { throw new AssertionError("Election Already in Progress"); } this.state = ELECTION_IN_PROGRESS; this.myVote = e; this.winner = null; this.votes.clear(); this.votes.put(e.getNodeID(), e); // Cast my vote logger.info("Election Started : " + e); }
private NodeID doElection(NodeID myNodeId, boolean isNew, WeightGeneratorFactory weightsFactory) throws GroupException, InterruptedException { // Step 1: publish to cluster NodeID, weight and election start Enrollment e = EnrollmentFactory.createEnrollment(myNodeId, isNew, weightsFactory); electionStarted(e); L2StateMessage msg = createElectionStartedMessage(e); debugInfo("Sending my election vote to all members"); groupManager.sendAll(msg); // Step 2: Wait for election completion waitTillElectionComplete(); // Step 3: Compute Winner Enrollment lWinner = computeResult(); if (lWinner != e) { logger.info("Election lost : Winner is : " + lWinner); Assert.assertNotNull(lWinner); return lWinner.getNodeID(); } // Step 4 : local host won the election, so notify world for acceptance msg = createElectionResultMessage(e); debugInfo("Won election, announcing to world and waiting for response..."); GroupResponse<L2StateMessage> responses = groupManager.sendAllAndWaitForResponse(msg); for (L2StateMessage response : responses.getResponses()) { Assert.assertEquals(msg.getMessageID(), response.inResponseTo()); if (response.getType() == L2StateMessage.RESULT_AGREED) { Assert.assertEquals(e, response.getEnrollment()); } else if (response.getType() == L2StateMessage.RESULT_CONFLICT) { logger.info( "Result Conflict: Local Result : " + e + " From : " + response.messageFrom() + " Result : " + response.getEnrollment()); return ServerID.NULL_ID; } else { throw new AssertionError( "Node : " + response.messageFrom() + " responded neither with RESULT_AGREED or RESULT_CONFLICT :" + response); } } // Step 5 : result agreed - I am the winner return myNodeId; }