edu.brown.utils.ArgumentsParser.java Source code

Java tutorial

Introduction

Here is the source code for edu.brown.utils.ArgumentsParser.java

Source

/***************************************************************************
 *   Copyright (C) 2009 by H-Store Project                                 *
 *   Brown University                                                      *
 *   Massachusetts Institute of Technology                                 *
 *   Yale University                                                       *
 *                                                                         *
 *   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.utils;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.text.ParseException;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Pattern;

import org.apache.commons.collections15.map.ListOrderedMap;
import org.apache.log4j.Logger;

import org.voltdb.CatalogContext;
import org.voltdb.VoltType;
import org.voltdb.catalog.*;
import org.voltdb.utils.JarReader;
import org.voltdb.utils.VoltTypeUtil;

import edu.brown.benchmark.AbstractProjectBuilder;
import edu.brown.catalog.CatalogUtil;
import edu.brown.catalog.ClusterConfiguration;
import edu.brown.catalog.FixCatalog;
import edu.brown.costmodel.AbstractCostModel;
import edu.brown.costmodel.SingleSitedCostModel;
import edu.brown.costmodel.TimeIntervalCostModel;
import edu.brown.designer.*;
import edu.brown.designer.indexselectors.*;
import edu.brown.designer.mappers.*;
import edu.brown.designer.partitioners.*;
import edu.brown.designer.partitioners.plan.PartitionPlan;
import edu.brown.hashing.*;
import edu.brown.logging.LoggerUtil;
import edu.brown.mappings.ParameterMappingsSet;
import edu.brown.markov.EstimationThresholds;
import edu.brown.statistics.*;
import edu.brown.workload.*;
import edu.brown.workload.filters.*;
import edu.brown.hstore.conf.HStoreConf;

/**
 * @author pavlo
 */
public class ArgumentsParser {
    protected static final Logger LOG = Logger.getLogger(ArgumentsParser.class);
    static {
        LoggerUtil.setupLogging();
    }

    // HACK
    public static boolean DISABLE_UPDATE_CATALOG = false;

    // --------------------------------------------------------------
    // INPUT PARAMETERS
    // --------------------------------------------------------------

    public static final String PARAM_CATALOG = "catalog";
    public static final String PARAM_CATALOG_JAR = PARAM_CATALOG + ".jar";
    public static final String PARAM_CATALOG_OUTPUT = PARAM_CATALOG + ".output";
    public static final String PARAM_CATALOG_TYPE = PARAM_CATALOG + ".type";
    public static final String PARAM_CATALOG_SCHEMA = PARAM_CATALOG + ".schema";
    public static final String PARAM_CATALOG_LABELS = PARAM_CATALOG + ".labels";
    public static final String PARAM_CATALOG_HOSTS = PARAM_CATALOG + ".hosts";
    public static final String PARAM_CATALOG_NUM_HOSTS = PARAM_CATALOG + ".numhosts";
    public static final String PARAM_CATALOG_HOST_CORES = PARAM_CATALOG + ".hosts.cores";
    public static final String PARAM_CATALOG_HOST_THREADS = PARAM_CATALOG + ".hosts.threads";
    public static final String PARAM_CATALOG_HOST_MEMORY = PARAM_CATALOG + ".hosts.memory";
    public static final String PARAM_CATALOG_PORT = PARAM_CATALOG + ".port";
    public static final String PARAM_CATALOG_PARTITION = PARAM_CATALOG + ".partition";
    public static final String PARAM_CATALOG_SITES_PER_HOST = PARAM_CATALOG + ".hosts.numsites";
    public static final String PARAM_CATALOG_PARTITIONS_PER_SITE = PARAM_CATALOG + ".site.numpartitions";

    public static final String PARAM_CONF = "conf";
    public static final String PARAM_CONF_OUTPUT = PARAM_CONF + ".output";

    public static final String PARAM_WORKLOAD = "workload";
    public static final String PARAM_WORKLOAD_XACT_LIMIT = PARAM_WORKLOAD + ".xactlimit";
    public static final String PARAM_WORKLOAD_XACT_WEIGHTS = PARAM_WORKLOAD + ".xactweights";
    public static final String PARAM_WORKLOAD_XACT_OFFSET = PARAM_WORKLOAD + ".xactoffset";
    public static final String PARAM_WORKLOAD_QUERY_LIMIT = PARAM_WORKLOAD + ".querylimit";
    public static final String PARAM_WORKLOAD_REMOVE_DUPES = PARAM_WORKLOAD + ".removedupes";
    public static final String PARAM_WORKLOAD_PROC_EXCLUDE = PARAM_WORKLOAD + ".procexclude";
    public static final String PARAM_WORKLOAD_PROC_INCLUDE = PARAM_WORKLOAD + ".procinclude";
    public static final String PARAM_WORKLOAD_PROC_SAMPLE = PARAM_WORKLOAD + ".sampling";
    public static final String PARAM_WORKLOAD_PROC_INCLUDE_MULTIPLIER = PARAM_WORKLOAD_PROC_INCLUDE + ".multiplier";
    public static final String PARAM_WORKLOAD_RANDOM_PARTITIONS = PARAM_WORKLOAD + ".randompartitions";
    public static final String PARAM_WORKLOAD_BASE_PARTITIONS = PARAM_WORKLOAD + ".basepartitions";
    public static final String PARAM_WORKLOAD_OUTPUT = PARAM_WORKLOAD + ".output";

    public static final String PARAM_STATS = "stats";
    public static final String PARAM_STATS_OUTPUT = PARAM_STATS + ".output";
    public static final String PARAM_STATS_SCALE_FACTOR = PARAM_STATS + ".scalefactor";

    public static final String PARAM_MAPPINGS = "mappings";
    public static final String PARAM_MAPPINGS_OUTPUT = PARAM_MAPPINGS + ".output";
    public static final String PARAM_MAPPINGS_THRESHOLD = PARAM_MAPPINGS + ".threshold";

    public static final String PARAM_MARKOV = "markov";
    public static final String PARAM_MARKOV_OUTPUT = PARAM_MARKOV + ".output";
    public static final String PARAM_MARKOV_THRESHOLDS = PARAM_MARKOV + ".thresholds";
    public static final String PARAM_MARKOV_THRESHOLDS_VALUE = PARAM_MARKOV + ".thresholds.value";
    public static final String PARAM_MARKOV_THRESHOLDS_OUTPUT = PARAM_MARKOV_THRESHOLDS + ".output";
    public static final String PARAM_MARKOV_PARTITIONS = PARAM_MARKOV + ".partitions";
    public static final String PARAM_MARKOV_TOPK = PARAM_MARKOV + ".topk";
    public static final String PARAM_MARKOV_ROUNDS = PARAM_MARKOV + ".rounds";
    public static final String PARAM_MARKOV_THREADS = PARAM_MARKOV + ".threads";
    public static final String PARAM_MARKOV_SPLIT = PARAM_MARKOV + ".split";
    public static final String PARAM_MARKOV_GLOBAL = PARAM_MARKOV + ".global";
    public static final String PARAM_MARKOV_RECOMPUTE_END = PARAM_MARKOV + ".recompute_end";
    public static final String PARAM_MARKOV_RECOMPUTE_WARMUP = PARAM_MARKOV + ".recompute_warmup";
    public static final String PARAM_MARKOV_SPLIT_TRAINING = PARAM_MARKOV_SPLIT + ".training";
    public static final String PARAM_MARKOV_SPLIT_VALIDATION = PARAM_MARKOV_SPLIT + ".validation";
    public static final String PARAM_MARKOV_SPLIT_TESTING = PARAM_MARKOV_SPLIT + ".testing";

    private static final String PARAM_CONFLICTS = "conflicts";
    public static final String PARAM_CONFLICTS_EXCLUDE_PROCEDURES = PARAM_CONFLICTS + ".exclude_procedures";
    public static final String PARAM_CONFLICTS_EXCLUDE_STATEMENTS = PARAM_CONFLICTS + ".exclude_statements";
    public static final String PARAM_CONFLICTS_FOCUS_PROCEDURE = PARAM_CONFLICTS + ".focus";

    public static final String PARAM_DESIGNER = "designer";
    public static final String PARAM_DESIGNER_PARTITIONER = PARAM_DESIGNER + ".partitioner";
    public static final String PARAM_DESIGNER_MAPPER = PARAM_DESIGNER + ".mapper";
    public static final String PARAM_DESIGNER_INDEXER = PARAM_DESIGNER + ".indexer";
    public static final String PARAM_DESIGNER_THREADS = PARAM_DESIGNER + ".threads";
    public static final String PARAM_DESIGNER_INTERVALS = PARAM_DESIGNER + ".intervals";
    public static final String PARAM_DESIGNER_COSTMODEL = PARAM_DESIGNER + ".costmodel";
    public static final String PARAM_DESIGNER_HINTS = PARAM_DESIGNER + ".hints";
    public static final String PARAM_DESIGNER_HINTS_PREFIX = PARAM_DESIGNER_HINTS + ".";
    public static final String PARAM_DESIGNER_CHECKPOINT = PARAM_DESIGNER + ".checkpoint";

    public static final String PARAM_PARTITION_PLAN = "partitionplan";
    public static final String PARAM_PARTITION_PLAN_OUTPUT = PARAM_PARTITION_PLAN + ".output";
    public static final String PARAM_PARTITION_PLAN_APPLY = PARAM_PARTITION_PLAN + ".apply";
    public static final String PARAM_PARTITION_PLAN_REMOVE_PROCS = PARAM_PARTITION_PLAN + ".removeprocs";
    public static final String PARAM_PARTITION_PLAN_RANDOM_PROCS = PARAM_PARTITION_PLAN + ".randomprocs";
    public static final String PARAM_PARTITION_PLAN_NO_SECONDARY = PARAM_PARTITION_PLAN + ".nosecondary";
    public static final String PARAM_PARTITION_PLAN_IGNORE_MISSING = PARAM_PARTITION_PLAN + ".ignore_missing";

    public static final String PARAM_PARTITION_MAP = "partitionmap";
    public static final String PARAM_PARTITION_MAP_OUTPUT = PARAM_PARTITION_MAP + ".output";

    private static final String PARAM_HASHER = "hasher";
    public static final String PARAM_HASHER_CLASS = PARAM_HASHER + ".class";
    public static final String PARAM_HASHER_PROFILE = PARAM_HASHER + ".profile";
    public static final String PARAM_HASHER_OUTPUT = PARAM_HASHER + ".output";

    private static final String PARAM_TERMINAL = "terminal";
    public static final String PARAM_TERMINAL_CSV = PARAM_TERMINAL + ".csv";
    public static final String PARAM_TERMINAL_HOST = PARAM_TERMINAL + ".host";
    public static final String PARAM_TERMINAL_PORT = PARAM_TERMINAL + ".port";

    private static final String PARAM_SITE = "site";
    public static final String PARAM_SITE_HOST = PARAM_SITE + ".host";
    public static final String PARAM_SITE_PORT = PARAM_SITE + ".port";
    public static final String PARAM_SITE_PARTITION = PARAM_SITE + ".partition";
    public static final String PARAM_SITE_ID = PARAM_SITE + ".id";
    public static final String PARAM_SITE_IGNORE_DTXN = PARAM_SITE + ".ignore_dtxn";
    public static final String PARAM_SITE_STATUS_INTERVAL = PARAM_SITE + ".statusinterval";
    public static final String PARAM_SITE_STATUS_INTERVAL_KILL = PARAM_SITE + ".statusinterval_kill";
    public static final String PARAM_SITE_CLEANUP_INTERVAL = PARAM_SITE + ".cleanup_interval";
    public static final String PARAM_SITE_CLEANUP_TXN_EXPIRE = PARAM_SITE + ".cleanup_txn_expire";
    public static final String PARAM_SITE_ENABLE_PROFILING = PARAM_SITE + ".enable_profiling";
    public static final String PARAM_SITE_MISPREDICT_CRASH = PARAM_SITE + ".mispredict_crash";

    public static final List<String> PARAMS = new ArrayList<String>();
    static {
        for (Field field : ArgumentsParser.class.getDeclaredFields()) {
            try {
                if (field.getName().startsWith("PARAM_")) {
                    ArgumentsParser.PARAMS.add(field.get(null).toString());
                }
            } catch (Exception ex) {
                ex.printStackTrace();
                System.exit(1);
            }
        } // FOR
    }; // STATIC

    /**
     * Parameter Key -> Value
     */
    private final Map<String, String> params = new LinkedHashMap<String, String>();

    private final Map<String, String> conf_params = new LinkedHashMap<String, String>();

    /**
     * "Leftover" Parameters (getopt style)
     */
    private final List<String> opt_params = new ArrayList<String>();

    /**
     * Special Case: Designer Hints Override
     */
    private final Map<String, String> hints_params = new ListOrderedMap<String, String>();

    /**
     * Catalog Attributes
     */
    public CatalogContext catalogContext = null;
    public Catalog catalog = null;
    public Database catalog_db = null;
    public File catalog_path = null;
    public ProjectType catalog_type = null;

    /**
     * Workload Trace Attributes
     */
    public Workload workload = null;
    public File workload_path = null;
    public Long workload_xact_limit = null;
    public Long workload_xact_offset = 0l;
    public Long workload_query_limit = null;
    public final Set<Integer> workload_base_partitions = new HashSet<Integer>();
    public Filter workload_filter = null;

    /**
     * Workload Statistics Attributes
     */
    public WorkloadStatistics stats = null;
    public File stats_path = null;

    /**
     * Transaction Estimation Stuff
     */
    public final ParameterMappingsSet param_mappings = new ParameterMappingsSet();
    public EstimationThresholds thresholds;

    /**
     * Designer Components
     */
    public int max_concurrent = 1;
    public int num_intervals = 100;
    public final DesignerHints designer_hints = new DesignerHints();
    public File designer_checkpoint;
    public Class<? extends AbstractPartitioner> partitioner_class = BranchAndBoundPartitioner.class;
    public Class<? extends AbstractMapper> mapper_class = AffinityMapper.class;
    public Class<? extends AbstractIndexSelector> indexer_class = SimpleIndexSelector.class;
    public PartitionPlan pplan;
    public PartitionMapping pmap;
    public IndexPlan iplan;
    public Class<? extends AbstractCostModel> costmodel_class = SingleSitedCostModel.class;
    public AbstractCostModel costmodel;

    /**
     * Hasher
     */
    public Class<? extends AbstractHasher> hasher_class = DefaultHasher.class;
    public AbstractHasher hasher;

    /**
     * Empty Constructor
     */
    public ArgumentsParser() {
        // Nothing to do
    }

    public List<String> getOptParams() {
        return (this.opt_params);
    }

    public int getOptParamCount() {
        return (this.opt_params.size());
    }

    public String getOptParam(int idx) {
        return (this.opt_params.get(idx));
    }

    @SuppressWarnings("unchecked")
    public <T> T getOptParam(int idx, VoltType vt) {
        assert (idx >= 0);
        String val = (idx < this.opt_params.size() ? this.opt_params.get(idx) : null);
        if (val != null) {
            try {
                return ((T) VoltTypeUtil.getObjectFromString(vt, val));
            } catch (ParseException ex) {
                throw new RuntimeException("Failed to cast optional parameter " + idx + " [value=" + val + "]", ex);
            }
        }
        return (null);
    }

    public Boolean getBooleanOptParam(int idx) {
        return (this.getOptParam(idx, VoltType.BOOLEAN));
    }

    public Byte getByteOptParam(int idx) {
        Object obj = this.getOptParam(idx, VoltType.TINYINT);
        if (obj != null)
            obj = ((Number) obj).byteValue();
        return ((Byte) obj);
    }

    public Short getShortOptParam(int idx) {
        Object obj = this.getOptParam(idx, VoltType.SMALLINT);
        if (obj != null)
            obj = ((Number) obj).shortValue();
        return ((Short) obj);
    }

    public Integer getIntOptParam(int idx) {
        Object obj = this.getOptParam(idx, VoltType.INTEGER);
        if (obj != null)
            obj = ((Number) obj).intValue();
        return ((Integer) obj);
    }

    public Long getLongOptParam(int idx) {
        return (this.getOptParam(idx, VoltType.BIGINT));
    }

    public Double getDoubleOptParam(int idx) {
        return (this.getOptParam(idx, VoltType.DECIMAL));
    }

    public Map<String, String> getParams() {
        return (this.params);
    }

    public String getParam(String key) {
        return (this.params.get(key));
    }

    public Integer getIntParam(String key) {
        String val = this.params.get(key);
        Integer ret = null;
        if (val != null)
            ret = Integer.valueOf(val);
        return (ret);
    }

    public Long getLongParam(String key) {
        String val = this.params.get(key);
        Long ret = null;
        if (val != null)
            ret = Long.valueOf(val);
        return (ret);
    }

    public Double getDoubleParam(String key) {
        String val = this.params.get(key);
        Double ret = null;
        if (val != null)
            ret = Double.valueOf(val);
        return (ret);
    }

    public Boolean getBooleanParam(String key, Boolean defaultValue) {
        String val = this.params.get(key);
        Boolean ret = defaultValue;
        if (val != null)
            ret = Boolean.valueOf(val);
        return (ret);
    }

    public Boolean getBooleanParam(String key) {
        return (this.getBooleanParam(key, null));
    }

    public File getFileParam(String key) {
        String val = this.params.get(key);
        File ret = null;
        if (val != null)
            ret = new File(val);
        return (ret);
    }

    public boolean hasParam(String key) {
        return (this.params.get(key) != null);
    }

    public boolean hasIntParam(String key) {
        if (this.hasParam(key)) {
            try {
                Long val = Long.valueOf(this.params.get(key));
                if (val != null)
                    return (true);
            } catch (NumberFormatException ex) {
                // Nothing...
            }
        }
        return (false);
    }

    public boolean hasDoubleParam(String key) {
        if (this.hasParam(key)) {
            try {
                Double val = Double.valueOf(this.params.get(key));
                if (val != null)
                    return (true);
            } catch (NumberFormatException ex) {
                // Nothing...
            }
        }
        return (false);
    }

    public boolean hasBooleanParam(String key) {
        if (this.hasParam(key)) {
            Boolean val = Boolean.valueOf(this.params.get(key));
            if (val != null)
                return (true);
        }
        return (false);
    }

    public void setDatabase(Database catalog_db) {
        this.catalog_db = catalog_db;
    }

    /**
     * Check whether they have all the parameters they need
     * 
     * @param params
     * @throws IllegalArgumentException
     */
    public void require(String... params) throws IllegalArgumentException {
        for (String param : params) {
            if (!this.hasParam(param)) {
                throw new IllegalArgumentException(
                        "Missing parameter '" + param + "'. Required Parameters = " + Arrays.asList(params));
            }
        } // FOR
        return;
    }

    public Map<String, String> getHStoreConfParameters() {
        return (this.conf_params);
    }

    /**
     * Return an object with the proper objects loaded
     * 
     * @param args
     * @return
     * @throws Exception
     */
    public static ArgumentsParser load(String args[], String... required) throws Exception {
        ArgumentsParser au = new ArgumentsParser();
        au.process(args, required);

        // System.out.println("catalog: " + au.catalog);
        // System.out.println("catalog_db: " + au.catalog_db);
        // System.out.println("workload: " + au.workload);
        // System.out.println("workload.limit: " + au.workload_limit);
        // System.out.println("stats: " + au.stats);

        return (au);
    }

    /**
     * @throws Exception
     */
    private void loadWorkload() throws Exception {
        final boolean debug = LOG.isDebugEnabled();
        // Workload Trace
        if (this.params.containsKey(PARAM_WORKLOAD)) {
            assert (this.catalog_db != null) : "Missing catalog!";
            File path = new File(this.params.get(PARAM_WORKLOAD));

            boolean weightedTxns = this.getBooleanParam(PARAM_WORKLOAD_XACT_WEIGHTS, false);
            if (debug)
                LOG.debug("Use Transaction Weights in Limits: " + weightedTxns);

            // This will prune out duplicate trace records...
            if (params.containsKey(PARAM_WORKLOAD_REMOVE_DUPES)) {
                DuplicateTraceFilter filter = new DuplicateTraceFilter();
                this.workload_filter = (this.workload_filter != null ? filter.attach(this.workload_filter)
                        : filter);
                if (debug)
                    LOG.debug("Attached " + filter.debugImpl());
            }

            // TRANSACTION OFFSET
            if (params.containsKey(PARAM_WORKLOAD_XACT_OFFSET)) {
                this.workload_xact_offset = Long.parseLong(params.get(PARAM_WORKLOAD_XACT_OFFSET));
                ProcedureLimitFilter filter = new ProcedureLimitFilter(-1l, this.workload_xact_offset,
                        weightedTxns);
                // Important! The offset should go in the front!
                this.workload_filter = (this.workload_filter != null ? filter.attach(this.workload_filter)
                        : filter);
                if (debug)
                    LOG.debug("Attached " + filter.debugImpl());
            }

            // BASE PARTITIONS
            if (params.containsKey(PARAM_WORKLOAD_RANDOM_PARTITIONS)
                    || params.containsKey(PARAM_WORKLOAD_BASE_PARTITIONS)) {
                BasePartitionTxnFilter filter = new BasePartitionTxnFilter(
                        new PartitionEstimator(this.catalogContext));

                // FIXED LIST
                if (params.containsKey(PARAM_WORKLOAD_BASE_PARTITIONS)) {
                    for (String p_str : this.getParam(PARAM_WORKLOAD_BASE_PARTITIONS).split(",")) {
                        workload_base_partitions.add(Integer.valueOf(p_str));
                    } // FOR
                      // RANDOM
                } else {
                    double factor = this.getDoubleParam(PARAM_WORKLOAD_RANDOM_PARTITIONS);
                    List<Integer> all_partitions = new ArrayList<Integer>(catalogContext.getAllPartitionIds());
                    Collections.shuffle(all_partitions, new Random());
                    workload_base_partitions
                            .addAll(all_partitions.subList(0, (int) (all_partitions.size() * factor)));
                }
                filter.addPartitions(workload_base_partitions);
                this.workload_filter = (this.workload_filter != null ? this.workload_filter.attach(filter)
                        : filter);
                if (debug)
                    LOG.debug("Attached " + filter.debugImpl());
            }

            // Txn Limit
            this.workload_xact_limit = this.getLongParam(PARAM_WORKLOAD_XACT_LIMIT);
            ObjectHistogram<String> proc_histogram = null;

            // Include/exclude procedures from the traces
            if (params.containsKey(PARAM_WORKLOAD_PROC_INCLUDE)
                    || params.containsKey(PARAM_WORKLOAD_PROC_EXCLUDE)) {
                Filter filter = new ProcedureNameFilter(weightedTxns);

                // INCLUDE
                String temp = params.get(PARAM_WORKLOAD_PROC_INCLUDE);
                if (temp != null && !temp.equals(ProcedureNameFilter.INCLUDE_ALL)) {

                    // We can take the counts for PROC_INCLUDE and scale them
                    // with the multiplier
                    double multiplier = 1.0d;
                    if (this.hasDoubleParam(PARAM_WORKLOAD_PROC_INCLUDE_MULTIPLIER)) {
                        multiplier = this.getDoubleParam(PARAM_WORKLOAD_PROC_INCLUDE_MULTIPLIER);
                        if (debug)
                            LOG.debug("Workload Procedure Multiplier: " + multiplier);
                    }

                    // Default Txn Frequencies
                    String procinclude = params.get(PARAM_WORKLOAD_PROC_INCLUDE);
                    if (procinclude.equalsIgnoreCase("default")) {
                        procinclude = AbstractProjectBuilder.getProjectBuilder(catalog_type)
                                .getTransactionFrequencyString();
                    }

                    Map<String, Integer> limits = new HashMap<String, Integer>();
                    int total_unlimited = 0;
                    int total = 0;
                    for (String proc_name : procinclude.split(",")) {
                        int limit = -1;
                        // Check if there is a limit for this procedure
                        if (proc_name.contains(":")) {
                            String pieces[] = proc_name.split(":");
                            proc_name = pieces[0];
                            limit = (int) Math.round(Integer.parseInt(pieces[1]) * multiplier);
                        }

                        if (limit < 0) {
                            if (proc_histogram == null) {
                                if (debug)
                                    LOG.debug("Generating procedure histogram from workload file");
                                proc_histogram = WorkloadUtil.getProcedureHistogram(path);
                            }
                            limit = (int) proc_histogram.get(proc_name, 0);
                            total_unlimited += limit;
                        } else {
                            total += limit;
                        }
                        limits.put(proc_name, limit);
                    } // FOR
                      // If we have a workload limit and some txns that we want
                      // to get unlimited
                      // records from, then we want to modify the other txns so
                      // that we fill in the "gap"
                    if (this.workload_xact_limit != null && total_unlimited > 0) {
                        int remaining = this.workload_xact_limit.intValue() - total - total_unlimited;
                        if (remaining > 0) {
                            for (Entry<String, Integer> e : limits.entrySet()) {
                                double ratio = e.getValue() / (double) total;
                                e.setValue((int) Math.ceil(e.getValue() + (ratio * remaining)));
                            } // FOR
                        }
                    }

                    ObjectHistogram<String> proc_multiplier_histogram = null;
                    if (debug) {
                        if (proc_histogram != null)
                            LOG.debug("Full Workload Histogram:\n" + proc_histogram);
                        proc_multiplier_histogram = new ObjectHistogram<String>();
                    }
                    total = 0;
                    for (Entry<String, Integer> e : limits.entrySet()) {
                        if (debug)
                            proc_multiplier_histogram.put(e.getKey(), e.getValue());
                        ((ProcedureNameFilter) filter).include(e.getKey(), e.getValue());
                        total += e.getValue();
                    } // FOR
                    if (debug)
                        LOG.debug("Multiplier Histogram [total=" + total + "]:\n" + proc_multiplier_histogram);
                }

                // EXCLUDE
                temp = params.get(PARAM_WORKLOAD_PROC_EXCLUDE);
                if (temp != null) {
                    for (String proc_name : params.get(PARAM_WORKLOAD_PROC_EXCLUDE).split(",")) {
                        ((ProcedureNameFilter) filter).exclude(proc_name);
                    } // FOR
                }

                // Sampling!!
                if (this.getBooleanParam(PARAM_WORKLOAD_PROC_SAMPLE, false)) {
                    if (debug)
                        LOG.debug("Attaching sampling filter");
                    if (proc_histogram == null)
                        proc_histogram = WorkloadUtil.getProcedureHistogram(path);
                    Map<String, Integer> proc_includes = ((ProcedureNameFilter) filter).getProcIncludes();
                    SamplingFilter sampling_filter = new SamplingFilter(proc_includes, proc_histogram);
                    filter = sampling_filter;
                    if (debug)
                        LOG.debug("Workload Procedure Histogram:\n" + proc_histogram);
                }

                // Attach our new filter to the chain (or make it the head if
                // it's the first one)
                this.workload_filter = (this.workload_filter != null ? this.workload_filter.attach(filter)
                        : filter);
                if (debug)
                    LOG.debug("Attached " + filter.debugImpl());
            }

            // TRANSACTION LIMIT
            if (this.workload_xact_limit != null) {
                ProcedureLimitFilter filter = new ProcedureLimitFilter(this.workload_xact_limit, weightedTxns);
                this.workload_filter = (this.workload_filter != null ? this.workload_filter.attach(filter)
                        : filter);
                if (debug)
                    LOG.debug("Attached " + filter.debugImpl());
            }

            // QUERY LIMIT
            if (params.containsKey(PARAM_WORKLOAD_QUERY_LIMIT)) {
                this.workload_query_limit = Long.parseLong(params.get(PARAM_WORKLOAD_QUERY_LIMIT));
                QueryLimitFilter filter = new QueryLimitFilter(this.workload_query_limit);
                this.workload_filter = (this.workload_filter != null ? this.workload_filter.attach(filter)
                        : filter);
            }

            if (this.workload_filter != null && debug)
                LOG.debug("Workload Filters: " + this.workload_filter.toString());
            this.workload = new Workload(this.catalog);
            this.workload.load(path, this.catalog_db, this.workload_filter);
            this.workload_path = path;
            if (this.workload_filter != null)
                this.workload_filter.reset();
        }

        // Workload Statistics
        if (this.catalog_db != null) {
            if (this.params.containsKey(PARAM_STATS)) {
                this.stats = new WorkloadStatistics(this.catalog_db);
                String path = this.params.get(PARAM_STATS);
                if (debug)
                    LOG.debug("Loading in workload statistics from '" + path + "'");
                this.stats_path = new File(path);
                try {
                    this.stats.load(this.stats_path, this.catalog_db);
                } catch (Throwable ex) {
                    throw new RuntimeException("Failed to load stats file '" + this.stats_path + "'", ex);
                }
            }

            // Scaling
            if (this.params.containsKey(PARAM_STATS_SCALE_FACTOR) && this.stats != null) {
                double scale_factor = this.getDoubleParam(PARAM_STATS_SCALE_FACTOR);
                LOG.info("Scaling TableStatistics: " + scale_factor);
                AbstractTableStatisticsGenerator generator = AbstractTableStatisticsGenerator
                        .factory(this.catalog_db, this.catalog_type, scale_factor);
                generator.apply(this.stats);
            }
        }
    }

    public void updateCatalog(Catalog catalog, File catalog_path) {
        this.catalog = catalog;
        this.catalogContext = new CatalogContext(catalog, catalog_path);
        this.catalog_db = CatalogUtil.getDatabase(catalog);
        if (catalog_path != null)
            this.catalog_path = catalog_path;
    }

    /**
     * @param args
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    public void process(String[] args, String... required) throws Exception {
        final boolean debug = LOG.isDebugEnabled();

        if (debug)
            LOG.debug("Processing " + args.length + " parameters...");
        final Pattern p = Pattern.compile("=");
        for (int i = 0, cnt = args.length; i < cnt; i++) {
            final String arg = args[i];
            final String[] parts = p.split(arg, 2);
            if (parts[0].startsWith("-"))
                parts[0] = parts[0].substring(1);

            if (parts.length == 1) {
                if (parts[0].startsWith("${") == false)
                    this.opt_params.add(parts[0]);
                continue;
            } else if (parts[0].equalsIgnoreCase("tag")) {
                continue;
            } else if (parts[1].startsWith("${") || parts[0].startsWith("#")) {
                continue;
            }
            if (debug)
                LOG.debug(String.format("%-35s = %s", parts[0], parts[1]));

            // DesignerHints Override
            if (parts[0].startsWith(PARAM_DESIGNER_HINTS_PREFIX)) {
                String param = parts[0].replace(PARAM_DESIGNER_HINTS_PREFIX, "").toLowerCase();
                try {
                    Field f = DesignerHints.class.getField(param);
                    this.hints_params.put(f.getName(), parts[1]);
                    if (debug)
                        LOG.debug(String.format("DesignerHints.%s = %s", param, parts[1]));
                } catch (NoSuchFieldException ex) {
                    throw new Exception("Unknown DesignerHints parameter: " + param, ex);
                }

            }
            // HStoreConf Parameter
            else if (HStoreConf.isConfParameter(parts[0])) {
                this.conf_params.put(parts[0].toLowerCase(), parts[1]);
            }
            // ArgumentsParser Parameter
            else if (PARAMS.contains(parts[0].toLowerCase())) {
                this.params.put(parts[0].toLowerCase(), parts[1]);
            }
            // Invalid!
            else {
                String suggestions = "";
                i = 0;
                String end = CollectionUtil.last(parts[0].split("\\."));
                for (String param : PARAMS) {
                    String param_end = CollectionUtil.last(param.split("\\."));
                    if (param.startsWith(parts[0]) || (end != null && param.endsWith(end))
                            || (end != null && param_end != null && param_end.startsWith(end))) {
                        if (suggestions.isEmpty())
                            suggestions = ". Possible Matches:";
                        suggestions += String.format("\n [%02d] %s", ++i, param);
                    }
                } // FOR
                throw new Exception("Unknown parameter '" + parts[0] + "'" + suggestions);
            }
        } // FOR

        // -------------------------------------------------------
        // CATALOGS
        // -------------------------------------------------------

        // Text File
        if (this.params.containsKey(PARAM_CATALOG)) {
            String path = this.params.get(PARAM_CATALOG);
            if (debug)
                LOG.debug("Loading catalog from file '" + path + "'");
            Catalog catalog = CatalogUtil.loadCatalog(path);
            if (catalog == null)
                throw new Exception("Failed to load catalog object from file '" + path + "'");
            this.updateCatalog(catalog, new File(path));
        }
        // Jar File
        else if (this.params.containsKey(PARAM_CATALOG_JAR)) {
            String path = this.params.get(PARAM_CATALOG_JAR);
            this.params.put(PARAM_CATALOG, path);
            File jar_file = new File(path);
            Catalog catalog = CatalogUtil.loadCatalogFromJar(path);
            if (catalog == null)
                throw new Exception("Failed to load catalog object from jar file '" + path + "'");
            if (debug)
                LOG.debug("Loaded catalog from jar file '" + path + "'");
            this.updateCatalog(catalog, jar_file);

            if (!this.params.containsKey(PARAM_CATALOG_TYPE)) {
                String jar_name = jar_file.getName();
                int jar_idx = jar_name.lastIndexOf(".jar");
                if (jar_idx != -1) {
                    ProjectType type = ProjectType.get(jar_name.substring(0, jar_idx));
                    if (type != null) {
                        if (debug)
                            LOG.debug("Set catalog type '" + type + "' from catalog jar file name");
                        this.catalog_type = type;
                        this.params.put(PARAM_CATALOG_TYPE, this.catalog_type.toString());
                    }
                }
            }

            // HACK: Extract the ParameterMappings embedded in jar and write them to a temp file
            // This is terrible, confusing, and a total mess...
            // I have no one to blame but myself...
            JarReader reader = new JarReader(jar_file.getAbsolutePath());
            for (String file : reader.getContentsFromJarfile()) {
                if (file.endsWith(".mappings")) {
                    String contents = new String(JarReader.readFileFromJarAtURL(jar_file.getAbsolutePath(), file));
                    File copy = FileUtil.writeStringToTempFile(contents, "mappings", true);
                    this.params.put(PARAM_MAPPINGS, copy.toString());
                    break;
                }
            } // FOR
        }
        // Schema File
        else if (this.params.containsKey(PARAM_CATALOG_SCHEMA)) {
            String path = this.params.get(PARAM_CATALOG_SCHEMA);
            Catalog catalog = CompilerUtil.compileCatalog(path);
            if (catalog == null)
                throw new Exception("Failed to load schema from '" + path + "'");
            if (debug)
                LOG.debug("Loaded catalog from schema file '" + path + "'");
            this.updateCatalog(catalog, new File(path));
        }

        // Catalog Type
        if (this.params.containsKey(PARAM_CATALOG_TYPE)) {
            String catalog_type = this.params.get(PARAM_CATALOG_TYPE);
            ProjectType type = ProjectType.get(catalog_type);
            if (type == null) {
                throw new Exception("Unknown catalog type '" + catalog_type + "'");
            }
            this.catalog_type = type;
        }

        // Update Cluster Configuration
        if (this.params.containsKey(ArgumentsParser.PARAM_CATALOG_HOSTS) && DISABLE_UPDATE_CATALOG == false) {
            ClusterConfiguration cc = new ClusterConfiguration(this.getParam(ArgumentsParser.PARAM_CATALOG_HOSTS));
            this.updateCatalog(FixCatalog.cloneCatalog(this.catalog, cc), null);
        }

        // Check the requirements after loading the catalog, because some of the
        // above parameters will set the catalog one
        if (required != null && required.length > 0)
            this.require(required);

        // -------------------------------------------------------
        // PHYSICAL DESIGN COMPONENTS
        // -------------------------------------------------------
        if (this.params.containsKey(PARAM_PARTITION_PLAN)) {
            assert (this.catalog_db != null);
            File path = new File(this.params.get(PARAM_PARTITION_PLAN));
            boolean ignoreMissing = this.getBooleanParam(ArgumentsParser.PARAM_PARTITION_PLAN_IGNORE_MISSING,
                    false);
            if (path.exists() || (path.exists() == false && ignoreMissing == false)) {
                if (debug)
                    LOG.debug("Loading in partition plan from '" + path + "'");
                this.pplan = new PartitionPlan();
                this.pplan.load(path, this.catalog_db);

                // Apply!
                if (this.params.containsKey(PARAM_PARTITION_PLAN_APPLY)
                        && this.getBooleanParam(PARAM_PARTITION_PLAN_APPLY)) {
                    boolean secondaryIndexes = this.getBooleanParam(PARAM_PARTITION_PLAN_NO_SECONDARY,
                            false) == false;
                    LOG.info(String.format("Applying PartitionPlan '%s' to catalog [enableSecondaryIndexes=%s]",
                            path.getName(), secondaryIndexes));
                    this.pplan.apply(this.catalog_db, secondaryIndexes);
                }
            }
        }

        // -------------------------------------------------------
        // DESIGNER COMPONENTS
        // -------------------------------------------------------

        if (this.params.containsKey(PARAM_DESIGNER_THREADS)) {
            this.max_concurrent = Integer.valueOf(this.params.get(PARAM_DESIGNER_THREADS));
        }
        if (this.params.containsKey(PARAM_DESIGNER_INTERVALS)) {
            this.num_intervals = Integer.valueOf(this.params.get(PARAM_DESIGNER_INTERVALS));
        }
        if (this.params.containsKey(PARAM_DESIGNER_HINTS)) {
            File path = this.getFileParam(PARAM_DESIGNER_HINTS);
            if (debug)
                LOG.debug("Loading in designer hints from '" + path + "'.\nForced Values:\n"
                        + StringUtil.formatMaps(this.hints_params));
            this.designer_hints.load(path, catalog_db, this.hints_params);
        }
        if (this.params.containsKey(PARAM_DESIGNER_CHECKPOINT)) {
            this.designer_checkpoint = new File(this.params.get(PARAM_DESIGNER_CHECKPOINT));
        }

        String designer_attributes[] = { PARAM_DESIGNER_PARTITIONER, PARAM_DESIGNER_MAPPER, PARAM_DESIGNER_INDEXER,
                PARAM_DESIGNER_COSTMODEL };
        ClassLoader loader = ClassLoader.getSystemClassLoader();
        for (String key : designer_attributes) {
            if (this.params.containsKey(key)) {
                String target_name = this.params.get(key);
                Class<?> target_class = loader.loadClass(target_name);
                assert (target_class != null);
                if (debug)
                    LOG.debug("Set " + key + " class to " + target_class.getName());

                if (key.equals(PARAM_DESIGNER_PARTITIONER)) {
                    this.partitioner_class = (Class<? extends AbstractPartitioner>) target_class;
                } else if (key.equals(PARAM_DESIGNER_MAPPER)) {
                    this.mapper_class = (Class<? extends AbstractMapper>) target_class;
                } else if (key.equals(PARAM_DESIGNER_INDEXER)) {
                    this.indexer_class = (Class<? extends AbstractIndexSelector>) target_class;
                } else if (key.equals(PARAM_DESIGNER_COSTMODEL)) {
                    this.costmodel_class = (Class<? extends AbstractCostModel>) target_class;

                    // Special Case: TimeIntervalCostModel
                    if (target_name.endsWith(TimeIntervalCostModel.class.getSimpleName())) {
                        this.costmodel = new TimeIntervalCostModel<SingleSitedCostModel>(this.catalogContext,
                                SingleSitedCostModel.class, this.num_intervals);
                    } else {
                        this.costmodel = ClassUtil.newInstance(this.costmodel_class,
                                new Object[] { this.catalogContext }, new Class[] { Database.class });
                    }
                } else {
                    assert (false) : "Invalid key '" + key + "'";
                }
            }
        } // FOR

        // -------------------------------------------------------
        // TRANSACTION ESTIMATION COMPONENTS
        // -------------------------------------------------------
        if (this.params.containsKey(PARAM_MAPPINGS) && DISABLE_UPDATE_CATALOG == false) {
            assert (this.catalog_db != null);
            File path = new File(this.params.get(PARAM_MAPPINGS));
            if (path.exists()) {
                this.param_mappings.load(path, this.catalog_db);
            } else {
                LOG.warn("The ParameterMappings file '" + path + "' does not exist");
            }
        }
        if (this.params.containsKey(PARAM_MARKOV_THRESHOLDS_VALUE)) {
            assert (this.catalog_db != null);
            float defaultValue = this.getDoubleParam(PARAM_MARKOV_THRESHOLDS_VALUE).floatValue();
            this.thresholds = new EstimationThresholds(defaultValue);
            this.params.put(PARAM_MARKOV_THRESHOLDS, this.thresholds.toString());
            LOG.debug("CREATED THRESHOLDS: " + this.thresholds);

        } else if (this.params.containsKey(PARAM_MARKOV_THRESHOLDS)) {
            assert (this.catalog_db != null);
            this.thresholds = new EstimationThresholds();
            File path = new File(this.params.get(PARAM_MARKOV_THRESHOLDS));
            if (path.exists()) {
                this.thresholds.load(path, this.catalog_db);
            } else {
                LOG.warn("The estimation thresholds file '" + path + "' does not exist");
            }
            LOG.debug("LOADED THRESHOLDS: " + this.thresholds);
        }

        // -------------------------------------------------------
        // HASHER
        // -------------------------------------------------------
        if (this.catalog != null) {
            if (this.params.containsKey(PARAM_HASHER_CLASS)) {
                String hasherClassName = this.params.get(PARAM_HASHER_CLASS);
                this.hasher_class = (Class<? extends AbstractHasher>) loader.loadClass(hasherClassName);
            }
            Class<?> paramClasses[] = new Class[] { CatalogContext.class, int.class };
            Object paramValues[] = new Object[] { this.catalogContext, this.catalogContext.numberOfPartitions };

            Constructor<? extends AbstractHasher> constructor = this.hasher_class.getConstructor(paramClasses);
            this.hasher = constructor.newInstance(paramValues);

            if (!(this.hasher instanceof DefaultHasher))
                LOG.debug("Loaded hasher " + this.hasher.getClass());

            if (this.params.containsKey(PARAM_HASHER_PROFILE)) {
                this.hasher.load(this.getFileParam(PARAM_HASHER_PROFILE), null);
            }
        }

        // -------------------------------------------------------
        // SAMPLE WORKLOAD TRACE
        // -------------------------------------------------------
        this.loadWorkload();
    }

    @Override
    public String toString() {
        Map<String, Object> m0 = new ListOrderedMap<String, Object>();
        m0.putAll(this.params);

        Map<String, Object> m1 = null;
        int opt_cnt = this.opt_params.size();
        if (opt_cnt > 0) {
            Map<String, Object> opt_inner = new ListOrderedMap<String, Object>();
            for (int i = 0; i < opt_cnt; i++) {
                opt_inner.put(String.format("#%02d", i), this.opt_params.get(i));
            }
            m1 = new ListOrderedMap<String, Object>();
            m1.put(String.format("Optional Parameters [%d]", opt_cnt), StringUtil.formatMaps(opt_inner));
        }

        return StringUtil.formatMaps(m0, m1);
    }
}