Package edu.brown.designer

Source Code of edu.brown.designer.DesignerHints

package edu.brown.designer;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import org.apache.commons.collections15.set.ListOrderedSet;
import org.apache.log4j.Logger;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONStringer;
import org.voltdb.catalog.CatalogType;
import org.voltdb.catalog.Column;
import org.voltdb.catalog.Database;
import org.voltdb.catalog.Procedure;
import org.voltdb.catalog.Table;
import org.voltdb.types.TimestampType;
import org.voltdb.utils.Pair;

import edu.brown.catalog.CatalogKey;
import edu.brown.catalog.CatalogUtil;
import edu.brown.catalog.special.ReplicatedColumn;
import edu.brown.designer.partitioners.plan.PartitionPlan;
import edu.brown.logging.LoggerUtil;
import edu.brown.logging.LoggerUtil.LoggerBoolean;
import edu.brown.utils.FileUtil;
import edu.brown.utils.JSONSerializable;
import edu.brown.utils.JSONUtil;
import edu.brown.utils.StringUtil;

public class DesignerHints implements Cloneable, JSONSerializable {
    private static final Logger LOG = Logger.getLogger(DesignerHints.class);
    private static final LoggerBoolean debug = new LoggerBoolean();
    private static final LoggerBoolean trace = new LoggerBoolean();
    static {
        LoggerUtil.attachObserver(LOG, debug, trace);
    }

    public static final Field[] MEMBERS;
    static {
        List<Field> fields = new ArrayList<Field>();
        Class<?> clazz = DesignerHints.class;
        for (Field f : clazz.getDeclaredFields()) {
            int modifiers = f.getModifiers();
            if (Modifier.isTransient(modifiers) == false && Modifier.isPublic(modifiers) == true && Modifier.isStatic(modifiers) == false) {
                fields.add(f);
            }
        } // FOR
        MEMBERS = fields.toArray(new Field[0]);
    } // STATIC

    // ----------------------------------------------------------------------------
    // INTERNAL DATA MEMBERS
    // ----------------------------------------------------------------------------

    /**
     * The location of the file that we loaded for this DesignerHints
     */
    private transient File source_file;

    /**
     * When we started keeping track of time
     */
    private transient TimestampType start_time = null;

    /**
     * The FileWriter handle where we dump out new solutions
     */
    private transient FileWriter log_solutions_costs_writer = null;

    // ----------------------------------------------------------------------------
    // DATA MEMBERS
    // ----------------------------------------------------------------------------

    /**
     * Whether the catalog should be forced into a random partitioning
     * configuration before we start working on it.
     */
    public boolean start_random = false;

    /**
     * Whether to exhaustively search all possible designs
     */
    public boolean exhaustive_search = false;

    /**
     * Whether to greedily search for a design
     */
    public boolean greedy_search = false;

    /**
     * Search time limits (seconds)
     */
    public Integer limit_total_time = null;
    public Integer limit_local_time = null;
    public double local_time_multiplier = 1.01;

    /**
     * Limit the # of back tracks
     */
    public Integer limit_back_tracks = null;
    public double back_tracks_multiplier = 1.01;

    /**
     * The amount of memory available to each partition
     */
    public long max_memory_per_partition = 0;

    /**
     * The list of procedures we should only consider
     */
    public final Set<String> proc_include = new HashSet<String>();
    public final Set<String> proc_exclude = new HashSet<String>();

    /**
     * Replication Candidate Control
     */
    public boolean enable_replication_readonly = true;
    public boolean enable_replication_readmostly = true;

    /**
     * Allow array ProcParameters to be used as partitioning candidates
     */
    public boolean enable_array_procparameter_candidates = false;

    /** Mark tables as read-only */
    public final Set<String> readonly_tables = new HashSet<String>();
    /** Mark tables as read-mostly */
    public final Set<String> readmostly_tables = new HashSet<String>();

    /** Whether we can have multi-attribute partitioning attributes */
    public boolean enable_multi_partitioning = false;

    /** Enable vertical partitioning search */
    public boolean enable_vertical_partitioning = false;

    /** Enable caching in cost models */
    public boolean enable_costmodel_caching = false;

    /** Enable skew calculations in cost models */
    public boolean enable_costmodel_skew = true;

    /** Enable execution calculations in cost models */
    public boolean enable_costmodel_execution = true;

    /** Enable the inclusion of Java execution partitions in cost models */
    public boolean enable_costmodel_java_execution = false;

    /** Enable Multipartition Penalty factoring */
    public boolean enable_costmodel_multipartition_penalty = true;

    /** Enable Idle Partition Penalty factoring */
    public boolean enable_costmodel_idlepartition_penalty = true;

    /** Enable searching for the partitioning ProcParameter */
    public boolean enable_procparameter_search = true;

    /** Enable increasing local search parameters after a restart */
    public boolean enable_local_search_increase = true;

    /** Enable partitioner checkpoints */
    public boolean enable_checkpoints = true;

    /**
     * Force a table to be replicated Set<TableKey>
     */
    public final Set<String> force_replication = new HashSet<String>();

    public Double force_replication_size_limit = null;

    /**
     * Force a table to be partitioned on a particular column TableKey ->
     * ColumnKey
     */
    public final Map<String, Set<String>> force_table_partition = new HashMap<String, Set<String>>();

    /**
     * Enable debugging on certain columns Set<ColumnKey>
     */
    public final Set<String> force_debugging = new HashSet<String>();

    /**
     * Force one column to be mapped to another column Map<ColumnKey, ColumnKey>
     */
    public final Map<String, String> force_dependency = new HashMap<String, String>();

    /**
     * Cost Model Weights
     */
    public double weight_costmodel_execution = 1.0;
    public double weight_costmodel_skew = 1.0;
    public double weight_costmodel_multipartition_penalty = 1.0;
    public int weight_costmodel_java_execution = 1;

    /**
     * Keep track of the cost of the solutions as we find them
     */
    public String log_solutions_costs = null;

    /**
     * A list of procedure names we should ignore when doing any calculations
     */
    public final Set<String> ignore_procedures = new HashSet<String>();
   
    /**
     * A list of table names we should ignore when doing any calculations
     */
    public final Set<String> ignore_tables = new HashSet<String>();

    /**
     * Relaxation Factors
     */
    public double relaxation_factor_min = 0.25;
    public double relaxation_factor_max = 0.5;
    public int relaxation_min_size = 5;

    /**
     * If we were given a target PartitionPlan, then we will check whether every
     * new solution equals this plan. If it does, then we will halt. This is
     * used to measure how long it takes us to find the optimal solution.
     */
    public File target_plan_path = null;
    public transient PartitionPlan target_plan = null;

    // ----------------------------------------------------------------------------
    // CONSTRUCTORS
    // ----------------------------------------------------------------------------

    /**
     * Empty Constructor
     */
    public DesignerHints() {

    }

    /**
     * Copy Constructor
     *
     * @param orig
     */
    public DesignerHints(DesignerHints orig) {
        this.start_time = orig.start_time;
        this.source_file = orig.source_file;
    }

    // ----------------------------------------------------------------------------
    // UTILITY METHODS
    // ----------------------------------------------------------------------------

    /**
     * Clone
     */
    public DesignerHints clone() {
        DesignerHints clone = new DesignerHints(this);
        try {
            clone.fromJSON(new JSONObject(this.toJSONString()), null);
        } catch (Exception ex) {
            LOG.fatal("Failed to clone DesignerHints", ex);
            System.exit(1);
        }
        return (clone);
    }

    @Override
    public int hashCode() {
        return this.toString().hashCode();
    }

    @Override
    public String toString() {
        Class<?> hints_class = this.getClass();
        SortedMap<String, Object> m = new TreeMap<String, Object>();
        for (Field f : hints_class.getFields()) {
            String key = f.getName().toUpperCase();
            Object val = null;
            try {
                val = f.get(this);
            } catch (IllegalAccessException ex) {
                val = ex.getMessage();
            }
            m.put(key, val);
        } // FOR
        return (StringUtil.formatMaps(m));
    }

    public File getSourceFile() {
        return (this.source_file);
    }

    // --------------------------------------------------------------------------------------------
    // COST LOGGING
    // --------------------------------------------------------------------------------------------

    public boolean shouldLogSolutionCosts() {
        return (this.log_solutions_costs != null);
    }

    /**
     * Write a solution cost out to a file. Each entry will also include the
     * time at which the new cost was discovered
     *
     * @param cost
     */
    public void logSolutionCost(double cost, double singlep_txns) {
        assert (this.log_solutions_costs != null);
        try {
            if (this.log_solutions_costs_writer == null) {
                File file = new File(this.log_solutions_costs);
                FileUtil.makeDirIfNotExists(file.getParent());
                this.log_solutions_costs_writer = new FileWriter(file, true);
                this.log_solutions_costs_writer.write("-- " + (new Date().toString()) + "\n");
                LOG.info("Creating solution costs log file: " + file.getAbsolutePath());
            }
            long offset = System.currentTimeMillis() - this.startGlobalSearchTimer().getMSTime();
            this.log_solutions_costs_writer.write(String.format("%d\t%.05f\t%.05f\n", offset, cost, singlep_txns));
            this.log_solutions_costs_writer.flush();
        } catch (Exception ex) {
            throw new RuntimeException("Failed to log solution cost to '" + this.log_solutions_costs + "'", ex);
        }
    }

    // --------------------------------------------------------------------------------------------
    // GLOBAL & LOCAL SEARCH TIMERS
    // --------------------------------------------------------------------------------------------

    /**
     * We're coming in after a checkpoint restart, so we need to offset the
     * total time by the time that already elapsed
     *
     * @param orig_start_time
     * @param last_checkpoint
     */
    public void offsetCheckpointTime(TimestampType orig_start_time, TimestampType last_checkpoint) {
        if (this.limit_total_time != null) {
            assert (last_checkpoint.getTime() > orig_start_time.getTime());
            int delta = (int) (last_checkpoint.getMSTime() - orig_start_time.getMSTime()) / 1000;
            this.limit_total_time -= delta;
        }
    }

    /**
     * Start the timer used to keep track of how long we are searching for
     * solutions
     */
    public TimestampType startGlobalSearchTimer() {
        if (this.start_time == null) {
            this.start_time = new TimestampType();
        }
        return (this.start_time);
    }

    public TimestampType getStartTime() {
        return (this.start_time);
    }

    public TimestampType getGlobalStopTime() {
        long stop = 9999999;
        if (this.limit_total_time != null && this.limit_total_time >= 0) {
            stop = (this.limit_total_time * 1000);
        }
        return new TimestampType((this.startGlobalSearchTimer().getMSTime() + stop) * 1000);
    }

    /**
     * Return the amount of time remaining (in ms) for the global search process
     *
     * @return
     */
    public long getRemainingGlobalTime() {
        return (this.getGlobalStopTime().getMSTime() - System.currentTimeMillis());
    }

    public TimestampType getNextLocalStopTime() {
        long now = System.currentTimeMillis();
        long stop = 9999999;
        if (this.limit_local_time != null && this.limit_local_time >= 0) {
            stop = (this.limit_local_time * 1000);
        }
        return new TimestampType((now + stop) * 1000);
    }

    /**
     * Returns the next stop time for the current time. This will the global
     * stop time if that comes before the next local stop time
     *
     * @return Next stop timestamp, True if it was the local time
     */
    public Pair<TimestampType, Boolean> getNextStopTime() {
        TimestampType next = null;
        Boolean is_local = null;
        TimestampType stop_local = null;
        TimestampType stop_total = null;

        if (this.limit_local_time != null && this.limit_local_time >= 0) {
            stop_local = this.getNextLocalStopTime();
        }
        if (this.limit_total_time != null && this.limit_total_time >= 0) {
            stop_total = this.getGlobalStopTime();
        }
        if (stop_local != null && stop_total != null) {
            if (stop_local.compareTo(stop_total) < 0) {
                next = stop_local;
                is_local = true;
            } else {
                next = stop_total;
                is_local = false;
            }
        } else if (stop_local != null) {
            next = stop_local;
            is_local = true;
        } else if (stop_total != null) {
            next = stop_total;
            is_local = false;
        }
        return (next != null ? Pair.of(next, is_local) : null);
    }

    /**
     * Return the ratio of the amount of time that remains for the global search
     * process 0.0 means that the search just started 1.0 means that the search
     * is out of time
     *
     * @return
     */
    public double getElapsedGlobalPercent() {
        long delta = (this.getGlobalStopTime().getMSTime() - this.getStartTime().getMSTime());
        long now = System.currentTimeMillis();
        double ratio = Math.abs((now - this.getStartTime().getMSTime()) / (double) delta);
        assert (ratio <= 1.0) : String.format("Invalid Elapsed Ratio: %f [delta=%d, now=%d, start=%d, stop=%d]", ratio, delta, now, getStartTime().getMSTime(), getGlobalStopTime().getMSTime());
        return ratio;
    }

    // --------------------------------------------------------------------------------------------
    // PARTITION INFO
    // --------------------------------------------------------------------------------------------

    public void addTablePartitionCandidate(Database catalog_db, String table_name, String column_name) {
        Table catalog_tbl = catalog_db.getTables().get(table_name);
        assert (catalog_tbl != null) : "Invalid table name '" + table_name + "'";

        Column catalog_col = null;
        if (column_name.equals(ReplicatedColumn.COLUMN_NAME)) {
            catalog_col = ReplicatedColumn.get(catalog_tbl);
        } else {
            catalog_col = catalog_tbl.getColumns().get(column_name);
        }
        assert (catalog_col != null) : "Invalid column name '" + table_name + "." + column_name + "'";
        this.addTablePartitionCandidate(catalog_tbl, catalog_col);
    }

    public void addTablePartitionCandidate(Table catalog_tbl, Column catalog_col) {
        final String table_key = CatalogKey.createKey(catalog_tbl);
        final String column_key = CatalogKey.createKey(catalog_col);

        if (!this.force_table_partition.containsKey(table_key)) {
            this.force_table_partition.put(table_key, new ListOrderedSet<String>());
        }
        this.force_table_partition.get(table_key).add(column_key);
    }

    public Collection<Column> getForcedTablePartitionCandidates(Table catalog_tbl) {
        final Database catalog_db = CatalogUtil.getDatabase(catalog_tbl);
        final String table_key = CatalogKey.createKey(catalog_tbl);
        ListOrderedSet<Column> ret = new ListOrderedSet<Column>();
        if (this.force_table_partition.containsKey(table_key)) {
            for (String column_key : this.force_table_partition.get(table_key)) {
                ret.add(CatalogKey.getFromKey(catalog_db, column_key, Column.class));
            } // FOR
        }
        return (ret);
    }

    public void enablePartitionCandidateDebugging(CatalogType catalog_item) {
        final String catalog_key = CatalogKey.createKey(catalog_item);
        this.force_debugging.add(catalog_key);
    }

    public boolean isDebuggingEnabled(String catalog_key) {
        return (this.force_debugging.contains(catalog_key));
    }

    public boolean isDebuggingEnabled(CatalogType catalog_item) {
        final String catalog_key = CatalogKey.createKey(catalog_item);
        return (this.isDebuggingEnabled(catalog_key));
    }

    /**
     * Returns true if this procedure should be ignored
     *
     * @param catalog_proc
     * @return
     */
    public boolean shouldIgnoreProcedure(Procedure catalog_proc) {
        return (this.ignore_procedures.contains(catalog_proc.getName()));
    }

    // --------------------------------------------------------------------------------------------
    // SERIALIZATION METHODS
    // --------------------------------------------------------------------------------------------

    /**
     * Load with the ability to override values
     */
    public void load(File input_path, Database catalog_db, Map<String, String> override) throws IOException {
        // First call the regular load() method to bring all of our options
        this.load(input_path, catalog_db);

        // Then construct a JSONObject from the map to override the parameters
        if (override.isEmpty() == false) {
            JSONStringer stringer = new JSONStringer();
            try {
                stringer.object();
                for (Entry<String, String> e : override.entrySet()) {
                    stringer.key(e.getKey().toUpperCase()).value(e.getValue());
                } // FOR
                stringer.endObject();
                this.fromJSON(new JSONObject(stringer.toString()), catalog_db);
            } catch (JSONException ex) {
                throw new IOException("Failed to load override parameters: " + override, ex);
            }
        }
    }

    @Override
    public void load(File input_path, Database catalog_db) throws IOException {
        JSONUtil.load(this, catalog_db, input_path);
        this.source_file = input_path;
    }

    @Override
    public void save(File output_path) throws IOException {
        JSONUtil.save(this, output_path);
    }

    @Override
    public String toJSONString() {
        return (JSONUtil.toJSONString(this));
    }

    @Override
    public void toJSON(JSONStringer stringer) throws JSONException {
        JSONUtil.fieldsToJSON(stringer, this, DesignerHints.class, DesignerHints.MEMBERS);
    }

    @Override
    public void fromJSON(JSONObject json_object, Database catalog_db) throws JSONException {
        JSONUtil.fieldsFromJSON(json_object, catalog_db, this, DesignerHints.class, true, DesignerHints.MEMBERS);

        // HACK: Convert negatives to nulls
        if (this.limit_back_tracks != null && this.limit_back_tracks < 0)
            this.limit_back_tracks = null;
        if (this.limit_local_time != null && this.limit_local_time < 0)
            this.limit_local_time = null;
        if (this.limit_total_time != null && this.limit_total_time < 0)
            this.limit_total_time = null;

        // HACK: Process wildcards
        if (this.ignore_procedures.size() > 0) {
            Set<String> to_add = new HashSet<String>();
            for (String proc_name : this.ignore_procedures) {
                if (proc_name.endsWith("*")) {
                    proc_name = proc_name.substring(0, proc_name.length() - 1);
                    for (Procedure catalog_proc : catalog_db.getProcedures()) {
                        if (catalog_proc.getName().startsWith(proc_name))
                            to_add.add(catalog_proc.getName());
                    } // FOR
                } // FOR
            } // FOR
            if (to_add.size() > 0) {
                if (debug.val)
                    LOG.debug("Added ignore procedures: " + to_add);
                this.ignore_procedures.addAll(to_add);
            }
        }
        // HACK: Process wildcards
        if (this.ignore_tables.size() > 0) {
            Set<String> to_add = new HashSet<String>();
            for (String table_name : this.ignore_tables) {
                if (table_name.endsWith("*")) {
                    table_name = table_name.substring(0, table_name.length() - 1);
                    for (Table catalog_tbl : catalog_db.getTables()) {
                        if (catalog_tbl.getName().startsWith(table_name))
                            to_add.add(catalog_tbl.getName());
                    } // FOR
                } // FOR
            } // FOR
            if (to_add.size() > 0) {
                if (debug.val)
                    LOG.debug("Added ignore tables: " + to_add);
                this.ignore_tables.addAll(to_add);
            }
        }

        // Target PartitionPlan
        if (this.target_plan_path != null && this.target_plan_path != null) {
            if (debug.val)
                LOG.debug("Loading in target PartitionPlan from '" + this.target_plan_path + "'");
            this.target_plan = new PartitionPlan();
            try {
                this.target_plan.load(this.target_plan_path, catalog_db);
            } catch (IOException ex) {
                throw new RuntimeException("Failed to load target PartitionPlan '" + this.target_plan_path + "'", ex);
            }
        }
    }

    /**
     * @param args
     */
    public static void main(String[] vargs) throws Exception {
        LoggerUtil.setupLogging();
        // Make an empty DesignerHints and print it out
        DesignerHints hints = new DesignerHints();
        System.out.println(JSONUtil.format(hints.toJSONString()));
    }

}
TOP

Related Classes of edu.brown.designer.DesignerHints

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.