/**
* Copyright (c) 2007-2009 Alysson Bessani, Eduardo Alchieri, Paulo Sousa, and the authors indicated in the @author tags
*
* This file is part of SMaRt.
*
* SMaRt is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SMaRt is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SMaRt. If not, see <http://www.gnu.org/licenses/>.
*/
package bftsmart.paxosatwar.executionmanager;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
/**
* This class manages information about the leader of each round of each consensus
* @author edualchieri
*/
public class LeaderModule {
// Each value of this map is a list of all the rounds of a consensus
// Each element of that list is a tuple which stands for a round, and the id
// of the process that was the leader for that round
private Map<Integer, List<ConsInfo>> leaderInfos = new HashMap<Integer, List<ConsInfo>>();
// This is the new way of storing info about the leader, uncoupled from consensus
private int currentLeader;
/**
* Creates a new instance of LeaderModule
*/
public LeaderModule() {
addLeaderInfo(-1, 0, 0);
addLeaderInfo(0, 0, 0);
currentLeader = 0;
}
/**
* Adds information about a leader
* @param c Consensus where the replica is a leader
* @param r Rounds of the consensus where the replica is a leader
* @param l ID of the leader
*/
public void addLeaderInfo(int c, int r, int l) {
List<ConsInfo> list = leaderInfos.get(c);
if (list == null) {
list = new LinkedList<ConsInfo>();
leaderInfos.put(c, list);
}
ConsInfo ci = findInfo(list, r);
if (ci != null) {
ci.leaderId = l;
} else {
list.add(new ConsInfo(r, l));
}
}
public void setNewLeader (int leader) {
this.currentLeader = leader;
}
/**
* Get the current leader
* @return current leader
*/
public int getCurrentLeader() {
return currentLeader;
}
/**
* Retrieves the tuple for the specified round, given a list of tuples
* @param l List of tuples formed by a round number and the ID of the leader
* @param r Number of the round to be searched
* @return The tuple for the specified round, or null if there is none
*/
private ConsInfo findInfo(List<ConsInfo> l, int r) {
ConsInfo ret = null;
for (int i = 0; i < l.size(); i++) {
ret = l.get(i);
if (ret.round == r) {
return ret;
}
}
return null;
}
/**
* Invoked by the acceptor object when a value is decided
* It adds a new tuple to the list, which corresponds to the next consensus
*
* @param c ID of the consensus established as being decided
* @param l ID of the replica established as being the leader for the round 0 of the next consensus
*/
public void decided(int c, int l) {
if (leaderInfos.get(c) == null) {
addLeaderInfo(c + 1, 0, l);
}
}
/**
* Retrieves the replica ID of the leader for the specified consensus's execution ID and round number
* TODO: This is more than a getter. Should'nt we change that?
* @param c consensus's execution ID
* @param r Round number for the specified consensus
* @return The replica ID of the leader
*/
public int getLeader(int c, int r) {
/***/
List<ConsInfo> list = leaderInfos.get(c);
if (list == null) {
//there are no information for the execution c
//let's see who were the leader of the next execution
list = new LinkedList<ConsInfo>();
leaderInfos.put(c, list);
List<ConsInfo> before = leaderInfos.get(c - 1);
if (before != null && before.size() > 0) {
//the leader for this round will be the leader of
ConsInfo ci = before.get(before.size() - 1);
list.add(new ConsInfo(r, ci.leaderId));
return ci.leaderId;
}
} else {
for (int i = 0; i < list.size(); i++) {
ConsInfo ci = list.get(i);
if (ci.round == r) {
return ci.leaderId;
}
}
}
return -1;
/***/
//return 0;
}
/** THIS IS JOAO'S CODE, FOR HANDLING STATE TRANSFER */
private ReentrantLock leaderInfosLock = new ReentrantLock();
public void removeStableConsenusInfos(int c) {
leaderInfosLock.lock();
leaderInfos.remove(c);
leaderInfosLock.unlock();
}
public void removeStableMultipleConsenusInfos(int cStart, int cEnd) {
leaderInfosLock.lock();
List<ConsInfo> list = leaderInfos.get(cEnd + 1);
if (list == null) {//this will never happen!!!
list = new LinkedList<ConsInfo>();
leaderInfos.put(cEnd + 1, list);
List<ConsInfo> rm = leaderInfos.get(cEnd);
if (rm != null) {
ConsInfo ci = (ConsInfo) rm.get(rm.size() - 1);
list.add(new ConsInfo(0, ci.leaderId));
}
}
for (int c = cStart; c <= cEnd; c++) {
leaderInfos.remove(c);
}
leaderInfosLock.unlock();
}
/********************************************************/
/**
* This class represents a tuple formed by a round number and the replica ID of that round's leader
*/
private class ConsInfo {
public int round;
public int leaderId;
public ConsInfo(int r, int l) {
this.round = r;
this.leaderId = l;
}
}
}