private PlanNodeCostEstimate getGroupCost(GroupReference groupReference) { int group = groupReference.getGroupId(); Memo memo = this.memo.orElseThrow(() -> new IllegalStateException("CachingCostProvider without memo cannot handle GroupReferences")); Optional<PlanNodeCostEstimate> cost = memo.getCumulativeCost(group); if (cost.isPresent()) { return cost.get(); } PlanNodeCostEstimate cumulativeCost = calculateCumulativeCost(memo.getNode(group)); verify(!memo.getCumulativeCost(group).isPresent(), "Group cost already set"); memo.storeCumulativeCost(group, cumulativeCost); return cumulativeCost; }
private PlanNodeStatsEstimate getGroupStats(GroupReference groupReference) { int group = groupReference.getGroupId(); Memo memo = this.memo.orElseThrow(() -> new IllegalStateException("CachingStatsProvider without memo cannot handle GroupReferences")); Optional<PlanNodeStatsEstimate> stats = memo.getStats(group); if (stats.isPresent()) { return stats.get(); } PlanNodeStatsEstimate groupStats = statsCalculator.calculateStats(memo.getNode(group), this, lookup, session, types); verify(!memo.getStats(group).isPresent(), "Group stats already set"); memo.storeStats(group, groupStats); return groupStats; } }
@Test public void testReplaceSubtree() { PlanNode plan = node(node(node())); Memo memo = new Memo(idAllocator, plan); assertEquals(memo.getGroupCount(), 3); // replace child of root node with subtree PlanNode transformed = node(node()); memo.replace(getChildGroup(memo, memo.getRootGroup()), transformed, "rule"); assertEquals(memo.getGroupCount(), 3); assertMatchesStructure(memo.extract(), node(plan.getId(), transformed)); }
@Test public void testEvictCostOnReplace() { PlanNode y = node(); PlanNode x = node(y); Memo memo = new Memo(idAllocator, x); int xGroup = memo.getRootGroup(); int yGroup = getChildGroup(memo, memo.getRootGroup()); PlanNodeCostEstimate yCost = PlanNodeCostEstimate.cpuCost(42); PlanNodeCostEstimate xCost = yCost.add(PlanNodeCostEstimate.networkCost(37)); memo.storeCumulativeCost(yGroup, yCost); memo.storeCumulativeCost(xGroup, xCost); assertEquals(memo.getCumulativeCost(yGroup), Optional.of(yCost)); assertEquals(memo.getCumulativeCost(xGroup), Optional.of(xCost)); memo.replace(yGroup, node(), "rule"); assertEquals(memo.getCumulativeCost(yGroup), Optional.empty()); assertEquals(memo.getCumulativeCost(xGroup), Optional.empty()); }
@Test public void testEvictStatsOnReplace() { PlanNode y = node(); PlanNode x = node(y); Memo memo = new Memo(idAllocator, x); int xGroup = memo.getRootGroup(); int yGroup = getChildGroup(memo, memo.getRootGroup()); PlanNodeStatsEstimate xStats = PlanNodeStatsEstimate.builder().setOutputRowCount(42).build(); PlanNodeStatsEstimate yStats = PlanNodeStatsEstimate.builder().setOutputRowCount(55).build(); memo.storeStats(yGroup, yStats); memo.storeStats(xGroup, xStats); assertEquals(memo.getStats(yGroup), Optional.of(yStats)); assertEquals(memo.getStats(xGroup), Optional.of(xStats)); memo.replace(yGroup, node(), "rule"); assertEquals(memo.getStats(yGroup), Optional.empty()); assertEquals(memo.getStats(xGroup), Optional.empty()); }
@Override public PlanNode optimize(PlanNode plan, Session session, TypeProvider types, SymbolAllocator symbolAllocator, PlanNodeIdAllocator idAllocator, WarningCollector warningCollector) { // only disable new rules if we have legacy rules to fall back to if (!SystemSessionProperties.isNewOptimizerEnabled(session) && !legacyRules.isEmpty()) { for (PlanOptimizer optimizer : legacyRules) { plan = optimizer.optimize(plan, session, symbolAllocator.getTypes(), symbolAllocator, idAllocator, warningCollector); } return plan; } Memo memo = new Memo(idAllocator, plan); Lookup lookup = Lookup.from(planNode -> Stream.of(memo.resolve(planNode))); Matcher matcher = new PlanNodeMatcher(lookup); Duration timeout = SystemSessionProperties.getOptimizerTimeout(session); Context context = new Context(memo, lookup, idAllocator, symbolAllocator, System.nanoTime(), timeout.toMillis(), session, warningCollector); exploreGroup(memo.getRootGroup(), context, matcher); return memo.extract(); }
private RuleApplication applyRule() { SymbolAllocator symbolAllocator = new SymbolAllocator(types.allTypes()); Memo memo = new Memo(idAllocator, plan); Lookup lookup = Lookup.from(planNode -> Stream.of(memo.resolve(planNode))); PlanNode memoRoot = memo.getNode(memo.getRootGroup()); return inTransaction(session -> applyRule(rule, memoRoot, ruleContext(statsCalculator, costCalculator, symbolAllocator, memo, lookup, session))); }
public PlanNode replace(int group, PlanNode node, String reason) { PlanNode old = getGroup(group).membership; checkArgument(new HashSet<>(old.getOutputSymbols()).equals(new HashSet<>(node.getOutputSymbols())), "%s: transformed expression doesn't produce same outputs: %s vs %s", reason, old.getOutputSymbols(), node.getOutputSymbols()); if (node instanceof GroupReference) { node = getNode(((GroupReference) node).getGroupId()); } else { node = insertChildrenAndRewrite(node); } incrementReferenceCounts(node, group); getGroup(group).membership = node; decrementReferenceCounts(old, group); evictStatisticsAndCost(group); return node; }
@Test public void testInitialization() { PlanNode plan = node(node()); Memo memo = new Memo(idAllocator, plan); assertEquals(memo.getGroupCount(), 2); assertMatchesStructure(plan, memo.extract()); }
private boolean exploreNode(int group, Context context, Matcher matcher) { PlanNode node = context.memo.getNode(group); boolean done = false; boolean progress = false; while (!done) { context.checkTimeoutNotExhausted(); done = true; Iterator<Rule<?>> possiblyMatchingRules = ruleIndex.getCandidates(node).iterator(); while (possiblyMatchingRules.hasNext()) { Rule<?> rule = possiblyMatchingRules.next(); if (!rule.isEnabled(context.session)) { continue; } Rule.Result result = transform(node, rule, matcher, context); if (result.getTransformedPlan().isPresent()) { node = context.memo.replace(group, result.getTransformedPlan().get(), rule.getClass().getName()); done = false; progress = true; } } } return progress; }
public PlanNode resolve(GroupReference groupReference) { return getNode(groupReference.getGroupId()); }
saveBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { memo = new Memo(); memo.setHeadLine(headLineTxt.getText().toString()); memo.setFullMemo(fullMemoTxt.getText().toString()); memo = datasource.createMemo(memo); finish(); } });
private PlanNode extract(PlanNode node) { return resolveGroupReferences(node, Lookup.from(planNode -> Stream.of(this.resolve(planNode)))); }
@Test public void testRemoveNode() { PlanNode z = node(); PlanNode y = node(z); PlanNode x = node(y); Memo memo = new Memo(idAllocator, x); assertEquals(memo.getGroupCount(), 3); int yGroup = getChildGroup(memo, memo.getRootGroup()); memo.replace(yGroup, memo.getNode(yGroup).getSources().get(0), "rule"); assertEquals(memo.getGroupCount(), 2); assertMatchesStructure( memo.extract(), node(x.getId(), node(z.getId()))); }
private boolean exploreChildren(int group, Context context, Matcher matcher) { boolean progress = false; PlanNode expression = context.memo.getNode(group); for (PlanNode child : expression.getSources()) { checkState(child instanceof GroupReference, "Expected child to be a group reference. Found: " + child.getClass().getName()); if (exploreGroup(((GroupReference) child).getGroupId(), context, matcher)) { progress = true; } } return progress; }
@Test public void testReplaceNode() { PlanNode z = node(); PlanNode y = node(z); PlanNode x = node(y); Memo memo = new Memo(idAllocator, x); assertEquals(memo.getGroupCount(), 3); // replace child of root node with another node, retaining child's child int yGroup = getChildGroup(memo, memo.getRootGroup()); GroupReference zRef = (GroupReference) getOnlyElement(memo.getNode(yGroup).getSources()); PlanNode transformed = node(zRef); memo.replace(yGroup, transformed, "rule"); assertEquals(memo.getGroupCount(), 3); assertMatchesStructure(memo.extract(), node(x.getId(), node(transformed.getId(), z))); }
private int getChildGroup(Memo memo, int group) { PlanNode node = memo.getNode(group); GroupReference child = (GroupReference) node.getSources().get(0); return child.getGroupId(); }
@Test public void testInsertNode() { PlanNode z = node(); PlanNode x = node(z); Memo memo = new Memo(idAllocator, x); assertEquals(memo.getGroupCount(), 2); int zGroup = getChildGroup(memo, memo.getRootGroup()); PlanNode y = node(memo.getNode(zGroup)); memo.replace(zGroup, y, "rule"); assertEquals(memo.getGroupCount(), 3); assertMatchesStructure( memo.extract(), node(x.getId(), node(y.getId(), node(z.getId())))); }
@Test public void testMultipleReferences() { PlanNode z = node(); PlanNode y = node(z); PlanNode x = node(y); Memo memo = new Memo(idAllocator, x); assertEquals(memo.getGroupCount(), 3); int yGroup = getChildGroup(memo, memo.getRootGroup()); PlanNode rewrittenZ = memo.getNode(yGroup).getSources().get(0); PlanNode y1 = node(rewrittenZ); PlanNode y2 = node(rewrittenZ); PlanNode newX = node(y1, y2); memo.replace(memo.getRootGroup(), newX, "rule"); assertEquals(memo.getGroupCount(), 4); assertMatchesStructure( memo.extract(), node(newX.getId(), node(y1.getId(), node(z.getId())), node(y2.getId(), node(z.getId())))); }