package edu.brown.catalog; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; import org.voltdb.catalog.CatalogType; import org.voltdb.catalog.Cluster; import org.voltdb.catalog.Column; import org.voltdb.catalog.Constraint; import org.voltdb.catalog.Database; import org.voltdb.catalog.Host; import org.voltdb.catalog.Index; import org.voltdb.catalog.ProcParameter; import org.voltdb.catalog.Procedure; import org.voltdb.catalog.Statement; import org.voltdb.catalog.StmtParameter; import org.voltdb.catalog.Table; import edu.brown.catalog.special.MultiAttributeCatalogType; import edu.brown.catalog.special.MultiColumn; import edu.brown.catalog.special.MultiProcParameter; import edu.brown.catalog.special.ReplicatedColumn; import edu.brown.utils.ClassUtil; public abstract class CatalogKeyOldVersion { public static final Logger LOG = Logger.getLogger(CatalogKeyOldVersion.class); private static final String PARENT_DELIMITER = "."; private static final String MULTIATTRIBUTE_DELIMITER = "#"; private static final Map<CatalogType, String> CACHE_CREATEKEY = new HashMap<CatalogType, String>(); private static final Map<Database, Map<String, CatalogType>> CACHE_GETFROMKEY = new HashMap<Database, Map<String, CatalogType>>(); /** * Returns a String key representation of the column as "Parent.Child" * * @param catalog_col * @return */ @SuppressWarnings("unchecked") public static <T extends CatalogType> String createKey(T catalog_item) { // There is a 7x speed-up when we use the cache versus always // constructing a new key String ret = CACHE_CREATEKEY.get(catalog_item); if (ret != null) return (ret); if (catalog_item == null) return (null); assert (catalog_item.getParent() != null) : catalog_item + " has null parent"; CatalogType parent = catalog_item.getParent(); ret = parent.getName() + PARENT_DELIMITER; // Special Case: MultiAttributeCatalogType if (catalog_item instanceof MultiAttributeCatalogType) { MultiAttributeCatalogType multicatalog = (MultiAttributeCatalogType) catalog_item; ret += multicatalog.getPrefix(); for (Object sub_item : multicatalog) { ret += MULTIATTRIBUTE_DELIMITER + ((CatalogType) sub_item).getName(); } // FOR } else { ret += catalog_item.getName(); // Special Case: StmtParameter // Since there may be Statement's with the same name but in // different Procedures, // we also want to include the Procedure name if (catalog_item instanceof StmtParameter) { assert (parent.getParent() != null); ret = parent.getParent().getName() + PARENT_DELIMITER + ret; } } CACHE_CREATEKEY.put(catalog_item, ret); return (ret); } /** * Returns a String key representation of the column as "Parent.Child" * * @param parent * @param child * @return */ public static String createKey(String parent, String child) { return (new StringBuilder().append(parent).append(PARENT_DELIMITER).append(child).toString()); } public static Collection<String> createKeys(Iterable<? extends CatalogType> map) { Collection<String> keys = new ArrayList<String>(); for (CatalogType catalog_item : map) { keys.add(createKey(catalog_item)); } // FOR return (keys); } /** * Return the name of the catalog object from the key * * @param catalog_key * @return */ public static String getNameFromKey(String catalog_key) { assert (catalog_key != null); return (catalog_key.substring(catalog_key.lastIndexOf(PARENT_DELIMITER) + 1)); } /** * Given a String key generated by createKey(), return the corresponding * catalog object for the given Database catalog. If the parent object does * not exist, this function will return null. If the parent exists but the * child does not exist, then it trips an assert * * @param catalog_db * @param key * @return */ @SuppressWarnings("unchecked") public static <T extends CatalogType> T getFromKey(Database catalog_db, String key, Class<T> catalog_class) { final boolean debug = LOG.isDebugEnabled(); if (debug) LOG.debug("Grabbing " + catalog_class + " object for '" + key + "'"); assert (catalog_db != null); assert (catalog_class != null); // Caching... Map<String, CatalogType> cache = CatalogKeyOldVersion.CACHE_GETFROMKEY.get(catalog_db); if (cache != null) { if (cache.containsKey(key)) return (T) cache.get(key); } else { cache = new HashMap<String, CatalogType>(); CatalogKeyOldVersion.CACHE_GETFROMKEY.put(catalog_db, cache); } T catalog_child = null; CatalogType catalog_parent = null; int idx = key.indexOf(PARENT_DELIMITER); assert (idx != -1) : "Invalid CatalogKeyOldVersion format '" + key + "'"; String parent_key = key.substring(0, idx); String child_key = key.substring(idx + 1); List<Class<?>> superclasses = ClassUtil.getSuperClasses(catalog_class); // Get the parent based on the type of the object they want back if (catalog_class.equals(Index.class) || catalog_class.equals(Constraint.class) || superclasses.contains(Column.class)) { catalog_parent = catalog_db.getTables().get(parent_key); } else if (catalog_class.equals(Statement.class) || superclasses.contains(ProcParameter.class)) { catalog_parent = catalog_db.getProcedures().get(parent_key); } else if (catalog_class.equals(Table.class) || catalog_class.equals(Procedure.class)) { catalog_parent = catalog_db; } else if (catalog_class.equals(Host.class)) { catalog_parent = (Cluster) catalog_db.getParent(); // Special Case: StmtParameter } else if (catalog_class.equals(StmtParameter.class)) { Procedure catalog_proc = catalog_db.getProcedures().get(parent_key); assert (catalog_proc != null); idx = child_key.indexOf('.'); parent_key = child_key.substring(0, idx); child_key = child_key.substring(idx + 1); catalog_parent = catalog_proc.getStatements().get(parent_key); } // Don't throw this error because it may be a dynamic catalog type that // we use for the Markov stuff // } else { // assert(false) : "Unexpected Catalog key type '" + catalog_class + // "'"; // } // It's ok for the parent to be missing, but it's *not* ok if the child // is missing if (catalog_parent != null) { if (debug) LOG.debug("Catalog Parent: " + CatalogUtil.getDisplayName(catalog_parent)); // COLUMN if (superclasses.contains(Column.class)) { // Special Case: Replicated Column if (child_key.equals(ReplicatedColumn.COLUMN_NAME)) { catalog_child = (T) ReplicatedColumn.get((Table) catalog_parent); // Special Case: MultiColumn } else if (child_key.startsWith(MultiColumn.PREFIX)) { int prefix_offset = MultiColumn.PREFIX.length() + MULTIATTRIBUTE_DELIMITER.length(); String names[] = child_key.substring(prefix_offset).split(MULTIATTRIBUTE_DELIMITER); assert (names.length > 1) : "Invalid MultiColumn Key: " + child_key; Column params[] = new Column[names.length]; for (int i = 0; i < names.length; i++) { params[i] = getFromKey(catalog_db, createKey(parent_key, names[i]), Column.class); } // FOR catalog_child = (T) MultiColumn.get(params); // Regular Columns } else { catalog_child = (T) ((Table) catalog_parent).getColumns().get(child_key); } // INDEX } else if (superclasses.contains(Index.class)) { catalog_child = (T) ((Table) catalog_parent).getIndexes().get(child_key); // CONSTRAINT } else if (superclasses.contains(Constraint.class)) { catalog_child = (T) ((Table) catalog_parent).getConstraints().get(child_key); // PROCPARAMETER } else if (superclasses.contains(ProcParameter.class)) { // Special Case: MultiProcParameter if (child_key.startsWith(MultiProcParameter.PREFIX)) { int prefix_offset = MultiProcParameter.PREFIX.length() + MULTIATTRIBUTE_DELIMITER.length(); String names[] = child_key.substring(prefix_offset).split(MULTIATTRIBUTE_DELIMITER); assert (names.length > 1) : "Invalid MultiProcParameter Key: " + child_key.substring(prefix_offset); ProcParameter params[] = new ProcParameter[names.length]; for (int i = 0; i < names.length; i++) { params[i] = getFromKey(catalog_db, createKey(parent_key, names[i]), ProcParameter.class); } // FOR catalog_child = (T) MultiProcParameter.get(params); // Regular ProcParameter } else { catalog_child = (T) ((Procedure) catalog_parent).getParameters().get(child_key); } // STATEMENT } else if (superclasses.contains(Statement.class)) { catalog_child = (T) ((Procedure) catalog_parent).getStatements().get(child_key); // STMTPARAMETER } else if (superclasses.contains(StmtParameter.class)) { catalog_child = (T) ((Statement) catalog_parent).getParameters().get(child_key); // TABLE } else if (superclasses.contains(Table.class)) { catalog_child = (T) ((Database) catalog_parent).getTables().get(child_key); if (catalog_child == null) { LOG.debug("TABLES: " + CatalogUtil.debug(((Database) catalog_parent).getTables())); } // PROCEDURE } else if (superclasses.contains(Procedure.class)) { catalog_child = (T) ((Database) catalog_parent).getProcedures().get(child_key); // HOST } else if (superclasses.contains(Host.class)) { catalog_child = (T) ((Cluster) catalog_parent).getHosts().get(child_key); // UNKNOWN! } else { LOG.fatal("Invalid child class '" + catalog_class + "' for catalog key " + key); assert (false); } if (catalog_child != null) cache.put(key, catalog_child); return (catalog_child); } return (null); } public static <T extends CatalogType> Collection<T> getFromKeys(Database catalog_db, Collection<String> keys, Class<T> catalog_class, Collection<T> items) { for (String key : keys) { items.add(CatalogKeyOldVersion.getFromKey(catalog_db, key, catalog_class)); } // FOR return (items); } public static <T extends CatalogType> Collection<T> getFromKeys(Database catalog_db, Collection<String> keys, Class<T> catalog_class) { return (getFromKeys(catalog_db, keys, catalog_class, new ArrayList<T>())); } }