1 /*
2 * ModeShape (http://www.modeshape.org)
3 * See the COPYRIGHT.txt file distributed with this work for information
4 * regarding copyright ownership. Some portions may be licensed
5 * to Red Hat, Inc. under one or more contributor license agreements.
6 * See the AUTHORS.txt file in the distribution for a full listing of
7 * individual contributors.
8 *
9 * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10 * is licensed to you under the terms of the GNU Lesser General Public License as
11 * published by the Free Software Foundation; either version 2.1 of
12 * the License, or (at your option) any later version.
13 *
14 * ModeShape is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this software; if not, write to the Free
21 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23 */
24 package org.modeshape.graph.query.optimize;
25
26 import java.util.LinkedList;
27 import net.jcip.annotations.Immutable;
28 import org.modeshape.common.collection.Problems;
29 import org.modeshape.common.util.Logger;
30 import org.modeshape.graph.query.QueryContext;
31 import org.modeshape.graph.query.plan.PlanHints;
32 import org.modeshape.graph.query.plan.PlanNode;
33
34 /**
35 * Optimizer implementation that optimizes a query using a stack of rules. Subclasses can override the
36 * {@link #populateRuleStack(LinkedList, PlanHints)} method to define the stack of rules they'd like to use, including the use of
37 * custom rules.
38 */
39 @Immutable
40 public class RuleBasedOptimizer implements Optimizer {
41
42 private static final Logger LOGGER = Logger.getLogger(RuleBasedOptimizer.class);
43
44 /**
45 * {@inheritDoc}
46 *
47 * @see org.modeshape.graph.query.optimize.Optimizer#optimize(QueryContext, PlanNode)
48 */
49 public PlanNode optimize( QueryContext context,
50 PlanNode plan ) {
51 LinkedList<OptimizerRule> rules = new LinkedList<OptimizerRule>();
52 populateRuleStack(rules, context.getHints());
53
54 Problems problems = context.getProblems();
55 while (rules.peek() != null && !problems.hasErrors()) {
56 OptimizerRule nextRule = rules.poll();
57 LOGGER.debug("Running query optimizer rule {0}", nextRule);
58 plan = nextRule.execute(context, plan, rules);
59 }
60
61 return plan;
62 }
63
64 /**
65 * Method that is used to create the initial rule stack. This method can be overridden by subclasses
66 *
67 * @param ruleStack the stack where the rules should be placed; never null
68 * @param hints the plan hints
69 */
70 protected void populateRuleStack( LinkedList<OptimizerRule> ruleStack,
71 PlanHints hints ) {
72 if (hints.hasSubqueries) {
73 ruleStack.addFirst(RaiseVariableName.INSTANCE);
74 }
75 ruleStack.addFirst(RewriteAsRangeCriteria.INSTANCE);
76 if (hints.hasJoin) {
77 ruleStack.addFirst(ChooseJoinAlgorithm.USE_ONLY_NESTED_JOIN_ALGORITHM);
78 ruleStack.addFirst(RewriteIdentityJoins.INSTANCE);
79 }
80 ruleStack.addFirst(PushProjects.INSTANCE);
81 ruleStack.addFirst(PushSelectCriteria.INSTANCE);
82 ruleStack.addFirst(AddAccessNodes.INSTANCE);
83 ruleStack.addFirst(RightOuterToLeftOuterJoins.INSTANCE);
84 ruleStack.addFirst(CopyCriteria.INSTANCE);
85 if (hints.hasView) {
86 ruleStack.addFirst(ReplaceViews.INSTANCE);
87 }
88 }
89 }