io.crate.operation.collect.ShardProjectorChain.java Source code

Java tutorial

Introduction

Here is the source code for io.crate.operation.collect.ShardProjectorChain.java

Source

/*
 * Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
 * license agreements.  See the NOTICE file distributed with this work for
 * additional information regarding copyright ownership.  Crate 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.
 *
 * However, if you have executed another commercial license agreement
 * with Crate these terms will supersede the license and you may use the
 * software solely pursuant to the terms of the relevant commercial agreement.
 */

package io.crate.operation.collect;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.ListenableFuture;
import io.crate.breaker.RamAccountingContext;
import io.crate.operation.projectors.CollectingProjector;
import io.crate.operation.projectors.ResultProvider;
import io.crate.operation.projectors.ProjectionToProjectorVisitor;
import io.crate.operation.projectors.Projector;
import io.crate.planner.RowGranularity;
import io.crate.planner.projection.Projection;
import org.elasticsearch.search.facet.FacetExecutor;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * a chain of connected projectors data is flowing through
 * with separate chains, zero or more chains to be executed on data shards
 * connected to the final chain of which there can be only one,
 * executed on a node.
 *
 * Currently only one projector can be executed on a shard
 *
 * <pre>
 * Data -> Shard chain 0 \
 *                        \
 * Data -> Shard chain 1 ----> Node chain --> Result
 *                        /
 * Data -> Shard chain 2 /
 * </pre>
 *
 * If there is no projector to be executed on a shard,
 * all data will go directly to the node chain.
 * <p>
 * Usage:
 *
 * <ul>
 *     <li> construct one from a list of projections
 *     <li> get a shard projector by calling {@linkplain #newShardDownstreamProjector(io.crate.operation.projectors.ProjectionToProjectorVisitor)}
 *          from a shard context. do this for every shard you have
 *     <li> call {@linkplain #startProjections()}
 *     <li> feed data to the shard projectors
 *     <li> get your result from {@linkplain #result()}
 *
 */
public class ShardProjectorChain implements ResultProvider {

    private final List<Projection> projections;
    protected final List<Projector> shardProjectors;
    protected final List<Projector> nodeProjectors;
    private Projector firstNodeProjector;
    private ResultProvider lastProjector;
    private int shardProjectionsIndex = -1;

    public ShardProjectorChain(int numShards, List<Projection> projections,
            ProjectionToProjectorVisitor nodeProjectorVisitor, RamAccountingContext ramAccountingContext) {
        this.projections = projections;
        nodeProjectors = new ArrayList<>();

        if (projections.size() == 0) {
            firstNodeProjector = new CollectingProjector();
            lastProjector = (ResultProvider) firstNodeProjector;
            nodeProjectors.add(firstNodeProjector);
            shardProjectors = ImmutableList.of();
            return;
        }

        int idx = 0;
        for (Projection projection : projections) {
            if (projection.requiredGranularity() == RowGranularity.SHARD) {
                shardProjectionsIndex = idx;
                break; // we can quit here since currently
                       // there can be only 1 projection on the shard
            }
            idx++;
        }

        Projector previousProjector = null;
        // create the node level projectors
        for (int i = shardProjectionsIndex + 1; i < projections.size(); i++) {
            Projector projector = nodeProjectorVisitor.process(projections.get(i), ramAccountingContext);
            nodeProjectors.add(projector);
            if (previousProjector != null) {
                previousProjector.downstream(projector);
            } else {
                firstNodeProjector = projector;
            }
            previousProjector = projector;
        }
        if (shardProjectionsIndex >= 0) {
            shardProjectors = new ArrayList<>((shardProjectionsIndex + 1) * numShards);
            // shardprojector will be created later
            if (nodeProjectors.isEmpty()) {
                // no node projectors
                previousProjector = firstNodeProjector = new CollectingProjector();
            }
        } else {
            shardProjectors = ImmutableList.of();
        }
        assert previousProjector != null;
        if (previousProjector instanceof ResultProvider) {
            lastProjector = (ResultProvider) previousProjector;
        } else {
            lastProjector = new CollectingProjector();
            previousProjector.downstream((Projector) lastProjector);
        }
    }

    /**
     * Creates a new shard downstream chain if needed and returns a projector to be used as downstream
     * this method also calls startProjection on newly created shard level projectors.
     *
     * @param projectorVisitor the visitor to create projections out of a projection
     * @return a new projector connected to the internal chain
     */
    public Projector newShardDownstreamProjector(ProjectionToProjectorVisitor projectorVisitor,
            RamAccountingContext ramAccountingContext) {
        if (shardProjectionsIndex < 0) {
            return firstNodeProjector;
        }
        Projector previousProjector = firstNodeProjector;
        Projector projector = null;
        for (int i = shardProjectionsIndex; i >= 0; i--) {
            projector = projectorVisitor.process(projections.get(i), ramAccountingContext);
            projector.downstream(previousProjector);
            shardProjectors.add(projector);
            previousProjector = projector;
        }
        return projector;
    }

    public ListenableFuture<Object[][]> result() {
        return lastProjector.result();
    }

    @Override
    public Iterator<Object[]> iterator() throws IllegalStateException {
        return lastProjector.iterator();
    }

    public void startProjections() {
        for (Projector projector : Lists.reverse(nodeProjectors)) {
            projector.startProjection();
        }
        if (shardProjectionsIndex >= 0) {
            for (Projector p : shardProjectors) {
                p.startProjection();
            }
        }
    }
}