All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.flink.table.planner.plan.nodes.exec.processor.utils.InputPriorityConflictResolver Maven / Gradle / Ivy

/*
 * 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.flink.table.planner.plan.nodes.exec.processor.utils;

import org.apache.flink.annotation.Internal;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.transformations.ShuffleMode;
import org.apache.flink.table.planner.plan.nodes.exec.ExecEdge;
import org.apache.flink.table.planner.plan.nodes.exec.ExecNode;
import org.apache.flink.table.planner.plan.nodes.exec.InputProperty;
import org.apache.flink.table.planner.plan.nodes.exec.batch.BatchExecExchange;
import org.apache.flink.table.planner.plan.nodes.exec.visitor.AbstractExecNodeExactlyOnceVisitor;
import org.apache.flink.table.types.logical.RowType;

import java.util.Collections;
import java.util.List;

/**
 * Subclass of the {@link InputPriorityGraphGenerator}.
 *
 * 

This class resolve conflicts by inserting a {@link BatchExecExchange} into the conflicting * input. */ @Internal public class InputPriorityConflictResolver extends InputPriorityGraphGenerator { private final ShuffleMode shuffleMode; private final Configuration configuration; /** * Create a {@link InputPriorityConflictResolver} for the given {@link ExecNode} graph. * * @param roots the first layer of nodes on the output side of the graph * @param safeDamBehavior when checking for conflicts we'll ignore the edges with {@link * InputProperty.DamBehavior} stricter or equal than this * @param shuffleMode when a conflict occurs we'll insert an {@link BatchExecExchange} node with * this shuffleMode to resolve conflict */ public InputPriorityConflictResolver( List> roots, InputProperty.DamBehavior safeDamBehavior, ShuffleMode shuffleMode, Configuration configuration) { super(roots, Collections.emptySet(), safeDamBehavior); this.shuffleMode = shuffleMode; this.configuration = configuration; } public void detectAndResolve() { createTopologyGraph(); } @Override protected void resolveInputPriorityConflict(ExecNode node, int higherInput, int lowerInput) { ExecNode higherNode = node.getInputEdges().get(higherInput).getSource(); ExecNode lowerNode = node.getInputEdges().get(lowerInput).getSource(); final ExecNode newNode; if (lowerNode instanceof BatchExecExchange) { BatchExecExchange exchange = (BatchExecExchange) lowerNode; InputProperty inputEdge = exchange.getInputProperties().get(0); InputProperty inputProperty = InputProperty.builder() .requiredDistribution(inputEdge.getRequiredDistribution()) .priority(inputEdge.getPriority()) .damBehavior(getDamBehavior()) .build(); if (isConflictCausedByExchange(higherNode, exchange)) { // special case: if exchange is exactly the reuse node, // we should split it into two nodes BatchExecExchange newExchange = new BatchExecExchange( inputProperty, (RowType) exchange.getOutputType(), "Exchange"); newExchange.setRequiredShuffleMode(shuffleMode); newExchange.setInputEdges(exchange.getInputEdges()); newNode = newExchange; } else { // create new BatchExecExchange with new inputProperty BatchExecExchange newExchange = new BatchExecExchange( inputProperty, (RowType) exchange.getOutputType(), exchange.getDescription()); newExchange.setRequiredShuffleMode(shuffleMode); newExchange.setInputEdges(exchange.getInputEdges()); newNode = newExchange; } } else { newNode = createExchange(node, lowerInput); } ExecEdge newEdge = ExecEdge.builder().source(newNode).target(node).build(); node.replaceInputEdge(lowerInput, newEdge); } private boolean isConflictCausedByExchange( ExecNode higherNode, BatchExecExchange lowerNode) { // check if `lowerNode` is the ancestor of `higherNode`, // if yes then conflict is caused by `lowerNode` ConflictCausedByExchangeChecker checker = new ConflictCausedByExchangeChecker(lowerNode); checker.visit(higherNode); return checker.found; } private BatchExecExchange createExchange(ExecNode node, int idx) { ExecNode inputNode = node.getInputEdges().get(idx).getSource(); InputProperty inputProperty = node.getInputProperties().get(idx); InputProperty.RequiredDistribution requiredDistribution = inputProperty.getRequiredDistribution(); if (requiredDistribution.getType() == InputProperty.DistributionType.BROADCAST) { // should not occur throw new IllegalStateException( "Trying to resolve input priority conflict on broadcast side. This is not expected."); } InputProperty newInputProperty = InputProperty.builder() .requiredDistribution(requiredDistribution) .priority(inputProperty.getPriority()) .damBehavior(getDamBehavior()) .build(); BatchExecExchange exchange = new BatchExecExchange( newInputProperty, (RowType) inputNode.getOutputType(), "Exchange"); exchange.setRequiredShuffleMode(shuffleMode); ExecEdge execEdge = ExecEdge.builder().source(inputNode).target(exchange).build(); exchange.setInputEdges(Collections.singletonList(execEdge)); return exchange; } private static class ConflictCausedByExchangeChecker extends AbstractExecNodeExactlyOnceVisitor { private final BatchExecExchange exchange; private boolean found; private ConflictCausedByExchangeChecker(BatchExecExchange exchange) { this.exchange = exchange; } @Override protected void visitNode(ExecNode node) { if (node == exchange) { found = true; } for (ExecEdge inputEdge : node.getInputEdges()) { visit(inputEdge.getSource()); if (found) { return; } } } } private InputProperty.DamBehavior getDamBehavior() { if (BatchExecExchange.getShuffleMode(configuration, shuffleMode) == ShuffleMode.BATCH) { return InputProperty.DamBehavior.BLOCKING; } else { return InputProperty.DamBehavior.PIPELINED; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy