/*************************************************************************** * Copyright (C) 2013 by H-Store Project * * Brown University * * Massachusetts Institute of Technology * * Yale University * * * * http://hstore.cs.brown.edu/ * * * * 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.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.collections15.set.ListOrderedSet; import org.apache.log4j.Logger; import org.voltdb.catalog.CatalogType; import org.voltdb.catalog.Statement; import org.voltdb.types.ExpressionType; import org.voltdb.types.QueryType; import org.voltdb.utils.Pair; import edu.brown.catalog.CatalogPair; import edu.brown.logging.LoggerUtil; import edu.brown.logging.LoggerUtil.LoggerBoolean; import edu.brown.statistics.Histogram; import edu.brown.statistics.ObjectHistogram; public class PredicatePairs extends ListOrderedSet<CatalogPair> { private static final long serialVersionUID = -7735075759916955292L; private static final Logger LOG = Logger.getLogger(PredicatePairs.class); private static final LoggerBoolean debug = new LoggerBoolean(); private static final LoggerBoolean trace = new LoggerBoolean(); static { LoggerUtil.attachObserver(LOG, debug, trace); } private final Set<Statement> catalog_stmts = new HashSet<Statement>(); /** * */ public PredicatePairs() { super(); } public PredicatePairs(Collection<Statement> catalog_stmts) { this(); this.catalog_stmts.addAll(catalog_stmts); } @Override public void clear() { super.clear(); this.catalog_stmts.clear(); } public Collection<Statement> getStatements() { return this.catalog_stmts; } /** * @return */ public Map<QueryType, Integer> getQueryCounts() { Map<QueryType, Integer> query_counts = new HashMap<QueryType, Integer>(); for (QueryType type : QueryType.values()) { query_counts.put(type, 0); } // FOR for (Statement catalog_stmt : this.catalog_stmts) { QueryType type = QueryType.get(catalog_stmt.getQuerytype()); query_counts.put(type, query_counts.get(type) + 1); } // FOR return (query_counts); } public boolean add(CatalogType element0, CatalogType element1) { return (this.add(element0, element1, ExpressionType.COMPARE_EQUAL, new HashSet<Statement>())); } /** * @param element0 * @param element1 * @param comparison_exp * @param catalog_stmts * @return */ public boolean add(CatalogType element0, CatalogType element1, ExpressionType comparison_exp, Statement... catalog_stmts) { Set<Statement> stmts = new HashSet<Statement>(); for (Statement stmt : catalog_stmts) { stmts.add(stmt); } return (this.add(element0, element1, comparison_exp, stmts)); } /** * @param element0 * @param element1 * @param comparison_exp * @param catalog_stmts * @return */ public boolean add(CatalogType element0, CatalogType element1, ExpressionType comparison_exp, Collection<Statement> catalog_stmts) { Set<QueryType> query_types = new HashSet<QueryType>(); for (Statement catalog_stmt : catalog_stmts) { query_types.add(QueryType.get(catalog_stmt.getQuerytype())); } // FOR boolean ret = this.add(CatalogPair.factory(element0, element1, comparison_exp, query_types)); if (ret) this.catalog_stmts.addAll(catalog_stmts); return (ret); } /** * @param match_class * @param search_key * @return */ public PredicatePairs createPredicatePairsForParent(Class<? extends CatalogType> match_class, CatalogType parent_search_key) { PredicatePairs ret = new PredicatePairs(this.catalog_stmts); // We're looking for Pairs where one of the elements matches the search_key, // and the other element is of the same type of match_class for (CatalogPair e : this) { if (e.getFirst().getClass().equals(match_class) && e.getSecond().getParent().equals(parent_search_key)) { ret.add(CatalogPair.factory(e.getSecond(), e.getFirst(), e.getComparisonExp(), e.getQueryTypes())); } else if (e.getSecond().getClass().equals(match_class) && e.getFirst().getParent().equals(parent_search_key)) { ret.add(e); } } // FOR return (ret); } /** * Find all elements in the ColumnSet that match both the search key and the * given class * * @param <T> * @param match_class * @param search_key * @return */ public <T extends CatalogType> Collection<T> findAll(Class<T> match_class, CatalogType search_key) { return (this.find(match_class, search_key, false, false)); } /** * Find all elements of the given match class in the ColumnSet where the * other element in the CatalogPair matches the search_key * * @param <T> * @param match_class * @param search_key * @return */ public <T extends CatalogType> Collection<T> findAllForOther(Class<T> match_class, CatalogType search_key) { return (this.find(match_class, search_key, false, true)); } /** * Find all elements of the given match class in the ColumnSet where that * element's parent matches the given search key * * @param <T> * @param match_class * @param parent_search_key * @return */ public <T extends CatalogType> Collection<T> findAllForParent(Class<T> match_class, CatalogType parent_search_key) { return (this.find(match_class, parent_search_key, true, false)); } /** * Find all elements of the given match class in the ColumnSet where the * other element in the CatalogPair has a parent that matches the search key * * @param <T> * @param match_class * @param parent_search_key * @return */ public <T extends CatalogType> Collection<T> findAllForOtherParent(Class<T> match_class, CatalogType parent_search_key) { return (this.find(match_class, parent_search_key, true, true)); } /** * @param <T> * @param match_class * @param search_key * @param use_parent * if set to true, the search_key is applied to the search * target's parent * @param use_other * if set to true, the search target is always the opposite of * the item of the element that we check the match_class to * @return */ @SuppressWarnings("unchecked") private <T extends CatalogType> Collection<T> find(Class<T> match_class, CatalogType search_key, boolean use_parent, boolean use_other) { if (debug.val) LOG.debug(String.format("find(match_class=%s, search_key=%s, use_parent=%s, use_other=%s)", match_class.getSimpleName(), search_key.fullName(), use_parent, use_other)); assert (search_key != null) : "Invalid search key"; Set<T> found = new HashSet<T>(); final int use_my_idxs[][] = { { 0, 0 }, { 1, 1 } }; final int use_other_idxs[][] = { { 0, 1 }, { 1, 0 } }; int lookup_idxs[][] = (use_other ? use_other_idxs : use_my_idxs); // We're looking for Pairs where one of the elements matches the // search_key, and // the other element is of the same type of match_class for (Pair<CatalogType, CatalogType> pair : this) { if (trace.val) LOG.trace(pair); int ctr = 0; for (int idxs[] : lookup_idxs) { T cur = (T) pair.get(idxs[0]); Class<?> cur_class = pair.get(idxs[0]).getClass(); List<Class<?>> all_classes = ClassUtil.getSuperClasses(cur_class); CatalogType cur_value = (CatalogType) pair.get(idxs[1]); if (use_parent) cur_value = cur_value.getParent(); if (trace.val) { LOG.trace("[" + ctr + "] cur: " + cur); LOG.trace("[" + ctr + "] class: " + cur_class.equals(match_class) + " " + cur_class); LOG.trace("[" + (ctr++) + "] cur_value: " + cur_value); } if (cur_value != null && cur_value.equals(search_key) && all_classes.contains(match_class)) { found.add(cur); break; } } // FOR } // FOR return (found); } /** * @param search_keys * @return */ public Collection<CatalogPair> findAll(CatalogType...search_keys) { List<CatalogPair> found = new ArrayList<CatalogPair>(); for (CatalogPair entry : this) { for (CatalogType key : search_keys) { if (entry.contains(key)) { found.add(entry); } } // FOR } // FOR return (found); } /** * @param search_key * @return */ public Collection<CatalogPair> findAllForParent(CatalogType search_key) { List<CatalogPair> found = new ArrayList<CatalogPair>(); for (CatalogPair entry : this) { if (entry.getFirst().getParent().equals(search_key) || entry.getSecond().getParent().equals(search_key)) { found.add(entry); } } // FOR return (found); } @SuppressWarnings("unchecked") public <T extends CatalogType> Collection<T> findAllForType(Class<T> search_key) { List<T> found = new ArrayList<T>(); for (CatalogPair e : this) { if (ClassUtil.getSuperClasses(e.getFirst().getClass()).contains(search_key)) { found.add((T) e.getFirst()); } if (ClassUtil.getSuperClasses(e.getSecond().getClass()).contains(search_key)) { found.add((T) e.getSecond()); } } // FOR return (found); } @SuppressWarnings("unchecked") public <T extends CatalogType> Histogram<T> buildHistogramForType(Class<T> search_key) { Histogram<T> h = new ObjectHistogram<T>(); for (CatalogPair e : this) { if (ClassUtil.getSuperClasses(e.getFirst().getClass()).contains(search_key)) { h.put((T) e.getFirst()); } if (ClassUtil.getSuperClasses(e.getSecond().getClass()).contains(search_key)) { h.put((T) e.getSecond()); } } // FOR return (h); } @Override public boolean equals(Object o) { if (this == o) return (true); if (!(o instanceof PredicatePairs)) return (false); // Otherwise, we need to loop through each of our Pairs and see if there // is a matching Pair of items on the other side PredicatePairs cset = (PredicatePairs) o; return (this.containsAll(cset) && cset.containsAll(this)); } public String debug() { String ret = this.getClass().getSimpleName()+": {\n"; for (CatalogPair pair : this) { ret += StringUtil.SPACER + pair.toString() + "\n"; } // FOR ret += "}"; return (ret); } }