/**
*
*/
package edu.brown.designer.partitioners;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.apache.log4j.Logger;
import org.voltdb.catalog.CatalogType;
import org.voltdb.catalog.Column;
import org.voltdb.catalog.ProcParameter;
import org.voltdb.catalog.Procedure;
import org.voltdb.catalog.Table;
import edu.brown.catalog.special.NullProcParameter;
import edu.brown.catalog.special.ReplicatedColumn;
import edu.brown.designer.AccessGraph;
import edu.brown.designer.Designer;
import edu.brown.designer.DesignerHints;
import edu.brown.designer.DesignerInfo;
import edu.brown.designer.partitioners.plan.PartitionPlan;
import edu.brown.statistics.TableStatistics;
import edu.brown.utils.CollectionUtil;
/**
* @author pavlo
*/
public class RandomPartitioner extends AbstractPartitioner {
protected static final Logger LOG = Logger.getLogger(RandomPartitioner.class);
private final Random rand = new Random(0);
private boolean limit_columns = true;
/**
* Full Constructor
*
* @param designer
* @param info
* @param limit_columns
*/
public RandomPartitioner(Designer designer, DesignerInfo info, boolean limit_columns) {
super(designer, info);
this.setLimitedColumns(limit_columns);
}
/**
* @param designer
* @param info
*/
public RandomPartitioner(Designer designer, DesignerInfo info) {
this(designer, info, true);
}
public void setLimitedColumns(boolean flag) {
LOG.debug("Limit Column Selection: " + (flag ? "ENABLED" : "DISABLED"));
this.limit_columns = flag;
}
/*
* (non-Javadoc)
* @see
* edu.brown.designer.partitioners.AbstractPartitioner#generate(edu.brown
* .designer.DesignerHints)
*/
@Override
public PartitionPlan generate(DesignerHints hints) throws Exception {
Map<CatalogType, CatalogType> pplan_map = new HashMap<CatalogType, CatalogType>();
// Do we need to worry about memory?
boolean calculate_memory = (hints.force_replication_size_limit != null && hints.max_memory_per_partition != 0);
// Generate the list of which columns we will randomly select from for
// each table
Map<Table, List<Column>> table_columns = new HashMap<Table, List<Column>>();
AccessGraph agraph = (this.limit_columns ? this.generateAccessGraph() : null);
for (Table catalog_tbl : info.catalogContext.database.getTables()) {
List<Column> columns = new ArrayList<Column>();
if (this.limit_columns) {
List<Column> column_keys = PartitionerUtil.generateColumnOrder(info, agraph, catalog_tbl, hints, true, false);
assert (!column_keys.isEmpty()) : "No potential partitioning columns selected for " + catalog_tbl;
columns.addAll(column_keys);
} else {
CollectionUtil.addAll(columns, catalog_tbl.getColumns());
}
table_columns.put(catalog_tbl, columns);
} // FOR
// TABLES
final int rounds = 10;
int round = rounds;
while (round >= (-1 * rounds)) {
double total_memory = 0d;
for (Table catalog_tbl : info.catalogContext.database.getTables()) {
TableStatistics ts = info.stats.getTableStatistics(catalog_tbl);
assert (ts != null);
List<Column> columns = table_columns.get(catalog_tbl);
assert (columns != null);
int size = columns.size();
// The way this works is that on each interation the value of
// 'round' is
// decreasing. This means that selecting a table replication
// decreases every round
// until it's at the point where we won't select replication at
// all
int idx = this.rand.nextInt((size * rounds) + (round < 0 ? 0 : round)) / rounds;
Column catalog_col = null;
if (idx == size) {
catalog_col = ReplicatedColumn.get(catalog_tbl);
if (calculate_memory)
total_memory += ts.tuple_size_total;
} else {
catalog_col = columns.get(idx);
if (calculate_memory)
total_memory += ts.tuple_size_total / info.getNumPartitions();
}
pplan_map.put(catalog_tbl, catalog_col);
} // FOR
total_memory = total_memory / (double) hints.max_memory_per_partition;
// If we're not over our memory limit, then quit here
if (total_memory <= 1.0)
break;
LOG.debug("[" + round + "] TotalMemory=" + total_memory);
// Otherwise make it so that we are less likely to select the
// partitioning attribute
// the next go around
round--;
} // WHILE
// PROCEDURES
for (Procedure catalog_proc : info.catalogContext.database.getProcedures()) {
if (catalog_proc.getSystemproc())
continue;
int size = catalog_proc.getParameters().size();
ProcParameter catalog_param = NullProcParameter.singleton(catalog_proc);
if (size > 0) {
int idx = this.rand.nextInt(size);
catalog_param = catalog_proc.getParameters().get(idx);
}
pplan_map.put(catalog_proc, catalog_param);
} // FOR
return (PartitionPlan.createFromMap(pplan_map));
}
}