/******************************************************************************* * Copyright (c) 2013 Imperial College London. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Raul Castro Fernandez - initial design and implementation * Martin Rouaux - Added methods to collapse replicas ******************************************************************************/ package uk.ac.imperial.lsds.seep.comm.routing; import java.io.Serializable; import java.util.ArrayList; public class StatefulRoutingImpl implements RoutingStrategyI, Serializable{ private static final long serialVersionUID = 1L; //These structures store the information for doing consistent hashing //downstreamNodeKeys stores the keys (within the INTEGER space of keys) where each node lies private ArrayList<Integer> downstreamNodeKeys = null; private ArrayList<Integer> keyToDownstreamRealIndex = null; public ArrayList<Integer> getDownstreamNodeKeys() { return downstreamNodeKeys; } public void setDownstreamNodeKeys(ArrayList<Integer> downstreamNodeKeys) { this.downstreamNodeKeys = downstreamNodeKeys; } public ArrayList<Integer> getKeyToDownstreamRealIndex() { return keyToDownstreamRealIndex; } // public void setKeyToDownstreamRealIndex(ArrayList<Integer> keyToDownstreamRealIndex) { // this.keyToDownstreamRealIndex = keyToDownstreamRealIndex; // } public StatefulRoutingImpl(ArrayList<Integer> keyToDownstreamRealIndex, ArrayList<Integer> downstreamNodeKeys){ this.keyToDownstreamRealIndex = keyToDownstreamRealIndex; this.downstreamNodeKeys = downstreamNodeKeys; } public StatefulRoutingImpl(int realIndex){ //Initialize structures to do consistent hashing downstreamNodeKeys = new ArrayList<Integer>(); keyToDownstreamRealIndex = new ArrayList<Integer>(); //For every downstream of the same type, save in a virtual index, the real index of that downstream boolean notExists = true; for(int i = 0; i<keyToDownstreamRealIndex.size(); i++){ if(keyToDownstreamRealIndex.get(i) == realIndex){ notExists = false; } } if(notExists){ keyToDownstreamRealIndex.add(realIndex); } //Compute the key and add it in the structure int key = Integer.MAX_VALUE; downstreamNodeKeys.add(key); } public int[] newReplica(int oldOpIndex, int newOpIndex) { //map real index to virtual index /** int oldVirtualIndex = reverseMap(oldOpIndex); */ int oldVirtualIndex = keyToDownstreamRealIndex.indexOf(oldOpIndex); //store newOpIndex as a virtualIndex /** virtualIndexToRealIndex.put(virtualIndex, newOpIndex); */ //System.out.println("OLD_VIRTUAL_INDEX: "+oldVirtualIndex); //. decide where to split key space int key = downstreamNodeKeys.get(oldVirtualIndex); //previous key is the min value if there was just one operator or the key of the previous operator to oldOpIndex int previousKey = oldVirtualIndex == 0 ? Integer.MIN_VALUE : downstreamNodeKeys.get(oldVirtualIndex-1); //the new key is the medium point between key and previous key long maxInteger = Integer.MAX_VALUE; // long difference = (key == Integer.MAX_VALUE && previousKey == Integer.MIN_VALUE) ? (maxInteger-Integer.MIN_VALUE) : (key-previousKey); int minBound; int maxBound; long difference; if(key == Integer.MAX_VALUE && previousKey == Integer.MIN_VALUE){ minBound = Integer.MIN_VALUE; maxBound = (int)maxInteger; difference = (maxInteger-Integer.MIN_VALUE); } else{ minBound = previousKey; maxBound = key; difference = (key-previousKey); } // long difference = maxBound-minBound; difference = (difference < 0) ? (difference * -1) : difference; long aux = key - (difference/2); int newKey = (int)aux; //System.out.println("KEY: "+key+" PREV_KEY: "+previousKey+" DIF: "+difference+" AUX: "+aux+" NEW_KEY: "+newKey); // install the new key and operator for dispatching, from this moment new tuples are buffered on // store in oldOpIndex, the value of newOpIndex, (so insert by the left) //explain +1 keyToDownstreamRealIndex.add(oldVirtualIndex+1, newOpIndex); downstreamNodeKeys.add(oldVirtualIndex, newKey); int[] bounds = {minBound, maxBound}; return bounds; } public int[] newStaticReplica(int oldOpIndex, int newOpIndex) { //map real index to virtual index /** int oldVirtualIndex = reverseMap(oldOpIndex); */ int oldVirtualIndex = keyToDownstreamRealIndex.indexOf(oldOpIndex); //store newOpIndex as a virtualIndex /** virtualIndexToRealIndex.put(virtualIndex, newOpIndex); */ //System.out.println("OLD_VIRTUAL_INDEX: "+oldVirtualIndex); //. decide where to split key space int key = downstreamNodeKeys.get(oldVirtualIndex); //previous key is the min value if there was just one operator or the key of the previous operator to oldOpIndex int previousKey = oldVirtualIndex == 0 ? Integer.MIN_VALUE : downstreamNodeKeys.get(oldVirtualIndex-1); //the new key is the medium point between key and previous key long maxInteger = Integer.MAX_VALUE; //long difference = (key == Integer.MAX_VALUE && previousKey == Integer.MIN_VALUE) ? (maxInteger-Integer.MIN_VALUE) : (key-previousKey); long difference = 0; int minBound; int maxBound; if(key == Integer.MAX_VALUE && previousKey == Integer.MIN_VALUE){ minBound = Integer.MIN_VALUE; maxBound = (int)maxInteger; difference = (maxInteger-Integer.MIN_VALUE); } else{ minBound = previousKey; maxBound = key; difference = (key-previousKey); } // long difference = maxBound-minBound; difference = (difference < 0) ? (difference * -1) : difference; long aux = key - (difference/2); int newKey = (int)aux; // install the new key and operator for dispatching, from this moment new tuples are buffered on // store in oldOpIndex, the value of newOpIndex, (so insert by the left) //explain +1 boolean notExists = true; for(int i = 0; i<keyToDownstreamRealIndex.size(); i++){ if(keyToDownstreamRealIndex.get(i) == newOpIndex){ notExists = false; } } if(notExists){ keyToDownstreamRealIndex.add(oldVirtualIndex+1, newOpIndex); downstreamNodeKeys.add(oldVirtualIndex, newKey); } // keyToDownstreamRealIndex.add(oldVirtualIndex+1, newOpIndex); // downstreamNodeKeys.add(oldVirtualIndex, newKey); int bounds[] = {minBound, maxBound}; return bounds; } /// \todo{OPTIMIZE THIS METHOD} public ArrayList<Integer> route(ArrayList<Integer> targets, int value) { // int hash = Router.customHash(value); int hash = value; int realIndex = -1; /** for(Integer nodeKey : downstreamNodeKeys){ */ //System.out.println("Downstream Node Keys size: "+downstreamNodeKeys.size()); //for(Integer key: downstreamNodeKeys){ // System.out.println("KEY: "+key); //} for(int i = 0; i<downstreamNodeKeys.size(); i++){ int nodeKey = downstreamNodeKeys.get(i); //If yes then we have the node to route the info if(hash < nodeKey){ realIndex = keyToDownstreamRealIndex.get(i); //System.out.println("Getting realIndex: "+realIndex); if(!targets.contains(realIndex)){ //System.out.println("And inside"); targets.add(realIndex); } return targets; } } return null; } public ArrayList<Integer> route(int value) { // System.out.println("WARNING...route(int value) in StatefulRoutingImpl"); ArrayList<Integer> targets = new ArrayList<Integer>(); return route(targets, value); } @Override public ArrayList<Integer> routeToAll(){ ArrayList<Integer> targets = new ArrayList<Integer>(); return routeToAll(targets); } @Override public ArrayList<Integer> routeToAll(ArrayList<Integer> targets) { // Just returning the whole set of real indexes ?? // for(int i = 0; i<keyToDownstreamRealIndex.size(); i++){ // System.out.println("index: "+i+" val: "+keyToDownstreamRealIndex.get(i)); // } // System.exit(0); return keyToDownstreamRealIndex; } @Override public int[] collapseReplica(int opIndex) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } @Override public int[] collapseStaticReplica(int opIndex) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } }