package edu.brown.catalog;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.voltdb.benchmark.tpcc.procedures.neworder;
import org.voltdb.catalog.Catalog;
import org.voltdb.catalog.CatalogMap;
import org.voltdb.catalog.CatalogType;
import org.voltdb.catalog.Cluster;
import org.voltdb.catalog.Column;
import org.voltdb.catalog.ColumnRef;
import org.voltdb.catalog.ConflictPair;
import org.voltdb.catalog.ConflictSet;
import org.voltdb.catalog.ConstraintRef;
import org.voltdb.catalog.Database;
import org.voltdb.catalog.Host;
import org.voltdb.catalog.MaterializedViewInfo;
import org.voltdb.catalog.ProcParameter;
import org.voltdb.catalog.Procedure;
import org.voltdb.catalog.Site;
import org.voltdb.catalog.Table;
import org.voltdb.catalog.TableRef;
import org.voltdb.compiler.VoltCompiler;
import edu.brown.BaseTestCase;
import edu.brown.catalog.special.MultiColumn;
import edu.brown.catalog.special.MultiProcParameter;
import edu.brown.utils.ClassUtil;
import edu.brown.utils.ProjectType;
public class TestCatalogCloner extends BaseTestCase {
private static final int NUM_PARTITIONS = 6;
/**
* ClassName.FieldName
*/
protected final Set<String> CHECK_FIELDS_EXCLUDE = new HashSet<String>();
{
CHECK_FIELDS_EXCLUDE.add("Cluster.hosts");
CHECK_FIELDS_EXCLUDE.add("Cluster.sites");
CHECK_FIELDS_EXCLUDE.add("Cluster.partitions");
CHECK_FIELDS_EXCLUDE.add("Database.users");
CHECK_FIELDS_EXCLUDE.add("Database.groups");
CHECK_FIELDS_EXCLUDE.add("Procedure.procparameter");
CHECK_FIELDS_EXCLUDE.add("Procedure.partitioncolumn");
// CHECK_FIELDS_EXCLUDE.add("Statement.fullplan");
// CHECK_FIELDS_EXCLUDE.add("PlanFragment.plannodetree");
};
protected final String VERTICAL_PARTITION_TABLE = "CUSTOMER";
protected final List<String> VERTICAL_PARTITION_COLUMNS = new ArrayList<String>();
{
VERTICAL_PARTITION_COLUMNS.add("C_ID");
VERTICAL_PARTITION_COLUMNS.add("C_FIRST");
VERTICAL_PARTITION_COLUMNS.add("C_LAST");
}
@Override
protected void setUp() throws Exception {
super.setUp(ProjectType.TPCC);
if (isFirstSetup()) {
this.addPartitions(NUM_PARTITIONS);
VoltCompiler.addVerticalPartition(catalog_db, VERTICAL_PARTITION_TABLE, VERTICAL_PARTITION_COLUMNS, true);
}
}
/**
* Recursively walkthrough the catalog and make sure that all the fields
* match between the two items
*
* @param <T>
* @param base_class
* @param item0
* @param item1
* @throws Exception
*/
protected <T extends CatalogType> void checkFields(Class<T> base_class, CatalogType item0, CatalogType item1) throws Exception {
String base_name = base_class.getSimpleName();
boolean debug = false;
assertNotNull("Null item for " + base_name, item0);
assertNotNull("Null item for " + base_name, item1);
if (debug)
System.err.println(CatalogUtil.getDisplayName(item0, true));
for (Method method_handle : base_class.getDeclaredMethods()) {
String method_name = method_handle.getName();
if (!method_name.startsWith("get"))
continue;
String field_name = base_name + "." + method_name.substring(3).toLowerCase();
if (debug)
System.err.print(" " + field_name + ": ");
if (CHECK_FIELDS_EXCLUDE.contains(field_name)) {
if (debug)
System.err.println("SKIP");
continue;
}
Object field_val0 = method_handle.invoke(item0);
Object field_val1 = method_handle.invoke(item1);
// CatalogMap
if (field_val0 instanceof CatalogMap) {
assert (field_val1 instanceof CatalogMap);
CatalogMap<?> map0 = (CatalogMap<?>) field_val0;
CatalogMap<?> map1 = (CatalogMap<?>) field_val1;
if (debug)
System.err.println(CatalogUtil.debug(map0) + " <-> " + CatalogUtil.debug(map1));
assertEquals("Mismatched CatalogMap sizes for " + field_name, map0.size(), map1.size());
Class<? extends CatalogType> generic_class = (Class<? extends CatalogType>) map0.getGenericClass();
assert (generic_class != null);
CatalogType map0_values[] = map0.values();
CatalogType map1_values[] = map0.values();
for (int i = 0, cnt = map0.size(); i < cnt; i++) {
CatalogType child0 = map0_values[i];
assertNotNull("Null child element at index " + i + " for " + field_name, child0);
CatalogType child1 = map1_values[i];
assertNotNull("Null child element at index " + i + " for " + field_name, child1);
this.checkFields(generic_class, child0, child1);
} // FOR
}
// ConstraintRefs
else if (field_val0 instanceof ConstraintRef) {
ConstraintRef ref0 = (ConstraintRef) field_val0;
ConstraintRef ref1 = (ConstraintRef) field_val1;
if (debug)
System.err.println(CatalogUtil.getDisplayName(ref0) + " <-> " + CatalogUtil.getDisplayName(ref1));
this.checkFields(Column.class, ref0.getConstraint(), ref1.getConstraint());
}
// TableRefs
else if (field_val0 instanceof TableRef) {
TableRef ref0 = (TableRef) field_val0;
TableRef ref1 = (TableRef) field_val1;
if (debug)
System.err.println(CatalogUtil.getDisplayName(ref0) + " <-> " + CatalogUtil.getDisplayName(ref1));
this.checkFields(Table.class, ref0.getTable(), ref1.getTable());
}
// ColumnRefs
else if (field_val0 instanceof ColumnRef) {
ColumnRef ref0 = (ColumnRef) field_val0;
ColumnRef ref1 = (ColumnRef) field_val1;
if (debug)
System.err.println(CatalogUtil.getDisplayName(ref0) + " <-> " + CatalogUtil.getDisplayName(ref1));
this.checkFields(Column.class, ref0.getColumn(), ref1.getColumn());
}
// CatalogMap
else if (field_val0 != null && ClassUtil.getSuperClasses(field_val0.getClass()).contains(CatalogType.class)) {
CatalogType type0 = (CatalogType) field_val0;
CatalogType type1 = (CatalogType) field_val1;
if (debug)
System.err.println(CatalogUtil.getDisplayName(type0) + " <-> " + CatalogUtil.getDisplayName(type1));
assertEquals("Mismatched values for " + field_name, type0.getName(), type1.getName());
}
// Scalar
else {
if (debug)
System.err.println(field_val0 + " <-> " + field_val1);
assertEquals("Mismatched values for " + field_name, field_val0, field_val1);
}
} // FOR (field)
}
private void checkProcedureConflicts(Procedure catalog_proc, CatalogMap<ConflictSet> conflicts0, CatalogMap<ConflictSet> conflicts1) {
assertEquals(catalog_proc.toString(), conflicts0.size(), conflicts1.size());
for (String procName : conflicts0.keySet()) {
assertNotNull(procName);
ConflictSet cs0 = conflicts0.get(procName);
assertNotNull(cs0);
ConflictSet cs1 = conflicts1.get(procName);
assertNotNull(cs1);
assertEquals(cs0.getReadwriteconflicts().size(), cs1.getReadwriteconflicts().size());
for (ConflictPair conflict0 : cs0.getReadwriteconflicts()) {
ConflictPair conflict1 = cs1.getReadwriteconflicts().get(conflict0.getName());
assertNotNull(conflict0.fullName(), conflict1);
assertEquals(conflict0.fullName(), conflict0.getStatement0().getName(), conflict1.getStatement0().getName());
assertEquals(conflict0.fullName(), conflict0.getStatement1().getName(), conflict1.getStatement1().getName());
assertEquals(conflict0.fullName(), conflict0.getAlwaysconflicting(), conflict1.getAlwaysconflicting());
assertEquals(conflict0.fullName(), conflict0.getConflicttype(), conflict1.getConflicttype());
for (TableRef ref0 : conflict0.getTables()) {
TableRef ref1 = conflict1.getTables().get(ref0.getName());
assertNotNull(ref0.fullName(), ref1);
assertEquals(ref0.fullName(), ref0.getTable().getName(), ref1.getTable().getName());
} // FOR
} // FOR
assertEquals(cs0.getWritewriteconflicts().size(), cs1.getWritewriteconflicts().size());
for (ConflictPair conflict0 : cs0.getWritewriteconflicts()) {
ConflictPair conflict1 = cs1.getWritewriteconflicts().get(conflict0.getName());
assertNotNull(conflict0.fullName(), conflict1);
assertEquals(conflict0.fullName(), conflict0.getStatement0().getName(), conflict1.getStatement0().getName());
assertEquals(conflict0.fullName(), conflict0.getStatement1().getName(), conflict1.getStatement1().getName());
assertEquals(conflict0.fullName(), conflict0.getAlwaysconflicting(), conflict1.getAlwaysconflicting());
assertEquals(conflict0.fullName(), conflict0.getConflicttype(), conflict1.getConflicttype());
for (TableRef ref0 : conflict0.getTables()) {
TableRef ref1 = conflict1.getTables().get(ref0.getName());
assertNotNull(ref0.fullName(), ref1);
assertEquals(ref0.fullName(), ref0.getTable().getName(), ref1.getTable().getName());
} // FOR
} // FOR
} // FOR
}
/**
* testCloneDatabase
*/
public void testCloneDatabase() throws Exception {
assertEquals(NUM_PARTITIONS, catalogContext.numberOfPartitions);
Collection<Integer> all_partitions = catalogContext.getAllPartitionIds();
assertNotNull(all_partitions);
// We want to make sure that it clones MultiProcParameters too!
Procedure target_proc = this.getProcedure(neworder.class);
List<MultiProcParameter> expected = new ArrayList<MultiProcParameter>();
int cnt = 3;
for (int i = 0; i < cnt; i++) {
ProcParameter col0 = target_proc.getParameters().get(i);
for (int ii = i + 1; ii < cnt; ii++) {
ProcParameter col1 = target_proc.getParameters().get(ii);
MultiProcParameter mpp = MultiProcParameter.get(col0, col1);
assertNotNull(mpp);
expected.add(mpp);
} // FOR
} // FOR
assertFalse(expected.isEmpty());
Database clone_db = CatalogCloner.cloneDatabase(catalog_db);
assertNotNull(clone_db);
Cluster catalog_cluster = CatalogUtil.getCluster(catalog_db);
assertNotNull(catalog_cluster);
Cluster clone_cluster = CatalogUtil.getCluster(clone_db);
assertNotNull(clone_cluster);
for (Host catalog_host : catalog_cluster.getHosts()) {
Host clone_host = clone_cluster.getHosts().get(catalog_host.getName());
assertNotNull(clone_host);
checkFields(Host.class, catalog_host, clone_host);
} // FOR
for (Site catalog_site : catalog_cluster.getSites()) {
Site clone_site = clone_cluster.getSites().get(catalog_site.getName());
assertNotNull(clone_site);
checkFields(Site.class, catalog_site, clone_site);
}
assertEquals(NUM_PARTITIONS, CatalogUtil.getNumberOfPartitions(clone_db));
Collection<Integer> clone_partitions = CatalogUtil.getAllPartitionIds(clone_db);
assertNotNull(clone_partitions);
assertEquals(all_partitions.size(), clone_partitions.size());
assert (all_partitions.containsAll(clone_partitions));
for (Table catalog_tbl : catalog_db.getTables()) {
Table clone_tbl = clone_db.getTables().get(catalog_tbl.getName());
assertNotNull(catalog_tbl.toString(), clone_tbl);
checkFields(Table.class, catalog_tbl, clone_tbl);
for (Column catalog_col : catalog_tbl.getColumns()) {
Column clone_col = clone_tbl.getColumns().get(catalog_col.getName());
assertNotNull(CatalogUtil.getDisplayName(catalog_col), clone_col);
assertEquals(CatalogUtil.getDisplayName(clone_col), clone_tbl, (Table) clone_col.getParent());
assertEquals(CatalogUtil.getDisplayName(clone_col), clone_tbl.hashCode(), clone_col.getParent().hashCode());
} // FOR
for (MaterializedViewInfo catalog_view : catalog_tbl.getViews()) {
assert (catalog_view.getGroupbycols().size() > 0);
MaterializedViewInfo clone_view = clone_tbl.getViews().get(catalog_view.getName());
checkFields(MaterializedViewInfo.class, catalog_view, clone_view);
} // FOR
} // FOR
for (Procedure catalog_proc : catalog_db.getProcedures()) {
Procedure clone_proc = clone_db.getProcedures().get(catalog_proc.getName());
assertNotNull(catalog_proc.toString(), clone_proc);
assertEquals(clone_proc.getParameters().toString(), catalog_proc.getParameters().size(), clone_proc.getParameters().size());
// Procedure Conflicts
this.checkProcedureConflicts(catalog_proc, catalog_proc.getConflicts(), clone_proc.getConflicts());
this.checkProcedureConflicts(catalog_proc, catalog_proc.getConflicts(), clone_proc.getConflicts());
for (ProcParameter catalog_param : catalog_proc.getParameters()) {
ProcParameter clone_param = clone_proc.getParameters().get(catalog_param.getIndex());
assertNotNull(CatalogUtil.getDisplayName(catalog_param), clone_param);
assertEquals(CatalogUtil.getDisplayName(clone_param), clone_proc, (Procedure) clone_param.getParent());
assertEquals(CatalogUtil.getDisplayName(clone_param), clone_proc.hashCode(), clone_param.getParent().hashCode());
} // FOR
}
}
/**
* testCloneDatabaseMultiColumn
*/
public void testCloneDatabaseMultiColumn() throws Exception {
// We want to make sure that it clones MultiColumns too!
Table catalog_tbl = this.getTable("WAREHOUSE");
Column columns[] = new Column[] { this.getColumn(catalog_tbl, "W_NAME"), this.getColumn(catalog_tbl, "W_YTD"), };
MultiColumn mc = MultiColumn.get(columns);
assertNotNull(mc);
catalog_tbl.setPartitioncolumn(mc);
Database clone_db = CatalogCloner.cloneDatabase(catalog_db);
assertNotNull(clone_db);
Table clone_tbl = this.getTable(clone_db, catalog_tbl.getName());
Column clone_col = clone_tbl.getPartitioncolumn();
assertNotNull(clone_col);
assert (clone_col instanceof MultiColumn);
MultiColumn clone_mc = (MultiColumn) clone_col;
assertEquals(mc.size(), clone_mc.size());
for (int i = 0; i < mc.size(); i++) {
Column catalog_col = mc.get(i);
assertNotNull(catalog_col);
clone_col = clone_mc.get(i);
assertNotNull(clone_col);
assertEquals(catalog_col, clone_col);
assertNotSame(catalog_col.hashCode(), clone_col.hashCode());
} // FOR
}
/**
* testCloneCatalog
*/
public void testCloneCatalog() throws Exception {
Catalog clone = CatalogCloner.cloneBaseCatalog(catalog);
assertNotNull(clone);
for (Cluster catalog_clus : catalog.getClusters()) {
Cluster clone_clus = clone.getClusters().get(catalog_clus.getName());
assertNotNull(clone_clus);
this.checkFields(Cluster.class, catalog_clus, clone_clus);
} // FOR (Cluster)
}
/**
* testClone
*/
public void testCloneItem() throws Exception {
Catalog clone = CatalogCloner.cloneBaseCatalog(catalog);
assertNotNull(clone);
CHECK_FIELDS_EXCLUDE.add("Table.constraints");
CHECK_FIELDS_EXCLUDE.add("Column.constraints");
// Test Table
Table catalog_tbl = catalog_db.getTables().get("DISTRICT");
assertNotNull(catalog_tbl);
Table clone_tbl = CatalogCloner.clone(catalog_tbl, clone);
assertNotNull(clone_tbl);
this.checkFields(Table.class, catalog_tbl, clone_tbl);
}
}