Package com.asakusafw.compiler.flow.stage

Source Code of com.asakusafw.compiler.flow.stage.StageCompiler

/**
* Copyright 2011-2014 Asakusa Framework Team.
*
* Licensed 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 com.asakusafw.compiler.flow.stage;

import java.io.IOException;
import java.text.MessageFormat;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.asakusafw.compiler.common.Precondition;
import com.asakusafw.compiler.flow.FlowCompilingEnvironment;
import com.asakusafw.compiler.flow.plan.FlowBlock;
import com.asakusafw.compiler.flow.plan.StageBlock;
import com.asakusafw.compiler.flow.plan.StageGraph;
import com.asakusafw.compiler.flow.stage.StageModel.Fragment;
import com.asakusafw.compiler.flow.stage.StageModel.ResourceFragment;
import com.asakusafw.compiler.flow.stage.StageModel.Unit;
import com.asakusafw.utils.collections.Lists;
import com.asakusafw.utils.collections.Sets;
import com.asakusafw.utils.java.model.syntax.Name;
import com.asakusafw.vocabulary.flow.graph.FlowElement;
import com.asakusafw.vocabulary.flow.graph.FlowResourceDescription;

/**
* ステージ内で利用されるプログラムをコンパイルする。
* @since 0.1.0
* @version 0.4.0
*/
public class StageCompiler {

    static final Logger LOG = LoggerFactory.getLogger(StageCompiler.class);

    private final FlowCompilingEnvironment environment;

    private final ShuffleAnalyzer shuffleAnalyzer;
    private final StageAnalyzer mapredAnalyzer;

    private final ShuffleKeyEmitter shuffleKeyEmitter;
    private final ShuffleValueEmitter shuffleValueEmitter;
    private final ShuffleGroupingComparatorEmitter shuffleGroupingEmitter;
    private final ShuffleSortComparatorEmitter shuffleSortingEmitter;
    private final ShufflePartitionerEmitter shuffleParitioningEmitter;

    private final FlowResourceEmitter flowResourceEmitter;
    private final MapFragmentEmitter mapFragmentEmitter;
    private final ShuffleFragmentEmitter shuffleFragmentEmitter;
    private final ReduceFragmentEmitter reduceFragmentEmitter;

    private final MapperEmitter mapperEmitter;
    private final ReducerEmitter reducerEmitter;
    private final CombinerEmitter combinerEmitter;

    /**
     * インスタンスを生成する。
     * @param environment 環境オブジェクト
     * @throws IllegalArgumentException 引数に{@code null}が指定された場合
     */
    public StageCompiler(FlowCompilingEnvironment environment) {
        Precondition.checkMustNotBeNull(environment, "environment"); //$NON-NLS-1$
        this.environment = environment;

        this.shuffleAnalyzer = new ShuffleAnalyzer(environment);
        this.mapredAnalyzer = new StageAnalyzer(environment);

        this.shuffleKeyEmitter = new ShuffleKeyEmitter(environment);
        this.shuffleValueEmitter = new ShuffleValueEmitter(environment);
        this.shuffleGroupingEmitter = new ShuffleGroupingComparatorEmitter(environment);
        this.shuffleSortingEmitter = new ShuffleSortComparatorEmitter(environment);
        this.shuffleParitioningEmitter = new ShufflePartitionerEmitter(environment);

        this.flowResourceEmitter = new FlowResourceEmitter(environment);
        this.mapFragmentEmitter = new MapFragmentEmitter(environment);
        this.shuffleFragmentEmitter = new ShuffleFragmentEmitter(environment);
        this.reduceFragmentEmitter = new ReduceFragmentEmitter(environment);

        this.mapperEmitter = new MapperEmitter(environment);
        this.reducerEmitter = new ReducerEmitter(environment);
        this.combinerEmitter = new CombinerEmitter(environment);
    }

    /**
     * 指定のステージグラフに含まれるすべてのステージをコンパイルし、モデルオブジェクトとして返す。
     * @param graph コンパイル対象のグラフ
     * @return 対応するコンパイル済みのステージ一覧
     * @throws IOException コンパイル結果の出力に失敗した場合
     * @throws IllegalArgumentException 引数に{@code null}が指定された場合
     */
    public List<StageModel> compile(StageGraph graph) throws IOException {
        Precondition.checkMustNotBeNull(graph, "graph"); //$NON-NLS-1$
        LOG.debug("ステージグラフの各ステージを{}をコンパイルします",
                graph.getInput().getSource().getDescription().getName());

        Map<FlowResourceDescription, CompiledType> resourceMap = compileResources(graph);
        List<StageModel> results = Lists.create();
        for (StageBlock block : graph.getStages()) {
            StageModel model = compileStage(block, resourceMap);
            results.add(model);
        }
        if (environment.hasError()) {
            throw new IOException(MessageFormat.format(
                    "エラーによりコンパイルは中断されました ({0})",
                    environment.getErrorMessage()));
        }
        return results;
    }

    private StageModel compileStage(
            StageBlock block,
            Map<FlowResourceDescription, CompiledType> resourceMap) throws IOException {
        assert block != null;
        assert resourceMap != null;
        LOG.debug("ステージブロック{}をコンパイルします", block);
        StageModel model = analyze(block);
        blessResources(model, resourceMap);
        compileShuffle(model);
        compileFragments(model);
        compileUnits(model);
        return model;
    }

    private void compileUnits(StageModel model) throws IOException {
        assert model != null;
        for (StageModel.MapUnit unit : model.getMapUnits()) {
            CompiledType compiled = mapperEmitter.emit(model, unit);
            unit.setCompiled(compiled);
        }
        if (model.getReduceUnits().isEmpty() == false) {
            CompiledType compiledReducer = reducerEmitter.emit(model);
            CompiledType compiledCombiner = combinerEmitter.emit(model);
            CompiledReduce compiled = new CompiledReduce(compiledReducer, compiledCombiner);
            for (StageModel.ReduceUnit unit : model.getReduceUnits()) {
                unit.setCompiled(compiled);
            }
        }
    }

    private void compileFragments(StageModel model) throws IOException {
        assert model != null;
        StageBlock block = model.getStageBlock();
        for (StageModel.MapUnit unit : model.getMapUnits()) {
            for (StageModel.Fragment fragment : unit.getFragments()) {
                if (fragment.isCompiled()) {
                    continue;
                }
                CompiledType compiled = mapFragmentEmitter.emit(fragment, block);
                fragment.setCompiled(compiled);
            }
        }

        ShuffleModel shuffle = model.getShuffleModel();
        if (shuffle == null) {
            return;
        }
        Name keyTypeName = shuffle.getCompiled().getKeyTypeName();
        Name valueTypeName = shuffle.getCompiled().getValueTypeName();
        for (ShuffleModel.Segment segment : shuffle.getSegments()) {
            CompiledShuffleFragment fragment = shuffleFragmentEmitter.emit(
                    segment,
                    keyTypeName,
                    valueTypeName,
                    block);
            segment.setCompiled(fragment);
        }

        for (StageModel.ReduceUnit unit : model.getReduceUnits()) {
            for (StageModel.Fragment fragment : unit.getFragments()) {
                if (fragment.isCompiled()) {
                    continue;
                }
                CompiledType compiled;
                if (fragment.isRendezvous()) {
                    compiled = reduceFragmentEmitter.emit(fragment, shuffle, block);
                } else {
                    compiled = mapFragmentEmitter.emit(fragment, block);
                }
                fragment.setCompiled(compiled);
            }
        }
    }

    private StageModel analyze(StageBlock block) throws IOException {
        ShuffleModel shuffle = shuffleAnalyzer.analyze(block);
        StageModel model = mapredAnalyzer.analyze(block, shuffle);
        if (mapredAnalyzer.hasError() || shuffleAnalyzer.hasError()) {
            mapredAnalyzer.clearError();
            shuffleAnalyzer.clearError();
            throw new IOException("ステージのコンパイルは中断されました");
        }
        return model;
    }

    private void compileShuffle(StageModel model) throws IOException {
        assert model != null;
        ShuffleModel shuffle = model.getShuffleModel();
        if (shuffle == null) {
            return;
        }
        Name keyTypeName = shuffleKeyEmitter.emit(shuffle);
        Name valueTypeName = shuffleValueEmitter.emit(shuffle);
        Name groupComparatorTypeName = shuffleGroupingEmitter.emit(shuffle, keyTypeName);
        Name sortComparatorTypeName = shuffleSortingEmitter.emit(shuffle, keyTypeName);
        Name partitionerTypeName = shuffleParitioningEmitter.emit(shuffle, keyTypeName, valueTypeName);
        CompiledShuffle compiled = new CompiledShuffle(
                keyTypeName,
                valueTypeName,
                groupComparatorTypeName,
                sortComparatorTypeName,
                partitionerTypeName);
        shuffle.setCompiled(compiled);
    }

    private Map<FlowResourceDescription, CompiledType> compileResources(
            StageGraph graph) throws IOException {
        assert graph != null;
        Set<FlowResourceDescription> resources = collectResources(graph);
        return flowResourceEmitter.emit(resources);
    }

    private Set<FlowResourceDescription> collectResources(StageGraph graph) {
        assert graph != null;
        Set<FlowResourceDescription> resources = Sets.create();
        for (StageBlock stage : graph.getStages()) {
            List<FlowBlock> blocks = Lists.create();
            blocks.addAll(stage.getMapBlocks());
            blocks.addAll(stage.getReduceBlocks());
            for (FlowBlock block : blocks) {
                for (FlowElement element : block.getElements()) {
                    for (FlowResourceDescription resource : element.getDescription().getResources()) {
                        resources.add(resource);
                    }
                }
            }
        }
        return resources;
    }

    private void blessResources(
            StageModel model,
            Map<FlowResourceDescription, CompiledType> resourceMap) {
        assert model != null;
        assert resourceMap != null;
        List<ResourceFragment> resources = Lists.create();
        List<Unit<?>> units = Lists.create();
        units.addAll(model.getMapUnits());
        units.addAll(model.getReduceUnits());
        for (Unit<?> unit : units) {
            for (Fragment fragment : unit.getFragments()) {
                resources.addAll(fragment.getResources());
            }
        }
        Set<FlowResourceDescription> saw = Sets.create();
        for (ResourceFragment fragment : resources) {
            if (fragment.isCompiled()) {
                continue;
            }
            CompiledType resolved = resourceMap.get(fragment.getDescription());
            if (resolved == null) {
                if (saw.contains(fragment.getDescription()) == false) {
                    environment.error(
                            "{}が解決されていません",
                            fragment.getDescription());
                    saw.add(fragment.getDescription());
                }
                continue;
            }
            fragment.setCompiled(resolved);
        }
    }
}
TOP

Related Classes of com.asakusafw.compiler.flow.stage.StageCompiler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.