Package edu.brown.benchmark.markov

Source Code of edu.brown.benchmark.markov.RandomGenerator$AffinityRecord

/***************************************************************************
*  Copyright (C) 2010 by H-Store Project                                  *
*  Brown University                                                       *
*  Massachusetts Institute of Technology                                  *
*  Yale University                                                        *
*                                                                         *
*  Written by:                                                            *
*  Andy Pavlo (pavlo@cs.brown.edu)                                        *
*  http://www.cs.brown.edu/~pavlo/                                        *
*                                                                         *
*  Permission is hereby granted, free of charge, to any person obtaining  *
*  a copy of this software and associated documentation files (the        *
*  "Software"), to deal in the Software without restriction, including    *
*  without limitation the rights to use, copy, modify, merge, publish,    *
*  distribute, sublicense, and/or sell copies of the Software, and to     *
*  permit persons to whom the Software is furnished to do so, subject to  *
*  the following conditions:                                              *
*                                                                         *
*  The above copyright notice and this permission notice shall be         *
*  included in all copies or substantial portions of the Software.        *
*                                                                         *
*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        *
*  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     *
*  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
*  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR      *
*  OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,  *
*  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR  *
*  OTHER DEALINGS IN THE SOFTWARE.                                        *
***************************************************************************/
package edu.brown.benchmark.markov;

import java.io.FileOutputStream;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONString;
import org.json.JSONStringer;
import org.voltdb.utils.Pair;

import edu.brown.rand.AbstractRandomGenerator;
import edu.brown.rand.RandomDistribution;
import edu.brown.statistics.ObjectHistogram;
import edu.brown.utils.FileUtil;

/**
* @author pavlo
*/
public class RandomGenerator extends AbstractRandomGenerator implements JSONString {
    public enum AffinityRecordMembers {
        MINIMUM, MAXIMUM, MAP, SIGMA,
    }

    /**
     * Table Name -> Affinity Record
     */
    protected final SortedMap<Pair<String, String>, AffinityRecord> affinity_map = new TreeMap<Pair<String, String>, AffinityRecord>();
    protected final transient SortedMap<String, Set<Pair<String, String>>> table_pair_xref = new TreeMap<String, Set<Pair<String, String>>>();

    /**
     *
     */
    protected class AffinityRecord {
        private final SortedMap<Integer, Integer> map = new TreeMap<Integer, Integer>();
        private final transient SortedMap<Integer, RandomDistribution.Zipf> distributions = new TreeMap<Integer, RandomDistribution.Zipf>();
        private double zipf_sigma = 1.01d;
        private int minimum;
        private int maximum;
        private transient int range;
        private final transient SortedMap<Integer, ObjectHistogram> histograms = new TreeMap<Integer, ObjectHistogram>();

        public AffinityRecord() {
            // For serialization...
        }

        public AffinityRecord(int minimum, int maximum) {
            this.minimum = minimum;
            this.maximum = maximum;
            this.range = this.maximum - this.minimum;
        }

        public double getZipfSigma() {
            return (this.zipf_sigma);
        }

        public void setZipfSigma(double zipf_sigma) {
            // We have to regenerate all the random number generators
            if (this.zipf_sigma != zipf_sigma) {
                this.zipf_sigma = zipf_sigma;
                for (int source : this.map.keySet()) {
                    int target = this.map.get(source);
                    this.distributions.put(source, new RandomDistribution.Zipf(RandomGenerator.this, target, target + this.range, this.zipf_sigma));
                } // FOR
            }
        }

        public int getMinimum() {
            return (this.minimum);
        }

        public int getMaximum() {
            return (this.maximum);
        }

        public Set<Integer> getSources() {
            return (this.map.keySet());
        }

        public int getTarget(int source) {
            return (this.map.get(source));
        }

        public RandomDistribution.Zipf getDistribution(int source) {
            return (this.distributions.get(source));
        }

        public ObjectHistogram getHistogram(int source) {
            return (this.histograms.get(source));
        }

        public void add(int source, int target) {
            this.map.put(source, target);
            this.distributions.put(source, new RandomDistribution.Zipf(RandomGenerator.this, target, target + this.range, this.zipf_sigma));
            this.histograms.put(source, new ObjectHistogram());
        }

        public void toJSONString(JSONStringer stringer) throws JSONException {
            stringer.key(AffinityRecordMembers.SIGMA.name()).value(this.zipf_sigma);
            stringer.key(AffinityRecordMembers.MINIMUM.name()).value(this.minimum);
            stringer.key(AffinityRecordMembers.MAXIMUM.name()).value(this.maximum);

            stringer.key(AffinityRecordMembers.MAP.name()).object();
            for (Integer source_id : this.map.keySet()) {
                stringer.key(source_id.toString()).value(this.map.get(source_id));
            } // FOR
            stringer.endObject();
        }

        public void fromJSONObject(JSONObject object) throws JSONException {
            this.zipf_sigma = object.getDouble(AffinityRecordMembers.SIGMA.name());
            this.minimum = object.getInt(AffinityRecordMembers.MINIMUM.name());
            this.maximum = object.getInt(AffinityRecordMembers.MAXIMUM.name());
            this.range = this.maximum - this.minimum;

            JSONObject jsonMap = object.getJSONObject(AffinityRecordMembers.MAP.name());
            Iterator<String> i = jsonMap.keys();
            while (i.hasNext()) {
                String key = i.next();
                Integer source = Integer.parseInt(key);
                Integer target = jsonMap.getInt(key);
                assert (source != null);
                assert (target != null);
                this.add(source, target);
            } // WHILE
        }

        @Override
        public String toString() {
            StringBuilder buffer = new StringBuilder();
            for (int source : this.map.keySet()) {
                int target = this.map.get(source);
                buffer.append(source).append(" => ").append(target).append("\n");
                buffer.append(this.histograms.get(source)).append("\n-------------\n");
            } // FOR
            return (buffer.toString());
        }
    } // END CLASS

    /**
     * Seeds the random number generator using the default Random() constructor.
     */
    public RandomGenerator() {
        super(0);
    }

    /**
     * Seeds the random number generator with seed.
     *
     * @param seed
     */
    public RandomGenerator(Integer seed) {
        super(seed);
    }

    /**
     * Set the Zipfian distribution sigma factor
     *
     * @param zipf_sigma
     */
    public void setZipfSigma(String table, double zipf_sigma) {
        assert (this.affinity_map.containsKey(table));
        this.affinity_map.get(table).setZipfSigma(zipf_sigma);
    }

    private void addAffinityRecord(Pair<String, String> pair, AffinityRecord record) {
        this.affinity_map.put(pair, record);
        if (!this.table_pair_xref.containsKey(pair.getFirst())) {
            this.table_pair_xref.put(pair.getFirst(), new HashSet<Pair<String, String>>());
        }
        this.table_pair_xref.get(pair.getFirst()).add(pair);
    }

    /**
     * Sets the affinity preference of a source value to a target
     *
     * @param source_id
     * @param target_id
     */
    public void addAffinity(String source_table, int source_id, String target_table, int target_id, int minimum, int maximum) {
        assert (minimum <= target_id) : "Min check failed (" + minimum + " <= " + target_id + ")";
        assert (maximum >= target_id);
        Pair<String, String> pair = Pair.of(source_table, target_table);
        AffinityRecord record = this.affinity_map.get(pair);
        if (record == null) {
            record = new AffinityRecord(minimum, maximum);
        } else {
            assert (this.affinity_map.get(pair).getMinimum() == minimum);
            assert (this.affinity_map.get(pair).getMaximum() == maximum);
        }
        record.add(source_id, target_id);
        this.addAffinityRecord(pair, record);
    }

    /**
     * Return all the tables that we have a record for
     *
     * @return
     */
    public Set<String> getTables() {
        return (this.table_pair_xref.keySet());
    }

    public Set<Pair<String, String>> getTables(String source_table) {
        return (this.table_pair_xref.get(source_table));
    }

    public Integer getTarget(String source_table, int source_id, String target_table) {
        Pair<String, String> pair = Pair.of(source_table, target_table);
        AffinityRecord record = this.affinity_map.get(pair);
        return (record != null ? record.getTarget(source_id) : null);
    }

    /**
     * @param record
     * @param source_id
     * @param exclude_base
     * @return
     */
    private int nextInt(AffinityRecord record, int source_id, boolean exclude_base) {
        RandomDistribution.Zipf zipf = record.getDistribution(source_id);
        assert (zipf != null);
        int value = zipf.nextInt();

        int max = record.getMaximum();
        if (exclude_base) {
            long range_start = record.getTarget((int) zipf.getMin());
            if (value >= range_start)
                value++;
            if (value > max) {
                value = (value % max) + 1;
                if (value == max)
                    value--;
            }
        } else if (value > max) {
            value = (value % max) + 1;
        }
        record.getHistogram(source_id).put(value);

        return (value);
    }

    @Override
    public int numberAffinity(int minimum, int maximum, int base, String source_table, String target_table) {
        Pair<String, String> pair = Pair.of(source_table, target_table);
        AffinityRecord record = this.affinity_map.get(pair);
        int value;

        /*
         * System.out.println("min=" + minimum); System.out.println("max=" +
         * maximum); System.out.println("base=" + base);
         * System.out.println("table=" + table); System.out.println("record=" +
         * (record != null)); System.exit(1);
         */

        // Use an AffinityRecord to generate next number
        if (record != null && record.getDistribution(base) != null) {
            value = this.nextInt(record, base, false);
            // Otherwise, just use the default random number generator
        } else {
            value = super.number(minimum, maximum);
        }
        return (value);
    }

    /**
     * Generate an affinity-skewed random number that excludes the number given
     */
    @Override
    public int numberExcluding(int minimum, int maximum, int excluding, String source_table, String target_table) {
        Pair<String, String> pair = Pair.of(source_table, target_table);
        AffinityRecord record = this.affinity_map.get(pair);
        int value;

        // Use an AffinityRecord to generate next number
        if (record != null && record.getDistribution(excluding) != null) {
            value = this.nextInt(record, excluding, true);

            // Otherwise, just use the default random number generator
        } else {
            value = super.numberExcluding(minimum, maximum, excluding);
        }
        return (value);
    }

    /**
     *
     */
    @Override
    public void loadProfile(String input_path) throws Exception {
        String contents = FileUtil.readFile(input_path);
        if (contents.isEmpty()) {
            throw new Exception("The partition plan file '" + input_path + "' is empty");
        }
        JSONObject jsonObject = new JSONObject(contents);
        System.out.println(jsonObject.toString(2));
        this.fromJSONObject(jsonObject);
    }

    /**
     * @param output_path
     * @throws Exception
     */
    @Override
    public void saveProfile(String output_path) throws Exception {
        String json = this.toJSONString();
        JSONObject jsonObject = new JSONObject(json);

        FileOutputStream out = new FileOutputStream(output_path);
        out.write(jsonObject.toString(2).getBytes());
        out.close();
    }

    @Override
    public String toJSONString() {
        JSONStringer stringer = new JSONStringer();
        try {
            stringer.object();
            this.toJSONString(stringer);
            stringer.endObject();
        } catch (JSONException e) {
            e.printStackTrace();
            System.exit(-1);
        }
        return stringer.toString();
    }

    public void toJSONString(JSONStringer stringer) throws JSONException {
        for (String source_table : this.getTables()) {
            stringer.key(source_table).object();
            for (Pair<String, String> pair : this.getTables(source_table)) {
                stringer.key(pair.getSecond()).object();
                this.affinity_map.get(pair).toJSONString(stringer);
                stringer.endObject();
            } // FOR
            stringer.endObject();
        } // FOR
    }

    public void fromJSONObject(JSONObject object) throws JSONException {
        Iterator<String> i = object.keys();
        while (i.hasNext()) {
            String source_table = i.next();
            JSONObject innerObject = object.getJSONObject(source_table);
            Iterator<String> j = innerObject.keys();
            while (j.hasNext()) {
                String target_table = j.next();
                Pair<String, String> pair = Pair.of(source_table, target_table);
                AffinityRecord record = new AffinityRecord();
                record.fromJSONObject(innerObject.getJSONObject(target_table));
                this.addAffinityRecord(pair, record);
            } // WHILE
        } // WHILE
    }

    @Override
    public String toString() {
        StringBuilder buffer = new StringBuilder();
        buffer.append(this.getClass().getSimpleName()).append("\n");
        for (String source_table : this.getTables()) {
            for (Pair<String, String> pair : this.getTables(source_table)) {
                buffer.append("TABLES: ").append(pair).append("\n");
                buffer.append(this.affinity_map.get(pair));
            } // FOR
        } // FOR
        return (buffer.toString());
    }

    /**
     * Construct profile for TPC-C warehouses.
     *
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        int minimum = 1;
        int num_warehouses = Integer.parseInt(args[0]);
        String output_path = args[1];
        RandomGenerator rand = new RandomGenerator();

        /**
         * int half = (int)Math.ceil(num_warehouses / 2.0d); String table_name =
         * Constants.TABLENAME_ORDERLINE; for (int ctr = minimum; ctr < half;
         * ctr++) { int source = ctr; int target = ctr + half;
         * rand.addAffinity(table_name, source, target, minimum,
         * num_warehouses); rand.addAffinity(table_name, target, source,
         * minimum, num_warehouses); } // FOR if ((half - minimum) % 2 == 1) {
         * rand.addAffinity(table_name, half, half, minimum, num_warehouses); }
         */
        System.out.println(rand.toJSONString());
        rand.saveProfile(output_path);
        System.out.println("Saved RandomGenerator profile to '" + output_path + "'");
    }
}
TOP

Related Classes of edu.brown.benchmark.markov.RandomGenerator$AffinityRecord

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.