package org.shanbo.feluca.model; import java.util.HashMap; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.locks.ReentrantLock; public class FloatReducerImpl implements FloatReducer{ /** * * @author lgn * */ static class Preparation{ int shardId; float[][] values; public Preparation(int shardId, float[][] values){ this.shardId = shardId; this.values = values; } } static class Workshop{ float[][][] reduceSlot; //ith, shardId, array float[][] result; public static abstract class Op{ public abstract float[] action(float[][] data); public int getLength(float[][] data){ int max = 0; for(int i = 0 ; i < data.length ; i++){ if (data[i] != null){ max = data[i].length; } } return max; } } public Workshop(Preparation[] input){ if (FloatWindow.isZipped(input[0].values)){//one degree reduceSlot = new float[1][][]; reduceSlot[0] = new float[input.length][]; result = new float[1][]; for(int i = 0 ; i < input.length; i++){ reduceSlot[0][i] = input[i].values[1]; } }else{ //two degree int maxSize = 0; for(int i = 0; i < input.length; i++){ maxSize = Math.max((int)input[i].values[0][input[i].values[0].length -1 ], maxSize); } reduceSlot = new float[maxSize + 1][][]; result = new float[maxSize + 1][]; for(int i = 0 ; i < maxSize + 1; i++){ // fills reduceSlot[i] = new float[input.length][]; } for(int i = 0; i < input.length; i++){ for(int j = 0 ; j < input[i].values[0].length; j++){ int flatIndex = (int)input[i].values[0][j]; reduceSlot[flatIndex][i] = input[i].values[j + 1]; } } } } void compute(Op op){ for(int i = 0 ; i < reduceSlot.length; i++){ result[i] = op.action(reduceSlot[i]); } } void toReturn(Preparation[] output){ if (FloatWindow.isZipped(output[0].values)){//one degree for(int i = 0 ; i < output.length; i++){ output[i].values[1] = result[0]; } }else{//two degree for(int i = 0; i < output.length; i++){ for(int j = 0 ; j < output[i].values[0].length; j++){ int flatIndex = (int)output[i].values[0][j]; output[i].values[j + 1] = result[flatIndex]; } } } } } /** * always single threaded-computing * @author lgn * */ static class ReduceProcessor{ Preparation[] input ; Workshop workshop; CyclicBarrier enterBarrier ; CyclicBarrier leaveBarrier ; volatile boolean reduceDone; ReentrantLock lock = new ReentrantLock(); public ReduceProcessor(int total){ enterBarrier = new CyclicBarrier(total); leaveBarrier = new CyclicBarrier(total); input = new Preparation[total]; } public void prepare(int clientId, float[][] values) throws InterruptedException{ input[clientId] = new Preparation(clientId, values); } public void doReduce(Workshop.Op op){ lock.lock(); try{ if (reduceDone == false){ workshop = new Workshop(input); workshop.compute(op); workshop.toReturn(input); reduceDone = true; enterBarrier.reset(); leaveBarrier.reset(); } }finally{ lock.unlock(); } } public float[][] getResult(int shardId) throws InterruptedException, BrokenBarrierException{ leaveBarrier.await(); reduceDone = false; //it's ok; because fastest thread still have to wait for others to enter the doReduce() return input[shardId].values; } public void waitForOther() throws InterruptedException, BrokenBarrierException{ enterBarrier.await(); } } HashMap<String, Workshop.Op> ops ; ReduceProcessor processor; public FloatReducerImpl(int total) { processor = new ReduceProcessor(total); ops = new HashMap<String, FloatReducerImpl.Workshop.Op>(); ops.put("sum", new Workshop.Op() { public float[] action(float[][] data) { float[] result = new float[getLength(data)]; for(int i = 0 ; i < result.length ; i++){ for(int j = 0 ; j < data.length; j++){ result[i] += (data[j] == null ? 0 : data[j][i]); } } return result; } }); } @Override public float[][] reduce(String op, float[][] data, int shardId) { Workshop.Op operation = ops.get(op); if (operation == null) return null; try { processor.prepare(shardId, data); processor.waitForOther(); processor.doReduce(operation); return processor.getResult(shardId); } catch (Exception e) { e.printStackTrace(); return null; } } }