package edu.brown.designer;
import java.io.File;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import org.voltdb.catalog.Database;
import org.voltdb.catalog.Procedure;
import edu.brown.catalog.ClusterConfiguration;
import edu.brown.catalog.FixCatalog;
import edu.brown.designer.generators.AccessGraphGenerator;
import edu.brown.designer.generators.PartitionPlanTreeGenerator;
import edu.brown.designer.indexselectors.AbstractIndexSelector;
import edu.brown.designer.mappers.AbstractMapper;
import edu.brown.designer.mappers.PartitionMapping;
import edu.brown.designer.partitioners.AbstractPartitioner;
import edu.brown.designer.partitioners.RandomPartitioner;
import edu.brown.designer.partitioners.plan.PartitionPlan;
import edu.brown.graphs.IGraph;
import edu.brown.hstore.conf.HStoreConf;
import edu.brown.utils.ArgumentsParser;
import edu.brown.workload.Workload;
public class Designer {
private static final Logger LOG = Logger.getLogger(Designer.class.getName());
// ----------------------------------------------------
// DESIGNER INFORMATION
// ----------------------------------------------------
protected final DesignerInfo info;
protected final DesignerHints hints;
protected final ArgumentsParser args;
protected PhysicalDesign design;
protected PartitionTree final_graph;
protected final Map<Procedure, AccessGraph> proc_access_graphs = new HashMap<Procedure, AccessGraph>();
protected final Map<Procedure, Set<IGraph<DesignerVertex, DesignerEdge>>> proc_graphs = new HashMap<Procedure, Set<IGraph<DesignerVertex, DesignerEdge>>>();
// ----------------------------------------------------
// PARTITIONING
// ----------------------------------------------------
protected final AbstractPartitioner partitioner;
protected PartitionPlan pplan;
// ----------------------------------------------------
// MAPPING
// ----------------------------------------------------
protected final AbstractMapper mapper;
protected PartitionMapping pmap;
// ----------------------------------------------------
// INDEX SELECTION
// ----------------------------------------------------
protected final AbstractIndexSelector indexer;
protected IndexPlan iplan;
/**
* Constructor
*/
public Designer(DesignerInfo info, DesignerHints hints, ArgumentsParser args) throws Exception {
this.info = info;
this.hints = hints;
this.args = args;
// Partitioner
assert (info.partitioner_class != null);
Constructor<? extends AbstractPartitioner> partitionerConstructor = info.partitioner_class.getConstructor(new Class[] { Designer.class, DesignerInfo.class });
assert (partitionerConstructor != null);
this.partitioner = partitionerConstructor.newInstance(new Object[] { this, this.info });
if (this.args.pplan != null)
this.pplan = this.args.pplan;
// Mapper
assert (info.mapper_class != null);
Constructor<? extends AbstractMapper> mapperConstructor = info.mapper_class.getConstructor(new Class[] { Designer.class, DesignerInfo.class });
assert (mapperConstructor != null);
this.mapper = mapperConstructor.newInstance(new Object[] { this, this.info });
if (this.args.pmap != null)
this.pmap = this.args.pmap;
// Indexer
assert (info.indexer_class != null);
Constructor<? extends AbstractIndexSelector> indexerConstructor = info.indexer_class.getConstructor(new Class[] { Designer.class, DesignerInfo.class });
assert (indexerConstructor != null);
this.indexer = indexerConstructor.newInstance(new Object[] { this, this.info });
if (this.args.iplan != null)
this.iplan = this.args.iplan;
// Initialize stuff!
this.init();
}
/**
*
*/
private void init() throws Exception {
//
// Step 1: Workload Analysis
//
for (Procedure catalog_proc : info.catalogContext.database.getProcedures()) {
if (catalog_proc.getSystemproc())
continue;
if ((!this.hints.proc_include.isEmpty() && !this.hints.proc_include.contains(catalog_proc.getName())) || this.hints.proc_exclude.contains(catalog_proc.getName())) {
LOG.debug("Skipping " + catalog_proc);
continue;
}
// Generate a new AccessGraph for this Procedure
LOG.debug("Generating AccessGraph for " + catalog_proc);
AccessGraph agraph = new AccessGraph(info.catalogContext.database);
new AccessGraphGenerator(info, catalog_proc).generate(agraph);
if (agraph.getVertexCount() == 0) {
if (LOG.isDebugEnabled())
LOG.warn("The workload analyzer created an AccessGraph for " + catalog_proc + " with no vertices. Skipping...");
continue;
}
this.proc_access_graphs.put(catalog_proc, agraph);
this.proc_graphs.put(catalog_proc, new LinkedHashSet<IGraph<DesignerVertex, DesignerEdge>>());
this.proc_graphs.get(catalog_proc).add(agraph);
} // FOR
}
public AbstractPartitioner getPartitioner() {
return this.partitioner;
}
public AbstractMapper getMapper() {
return this.mapper;
}
public AbstractIndexSelector getIndexer() {
return this.indexer;
}
public DesignerInfo getDesignerInfo() {
return (this.info);
}
public Set<Procedure> getProcedures() {
return (this.proc_access_graphs.keySet());
}
public DependencyGraph getDependencyGraph() {
return (this.info.dgraph);
}
// public PartitionTree getPartitionTree() {
// return (this.pplan.getPartitionTree());
// }
public AccessGraph getAccessGraph(Procedure catalog_proc) {
return (this.proc_access_graphs.get(catalog_proc));
}
public Set<IGraph<DesignerVertex, DesignerEdge>> getGraphs(Procedure catalog_proc) {
return (this.proc_graphs.get(catalog_proc));
}
public IGraph<DesignerVertex, DesignerEdge> getFinalGraph() {
return (this.final_graph);
}
public Database getDatabase() {
return this.info.catalogContext.database;
}
public Workload getWorkload() {
return this.info.workload;
}
public PartitionPlan getPartitionPlan() {
return (this.pplan);
}
public void apply() throws Exception {
//
// Apply the mapping and check whether we are single-sited
//
/*
* Catalog catalog = this.design.createCatalog();
* System.out.println("============================================");
* Database catalog_db = CatalogUtil.getDatabase(catalog); for (Table
* catalog_tbl : catalog_db.getTables()) {
* System.out.println(catalog_tbl); Map<String, Object> fields = new
* HashMap<String, Object>(); fields.put("isreplicated",
* catalog_tbl.getIsreplicated()); fields.put("partitioncolumn",
* catalog_tbl.getPartitioncolumn()); for (String field :
* fields.keySet()) { System.out.println(" " + field + ": " +
* fields.get(field)); } System.out.println(); }
*/
}
/**
*
*/
public PhysicalDesign process() throws Exception {
//
// Step 2: Table Partitioner
//
if (this.pplan == null) {
if (this.hints.start_random) {
LOG.debug("Randomizing the catalog partitioning attributes");
PartitionPlan random_pplan = new RandomPartitioner(this, this.info, false).generate(this.hints);
random_pplan.apply(this.info.catalogContext.database);
LOG.debug("Randomized Catalog:\n" + random_pplan);
}
LOG.debug("Creating partition plan using " + this.partitioner.getClass().getSimpleName());
this.pplan = this.partitioner.generate(this.hints);
if (this.args.hasParam(ArgumentsParser.PARAM_PARTITION_PLAN_OUTPUT)) {
File path = this.args.getFileParam(ArgumentsParser.PARAM_PARTITION_PLAN_OUTPUT);
this.pplan.save(path);
LOG.info("Saved generated PartitionPlan to '" + path.getName() + "'");
}
}
LOG.info("Partition Plan:\n" + this.pplan.toString());
this.design = new PhysicalDesign(info.catalogContext.database);
this.design.plan = this.pplan;
this.final_graph = new PartitionTree(this.info.catalogContext.database);
new PartitionPlanTreeGenerator(this.info, this.pplan).generate(this.final_graph);
// System.out.println(this.plan);
// System.exit(1);
//
// Step 3: Partition Placement/Mapper
//
if (false && this.pmap == null) {
LOG.info("Creating partition mapping using " + this.mapper.getClass().getSimpleName());
this.pmap = this.mapper.generate(this.hints, this.pplan);
System.out.println(this.pmap);
}
//
// Step 4: Index Selector
//
return (this.design);
}
/**
* @param args
*/
public static void main(String[] vargs) throws Exception {
ArgumentsParser args = ArgumentsParser.load(vargs);
args.require(ArgumentsParser.PARAM_CATALOG,
ArgumentsParser.PARAM_WORKLOAD,
ArgumentsParser.PARAM_STATS,
ArgumentsParser.PARAM_MAPPINGS
);
HStoreConf.initArgumentsParser(args);
System.err.println("TEMP DIR: " + HStoreConf.singleton().global.temp_dir);
if (args.hasParam(ArgumentsParser.PARAM_CATALOG_HOSTS)) {
ClusterConfiguration cc = new ClusterConfiguration(args.getParam(ArgumentsParser.PARAM_CATALOG_HOSTS));
args.updateCatalog(FixCatalog.cloneCatalog(args.catalog, cc), null);
}
// Create the container object that will hold all the information that
// the designer will need to use
DesignerInfo info = new DesignerInfo(args);
DesignerHints hints = args.designer_hints;
long start = System.currentTimeMillis();
// System.out.println("WHITELIST: " + hints.proc_include);
Designer designer = new Designer(info, hints, args);
PhysicalDesign design = designer.process();
LOG.info("STOP: " + (System.currentTimeMillis() - start) / 1000d);
// if (args.hasParam(ArgumentsParser.PARAM_PARTITION_PLAN_OUTPUT)) {
// String output =
// args.getParam(ArgumentsParser.PARAM_PARTITION_PLAN_OUTPUT);
// LOG.info("Saving PartitionPlan to '" + output + "'");
// PartitionPlan pplan = design.plan;
// pplan.save(output);
// }
// int total = 0;
// int singlesited = 0;
// SingleSitedCostModel cmodel = new
// SingleSitedCostModel(design.catalog_db);
// for (AbstractTraceElement element : info.workload) {
// if (element instanceof TransactionTrace) {
// TransactionTrace xact = (TransactionTrace)element;
// total++;
// SingleSitedCostModel.CostEstimate estimate =
// cmodel.isSingleSited(design.catalog_db, xact, null);
// if (estimate.singlesited_xact) singlesited++;
// }
// } // FOR
// System.out.println("SINGLE-SITED: " + singlesited + "/" + total);
// design.apply(catalog);
// Let's try to recompile this mofo!
// VoltCompiler compiler = new VoltCompiler(null,
// BackendTarget.HSQLDB_BACKEND, 1, 1, "localhost", System.out);
// compiler.recompile(jar_path, catalog);
// System.out.println(catalog.serialize());
// System.out.println(graph.toString(true));
// System.out.println(graph.toString(true));
}
}