package edu.usc.enl.dynamicmeasurement.algorithms.tasks.hhh.flow.hhfringe;
import edu.usc.enl.dynamicmeasurement.algorithms.tasks.hhh.NeedInitHHHAlgorithm;
import edu.usc.enl.dynamicmeasurement.algorithms.tasks.hhh.flow.FlowHHHAlgorithm;
import edu.usc.enl.dynamicmeasurement.algorithms.tasks.multitask.singleswitch.SingleSwitchTask;
import edu.usc.enl.dynamicmeasurement.model.WildcardPattern;
import edu.usc.enl.dynamicmeasurement.util.Util;
import org.w3c.dom.Element;
import java.util.Collection;
import java.util.LinkedList;
import java.util.TreeMap;
/**
* Created with IntelliJ IDEA.
* User: masoud
* Date: 2/25/13
* Time: 9:11 AM <br/>
* The TCAM based HHH detection algorithm on a single switch that tries to maximize the total weight of nodes
* only at the fringe of monitored prefix tree (monitored prefixes). <br/>
* Note that this algorithm is only to test ideas and does not respect resource allocation or estimate accuracy yet
*/
public class HHFringe extends FlowHHHAlgorithm implements NeedInitHHHAlgorithm, SingleSwitchTask.SingleSwitchTaskImplementation {
private final TreeMap<WildcardPattern, WildcardPattern> monitors;
public HHFringe(Element element) {
super(element);
int capacity = Util.getNetwork().getFirstMonitorPoints().getCapacity();
monitors = new TreeMap<>(WildcardPattern.WILDCARDNUM_COMPARATOR);
initMonitors(capacity, this, taskWildcardPattern);
}
@Override
public Collection<WildcardPattern> getMonitors() {
return monitors.keySet();
}
@Override
public void finish() {
super.finish();
}
@Override
public void setCapacityShare(int resource) {
}
@Override
public double estimateAccuracy() {
return 1;
}
@Override
public int getUsedResourceShare() {
return monitors.size();
}
@Override
public void update() {
//assumes a tree that covers all leaves
LinkedList<WildcardPattern> waitingLeftsStack = new LinkedList<>();
LinkedList<WildcardPattern> toProcess = new LinkedList<>(monitors.keySet());
while (toProcess.size() > 0) {
WildcardPattern wildcardPattern = toProcess.pop();
if (wildcardPattern.getWeight() > threshold) {
if (wildcardPattern.canGoDown()) {
//go down
monitors.remove(wildcardPattern);
try {
WildcardPattern left = wildcardPattern.clone().goDown(false);
WildcardPattern right = wildcardPattern.clone().goDown(true);
left.setWeight(wildcardPattern.getWeight() / 2);
right.setWeight(wildcardPattern.getWeight() / 2);
monitors.put(left, left);
monitors.put(right, right);
toProcess.push(left);
toProcess.push(right);
} catch (WildcardPattern.InvalidWildCardValue invalidWildCardValue) {
invalidWildCardValue.printStackTrace();
}
}
} else {
//candidate for going up
if (wildcardPattern.canGoUp()) {
if (wildcardPattern.isLeft()) {
waitingLeftsStack.push(wildcardPattern);
} else {
WildcardPattern left = null;
if (waitingLeftsStack.size() > 0) {
left = waitingLeftsStack.pop();
if (!left.isSibling(wildcardPattern)) {
waitingLeftsStack.push(left);
left = null;
}
}
if (left != null) {
//merge
double parentWeight = wildcardPattern.getWeight() + left.getWeight();
if (parentWeight <= threshold) {
monitors.remove(wildcardPattern);
monitors.remove(left);
WildcardPattern parent = wildcardPattern.goUp();
parent.setWeight(parentWeight);
monitors.put(parent, parent);
toProcess.push(parent);
}
}
}
}
}
}
}
@Override
public void addMonitor(WildcardPattern wildcardPattern) {
monitors.put(wildcardPattern, wildcardPattern);
}
@Override
public WildcardPattern pollAMonitor() {
return monitors.pollLastEntry().getKey();
}
}