main.java.repartition.RBPTA.java Source code

Java tutorial

Introduction

Here is the source code for main.java.repartition.RBPTA.java

Source

/*******************************************************************************
 * Copyright [2014] [Joarder Kamal]
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 *******************************************************************************/

package main.java.repartition;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;

import main.java.cluster.Cluster;
import main.java.cluster.Partition;
import main.java.cluster.Server;
import main.java.entry.Global;
import main.java.utils.IntPair;
import main.java.utils.Matrix;
import main.java.utils.MatrixElement;
import main.java.utils.Utility;
import main.java.workload.Transaction;

import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
import org.paukov.combinatorics.Factory;
import org.paukov.combinatorics.Generator;
import org.paukov.combinatorics.ICombinatoricsVector;

/*
 * Repartition Based on Partition-level Transactional Association (RBPTA)
 */

public class RBPTA {

    public static Matrix association;

    public static void init(Cluster cluster) {
        int M = cluster.getPartitions().size() + 1;
        int N = M;
        association = Utility.createMatrix(M, N);
    }

    public static void updateAssociation(Cluster cluster, Transaction tr) {
        //System.out.println(">> "+tr.toString());
        // Based on: https://code.google.com/p/combinatoricslib/
        // Get all the pairs of combinations of Partition accessed by this Transaction
        // Create the initial vector
        ICombinatoricsVector<Integer> initialVector = Factory.createVector(tr.getTr_partitionSet().keySet());

        // Create a simple combination generator to generate 2-combinations of the initial vector
        Generator<Integer> gen = Factory.createSimpleCombinationGenerator(initialVector, 2);

        // Print all possible combinations
        for (ICombinatoricsVector<Integer> combination : gen) {

            int p_a_id = combination.getValue(0);
            int p_b_id = combination.getValue(1);

            int p_a_trData = tr.getTr_partitionSet().get(p_a_id).size();
            int p_b_trData = tr.getTr_partitionSet().get(p_b_id).size();

            double entropy = getEntropy(p_a_trData, p_b_trData);
            entropy /= 2;
            double association_value = (1 / tr.getTr_period()) * (p_a_trData + p_b_trData) * entropy;
            //double association_value = entropy;
            //System.out.println("\t>> P"+p_a_id+"-P"+p_b_id);
            //System.out.println("\t\t--> New entropy = "+entropy);

            if (p_b_id > p_a_id) {
                double old_association = association.getMatrix()[p_b_id][p_a_id].getValue();
                //System.out.println("\t\t--> Old association = "+old_association);

                double new_association = old_association * Global.expAvgWt
                        + association_value * (1 - Global.expAvgWt);

                association.getMatrix()[p_b_id][p_a_id].setValue(new_association);
                //System.out.println("\t\t--> New association = "+new_association);

            } else {
                double old_association = association.getMatrix()[p_a_id][p_b_id].getValue();
                //System.out.println("\t\t--> Old association = "+old_association);

                double new_association = old_association * Global.expAvgWt
                        + association_value * (1 - Global.expAvgWt);

                association.getMatrix()[p_a_id][p_b_id].setValue(new_association);
                //System.out.println("\t\t--> New association = "+new_association);
            }
        }

        // Verification
        //System.out.println("====================================================================");
        //association.print();
        //this.migrationDecision(cluster);
    }

    private static double getEntropy(int p_a_trData, int p_b_trData) {
        double entropy = 0.0d;

        double p_total = p_a_trData + p_b_trData;
        entropy = (-(p_a_trData / p_total) * (Math.log(p_a_trData / p_total) / Math.log(2))
                - (p_b_trData / p_total) * (Math.log(p_b_trData / p_total) / Math.log(2)));

        return entropy;
    }

    @SuppressWarnings("rawtypes")
    static TreeSet sgGainRank;
    @SuppressWarnings("rawtypes")
    static TreeSet lbGainRank;

    // Migration decision
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static IntPair migrationDecision(Cluster cluster) {

        ArrayList<SwappingCandidate> swappingCandidates = new ArrayList<SwappingCandidate>();
        Set<Integer> serverSet = new TreeSet<Integer>();

        for (Server s : cluster.getServers())
            serverSet.add(s.getServer_id());

        ICombinatoricsVector<Integer> initialVector = Factory.createVector(serverSet);

        // Create a simple combination generator to generate 2-combinations of the initial vector
        Generator<Integer> gen = Factory.createSimpleCombinationGenerator(initialVector, 2);

        Server s_a = null;
        Server s_b = null;

        // Print all possible combinations
        for (ICombinatoricsVector<Integer> combination : gen) {

            s_a = cluster.getServer(combination.getValue(0));
            s_b = cluster.getServer(combination.getValue(1));

            for (int p_a_id : s_a.getServer_partitions()) {
                Partition p_a = cluster.getPartition(p_a_id);

                // Sets for preserving the ranks
                sgGainRank = new TreeSet();
                lbGainRank = new TreeSet();

                for (int p_b_id : s_b.getServer_partitions()) {

                    Partition p_b = cluster.getPartition(p_b_id);
                    MatrixElement me = null;

                    if (p_a_id > p_b_id)
                        me = association.getMatrix()[p_a_id][p_b_id];
                    else
                        me = association.getMatrix()[p_b_id][p_a_id];

                    SwappingCandidate sc = new SwappingCandidate(me.getId());

                    sc.p_pair.x = me.getRow_pos();
                    sc.p_pair.y = me.getCol_pos();

                    sc.s_pair.x = s_a.getServer_id();
                    sc.s_pair.y = s_b.getServer_id();

                    sc.swapping_gain = getSwappingGain(cluster, p_a, p_b);
                    sc.lb_gain = getLbGain(cluster, sc);

                    sgGainRank.add(sc.swapping_gain);
                    lbGainRank.add(sc.lb_gain);

                    swappingCandidates.add(sc);

                } // end-for()
            } // end-for()
        } // end-while()

        // Testing
        /*System.out.println("--> List of potential swapping candidates: ");
        for(SwappingCandidate s : swappingCandidates) {
           System.out.println("\t\t"+s.toString());
        }*/

        // Chose the best swapping candidate
        if (swappingCandidates.size() != 0) {
            // Sorting
            if (Global.lambda == 1.0) {
                // Sort the array list by swapping gain in decending order
                Collections.sort(swappingCandidates, new Comparator<SwappingCandidate>() {
                    @Override
                    public int compare(SwappingCandidate sc1, SwappingCandidate sc2) {
                        return (((double) sc1.swapping_gain > (double) sc2.swapping_gain) ? -1
                                : ((double) sc1.swapping_gain < (double) sc2.swapping_gain) ? 1 : 0);
                    }
                });

            } else if ((1 - Global.lambda) == 1.0) {
                // Sort the array list by lb gain in ascending order
                Collections.sort(swappingCandidates, new Comparator<SwappingCandidate>() {
                    @Override
                    public int compare(SwappingCandidate sc1, SwappingCandidate sc2) {
                        return (((double) sc2.lb_gain > (int) sc1.lb_gain) ? -1
                                : ((double) sc2.lb_gain < (int) sc2.lb_gain) ? 1 : 0);
                    }
                });

            } else {
                // Sort the array list by the value of combined rank (descending order)
                Collections.sort(swappingCandidates, new Comparator<SwappingCandidate>() {
                    @Override
                    public int compare(SwappingCandidate sc1, SwappingCandidate sc2) {
                        int sg_rank1 = ((TreeSet) sgGainRank).headSet(sc1.swapping_gain).size();
                        int sg_rank2 = ((TreeSet) sgGainRank).headSet(sc2.swapping_gain).size();

                        int lb_rank1 = ((TreeSet) lbGainRank).tailSet(sc1.lb_gain).size();
                        int lb_rank2 = ((TreeSet) lbGainRank).tailSet(sc2.lb_gain).size();

                        sc1.combined_rank = sg_rank1 * Global.lambda + lb_rank1 * (1 - Global.lambda);
                        sc2.combined_rank = sg_rank2 * Global.lambda + lb_rank2 * (1 - Global.lambda);

                        return (((double) sc1.combined_rank > (double) sc2.combined_rank) ? -1
                                : ((double) sc1.combined_rank < (double) sc2.combined_rank) ? 1 : 0);
                    }
                });
            }

            /*Global.LOGGER.info("----------------------------------------------");
            Global.LOGGER.info("Sorted list of potential swapping pairs:");         
            for(SwappingCandidate sc : swappingCandidates)
               Global.LOGGER.info("--"+sc.toString());*/

            // Select the target swapping candidate
            SwappingCandidate target_candidate = swappingCandidates.get(0);

            //Global.LOGGER.info("----------------------------------------------");
            //Global.LOGGER.info("Selected swapping pair: "+target_candidate.toString());

            return (new IntPair(target_candidate.p_pair.x, target_candidate.p_pair.y));

        } else {
            return null;
        }
    }

    // Returns the actual gain for a swapping Pi/Si with Pj/Sj 
    private static double getSwappingGain(Cluster cluster, Partition p_i, Partition p_j) {

        int p_i_id = p_i.getPartition_id();
        int p_j_id = p_j.getPartition_id();

        Server s_i = cluster.getServer(p_i.getPartition_serverId());
        Server s_j = cluster.getServer(p_j.getPartition_serverId());

        double value = 0.0d;
        double gain = 0.0d;
        double loss = 0.0d;

        // Get the gain for Pi-->Sj
        for (int p_id : s_j.getServer_partitions()) {
            if (p_i_id != p_id) {
                if (p_i_id > p_id)
                    value = association.getMatrix()[p_i_id][p_id].getValue();
                else
                    value = association.getMatrix()[p_id][p_i_id].getValue();

                gain += value;
            }
        }

        // Get the gain for Pj-->Si
        for (int p_id : s_i.getServer_partitions()) {
            if (p_j_id != p_id) {
                if (p_j_id > p_id)
                    value = association.getMatrix()[p_j_id][p_id].getValue();
                else
                    value = association.getMatrix()[p_id][p_j_id].getValue();

                gain += value;
            }
        }

        // Get the loss for Pi<--Si
        for (int p_id : s_i.getServer_partitions()) {
            if (p_i_id != p_id) {
                if (p_i_id > p_id)
                    value = association.getMatrix()[p_i_id][p_id].getValue();
                else
                    value = association.getMatrix()[p_id][p_i_id].getValue();

                loss += value;
            }
        }

        // Get the loss for Pj<--Sj
        for (int p_id : s_j.getServer_partitions()) {
            if (p_j_id != p_id) {
                if (p_j_id > p_id)
                    value = association.getMatrix()[p_j_id][p_id].getValue();
                else
                    value = association.getMatrix()[p_id][p_j_id].getValue();

                loss += value;
            }
        }

        // Returns the actual gain
        return (gain - loss);
    }

    // Returns the difference of data volume of two partitions as a distance
    private static double getLbGain(Cluster cluster, SwappingCandidate sc) {

        DescriptiveStatistics sc_partition_data = new DescriptiveStatistics();

        for (Partition p : cluster.getPartitions())
            if (sc.p_pair.x == p.getPartition_id() || sc.p_pair.y == p.getPartition_id())
                sc_partition_data.addValue(p.getPartition_dataSet().size());

        return sc_partition_data.getVariance();
    }
}

// A specialised Element Class
class SwappingCandidate {
    int id;
    IntPair p_pair;
    IntPair s_pair;
    double swapping_gain;
    double lb_gain;
    double combined_rank;

    public SwappingCandidate(int id) {
        this.setId(id);
        this.p_pair = new IntPair(-1, -1);
        this.s_pair = new IntPair(-1, -1);
        this.swapping_gain = 0.0;
        this.lb_gain = 0.0;
        this.combined_rank = 0.0;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public boolean equals(Object object) {
        if (!(object instanceof MatrixElement)) {
            return false;
        }

        MatrixElement e = (MatrixElement) object;
        return (this.getId() == e.getId());
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + this.id;
        return result;
    }

    @Override
    public String toString() {
        return ("P" + this.p_pair + "/S" + this.s_pair + " [Swapping Gain(" + this.swapping_gain + ") | "
                + " Lb gain(" + this.lb_gain + ") | Combined rank(" + this.combined_rank + "]");
    }
}