use of org.apache.flink.table.planner.plan.nodes.exec.ExecNode in project flink by apache.
the class InputPriorityConflictResolverTest method testDeadlockCausedByExchange.
@Test
public void testDeadlockCausedByExchange() {
// P1 = PIPELINED + priority 1
//
// 0 -(P0)-> exchange --(P0)-> 1
// \-(P1)-/
TestingBatchExecNode[] nodes = new TestingBatchExecNode[2];
for (int i = 0; i < nodes.length; i++) {
nodes[i] = new TestingBatchExecNode("TestingBatchExecNode" + i);
}
BatchExecExchange exchange = new BatchExecExchange(InputProperty.builder().requiredDistribution(InputProperty.ANY_DISTRIBUTION).build(), (RowType) nodes[0].getOutputType(), "Exchange");
exchange.setRequiredExchangeMode(StreamExchangeMode.BATCH);
ExecEdge execEdge = ExecEdge.builder().source(nodes[0]).target(exchange).build();
exchange.setInputEdges(Collections.singletonList(execEdge));
nodes[1].addInput(exchange, InputProperty.builder().priority(0).build());
nodes[1].addInput(exchange, InputProperty.builder().priority(1).build());
InputPriorityConflictResolver resolver = new InputPriorityConflictResolver(Collections.singletonList(nodes[1]), InputProperty.DamBehavior.END_INPUT, StreamExchangeMode.BATCH, new Configuration());
resolver.detectAndResolve();
ExecNode<?> input0 = nodes[1].getInputNodes().get(0);
ExecNode<?> input1 = nodes[1].getInputNodes().get(1);
Assert.assertNotSame(input0, input1);
Consumer<ExecNode<?>> checkExchange = execNode -> {
Assert.assertTrue(execNode instanceof BatchExecExchange);
BatchExecExchange e = (BatchExecExchange) execNode;
Assert.assertEquals(Optional.of(StreamExchangeMode.BATCH), e.getRequiredExchangeMode());
Assert.assertEquals(nodes[0], e.getInputEdges().get(0).getSource());
};
checkExchange.accept(input0);
checkExchange.accept(input1);
}
use of org.apache.flink.table.planner.plan.nodes.exec.ExecNode in project flink by apache.
the class ExecNodePlanDumper method dagToString.
/**
* Converts an {@link ExecNode} DAG to a string as a tree style.
*
* <p>The following DAG of {@link ExecNode}
*
* <pre>{@code
* Sink1 Sink2
* | |
* Filter3 Filter4
* \ /
* Join
* / \
* Filter1 Filter2
* \ /
* Project
* |
* Scan
* }</pre>
*
* <p>would be converted to the tree style as following:
*
* <pre>{@code
* Join(reuse_id=[2])
* :- Filter1
* : +- Project(reuse_id=[1])
* : +- Scan
* +- Filter2
* +- Reused(reference_id=[1])
*
* Sink1
* +- Filter3
* +- Reused(reference_id=[2])
*
* Sink2
* +- Filter4
* +- Reused(reference_id=[2])
* }</pre>
*
* @param nodes the ExecNodes to convert
* @return the plan of ExecNode
*/
public static String dagToString(List<ExecNode<?>> nodes) {
Preconditions.checkArgument(nodes != null && !nodes.isEmpty(), "nodes should not be null or empty.");
if (nodes.size() == 1) {
return treeToString(nodes.get(0));
}
// nodes that stop visit when meet them
final List<ExecNode<?>> stopVisitNodes = new ArrayList<>();
final StringBuilder sb = new StringBuilder();
final DagReuseInfo reuseInfo = new DagReuseInfo(nodes, new ArrayList<>());
final ExecNodeVisitor visitor = new ExecNodeVisitorImpl() {
@Override
public void visit(ExecNode<?> node) {
int visitedTimes = reuseInfo.addVisitedTimes(node);
boolean isFirstVisit = visitedTimes == 1;
if (isFirstVisit) {
super.visit(node);
}
int reuseId = reuseInfo.getReuseId(node);
boolean isReuseNode = reuseId >= 0;
if (node instanceof CommonExecLegacySink || node instanceof CommonExecSink || (isReuseNode && isFirstVisit)) {
if (isReuseNode) {
reuseInfo.setFirstVisited(node, true);
}
String reusePlan = doConvertTreeToString(node, reuseInfo, false, stopVisitNodes, false);
sb.append(reusePlan).append(System.lineSeparator());
if (isReuseNode) {
// update visit info after the reuse node visited
stopVisitNodes.add(node);
reuseInfo.setFirstVisited(node, false);
}
}
}
};
nodes.forEach(visitor::visit);
if (sb.length() > 0) {
// delete last line separator
sb.deleteCharAt(sb.length() - 1);
}
return sb.toString();
}
Aggregations