package edu.harvard.mcb.leschziner.event;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Vector;
import com.hazelcast.core.ItemEvent;
import com.hazelcast.core.ItemListener;
import edu.harvard.mcb.leschziner.distributed.DistributedTaskHandler;
/**
* Represents a point in a pipeline's progression, as measured by the posting of
* specific events in particular numbers
*
* @author spartango
*
*/
public class Checkpoint implements ItemListener<ProcessingEvent> {
protected long completions;
protected long expectedCompletions;
protected long totalOutput;
protected long totalRuntime;
protected final Collection<ErrorEvent> errors;
protected final Collection<Checkpoint> dependents;
protected BufferedQueue<ProcessingEvent> eventQueue;
protected boolean reached;
public Checkpoint() {
expectedCompletions = 0;
totalRuntime = 0;
completions = 0;
totalOutput = 0;
dependents = new Vector<>();
errors = new LinkedList<>();
reached = false;
}
public long getExpectedCompletions() {
return expectedCompletions;
}
public void setExpectedCompletions(long expectedCompletions) {
this.expectedCompletions = expectedCompletions;
checkReached();
}
public long getCompletions() {
return completions;
}
public long getTotalRuntime() {
return totalRuntime;
}
public Collection<ErrorEvent> getErrors() {
return errors;
}
public Collection<Checkpoint> getDependents() {
return dependents;
}
public void addDependent(Checkpoint c) {
dependents.add(c);
}
public void removeDependent(Checkpoint c) {
dependents.remove(c);
}
public double getProgress() {
if (expectedCompletions > 0) {
return (double) (completions) / expectedCompletions;
} else {
return 0;
}
}
public double getCompletionRate() {
if (totalRuntime > 0)
return 1000.0 * completions / totalRuntime;
else
return 0;
}
public int getErrorCount() {
return errors.size();
}
public void setEventSource(DistributedTaskHandler source) {
this.eventQueue = source.getEventQueue();
source.getEventQueue().addItemListener(this, true);
}
@Override public void itemAdded(ItemEvent<ProcessingEvent> e) {
ProcessingEvent event = eventQueue.poll();
if (event == null) {
return;
}
if (event instanceof CompletionEvent) {
CompletionEvent completeEvent = ((CompletionEvent) event);
completions++;
totalRuntime += completeEvent.getRunTime();
totalOutput += completeEvent.getOutputCount();
checkReached();
} else if (event instanceof ErrorEvent) {
// Save this event
errors.add((ErrorEvent) event);
}
}
@Override public void itemRemoved(ItemEvent<ProcessingEvent> e) {
// Not all that interested to know when items are removed
}
public void onReached() {
reached = true;
System.out.println("["
+ this
+ "]: Reached Checkpoint, producing "
+ completions
+ " / "
+ expectedCompletions
+ " at "
+ getCompletionRate()
+ "/ms with "
+ getErrorCount()
+ " errors");
setDependentExpectations(totalOutput);
}
protected void setDependentExpectations(long output) {
for (Checkpoint dependent : dependents) {
dependent.setExpectedCompletions(output);
}
}
public long getTotalOutput() {
return totalOutput;
}
public BufferedQueue<ProcessingEvent> getEventQueue() {
return eventQueue;
}
public boolean isReached() {
return reached;
}
protected boolean checkConditions() {
return !reached
&& expectedCompletions != 0
&& completions >= expectedCompletions;
}
private synchronized void checkReached() {
if (checkConditions()) {
onReached();
}
}
}