package edu.usc.enl.dynamicmeasurement.algorithms.tasks.hhh.flow.overlappingsingleswitch; 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 org.w3c.dom.Element; import java.util.*; /** * Created with IntelliJ IDEA. * User: Masoud * Date: 1/28/13 * Time: 1:42 PM <br/> * A single switch TCAM divide & merge algorithm that can handle overlapping monitored prefixes. * The general algorithm works like this: * pick the maximum node to divide * pick the two nodes with minimum total weight to merge. Merge them to their common ancestor. * This algorithm is only implemented to test this idea and does not work in the resource allocator framework */ public class OverlappingSingleSwitch extends FlowHHHAlgorithm implements SingleSwitchTask.SingleSwitchTaskImplementation { private TreeMap<WildcardPattern, OverlappingWildcardPattern> monitors; private TreeMap<WildcardPattern, WildcardPattern> weights; public OverlappingSingleSwitch(Element element) { super(element); int capacity = 1024;//Util.getNetwork().getFirstMonitorPoints().getCapacity(); monitors = new TreeMap<>(WildcardPattern.WILDCARDNUM_COMPARATOR); weights = new TreeMap<>(WildcardPattern.WEIGHT_COMPARATOR); int unusedCapacity; int startLevel = (int) (Math.log(capacity) / Math.log(2)); if (startLevel < taskWildcardPattern.getWildcardNum()) { unusedCapacity = capacity - (1 << startLevel); } else { startLevel = taskWildcardPattern.getWildcardNum(); unusedCapacity = 0; } // int unusedCapacity = capacity - (1 << startLevel); int preliminaryLevel = taskWildcardPattern.getWildcardNum() - startLevel; long baseData = taskWildcardPattern.getData() << startLevel; for (int i = 0; i < 1 << startLevel; i++) { WildcardPattern wildcardPattern = new WildcardPattern(baseData + i, preliminaryLevel, 0); monitors.put(wildcardPattern, new OverlappingWildcardPattern(wildcardPattern)); } // System.out.println(monitors.firstKey().getCommonParent2(monitors.lastKey())); for (int i = 0; i < unusedCapacity; i++) { monitors.firstEntry().getValue().breakNode(); } } @Override public Collection<WildcardPattern> getMonitors() { return monitors.keySet(); } @Override public void update() { // printMonitors(); weights.clear(); for (WildcardPattern wildcardPattern : monitors.keySet()) { weights.put(wildcardPattern, wildcardPattern); } //give weight to orphans for (OverlappingWildcardPattern overlappingWildcardPattern : monitors.values()) { overlappingWildcardPattern.giveOrphansShare(); } WildcardPattern[] maxMins = new WildcardPattern[3]; boolean canUpdate = true; int step = 0; while (canUpdate) { canUpdate = findMaxAndTwoMin(maxMins); if (canUpdate) { commitMins(maxMins); } // printMonitors(); displayHook(null, step++); } } @Override public void setCapacityShare(int resource) { } @Override public double estimateAccuracy() { return 1; } @Override public int getUsedResourceShare() { return monitors.size(); } /* private boolean findMaxAndTwoMin2(WildcardPattern[] toFill) { WildcardPattern first = null; WildcardPattern second = null; WildcardPattern max = null; for (WildcardPattern wildcardPattern : monitors.keySet()) { if (wildcardPattern.canGoUp()) { if (first == null || wildcardPattern.getWeight() < first.getWeight()) { second = first; first = wildcardPattern; } else { if (second == null || wildcardPattern.getWeight() < second.getWeight()) { second = wildcardPattern; } } } if (max == null || wildcardPattern.getWeight() > max.getWeight()) { max = wildcardPattern; } } toFill[0] = first; toFill[1] = second; toFill[2] = max; return !(max == null || first == null || second == null || max.getWeight() < first.getWeight() + second.getWeight()); }*/ private boolean findMaxAndTwoMin(WildcardPattern[] toFill) { if (weights.size() != monitors.size()) { System.out.println(); } WildcardPattern first = null; WildcardPattern second = null; double minWeight = -1; WildcardPattern max = null; do { if (max == null) { max = weights.firstKey(); } else { max = weights.lowerKey(max); } } while (max != null && !max.canGoDown()); // System.out.println("++++++++++++++++"); // for (WildcardPattern wildcardPattern : weights.keySet()) { // System.out.println(wildcardPattern); // } // TreeMap<WildcardPattern, WildcardPattern> a = new TreeMap<>(new WildcardPattern.WeightComparator()); // a.putAll(weights); // System.out.println("-------------------"); if (max != null) { WildcardPattern[] newNodes = commitMax(max); for (WildcardPattern min : weights.descendingKeySet()) { if (min.equals(newNodes[0]) || min.equals(newNodes[1])) { continue; } for (WildcardPattern larger : weights.descendingMap().tailMap(min, false).keySet()) { if (larger.equals(newNodes[0]) || larger.equals(newNodes[1])) { continue; } //check end condition if (min.getWeight() + larger.getWeight() >= max.getWeight()) { //this min object is useless to check more break; } //check if larger can be paired with min double newNodeWeight = canPair(min, larger); if (newNodeWeight >= 0) { //now check with current first and second if ((first == null && newNodeWeight < max.getWeight()) || minWeight > newNodeWeight) { first = min; second = larger; minWeight = newNodeWeight; } break; } } } if (first == null) { commitMins(newNodes); } } toFill[0] = first; toFill[1] = second; toFill[2] = max; return max != null && first != null; } private double canPair(WildcardPattern min0, WildcardPattern min1) { WildcardPattern commonParent = min0.getCommonParent(min1); if (commonParent.equals(min0)) { if (getAncestor(min1).equals(commonParent)) { //is it nearest return min0.getWeight() + min1.getWeight(); } return -1; } else if (commonParent.equals(min1)) { try { if (getAncestor(min0).equals(commonParent)) {//is it nearest return min0.getWeight() + min1.getWeight(); } } catch (Exception e) { e.printStackTrace(); } return -1; } else { boolean okFor0; boolean okFor1; WildcardPattern ancestor0 = getAncestor(min0); WildcardPattern ancestor1 = getAncestor(min1); if (ancestor0 == null || (ancestor0.match(commonParent) && !ancestor0.equals(commonParent))) { //is null or above commonparent okFor0 = true; } else { okFor0 = ancestor0.equals(commonParent); } if (ancestor1 == null || (ancestor1.match(commonParent) && !ancestor1.equals(commonParent))) { //is null or above commonparent okFor1 = true; } else { okFor1 = ancestor1.equals(commonParent); } if (okFor0 && okFor1) { //get orphans from ancestor double weight = min0.getWeight() + min1.getWeight(); WildcardPattern ancestor = getAncestor(commonParent); if (ancestor != null) { OverlappingWildcardPattern ancestorOverlappingWildcardPattern = monitors.get(ancestor); if (ancestorOverlappingWildcardPattern.representsOrphans()) { weight += ancestorOverlappingWildcardPattern.getOrphanWildcardPatterns(commonParent, new ArrayList<WildcardPattern>()); } else { throw new RuntimeException("Ancestor without orphans! " + ancestor); } } return weight; } else { return -1; } } } private WildcardPattern[] commitMax(WildcardPattern max) { return monitors.get(max).breakNode(); } private void addMonitor(WildcardPattern w, OverlappingWildcardPattern o) { monitors.put(w, o); weights.put(w, w); } private void removeMonitor(WildcardPattern w) { monitors.remove(w); weights.remove(w); } private void commitMins(WildcardPattern[] mins) { WildcardPattern commonParent = mins[0].getCommonParent(mins[1]); WildcardPattern ancestor0 = null; WildcardPattern ancestor1 = null; boolean goToAncestor0 = false; boolean goToAncestor1 = false; if (commonParent.equals(mins[0])) { ancestor1 = getAncestor(mins[1]); goToAncestor1 = true; } else if (commonParent.equals(mins[1])) { ancestor0 = getAncestor(mins[0]); goToAncestor0 = true; } else { ancestor0 = getAncestor(mins[0]); ancestor1 = getAncestor(mins[1]); if (ancestor0 == null || (ancestor0.match(commonParent) && !ancestor0.equals(commonParent))) { //is null or above commonparent goToAncestor0 = false; } else { goToAncestor0 = !ancestor0.equals(commonParent); } if (ancestor1 == null || (ancestor1.match(commonParent) && !ancestor1.equals(commonParent))) { //is null or above commonparent goToAncestor1 = false; } else { goToAncestor1 = !ancestor1.equals(commonParent); } } if (goToAncestor0 && goToAncestor1) { // check which has min sum if (mins[0].getWeight() + ancestor0.getWeight() > mins[1].getWeight() + ancestor1.getWeight()) { gotoAncestor(mins[1], ancestor0); } else { //if equal mins[0] was smaller gotoAncestor(mins[0], ancestor0); } } else if (goToAncestor0) { gotoAncestor(mins[0], ancestor0); } else if (goToAncestor1) { gotoAncestor(mins[1], ancestor1); } else { commonParent.setWeight(mins[0].getWeight() + mins[1].getWeight()); OverlappingWildcardPattern commonParentOverlappingWildcardPattern = monitors.get(commonParent); if (commonParentOverlappingWildcardPattern != null) { //must divide the common parent //in the first step left and right are not full so give each a token commonParentOverlappingWildcardPattern.add(monitors.get(mins[0])); commonParentOverlappingWildcardPattern.add(monitors.get(mins[1])); commonParentOverlappingWildcardPattern.addWeight(commonParent.getWeight()); commonParentOverlappingWildcardPattern.breakNode(); } else { commonParentOverlappingWildcardPattern = new OverlappingWildcardPattern(commonParent); //common parent must be the monitor //but need to track orphans. // 1) query nearest ancestor for orphans WildcardPattern ancestor = getAncestor(commonParent); // 2) if there is ancestor if (ancestor != null) { //3) if there is any orphan under me OverlappingWildcardPattern ancestorOverlappingWildcardPattern = monitors.get(ancestor); if (ancestorOverlappingWildcardPattern.representsOrphans()) { ArrayList<WildcardPattern> orphans = new ArrayList<>(); ancestorOverlappingWildcardPattern.getOrphanWildcardPatterns(commonParent, orphans); if (orphans.size() > 0) { double weight = ancestorOverlappingWildcardPattern.removeOrphanWildcardPatterns(orphans); commonParent.setWeight(commonParent.getWeight() + weight); commonParentOverlappingWildcardPattern.addOrphans(orphans); addMonitor(mins, commonParent, commonParentOverlappingWildcardPattern); try { ancestorOverlappingWildcardPattern.reArrange(); } catch (WildcardPattern.InvalidWildCardValue invalidWildCardValue) { System.out.println("Ancestor cannot go down!"); invalidWildCardValue.printStackTrace(); } } else { //OK no orphan under me from ancestor but these two may be orphan or has orphans addMonitor(mins, commonParent, commonParentOverlappingWildcardPattern); } } else { throw new RuntimeException("Ancestor without orphans! " + ancestor); } } else { //no ancestor. No orphans //OK no orphan under me from ancestor but these two may be orphan or has orphans addMonitor(mins, commonParent, commonParentOverlappingWildcardPattern); } } removeMonitor(mins[0]); removeMonitor(mins[1]); } } private void gotoAncestor(WildcardPattern min, WildcardPattern ancestor0) { OverlappingWildcardPattern ancestor0OverlappingWildcardPattern = monitors.get(ancestor0); ancestor0OverlappingWildcardPattern.add(monitors.get(min)); ancestor0OverlappingWildcardPattern.addWeight(min.getWeight()); removeMonitor(min); } private void addMonitor(WildcardPattern[] mins, WildcardPattern commonParent, OverlappingWildcardPattern commonParentOverlappingWildcardPattern) { OverlappingWildcardPattern min0 = monitors.get(mins[0]); OverlappingWildcardPattern min1 = monitors.get(mins[1]); if (!min0.representsOrphans() && !min1.representsOrphans() && commonParent.isChild(mins[0]) && commonParent.isChild((mins[1]))) { // I will be just a leaf so no orphan is necessary } else { commonParentOverlappingWildcardPattern.add(min0); commonParentOverlappingWildcardPattern.add(min1); } addMonitor(commonParent, commonParentOverlappingWildcardPattern); } private WildcardPattern getAncestor(WildcardPattern commonParent) { WildcardPattern ancestor = null; commonParent = commonParent.clone().goUp(); for (WildcardPattern wildcardPattern : monitors.descendingKeySet()) {//TOP TO BOTTOM if (wildcardPattern.getWildcardNum() < commonParent.getWildcardNum()) { break; } if (wildcardPattern.match(commonParent)) { //find lowest level ancester ancestor = wildcardPattern; } } return ancestor; } private class OverlappingWildcardPattern { private WildcardPattern wildcardPattern; private Set<WildcardPattern> orphanWildcardPatterns; private OverlappingWildcardPattern(WildcardPattern wildcardPattern) { this.wildcardPattern = wildcardPattern; } public void add(OverlappingWildcardPattern overlappingWildcardPattern) { if (orphanWildcardPatterns == null) { orphanWildcardPatterns = new HashSet<>(); } if (overlappingWildcardPattern.representsOrphans()) { orphanWildcardPatterns.addAll(overlappingWildcardPattern.getOrphanWildcardPatterns()); //would be nice if merge mergable orphans } else { orphanWildcardPatterns.add(overlappingWildcardPattern.wildcardPattern); //would be nice if merge mergable orphans } } public void addOrphan(WildcardPattern orphan) { if (orphanWildcardPatterns == null) { orphanWildcardPatterns = new HashSet<>(); } orphanWildcardPatterns.add(orphan);//would be nice if merge mergable orphans } public void addOrphans(Collection<WildcardPattern> orphans) { if (orphanWildcardPatterns == null) { orphanWildcardPatterns = new HashSet<>(); } orphanWildcardPatterns.addAll(orphans);//would be nice if merge mergable orphans } public Collection<WildcardPattern> getOrphanWildcardPatterns() { return orphanWildcardPatterns; } private double getOrphanWildcardPatterns(WildcardPattern toMatch, Collection<WildcardPattern> orphans) { return getOrphanWildcardPatterns(toMatch, orphans, orphanWildcardPatterns); } private double getOrphanWildcardPatterns(WildcardPattern toMatch, Collection<WildcardPattern> toFill, Collection<WildcardPattern> toSearchIn) { double weight = 0; for (WildcardPattern orphanWildcardPattern : toSearchIn) { if (toMatch.match(orphanWildcardPattern)) { toFill.add(orphanWildcardPattern); weight += orphanWildcardPattern.getWeight(); } } return weight; } private double removeOrphanWildcardPatterns(Collection<WildcardPattern> orphans) { double weight = 0; orphanWildcardPatterns.removeAll(orphans); for (WildcardPattern orphan : orphans) { orphanWildcardPatterns.remove(orphan); weight += orphan.getWeight(); } weights.remove(wildcardPattern); wildcardPattern.setWeight(wildcardPattern.getWeight() - weight); weights.put(wildcardPattern, wildcardPattern); return weight; } private boolean representsOrphans() { return orphanWildcardPatterns != null && orphanWildcardPatterns.size() > 0; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof OverlappingWildcardPattern)) return false; OverlappingWildcardPattern that = (OverlappingWildcardPattern) o; if (!wildcardPattern.equals(that.wildcardPattern)) return false; return true; } @Override public int hashCode() { return wildcardPattern.hashCode(); } @Override public String toString() { return "wildcardPattern=" + wildcardPattern + ", orphanWildcardPatterns=" + orphanWildcardPatterns + '}'; } /** * both left and right must have orphans */ private WildcardPattern[] breakNode() { WildcardPattern[] newNodes = new WildcardPattern[2]; try { removeMonitor(wildcardPattern); if (this.representsOrphans()) { //find common parent for right and left orphans Collection<WildcardPattern> tempOrphanWildcardPatterns = new ArrayList<>(this.getOrphanWildcardPatterns().size()); boolean addLeft = false; boolean addRight = false; { //left WildcardPattern left = wildcardPattern.clone().goDown(false); double leftWeight = this.getOrphanWildcardPatterns(left, tempOrphanWildcardPatterns); left = getCommonOrphansParent(tempOrphanWildcardPatterns); if (tempOrphanWildcardPatterns.size() > 0) { left.setWeight(leftWeight); OverlappingWildcardPattern value = new OverlappingWildcardPattern(left); if (tempOrphanWildcardPatterns.size() > 1) { value.addOrphans(tempOrphanWildcardPatterns); } addMonitor(left, value); addLeft = true; tempOrphanWildcardPatterns.clear(); newNodes[0] = left; } } { //right WildcardPattern right = wildcardPattern.clone().goDown(true); double rightWeight = this.getOrphanWildcardPatterns(right, tempOrphanWildcardPatterns); right = getCommonOrphansParent(tempOrphanWildcardPatterns); if (tempOrphanWildcardPatterns.size() > 0) { right.setWeight(rightWeight); OverlappingWildcardPattern value = new OverlappingWildcardPattern(right); if (tempOrphanWildcardPatterns.size() > 1) { value.addOrphans(tempOrphanWildcardPatterns); } addMonitor(right, value); addRight = true; newNodes[1] = right; } } if (!addLeft || !addRight) { throw new RuntimeException("No empty right or left" + this); } } else { // regular break WildcardPattern left = wildcardPattern.clone().goDown(false); left.setWeight(wildcardPattern.getWeight() / 2); addMonitor(left, new OverlappingWildcardPattern(left)); newNodes[0] = left; WildcardPattern right = wildcardPattern.clone().goDown(true); right.setWeight(wildcardPattern.getWeight() / 2); addMonitor(right, new OverlappingWildcardPattern(right)); newNodes[1] = right; } } catch (WildcardPattern.InvalidWildCardValue invalidWildCardValue) { invalidWildCardValue.printStackTrace(); } return newNodes; } public WildcardPattern getCommonOrphansParent(Collection<WildcardPattern> wildcardPatternsSet) { if (wildcardPatternsSet.size() == 0) { return null; } Iterator<WildcardPattern> itr = wildcardPatternsSet.iterator(); WildcardPattern output = itr.next().clone(); while (itr.hasNext()) { output = output.getCommonParent(itr.next()); } output.setWeight(0); return output; } public void reArrange() throws WildcardPattern.InvalidWildCardValue { //check to have orphans from both left and right Collection<WildcardPattern> leftOrphanWildcardPatterns = new ArrayList<>(this.getOrphanWildcardPatterns().size()); WildcardPattern left = wildcardPattern.clone().goDown(false); this.getOrphanWildcardPatterns(left, leftOrphanWildcardPatterns); boolean leftHasOrphans = leftOrphanWildcardPatterns.size() > 0; Collection<WildcardPattern> rightOrphanWildcardPatterns = new ArrayList<>(this.getOrphanWildcardPatterns().size()); WildcardPattern right = wildcardPattern.clone().goDown(true); this.getOrphanWildcardPatterns(right, rightOrphanWildcardPatterns); boolean rightHasOrphans = rightOrphanWildcardPatterns.size() > 0; if (leftHasOrphans && rightHasOrphans) { //stay } else if (!leftHasOrphans && !rightHasOrphans) { throw new RuntimeException("reArrange " + this + " no orphans in right or left"); } else if (!leftHasOrphans) { //go to right which has orphans. right cannot be in monitors handToChild(rightOrphanWildcardPatterns); } else { //go to left handToChild(leftOrphanWildcardPatterns); } } private void handToChild(Collection<WildcardPattern> childOrphanWildcardPatterns) { WildcardPattern child; child = getCommonOrphansParent(childOrphanWildcardPatterns); removeMonitor(wildcardPattern); OverlappingWildcardPattern value = new OverlappingWildcardPattern(child); if (childOrphanWildcardPatterns.size() > 1) {//this is not a leaf value.addOrphans(childOrphanWildcardPatterns); } child.setWeight(wildcardPattern.getWeight()); //it cannot be there otherwise I did not have those orphans if (monitors.containsKey(child)) { throw new RuntimeException("Child should not be in monitors " + child); } addMonitor(child, value); } public void addWeight(double weight) { weights.remove(wildcardPattern); wildcardPattern.setWeight(wildcardPattern.getWeight() + weight); weights.put(wildcardPattern, wildcardPattern); } public void giveOrphansShare() { if (representsOrphans()) { try { if (orphanWildcardPatterns.contains(wildcardPattern)) { throw new RuntimeException("I am my orphan!" + this); } WildcardPattern mergedOrphan = giveOrphansShare(wildcardPattern, orphanWildcardPatterns, wildcardPattern.getWeight()); if (mergedOrphan != null && mergedOrphan.equals(wildcardPattern)) { orphanWildcardPatterns.clear(); } } catch (WildcardPattern.InvalidWildCardValue invalidWildCardValue) { invalidWildCardValue.printStackTrace(); } } } private WildcardPattern giveOrphansShare(WildcardPattern toMatch, Collection<WildcardPattern> consideringOrphans, double share) throws WildcardPattern.InvalidWildCardValue { if (consideringOrphans.size() == 1) { //if it is leaf so at most it has one orphan //give all to this WildcardPattern onlyOrphan = consideringOrphans.iterator().next(); onlyOrphan.setWeight(share); return onlyOrphan; } if (consideringOrphans.size() == 2) { //check for merge Iterator<WildcardPattern> iterator = consideringOrphans.iterator(); WildcardPattern first = iterator.next(); WildcardPattern second = iterator.next(); if (first.isSibling(second)) { return mergeOrphans(toMatch, share, first, second); } } ArrayList<WildcardPattern> leftOrphans = new ArrayList<>(); WildcardPattern left = toMatch.clone().goDown(false); getOrphanWildcardPatterns(left, leftOrphans, consideringOrphans); ArrayList<WildcardPattern> rightOrphans = new ArrayList<>(); WildcardPattern right = toMatch.clone().goDown(true); getOrphanWildcardPatterns(right, rightOrphans, consideringOrphans); if (leftOrphans.size() > 0 && rightOrphans.size() > 0) { //devide share by 2 WildcardPattern mergedLeft = giveOrphansShare(left, leftOrphans, share / 2); WildcardPattern mergedRight = giveOrphansShare(right, rightOrphans, share / 2); if (mergedLeft != null && mergedRight != null && mergedLeft.isSibling(mergedRight)) { return mergeOrphans(toMatch, share, mergedLeft, mergedRight); } return null; } else if (leftOrphans.size() > 0) { //run for left return giveOrphansShare(left, leftOrphans, share); } else { //run for left return giveOrphansShare(right, rightOrphans, share); } } private WildcardPattern mergeOrphans(WildcardPattern toMatch, double share, WildcardPattern first, WildcardPattern second) { orphanWildcardPatterns.remove(first); orphanWildcardPatterns.remove(second); WildcardPattern parent = first.goUp(); orphanWildcardPatterns.add(parent); parent.setWeight(share); return parent; } } }