package ch.usi.da.paxos.old;
/*
* 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.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import ch.usi.da.paxos.storage.Decision;
/**
* Name: LearnerWriter<br>
* Description: <br>
*
* Creation date: Apr 9, 2012<br>
* $Id$
*
* @author Samuel Benz benz@geoid.ch
*/
public class LearnerWriter implements Runnable {
private final Learner learner;
private final LinkedList<Decision> list = new LinkedList<Decision>();
private AtomicLong next_instance = new AtomicLong(1);
private AtomicLong max_seen_instance = new AtomicLong(0);
private Set<Long> requested = new HashSet<Long>();
private Set<String> delivered = new HashSet<String>(1000);
/**
* Public constructor
*
* @param learner
*/
public LearnerWriter(Learner learner){
this.learner = learner;
}
@Override
public void run() {
int break_counter = 0;
while(true){
// fill list (sorted)
try {
Decision d = learner.getDecisions().poll(1,TimeUnit.SECONDS);
if(d != null){
if(requested.contains(d.getInstance())){
requested.remove(d.getInstance());
}
if(d.getInstance().longValue() > max_seen_instance.get()){
max_seen_instance.set(d.getInstance().longValue());
}
if(d.getInstance() == next_instance.get()){
list.add(d);
next_instance.incrementAndGet();
}else{
int pos = findPos(d.getInstance());
if(pos >= 0){
list.add(pos,d);
if(pos == list.size()-1){
next_instance.set(d.getInstance().longValue()+1);
}
}
}
}
} catch (InterruptedException e) {
}
// request missing
if((max_seen_instance.get() - learner.getInstance().get()) > 20){
long first = max_seen_instance.get();
int max = 10;
if(!list.isEmpty()){
first = list.get(0).getInstance().longValue();
}
int n = 0;
for(long i = learner.getInstance().get();i<first;i++){
if(!requested.contains(new Long(i))){
requested.add(new Long(i));
learner.getRequests().add(new Long(i));
n++;
if(n > max){ break; };
}
}
}
if(break_counter > 2){
requested.remove(learner.getInstance().get());
break_counter = 0;
}
// read list
Iterator<Decision> i = list.iterator();
while(i.hasNext()){
Decision d = i.next();
if(d.getInstance().longValue() == learner.getInstance().get()){
i.remove();
learner.getInstance().incrementAndGet();
//System.out.println(d);
if(d.getValue() != null && d.getValue().getValue().length>0){
if(!delivered.contains(d.getValue().getID())){
System.out.println(new String(d.getValue().getValue()));
delivered.add(d.getValue().getID());
}
}
}else if (d.getInstance().longValue() < learner.getInstance().get()){
i.remove(); // duplicate
}else{
break_counter++;
//System.err.println("queue:" + d.getInstance().longValue() + " server:" + learner.getInstance().get() + " break:" + break_counter);
break; // since the list is sorted
}
}
}
}
private int findPos(Long instance) {
int pos = 0;
Iterator<Decision> i = list.iterator();
// ok, this would be possible in log(n) and not n ...
while(i.hasNext()){
Decision d = i.next();
if(instance == d.getInstance().longValue()){
return -1;
}else if(instance < d.getInstance().longValue()){
return pos;
}
pos++;
}
return pos;
}
}