Java tutorial
/* * 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.List; 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<>()); 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<>()); 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, 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) { List<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; } }