URingPaxos-master/src/java/ch/usi/da/paxos/old/LearnerWriter.java
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;
	}

}
