this.peer = peer;
LOG.info("Constructor: " + getName());
}
public void run() {
try {
Vote v = null;
while(true) {
peer.setPeerState(ServerState.LOOKING);
LOG.info("Going to call leader election again.");
v = peer.getElectionAlg().lookForLeader();
if(v == null){
LOG.info("Thread " + i + " got a null vote");
break;
}
/*
* A real zookeeper would take care of setting the current vote. Here
* we do it manually.
*/
peer.setCurrentVote(v);
LOG.info("Finished election: " + i + ", " + v.id);
votes[i] = v;
/*
* Get the current value of the logical clock for this peer.
*/
int lc = (int) ((FastLeaderElection) peer.getElectionAlg()).getLogicalClock();
if (v.id == ((long) i)) {
/*
* A leader executes this part of the code. If it is the first leader to be
* elected, then it fails right after. Otherwise, it waits until it has enough
* followers supporting it.
*/
LOG.info("I'm the leader: " + i);
synchronized(FLETest.this) {
if (leaderDies) {
LOG.info("Leader " + i + " dying");
leaderDies = false;
((FastLeaderElection) peer.getElectionAlg()).shutdown();
leader = -1;
LOG.info("Leader " + i + " dead");
//round++;
FLETest.this.notifyAll();
break;
} else {
synchronized(voteMap){
if(voteMap.get(lc) == null)
voteMap.put(lc, new HashSet<TestVote>());
HashSet<TestVote> hs = voteMap.get(lc);
hs.add(new TestVote(i, v.id));
if(countVotes(hs, v.id) > (count/2)){
leader = i;
LOG.info("Got majority: " + i);
} else {
voteMap.wait(3000);
LOG.info("Notified or expired: " + i);
hs = voteMap.get(lc);
if(countVotes(hs, v.id) > (count/2)){
leader = i;
LOG.info("Got majority: " + i);
} else {
//round++;
}
}
}
FLETest.this.notifyAll();
if(leader == i){
synchronized(finalObj){
successCount++;
if(successCount > (count/2)) finalObj.notify();
}
break;
}
}
}
} else {
/*
* Followers execute this part. They first add their vote to voteMap, and then
* they wait for bounded amount of time. A leader notifies followers through the
* FLETest.this object.
*
* Note that I can get FLETest.this, and then voteMap before adding the vote of
* a follower, otherwise a follower would be blocked out until the leader notifies
* or leaves the synchronized block on FLEtest.this.
*/
LOG.info("Logical clock " + ((FastLeaderElection) peer.getElectionAlg()).getLogicalClock());
synchronized(voteMap){
LOG.info("Voting on " + votes[i].id + ", round " + ((FastLeaderElection) peer.getElectionAlg()).getLogicalClock());
if(voteMap.get(lc) == null)
voteMap.put(lc, new HashSet<TestVote>());
HashSet<TestVote> hs = voteMap.get(lc);
hs.add(new TestVote(i, votes[i].id));
if(countVotes(hs, votes[i].id) > (count/2)){
LOG.info("Logical clock: " + lc + ", " + votes[i].id);
voteMap.notify();
}
}
/*
* In this part a follower waits until the leader notifies it, and remove its
* vote if the leader takes too long to respond.
*/
synchronized(FLETest.this){
if (leader != votes[i].id) FLETest.this.wait(3000);
LOG.info("The leader: " + leader + " and my vote " + votes[i].id);
synchronized(voteMap){
if (leader == votes[i].id) {
synchronized(finalObj){
successCount++;
if(successCount > (count/2)) finalObj.notify();
}
break;
} else {
HashSet<TestVote> hs = voteMap.get(lc);
TestVote toRemove = null;
for(TestVote tv : hs){
if(v.id == i){
toRemove = tv;
break;
}
}
hs.remove(toRemove);
}
}
}
}
/*
* Add some randomness to the execution.
*/
Thread.sleep(rand.nextInt(500));
peer.setCurrentVote(new Vote(peer.getId(), 0));
}
LOG.debug("Thread " + i + " votes " + v);
} catch (InterruptedException e) {
e.printStackTrace();
}