Package edu.brown.optimizer

Source Code of edu.brown.optimizer.BasePlanOptimizerTestCase$PlanOptimizerTestProjectBuilder

package edu.brown.optimizer;

import java.io.File;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections15.CollectionUtils;
import org.voltdb.catalog.CatalogMap;
import org.voltdb.catalog.Column;
import org.voltdb.expressions.AbstractExpression;
import org.voltdb.expressions.TupleValueExpression;
import org.voltdb.planner.PlanColumn;
import org.voltdb.planner.PlannerContext;
import org.voltdb.plannodes.AbstractPlanNode;
import org.voltdb.plannodes.AbstractScanPlanNode;
import org.voltdb.plannodes.AggregatePlanNode;
import org.voltdb.plannodes.DistinctPlanNode;
import org.voltdb.plannodes.NestLoopIndexPlanNode;
import org.voltdb.plannodes.OrderByPlanNode;
import org.voltdb.plannodes.ProjectionPlanNode;
import org.voltdb.plannodes.SeqScanPlanNode;
import org.voltdb.types.ExpressionType;
import org.voltdb.types.PlanNodeType;

import edu.brown.BaseTestCase;
import edu.brown.benchmark.AbstractProjectBuilder;
import edu.brown.expressions.ExpressionTreeWalker;
import edu.brown.plannodes.PlanNodeTreeWalker;
import edu.brown.plannodes.PlanNodeUtil;
import edu.brown.utils.CollectionUtil;

public abstract class BasePlanOptimizerTestCase extends BaseTestCase {
   
    public static class PlanOptimizerTestProjectBuilder extends AbstractProjectBuilder {
       
        public PlanOptimizerTestProjectBuilder(String name) {
            super("test-" + name, AbstractProjectBuilder.class, null, null);
           
            File schema = new File(BasePlanOptimizerTestCase.class.getResource("test-planopt-ddl.sql").getFile());
            assert(schema.exists()) : "Missing test schema file: " + schema;
            this.addSchema(schema);
           
            this.addTablePartitionInfo("TABLEA", "A_ID");
            this.addTablePartitionInfo("TABLEB", "B_A_ID");
            this.addTablePartitionInfo("TABLEC", "C_B_A_ID");
        }
    }
   
   
    @Override
    protected void setUp(AbstractProjectBuilder projectBuilder) throws Exception {
        super.setUp(projectBuilder);
    }
   
    public void checkColumnIndex(TupleValueExpression expr, Map<String, Integer> tbl_map) {
        // check column exists in the map
        assert (tbl_map.containsKey(expr.getColumnAlias())) : expr.getColumnAlias() + " does not exist in scanned table";
        // check column has correct index
        assert (expr.getColumnIndex() == tbl_map.get(expr.getColumnAlias())) : "Column : " + expr.getColumnAlias() + " has offset: " + expr.getColumnIndex() + " expected: "
                + tbl_map.get(expr.getColumnAlias());
    }

    public void checkColumnIndex(Column col, Map<String, Integer> tbl_map) {
        // check column exists in the map
        assert (tbl_map.containsKey(col.getName())) : col.getName() + " does not exist in intermediate table";
        // check column has correct index
        assert (col.getIndex() == tbl_map.get(col.getName())) : "Column : " + col.getName() + " has offset: " + col.getIndex() + " expected: " + tbl_map.get(col.getName());
    }

    /** Given a ScanNode, builds a map mapping column names to indices. **/
    public Map<String, Integer> buildTableMap(AbstractScanPlanNode node) {
        // build hashmap mapping column names to column index values
        final Map<String, Integer> tbl_col_index_map = new HashMap<String, Integer>();
        CatalogMap<Column> node_map = catalog_db.getTables().get(node.getTargetTableName()).getColumns();
        assert (node_map != null) : " Failed to retrieve columns for table: " + node.getTargetTableName();
        Column[] node_tbl_cols = new Column[node_map.size()];
        node_map.toArray(node_tbl_cols);
        for (Column col : node_tbl_cols) {
            tbl_col_index_map.put(col.getName(), col.getIndex());
        }
        return tbl_col_index_map;
    }

    /**
     * Given a plan node, checks to see all the expressions within the plan node
     * match up with the intermediate table
     **/
    public void checkExpressionOffsets(AbstractPlanNode node, final Map<String, Integer> tbl_map) {
        // check all tuplevalueexpression offsets in the scannode
        // System.out.println("map: " + tbl_map);
       
        Collection<AbstractExpression> exps = CollectionUtils.union(PlanNodeUtil.getExpressionsForPlanNode(node),
                                                                    PlanNodeUtil.getOutputExpressionsForPlanNode(node));
        assert(exps.size() > 0) : "No Expressions: " + node;
        for (AbstractExpression exp : exps) {
            new ExpressionTreeWalker() {
                @Override
                protected void callback(AbstractExpression exp_element) {
                    if (exp_element instanceof TupleValueExpression) {
                         System.out.println("element column: " +
                         ((TupleValueExpression)exp_element).getColumnAlias()
                         + " element index: " +
                         ((TupleValueExpression)exp_element).getColumnIndex());
                        checkColumnIndex((TupleValueExpression) exp_element, tbl_map);
                    }
                }
            }.traverse(exp);
        }
    }

    /** Updates intermediate table for column offsets **/
    public void updateIntermediateTblOffset(AbstractPlanNode node, final Map<String, Integer> intermediate_offset_tbl) {
        int offset_cnt = 0;
        intermediate_offset_tbl.clear();
        for (Integer col_guid : node.getOutputColumnGUIDs()) {
            PlanColumn plan_col = PlannerContext.singleton().get(col_guid);
            // TupleValueExpression tv_expr =
            // (TupleValueExpression)plan_col.getExpression();
            intermediate_offset_tbl.put(plan_col.getDisplayName(), offset_cnt);
            offset_cnt++;
        }
    }

    /** Updates intermediate table for column GUIDs **/
    public void updateIntermediateTblGUIDs(AbstractPlanNode node, final Map<String, Integer> intermediate_GUID_tbl) {
//        int offset_cnt = 0;
        intermediate_GUID_tbl.clear();
        for (Integer col_guid : node.getOutputColumnGUIDs()) {
            PlanColumn plan_col = PlannerContext.singleton().get(col_guid);
            // TupleValueExpression tv_expr =
            // (TupleValueExpression)plan_col.getExpression();
            intermediate_GUID_tbl.put(plan_col.getDisplayName(), plan_col.guid());
        }
    }

    public void checkTableOffsets(AbstractPlanNode node, final Map<String, Integer> tbl_map) {
        /** Aggregates **/
        if (node instanceof AggregatePlanNode) {
            /** check aggregate column offsets **/
            for (Integer col_guid : ((AggregatePlanNode) node).getAggregateColumnGuids()) {
                PlanColumn plan_col = PlannerContext.singleton().get(col_guid);
                assert (plan_col.getExpression().getExpressionType().equals(ExpressionType.VALUE_TUPLE)) : " plan column expression type is: " + plan_col.getExpression().getExpressionType()
                        + " NOT TupleValueExpression";
                TupleValueExpression tv_exp = (TupleValueExpression) plan_col.getExpression();
                checkColumnIndex(tv_exp, tbl_map);
            }
            /** check output column offsets **/
            for (Integer col_guid : ((AggregatePlanNode) node).getAggregateOutputColumns()) {
                PlanColumn plan_col = PlannerContext.singleton().get(col_guid);
                assert (plan_col.getExpression().getExpressionType().equals(ExpressionType.VALUE_TUPLE)) : " plan column expression type is: " + plan_col.getExpression().getExpressionType()
                        + " NOT TupleValueExpression";
                TupleValueExpression tv_exp = (TupleValueExpression) plan_col.getExpression();
                checkColumnIndex(tv_exp, tbl_map);
            }
            /** check group by column offsets **/
            for (Integer col_guid : ((AggregatePlanNode) node).getGroupByColumnOffsets()) {
                PlanColumn plan_col = PlannerContext.singleton().get(col_guid);
                assert (plan_col.getExpression().getExpressionType().equals(ExpressionType.VALUE_TUPLE)) : " plan column expression type is: " + plan_col.getExpression().getExpressionType()
                        + " NOT TupleValueExpression";
                TupleValueExpression tv_exp = (TupleValueExpression) plan_col.getExpression();
                checkColumnIndex(tv_exp, tbl_map);
            }
            /** Order By's **/
        } else if (node instanceof OrderByPlanNode) {

        } else {
            // check the offsets of the output column
            // Set<TupleValueExpression> ExpressionUtil.getExpressions(node,
            // TupleValueExpression.class);
            for (Integer col_guid : node.getOutputColumnGUIDs()) {
                PlanColumn plan_col = PlannerContext.singleton().get(col_guid);
                new ExpressionTreeWalker() {
                    @Override
                    protected void callback(AbstractExpression element) {
                        if (element.getClass().equals(TupleValueExpression.class)) {
                            assert (element.getExpressionType().equals(ExpressionType.VALUE_TUPLE)) : "plan column expression type is: " + element.getExpressionType() + " NOT TupleValueExpression";
                            TupleValueExpression tv_exp = (TupleValueExpression) element;
                            checkColumnIndex(tv_exp, tbl_map);
                        }
                        return;
                    }
                }.traverse(plan_col.getExpression());
            }
        }
    }

    /**
     * make sure the output columns of a node exactly match its inline columns
     * (guid for guid)
     **/
    public void checkMatchInline(AbstractPlanNode node, AbstractPlanNode inline_node) {
        for (int i = 0; i < node.getOutputColumnGUIDs().size(); i++) {
            Integer guid0 = node.getOutputColumnGUIDs().get(i);
            assertNotNull(guid0);
            Integer guid1 = inline_node.getOutputColumnGUIDs().get(i);
            assertNotNull(guid1);
            assertEquals(node + " Node guid doesn't match inline plan guid", guid0, guid1);
        }
    }

    /**
     * walk through the output columns of the current plan_node and compare the
     * GUIDs of the output columns of the child of the current plan_node
     **/
    public void checkNodeColumnGUIDs(AbstractPlanNode plan_node, Map<String, Integer> intermediate_GUID_tbl) {
        for (Integer orig_guid : plan_node.getOutputColumnGUIDs()) {
            PlanColumn orig_pc = PlannerContext.singleton().get(orig_guid);
            assertNotNull(orig_pc);
           
            // XXX boolean found = false;
            for (String int_name : intermediate_GUID_tbl.keySet()) {
                Integer new_guid = intermediate_GUID_tbl.get(int_name);
                if (orig_pc.getDisplayName().equals(int_name)) {
                    assertEquals(plan_node + " Column name: " + int_name + " guid id: " + orig_guid + " doesn't match guid from child: ",
                                 orig_guid, new_guid);
                }
            }
        }
    }

    /** walk the tree starting at the given root and validate **/
    public void validateNodeColumnOffsets(AbstractPlanNode node) {
        final int total_depth = PlanNodeUtil.getDepth(node);

        // maintain data structure - (most recent "immediate" table)
        final Map<String, Integer> intermediate_offset_tbl = new HashMap<String, Integer>();
        // maintain column name to GUID
        final Map<String, Integer> intermediate_GUID_tbl = new HashMap<String, Integer>();

        new PlanNodeTreeWalker() {
            @Override
            protected void callback(AbstractPlanNode element) {
                // skip the column offset checking for the root send - the EE
                // doesn't care
                if (this.getDepth() != 0) {
                    /** Bottom Scan Node **/
                    if (this.getDepth() == total_depth && element instanceof AbstractScanPlanNode) {
                        // if its bottom most node (scan node), check offsets
                        // against
                        // the table being scanned
                        Map<String, Integer> target_tbl_map = buildTableMap((AbstractScanPlanNode) element);
                        checkExpressionOffsets(element, target_tbl_map);
                        checkTableOffsets(element, target_tbl_map);
                        // if inline nodes exist, check offsets of output
                        // columns match inline projection output columns
                        if (element.getInlinePlanNodes().size() > 0) {
                            // only 1 inline plan node - must be projection
                            assert (element.getInlinePlanNodes().size() == 1) : "More than 1 Inline Nodes in leaf Scan Node";
                            assert (element.getInlinePlanNode(PlanNodeType.PROJECTION) != null) : "Leaf scan node's inline node is not a projection";
                            // TO D0: compare inline projection columns with
                            // output columns of scan - should be identical
                            checkMatchInline(element, element.getInlinePlanNode(PlanNodeType.PROJECTION));
                        }
                        // update the intermediate table offsets + GUIDS - with
                        // output columns from the scan
                        updateIntermediateTblOffset(element, intermediate_offset_tbl);
                        updateIntermediateTblGUIDs(element, intermediate_GUID_tbl);
                    }
                    /** NestLoopIndex Node **/
                    else if (element instanceof NestLoopIndexPlanNode) {
                        // The only type of join we're currently handling. The
                        // join mashes the Receive node
                        // intermediate table with the inline index scan
                        // check the inline scan node's column offsets are based
                        // on the "mashing" of the intermediate table
                        // and the target scan table
                        assert (element.getInlinePlanNodes().size() == 1) : "More than 1 Inline Nodes in NestLoopIndex";
                        assert (element.getInlinePlanNode(PlanNodeType.INDEXSCAN) != null || element.getInlinePlanNode(PlanNodeType.SEQSCAN) != null) : "No scan nodes exist in inline plan nodes";
                        AbstractScanPlanNode scan_node = (AbstractScanPlanNode) CollectionUtil.first(element.getInlinePlanNodes().values());
                        // get all columns of the "target table" being scanned
                        // and append them to the current intermediate table
                        // + determine new offsets + determine new guids
                        Map<String, Integer> scan_node_map = buildTableMap(scan_node);
                        Integer intermediate_tbl_offset = intermediate_offset_tbl.size();
                        for (Map.Entry<String, Integer> col : scan_node_map.entrySet()) {
                            intermediate_offset_tbl.put(col.getKey(), intermediate_tbl_offset + col.getValue());
                        }
                        for (Integer col_guid : scan_node.getOutputColumnGUIDs()) {
                            PlanColumn plan_col = PlannerContext.singleton().get(col_guid);
                            intermediate_GUID_tbl.put(plan_col.getDisplayName(), plan_col.guid());
                        }
                        // check that expression column offsets + output column
                        // offsets match + GUIDs match with the original target
                        // table
                        checkExpressionOffsets(scan_node, intermediate_offset_tbl);
                        checkTableOffsets(scan_node, intermediate_offset_tbl);
                        checkMatchInline(element, scan_node);
                        checkNodeColumnGUIDs(element, intermediate_GUID_tbl);
                    }
                    /** Projection Node **/
                    else if (element instanceof ProjectionPlanNode) {
                        // check that expression column offsets + output column
                        // offsets match + GUIDs match with the original target
                        // table
                        checkExpressionOffsets(element, intermediate_offset_tbl);
                        checkTableOffsets(element, intermediate_offset_tbl);
                        checkNodeColumnGUIDs(element, intermediate_offset_tbl);
                        // update intermediate table (offset + guids)
                        updateIntermediateTblOffset(element, intermediate_offset_tbl);
                        updateIntermediateTblGUIDs(element, intermediate_GUID_tbl);
                    } else if (element instanceof AggregatePlanNode) {
                        // only want to check the expression here because the
                        // output will be different for aggregates
                        checkExpressionOffsets(element, intermediate_offset_tbl);
                        // update intermediate table to reflect output of
                        // aggregates
                        updateIntermediateTblOffset(element, intermediate_offset_tbl);
                    } else if (element instanceof OrderByPlanNode) {
                        // check sort column GUIDs against the intermediate
                        // table
                        for (int order_node_guid : ((OrderByPlanNode) element).getSortColumnGuids()) {
                            PlanColumn order_node_pc = PlannerContext.singleton().get(order_node_guid);
                            int int_order_node_guid = -1;
                            int_order_node_guid = intermediate_GUID_tbl.get(order_node_pc.getDisplayName());
                            assert (int_order_node_guid != -1) : order_node_pc.getDisplayName() + " doesn't exist in intermediate table";
                            assert (order_node_guid == int_order_node_guid) : order_node_pc.getDisplayName() + " sort column guid: " + order_node_guid + " doesn't match: " + int_order_node_guid;
                        }
                        // only want to check the expression here because the
                        // output will be different for aggregates
                        checkExpressionOffsets(element, intermediate_offset_tbl);
                        // update intermediate table to reflect output of
                        // aggregates
                        updateIntermediateTblOffset(element, intermediate_offset_tbl);
                    }
                    /**
                     * Any other types of AbstractPlanNode (Send, Recieve,
                     * Limit, etc.)
                     **/
                    else {
                        checkExpressionOffsets(element, intermediate_offset_tbl);
                        checkTableOffsets(element, intermediate_offset_tbl);
                    }
                }
            }
        }.traverse(node);
    }

    public static void validate(final AbstractPlanNode node) throws Exception {
           
//            System.err.println("Validating: " + node + " / " + node.getPlanNodeType());
           
            switch (node.getPlanNodeType()) {
                // Make sure that the output columns from this node match the output
                // columns of the scan node below us that is feeding into it
    //            case NESTLOOPINDEX: {
    //                assert(root.getChildPlanNodeCount() == 1);
    //                AbstractPlanNode child = root.getChild(0);
    //                assert(child != null);
    //                if ((child instanceof SeqScanPlanNode) == false) break;
    //               
    //                PlannerContext plannerContext = PlannerContext.singleton();
    //                for (int i = 0, cnt = child.getOutputColumnGUIDCount(); i < cnt; i++) {
    //                    int child_guid  = child.getOutputColumnGUID(i);
    //                    PlanColumn child_col = plannerContext.get(child_guid);
    //                    assert(child_col != null);
    //                   
    //                    int root_guid = root.getOutputColumnGUID(i);
    //                    PlanColumn root_col = plannerContext.get(root_guid);
    //                    assert(root_col != null);
    //                   
    //                    if (child_guid != root_guid) {
    //                        throw new Exception(String.format("Output Column mismatch at position %d : %s != %s",
    //                                                          i, child_col, root_col));
    //                    }
    //                } // FOR
    //                break;
    //            }
                case DISTINCT: {
                    // Make sure the DISTINCT column is in the output columns
                    DistinctPlanNode cast_node = (DistinctPlanNode)node;
                    Integer distinct_col = cast_node.getDistinctColumnGuid();
                    assertTrue(String.format("%s is missing DISTINCT PlanColumn GUID %d in its output columns", cast_node, distinct_col),
                              cast_node.getOutputColumnGUIDs().contains(distinct_col));
                   
                    break;
                }
                case HASHAGGREGATE:
                case AGGREGATE: {
                    // Every PlanColumn referenced in this node must appear in its children's output
                    Collection<Integer> planCols = node.getOutputColumnGUIDs();
                    assert(planCols != null);
                   
//                    System.err.println(PlanNodeUtil.debugNode(node));
                    AggregatePlanNode cast_node = (AggregatePlanNode)node;
                    assertEquals(cast_node.toString(), cast_node.getAggregateTypes().size(), cast_node.getAggregateColumnGuids().size());
                    assertEquals(cast_node.toString(), cast_node.getAggregateTypes().size(), cast_node.getAggregateColumnNames().size());
                    assertEquals(cast_node.toString(), cast_node.getAggregateTypes().size(), cast_node.getAggregateOutputColumns().size());
                   
                   
//                    Set<Integer> foundCols = new HashSet<Integer>();
//                    for (AbstractPlanNode child : node.getChildren()) {
//                        Collection<Integer> childCols = PlanNodeUtil.getOutputColumnIdsForPlanNode(child);
//                        System.err.println("CHILD " + child + " OUTPUT: " + childCols);
//                       
//                        for (Integer childCol : childCols) {
//                            if (planCols.contains(childCol)) {
//                                foundCols.add(childCol);
//                            }
//                        } // FOR
//                        if (foundCols.size() == planCols.size()) break;
//                    } // FOR
//                   
//                    if (PlanNodeUtil.getPlanNodes(node, SeqScanPlanNode.class).isEmpty() && // HACK
//                        foundCols.containsAll(planCols) == false) {
//                        throw new Exception(String.format("Failed to find all of the columns referenced by %s in the output columns of %s",
//                                                          node, planCols));
//                    }
                    break;
                }
               
               
            } // SWITCH
           
            for (AbstractPlanNode child : node.getChildren()) {
                BasePlanOptimizerTestCase.validate(child);
            }
            return;
        }
   
}
TOP

Related Classes of edu.brown.optimizer.BasePlanOptimizerTestCase$PlanOptimizerTestProjectBuilder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.