private boolean updateCurrent(LeaderElection req) { boolean isNew = false; if (current == null) { current = new ElectionState(); isNew = true; } else { if (req.getExpires() > current.maxDuration) { isNew = false; // If this election was started after the current election, dont do anything! logger.info("Ignoring this election - older election already in progress! Not voting!"); return isNew; } else { isNew = true; } } if (req.getCandidateId() == this.nodeId) { // logger.info("Updating election details in RAFT Election"); isNew = false; } current.electionID = req.getElectId(); current.candidate = req.getCandidateId(); current.desc = req.getDesc(); current.maxDuration = req.getExpires(); current.startedOn = System.currentTimeMillis(); current.state = req.getAction(); current.id = -1; // TODO me or sender? current.active = true; return isNew; }
/** @param args */ public void processRequest(Management mgmt) { if (!mgmt.hasElection()) return; LeaderElection req = mgmt.getElection(); // when a new node joins the network it will want to know who the leader // is - we kind of ram this request-response in the process request // though there has to be a better place for it if (req.getAction().getNumber() == LeaderElection.ElectAction.WHOISTHELEADER_VALUE) { respondToWhoIsTheLeader(mgmt); return; } else if (req.getAction().getNumber() == LeaderElection.ElectAction.THELEADERIS_VALUE) { logger.info( "Node " + conf.getNodeId() + " got an answer on who the leader is. Its Node " + req.getCandidateId()); this.leaderNode = req.getCandidateId(); this.termId = req.getTermId(); // the current term id // TODO Last log index to be synced return; } // else fall through to an election // if the time has expired, an election is initiated. if (req.hasExpires()) { long ct = System.currentTimeMillis(); if (ct > req.getExpires()) { // ran out of time so the election is over if (election != null) election.clear(); return; } } Management rtn = electionInstance().process(mgmt); if (rtn != null) ConnectionManager.broadcast(rtn); }
/* * (non-Javadoc) * * @see poke.server.election.Election#process(eye.Comm.LeaderElection) * * @return The Management instance returned represents the message to send * on. If null, no action is required. Not a great choice to convey to the * caller; can be improved upon easily. */ @Override public Management process(Management mgmt) { if (!mgmt.hasElection()) return null; LeaderElection req = mgmt.getElection(); if (req.getExpires() <= System.currentTimeMillis()) { // election has expired without a conclusion? } Management rtn = null; if (req.getAction().getNumber() == ElectAction.DECLAREELECTION_VALUE) { // an election is declared! // required to eliminate duplicate messages - on a declaration, // should not happen if the network does not have cycles List<VectorClock> rtes = mgmt.getHeader().getPathList(); for (VectorClock rp : rtes) { if (rp.getNodeId() == this.nodeId) { // message has already been sent to me, don't use and // forward return null; } } // I got here because the election is unknown to me // this 'if debug is on' should cover the below dozen or so // println()s. It is here to help with seeing when an election // occurs. if (logger.isDebugEnabled()) {} System.out.println("\n\n*********************************************************"); System.out.println(" RAFT ELECTION: Election declared"); System.out.println(" Election ID: " + req.getElectId()); System.out.println(" Rcv from: Node " + mgmt.getHeader().getOriginator()); System.out.println(" Expires: " + new Date(req.getExpires())); System.out.println(" Nominates: Node " + req.getCandidateId()); System.out.println(" Desc: " + req.getDesc()); System.out.print(" Routing tbl: ["); for (VectorClock rp : rtes) System.out.print( "Node " + rp.getNodeId() + " (" + rp.getVersion() + "," + rp.getTime() + "), "); System.out.println("]"); System.out.println("*********************************************************\n\n"); // sync master IDs to current election ElectionIDGenerator.setMasterID(req.getElectId()); /** * a new election can be declared over an existing election. * * <p>TODO need to have an monotonically increasing ID that we can test */ boolean isNew = updateCurrent(req); rtn = castVote(mgmt, isNew); } else if (req.getAction().getNumber() == ElectAction.DECLAREVOID_VALUE) { // no one was elected, I am dropping into standby mode logger.info("TODO: no one was elected, I am dropping into standby mode"); this.clear(); notify(false, null); } else if (req.getAction().getNumber() == ElectAction.DECLAREWINNER_VALUE) { // some node declared itself the leader logger.info( "Election " + req.getElectId() + ": Node " + req.getCandidateId() + " is declared the leader"); updateCurrent(mgmt.getElection()); current.active = false; // it's over notify(true, req.getCandidateId()); } else if (req.getAction().getNumber() == ElectAction.ABSTAIN_VALUE) { // for some reason, a node declines to vote - therefore, do nothing } else if (req.getAction().getNumber() == ElectAction.NOMINATE_VALUE) { boolean isNew = updateCurrent(mgmt.getElection()); rtn = castVote(mgmt, isNew); } else { // this is me! } return rtn; }