blob: fbd88addba3bd8a9547ef50d92087e0aa448c225 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tajo.engine.codegen;
import com.google.common.collect.Maps;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tajo.catalog.Schema;
import org.apache.tajo.exception.TajoException;
import org.apache.tajo.plan.LogicalPlan;
import org.apache.tajo.plan.Target;
import org.apache.tajo.plan.expr.EvalNode;
import org.apache.tajo.plan.logical.*;
import org.apache.tajo.plan.util.PlannerUtil;
import org.apache.tajo.plan.visitor.BasicLogicalPlanVisitor;
import org.apache.tajo.util.Pair;
import java.util.Collections;
import java.util.Map;
import java.util.Stack;
public class ExecutorPreCompiler extends BasicLogicalPlanVisitor<ExecutorPreCompiler.CompilationContext, LogicalNode> {
private static final Log LOG = LogFactory.getLog(ExecutorPreCompiler.class);
private static final ExecutorPreCompiler instance;
static {
instance = new ExecutorPreCompiler();
}
public static void compile(CompilationContext context, LogicalNode node) throws TajoException {
instance.visit(context, null, null, node, new Stack<LogicalNode>());
context.compiledEval = Collections.unmodifiableMap(context.compiledEval);
}
public static Map<Pair<Schema, EvalNode>, EvalNode> compile(TajoClassLoader classLoader, LogicalNode node)
throws TajoException {
CompilationContext context = new CompilationContext(classLoader);
instance.visit(context, null, null, node, new Stack<LogicalNode>());
return context.compiledEval;
}
public static class CompilationContext {
private final EvalCodeGenerator compiler;
private Map<Pair<Schema,EvalNode>, EvalNode> compiledEval;
public CompilationContext(TajoClassLoader classLoader) {
this.compiler = new EvalCodeGenerator(classLoader);
this.compiledEval = Maps.newHashMap();
}
public EvalCodeGenerator getCompiler() {
return compiler;
}
public Map<Pair<Schema, EvalNode>, EvalNode> getPrecompiedEvals() {
return compiledEval;
}
}
private static void compileIfAbsent(CompilationContext context, Schema schema, EvalNode eval) {
Pair<Schema, EvalNode> key = new Pair<Schema, EvalNode>(schema, eval);
if (!context.compiledEval.containsKey(key)) {
try {
EvalNode compiled = context.compiler.compile(schema, eval);
context.compiledEval.put(key, compiled);
} catch (Throwable t) {
// If any compilation error occurs, it works in a fallback mode. This mode just uses EvalNode objects
// instead of a compiled EvalNode.
context.compiledEval.put(key, eval);
LOG.warn(t, t);
}
}
}
private static void compileProjectableNode(CompilationContext context, Schema schema, Projectable node) {
Target[] targets;
if (node.hasTargets()) {
targets = node.getTargets();
} else {
targets = PlannerUtil.schemaToTargets(node.getOutSchema());
}
for (Target target : targets) {
compileIfAbsent(context, schema, target.getEvalTree());
}
}
private static void compileSelectableNode(CompilationContext context, Schema schema, SelectableNode node) {
if (node.hasQual()) {
compileIfAbsent(context, schema, node.getQual());
}
}
@Override
public LogicalNode visitProjection(CompilationContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
ProjectionNode node, Stack<LogicalNode> stack) throws TajoException {
super.visitProjection(context, plan, block, node, stack);
compileProjectableNode(context, node.getInSchema(), node);
return node;
}
@Override
public LogicalNode visitHaving(CompilationContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
HavingNode node, Stack<LogicalNode> stack) throws TajoException {
super.visitHaving(context, plan, block, node, stack);
compileSelectableNode(context, node.getInSchema(), node);
return node;
}
@Override
public LogicalNode visitGroupBy(CompilationContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
GroupbyNode node, Stack<LogicalNode> stack) throws TajoException {
super.visitGroupBy(context, plan, block, node, stack);
compileProjectableNode(context, node.getInSchema(), node);
return node;
}
@Override
public LogicalNode visitWindowAgg(CompilationContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
WindowAggNode node, Stack<LogicalNode> stack) throws TajoException {
super.visitWindowAgg(context, plan, block, node, stack);
compileProjectableNode(context, node.getInSchema(), node);
return node;
}
public LogicalNode visitDistinctGroupby(CompilationContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
DistinctGroupbyNode node, Stack<LogicalNode> stack) throws TajoException {
super.visitDistinctGroupby(context, plan, block, node, stack);
compileProjectableNode(context, node.getInSchema(), node);
return node;
}
@Override
public LogicalNode visitFilter(CompilationContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
SelectionNode node, Stack<LogicalNode> stack) throws TajoException {
super.visitFilter(context, plan, block, node, stack);
compileSelectableNode(context, node.getInSchema(), node);
return node;
}
@Override
public LogicalNode visitJoin(CompilationContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
JoinNode node, Stack<LogicalNode> stack) throws TajoException {
super.visitJoin(context, plan, block, node, stack);
compileProjectableNode(context, node.getInSchema(), node);
if (node.hasJoinQual()) {
compileIfAbsent(context, node.getInSchema(), node.getJoinQual());
}
return node;
}
@Override
public LogicalNode visitTableSubQuery(CompilationContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
TableSubQueryNode node, Stack<LogicalNode> stack) throws TajoException {
stack.push(node);
visit(context, plan, null, node.getSubQuery(), stack);
stack.pop();
if (node.hasTargets()) {
for (Target target : node.getTargets()) {
compileIfAbsent(context, node.getLogicalSchema(), target.getEvalTree());
}
}
return node;
}
@Override
public LogicalNode visitPartitionedTableScan(CompilationContext context, LogicalPlan plan,
LogicalPlan.QueryBlock block, PartitionedTableScanNode node,
Stack<LogicalNode> stack) throws TajoException {
visitScan(context, plan, block, node, stack);
return node;
}
@Override
public LogicalNode visitScan(CompilationContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
ScanNode node, Stack<LogicalNode> stack) throws TajoException {
compileProjectableNode(context, node.getInSchema(), node);
compileSelectableNode(context, node.getInSchema(), node);
return node;
}
@Override
public LogicalNode visitIndexScan(CompilationContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
IndexScanNode node, Stack<LogicalNode> stack) throws TajoException {
visitScan(context, plan, block, node, stack);
return node;
}
}