private ElectionResult countVotes( HashMap<InetSocketAddress, Vote> votes, HashSet<Long> heardFrom) { ElectionResult result = new ElectionResult(); // Initialize with null vote result.vote = new Vote(Long.MIN_VALUE, Long.MIN_VALUE); result.winner = new Vote(Long.MIN_VALUE, Long.MIN_VALUE); Collection<Vote> votesCast = votes.values(); // First make the views consistent. Sometimes peers will have // different zxids for a server depending on timing. for (Iterator<Vote> i = votesCast.iterator(); i.hasNext(); ) { Vote v = i.next(); if (!heardFrom.contains(v.id)) { // Discard votes for machines that we didn't hear from i.remove(); continue; } for (Vote w : votesCast) { if (v.id == w.id) { if (v.zxid < w.zxid) { v.zxid = w.zxid; } } } } HashMap<Vote, Integer> countTable = new HashMap<Vote, Integer>(); // Now do the tally for (Vote v : votesCast) { Integer count = countTable.get(v); if (count == null) { count = Integer.valueOf(0); } countTable.put(v, count + 1); if (v.id == result.vote.id) { result.count++; } else if (v.zxid > result.vote.zxid || (v.zxid == result.vote.zxid && v.id > result.vote.id)) { result.vote = v; result.count = 1; } } result.winningCount = 0; LOG.info("Election tally: "); for (Entry<Vote, Integer> entry : countTable.entrySet()) { if (entry.getValue() > result.winningCount) { result.winningCount = entry.getValue(); result.winner = entry.getKey(); } LOG.info(entry.getKey().id + "\t-> " + entry.getValue()); } return result; }
private void leaveInstance(Vote v) { if (LOG.isDebugEnabled()) { LOG.debug( "About to leave FLE instance: leader=" + v.getId() + ", zxid=0x" + Long.toHexString(v.getZxid()) + ", my id=" + self.getId() + ", my state=" + self.getPeerState()); } recvqueue.clear(); }
/** * Termination predicate. Given a set of votes, determines if have sufficient to declare the end * of the election round. * * @param votes Set of votes * @param l Identifier of the vote received last * @param zxid zxid of the the vote received last */ protected boolean termPredicate(HashMap<Long, Vote> votes, Vote vote) { HashSet<Long> set = new HashSet<Long>(); /* * First make the views consistent. Sometimes peers will have different * zxids for a server depending on timing. */ for (Map.Entry<Long, Vote> entry : votes.entrySet()) { if (vote.equals(entry.getValue())) { set.add(entry.getKey()); } } return self.getQuorumVerifier().containsQuorum(set); }
public void run() { Message response; while (!stop) { // Sleeps on receive try { response = manager.pollRecvQueue(3000, TimeUnit.MILLISECONDS); if (response == null) continue; /* * If it is from an observer, respond right away. Note * that the following predicate assumes that if a server * is not a follower, then it must be an observer. If we * ever have any other type of learner in the future, * we'll have to change the way we check for observers. */ if (!self.getVotingView().containsKey(response.sid)) { Vote current = self.getCurrentVote(); ToSend notmsg = new ToSend( ToSend.mType.notification, current.getId(), current.getZxid(), logicalclock, self.getPeerState(), response.sid, current.getPeerEpoch()); sendqueue.offer(notmsg); } else { // Receive new message if (LOG.isDebugEnabled()) { LOG.debug("Receive new notification message. My id = " + self.getId()); } /* * We check for 28 bytes for backward compatibility */ if (response.buffer.capacity() < 28) { LOG.error("Got a short response: " + response.buffer.capacity()); continue; } boolean backCompatibility = (response.buffer.capacity() == 28); response.buffer.clear(); // Instantiate Notification and set its attributes Notification n = new Notification(); // State of peer that sent this message QuorumPeer.ServerState ackstate = QuorumPeer.ServerState.LOOKING; switch (response.buffer.getInt()) { case 0: ackstate = QuorumPeer.ServerState.LOOKING; break; case 1: ackstate = QuorumPeer.ServerState.FOLLOWING; break; case 2: ackstate = QuorumPeer.ServerState.LEADING; break; case 3: ackstate = QuorumPeer.ServerState.OBSERVING; break; default: continue; } n.leader = response.buffer.getLong(); n.zxid = response.buffer.getLong(); n.electionEpoch = response.buffer.getLong(); n.state = ackstate; n.sid = response.sid; if (!backCompatibility) { n.peerEpoch = response.buffer.getLong(); } else { if (LOG.isInfoEnabled()) { LOG.info("Backward compatibility mode, server id=" + n.sid); } n.peerEpoch = ZxidUtils.getEpochFromZxid(n.zxid); } /* * Version added in 3.4.6 */ n.version = (response.buffer.remaining() >= 4) ? response.buffer.getInt() : 0x0; /* * Print notification info */ if (LOG.isInfoEnabled()) { printNotification(n); } /* * If this server is looking, then send proposed * leader */ if (self.getPeerState() == QuorumPeer.ServerState.LOOKING) { recvqueue.offer(n); /* * Send a notification back if the peer that * sent this message is also looking and its * logical clock is lagging behind. */ if ((ackstate == QuorumPeer.ServerState.LOOKING) && (n.electionEpoch < logicalclock)) { Vote v = getVote(); ToSend notmsg = new ToSend( ToSend.mType.notification, v.getId(), v.getZxid(), logicalclock, self.getPeerState(), response.sid, v.getPeerEpoch()); sendqueue.offer(notmsg); } } else { /* * If this server is not looking, but the one * that sent the ack is looking, then send back * what it believes to be the leader. */ Vote current = self.getCurrentVote(); if (ackstate == QuorumPeer.ServerState.LOOKING) { if (LOG.isDebugEnabled()) { LOG.debug( "Sending new notification. My id = " + self.getId() + " recipient=" + response.sid + " zxid=0x" + Long.toHexString(current.getZxid()) + " leader=" + current.getId()); } ToSend notmsg; if (n.version > 0x0) { notmsg = new ToSend( ToSend.mType.notification, current.getId(), current.getZxid(), current.getElectionEpoch(), self.getPeerState(), response.sid, current.getPeerEpoch()); } else { Vote bcVote = self.getBCVote(); notmsg = new ToSend( ToSend.mType.notification, bcVote.getId(), bcVote.getZxid(), bcVote.getElectionEpoch(), self.getPeerState(), response.sid, bcVote.getPeerEpoch()); } sendqueue.offer(notmsg); } } } } catch (InterruptedException e) { System.out.println( "Interrupted Exception while waiting for new message" + e.toString()); } } LOG.info("WorkerReceiver is down"); }