package ch.usi.da.paxos.ring;
/*
* Copyright (c) 2013 Università della Svizzera italiana (USI)
*
* This file is part of URingPaxos.
*
* URingPaxos 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.
*
* URingPaxos 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 URingPaxos. If not, see <http://www.gnu.org/licenses/>.
*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import org.apache.log4j.Logger;
import ch.usi.da.paxos.api.ConfigKey;
import ch.usi.da.paxos.api.Learner;
import ch.usi.da.paxos.api.PaxosRole;
import ch.usi.da.paxos.storage.Decision;
/**
* Name: MultiLearnerRole<br>
* Description: <br>
*
* Deprecated: use ElasticLearnerRole
* Just here to make the code downward compatible!
*
* Creation date: Mar 04, 2013<br>
* $Id$
*
* @author Samuel Benz benz@geoid.ch
*/
@Deprecated
public class MultiLearnerRole extends Role implements Learner {
private final static Logger logger = Logger.getLogger(MultiLearnerRole.class);
private final Map<Integer,RingDescription> ringmap = new HashMap<Integer,RingDescription>();
private final List<Integer> ring = new ArrayList<Integer>();
private final int maxRing = 20;
private final BlockingQueue<Decision> values = new LinkedBlockingQueue<Decision>();
private final LearnerRole[] learner = new LearnerRole[maxRing];
private int M = 1;
private int deliverRing;
private final long[] skip_count = new long[maxRing];
private boolean deliver_skip_messages = false;
/**
* @param rings a list of rings
*/
@Deprecated
public MultiLearnerRole(List<RingDescription> rings) {
int minRing = maxRing+1;
for(RingDescription ring : rings){
if(ring.getRingID() < minRing){
minRing = ring.getRingID();
}
this.ring.add(ring.getRingID());
this.ringmap.put(ring.getRingID(),ring);
}
Collections.sort(ring);
RingManager firstRing = rings.get(0).getRingManager();
deliverRing = minRing;
logger.debug("MultiRingLearner initial deliverRing=" + deliverRing);
if(firstRing.getConfiguration().containsKey(ConfigKey.deliver_skip_messages)){
if(firstRing.getConfiguration().get(ConfigKey.deliver_skip_messages).contains("1")){
deliver_skip_messages = true;
}
logger.info("MultiRingLearner deliver_skip_messages: " + (deliver_skip_messages ? "enabled" : "disabled"));
}
}
@Override
public void run() {
for(Entry<Integer,RingDescription> e : ringmap.entrySet()){
// create learners
RingManager ring = e.getValue().getRingManager();
Role r = new LearnerRole(ring);
learner[e.getKey()] = (LearnerRole) r;
logger.debug("MultiRingLeaner register role: " + PaxosRole.Learner + " at node " + ring.getNodeID() + " in ring " + ring.getRingID());
ring.registerRole(PaxosRole.Learner);
Thread t = new Thread(r);
t.setName(PaxosRole.Learner + "-" + e.getKey());
t.start();
skip_count[e.getKey()] = 0;
}
int count = 0;
while(true){
try{
if(skip_count[deliverRing] > 0){
count++;
skip_count[deliverRing]--;
//logger.debug("MultiRingLearner " + ringmap.get(deliverRing).getNodeID() + " ring " + deliverRing + " skiped a value (" + skip_count[deliverRing] + " skips left)");
}else{
Decision d = learner[deliverRing].getDecisions().take();
if(d.getValue() != null && d.getValue().isSkip()){
// skip message
try {
long skip = Long.parseLong(new String(d.getValue().getValue()));
skip_count[deliverRing] = skip_count[deliverRing] + skip;
}catch (NumberFormatException e) {
logger.error("MultiRingLearner received incomplete SKIP message! -> " + d,e);
}
if(deliver_skip_messages){
values.add(d);
}
}else{
count++;
// learning an actual proposed value
values.add(d);
}
}
if(count >= M){
count = 0;
deliverRing = getRingSuccessor(deliverRing);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}
private int getRingSuccessor(int id){
int pos = ring.indexOf(new Integer(id));
if(pos+1 >= ring.size()){
return ring.get(0);
}else{
return ring.get(pos+1);
}
}
@Override
public BlockingQueue<Decision> getDecisions() {
return values;
}
public void setSafeInstance(Integer ring, Long instance) {
learner[ring].setSafeInstance(ring,instance);
}
}