Search in sources :

Example 1 with PlanNodeType

use of org.voltdb.types.PlanNodeType in project voltdb by VoltDB.

the class InlineOrderByIntoMergeReceive method applyOptimization.

/**
     * For MP queries, the coordinator's OrderBy node can be replaced with
     * a specialized Receive node that merges individual partitions results
     * into a final result set if the partitions result set is sorted
     * in the order matching the ORDER BY order
     *
     * @param orderbyNode - ORDER BY node to optimize
     * @return optimized plan
     */
AbstractPlanNode applyOptimization(OrderByPlanNode orderbyNode) {
    // Find all child RECEIVE nodes. We are not interested in the MERGERECEIVE nodes there
    // because they could only come from subqueries.
    List<AbstractPlanNode> receives = orderbyNode.findAllNodesOfType(PlanNodeType.RECEIVE);
    if (receives.isEmpty()) {
        return orderbyNode;
    }
    assert (receives.size() == 1);
    ReceivePlanNode receive = (ReceivePlanNode) receives.get(0);
    // Make sure that this receive node belongs to the same coordinator fragment that
    // the ORDER BY node does. Alternatively, it could belong to a distributed subquery.
    // Walk up the tree starting at the receive node until we hit either a scan node
    // (distributed subquery) or the original order by node (distributed order by)
    // Collect all nodes that are currently in between ORDER BY and RECEIVE nodes
    // If the optimization is possible, they will be converted to inline nodes of
    // the MERGE RECEIVE node. The expected node types are:
    //      LIMIT, AGGREGATE/PARTIALAGGREGATE/HASHAGGREGATE
    // The HASHAGGREGATE must be convertible to AGGREGATE or PARTIALAGGREGATE for optimization
    // to be applicable.
    // LIMIT can be already inline with ORDER BY node
    AbstractPlanNode limitNode = orderbyNode.getInlinePlanNode(PlanNodeType.LIMIT);
    AbstractPlanNode aggregateNode = null;
    AbstractPlanNode inlineCandidate = receive.getParent(0);
    while (orderbyNode != inlineCandidate) {
        if (inlineCandidate instanceof AbstractScanPlanNode) {
            // it's a subquery
            return orderbyNode;
        }
        PlanNodeType nodeType = inlineCandidate.getPlanNodeType();
        if (nodeType == PlanNodeType.LIMIT && limitNode == null) {
            limitNode = inlineCandidate;
        } else if ((nodeType == PlanNodeType.AGGREGATE || nodeType == PlanNodeType.PARTIALAGGREGATE) && aggregateNode == null) {
            aggregateNode = inlineCandidate;
        } else if (nodeType == PlanNodeType.HASHAGGREGATE && aggregateNode == null) {
            aggregateNode = convertToSerialAggregation(inlineCandidate, orderbyNode);
            if (PlanNodeType.HASHAGGREGATE == aggregateNode.getPlanNodeType()) {
                return orderbyNode;
            }
        } else {
            // Don't know how to handle this node or there is already a node of this type
            return orderbyNode;
        }
        // move up one node
        assert (inlineCandidate.getParentCount() == 1);
        inlineCandidate = inlineCandidate.getParent(0);
    }
    assert (receive.getChildCount() == 1);
    AbstractPlanNode partitionRoot = receive.getChild(0);
    if (!partitionRoot.isOutputOrdered(orderbyNode.getSortExpressions(), orderbyNode.getSortDirections())) {
        // Partition results are not ordered
        return orderbyNode;
    }
    // the new MERGERECIEVE node.. All in-between nodes will be inlined
    assert (orderbyNode.getParentCount() <= 1);
    AbstractPlanNode rootNode = (orderbyNode.getParentCount() == 1) ? orderbyNode.getParent(0) : null;
    MergeReceivePlanNode mergeReceive = new MergeReceivePlanNode();
    assert (receive.getChildCount() == 1);
    mergeReceive.addAndLinkChild(receive.getChild(0));
    receive.removeFromGraph();
    if (rootNode == null) {
        rootNode = mergeReceive;
    } else {
        rootNode.clearChildren();
        rootNode.addAndLinkChild(mergeReceive);
    }
    // Add inline ORDER BY node and remove inline LIMIT node if any
    mergeReceive.addInlinePlanNode(orderbyNode);
    if (limitNode != null) {
        orderbyNode.removeInlinePlanNode(PlanNodeType.LIMIT);
    }
    // Add inline aggregate
    if (aggregateNode != null) {
        if (limitNode != null) {
            // Inline LIMIT with aggregate
            aggregateNode.addInlinePlanNode(limitNode);
        }
        mergeReceive.addInlinePlanNode(aggregateNode);
    }
    // Add LIMIT if it is exist and wasn't inline with aggregate node
    if (limitNode != null && aggregateNode == null) {
        mergeReceive.addInlinePlanNode(limitNode);
    }
    // return the new root
    return rootNode;
}
Also used : AbstractPlanNode(org.voltdb.plannodes.AbstractPlanNode) PlanNodeType(org.voltdb.types.PlanNodeType) AbstractScanPlanNode(org.voltdb.plannodes.AbstractScanPlanNode) ReceivePlanNode(org.voltdb.plannodes.ReceivePlanNode) MergeReceivePlanNode(org.voltdb.plannodes.MergeReceivePlanNode) MergeReceivePlanNode(org.voltdb.plannodes.MergeReceivePlanNode)

Example 2 with PlanNodeType

use of org.voltdb.types.PlanNodeType in project voltdb by VoltDB.

the class testPlannerTester method testLoadJoinType.

public void testLoadJoinType() throws FileNotFoundException {
    AbstractPlanNode pn = null;
    pn = compile("select * from l, t where l.b=t.b limit ?;");
    plannerTester.setUpForTest(m_currentDir + "tests/frontend/org/voltdb/planner/testplans-plannerTester-ddl.sql", "testplans-plannerTester-ddl");
    System.out.println(pn.toExplainPlanString());
    System.out.println(pn.toJSONString());
    plannerTester.writePlanToFile(pn, m_homeDir, "prettyJson.txt", "");
    ArrayList<String> getsql = new ArrayList<>();
    AbstractPlanNode pn2 = plannerTester.loadPlanFromFile(m_homeDir + "prettyJson.txt", getsql);
    System.out.println(pn2.toExplainPlanString());
    ArrayList<AbstractPlanNode> list1 = pn.getPlanNodeList();
    ArrayList<AbstractPlanNode> list2 = pn2.getPlanNodeList();
    assertTrue(list1.size() == list2.size());
    for (int i = 0; i < list1.size(); i++) {
        Map<PlanNodeType, AbstractPlanNode> inlineNodes1 = list1.get(i).getInlinePlanNodes();
        Map<PlanNodeType, AbstractPlanNode> inlineNodes2 = list2.get(i).getInlinePlanNodes();
        if (inlineNodes1 != null) {
            assertTrue(inlineNodes1.size() == inlineNodes2.size());
        }
    }
}
Also used : AbstractPlanNode(org.voltdb.plannodes.AbstractPlanNode) PlanNodeType(org.voltdb.types.PlanNodeType) ArrayList(java.util.ArrayList)

Example 3 with PlanNodeType

use of org.voltdb.types.PlanNodeType in project voltdb by VoltDB.

the class PlannerTestCase method assertLeftChain.

/**
     * Assert that a plan's left-most branch is made up of plan nodes of
     * expected classes.
     * @param expectedClasses a list of expected AbstractPlanNode classes
     * @param actualPlan the top of a plan node tree expected to have instances
     *                   of the expected classes along its left-most branch
     *                   listed from top to bottom.
     */
protected static void assertLeftChain(AbstractPlanNode start, PlanNodeType... nodeTypes) {
    AbstractPlanNode pn = start;
    for (PlanNodeType type : nodeTypes) {
        assertFalse("Child node(s) are missing from the actual plan chain.", pn == null);
        if (!type.equals(pn.getPlanNodeType())) {
            fail("Expecting plan node of type " + type + ", " + "instead found " + pn.getPlanNodeType() + ".");
        }
        pn = (pn.getChildCount() > 0) ? pn.getChild(0) : null;
    }
    assertTrue("Actual plan chain was longer than expected", pn == null);
}
Also used : AbstractPlanNode(org.voltdb.plannodes.AbstractPlanNode) PlanNodeType(org.voltdb.types.PlanNodeType)

Example 4 with PlanNodeType

use of org.voltdb.types.PlanNodeType in project voltdb by VoltDB.

the class PlannerTestCase method assertTopDownTree.

/**
     * Assert that a plan node tree contains the expected types of plan nodes
     * in the order listed, assuming a top-down left-to-right depth-first
     * traversal through the child vector. A null plan node type in the list
     * will match any plan node or subtree at the corresponding position.
     **/
protected static void assertTopDownTree(AbstractPlanNode start, PlanNodeType... nodeTypes) {
    Stack<AbstractPlanNode> stack = new Stack<>();
    stack.push(start);
    for (PlanNodeType type : nodeTypes) {
        // Process each node before its children or later siblings.
        AbstractPlanNode parent;
        try {
            parent = stack.pop();
        } catch (EmptyStackException ese) {
            fail("No node was found in the tree to match node type " + type);
            // This dead code hushes warnings.
            return;
        }
        int childCount = parent.getChildCount();
        if (type == null) {
            // A null type wildcard matches any child TREE or NODE.
            System.out.println("DEBUG: Suggestion -- expect " + parent.getPlanNodeType() + " with " + childCount + " direct children.");
            continue;
        }
        assertEquals(type, parent.getPlanNodeType());
        // Iterate from the last child to the first.
        while (childCount > 0) {
            // Push each child to be processed before its parent's
            // or its own later (already pushed) siblings.
            stack.push(parent.getChild(--childCount));
        }
    }
    assertTrue("Extra plan node(s) (" + stack.size() + ") were found in the tree with no node type to match", stack.isEmpty());
}
Also used : AbstractPlanNode(org.voltdb.plannodes.AbstractPlanNode) PlanNodeType(org.voltdb.types.PlanNodeType) EmptyStackException(java.util.EmptyStackException) Stack(java.util.Stack)

Example 5 with PlanNodeType

use of org.voltdb.types.PlanNodeType in project voltdb by VoltDB.

the class AbstractPlanNode method toJSONString.

public void toJSONString(JSONStringer stringer) throws JSONException {
    stringer.keySymbolValuePair(Members.ID.name(), m_id);
    stringer.keySymbolValuePair(Members.PLAN_NODE_TYPE.name(), getPlanNodeType().toString());
    if (m_inlineNodes.size() > 0) {
        PlanNodeType[] types = new PlanNodeType[m_inlineNodes.size()];
        int i = 0;
        for (PlanNodeType type : m_inlineNodes.keySet()) {
            types[i++] = type;
        }
        Arrays.sort(types);
        stringer.key(Members.INLINE_NODES.name()).array();
        for (PlanNodeType type : types) {
            AbstractPlanNode node = m_inlineNodes.get(type);
            assert (node != null);
            stringer.value(node);
        }
        stringer.endArray();
    }
    if (m_children.size() > 0) {
        stringer.key(Members.CHILDREN_IDS.name()).array();
        for (AbstractPlanNode node : m_children) {
            stringer.value(node.getPlanNodeId().intValue());
        }
        stringer.endArray();
    }
    outputSchemaToJSON(stringer);
}
Also used : PlanNodeType(org.voltdb.types.PlanNodeType)

Aggregations

PlanNodeType (org.voltdb.types.PlanNodeType)14 AbstractPlanNode (org.voltdb.plannodes.AbstractPlanNode)12 ArrayList (java.util.ArrayList)4 AbstractScanPlanNode (org.voltdb.plannodes.AbstractScanPlanNode)3 ReceivePlanNode (org.voltdb.plannodes.ReceivePlanNode)2 EmptyStackException (java.util.EmptyStackException)1 LinkedHashMap (java.util.LinkedHashMap)1 LinkedList (java.util.LinkedList)1 Stack (java.util.Stack)1 JSONArray (org.json_voltpatches.JSONArray)1 JSONException (org.json_voltpatches.JSONException)1 JSONObject (org.json_voltpatches.JSONObject)1 JSONString (org.json_voltpatches.JSONString)1 AbstractExpression (org.voltdb.expressions.AbstractExpression)1 SelectSubqueryExpression (org.voltdb.expressions.SelectSubqueryExpression)1 AbstractReceivePlanNode (org.voltdb.plannodes.AbstractReceivePlanNode)1 AggregatePlanNode (org.voltdb.plannodes.AggregatePlanNode)1 HashAggregatePlanNode (org.voltdb.plannodes.HashAggregatePlanNode)1 IndexScanPlanNode (org.voltdb.plannodes.IndexScanPlanNode)1 MergeReceivePlanNode (org.voltdb.plannodes.MergeReceivePlanNode)1