2018-03-13 23:45:55 +09:00
|
|
|
/*
|
2020-01-02 07:24:59 -05:00
|
|
|
* Copyright (C) 2018-2020 Lightbend Inc. <https://www.lightbend.com>
|
2018-03-13 23:45:55 +09:00
|
|
|
*/
|
|
|
|
|
|
2017-03-16 09:30:00 +01:00
|
|
|
package jdocs.stream;
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
import java.util.Arrays;
|
|
|
|
|
|
2016-01-20 10:00:37 +02:00
|
|
|
import akka.NotUsed;
|
2017-03-16 09:30:00 +01:00
|
|
|
import jdocs.AbstractJavaTest;
|
2017-03-17 03:02:47 +08:00
|
|
|
import akka.testkit.javadsl.TestKit;
|
2016-01-13 16:25:24 +01:00
|
|
|
import org.junit.AfterClass;
|
|
|
|
|
import org.junit.BeforeClass;
|
|
|
|
|
import org.junit.Test;
|
|
|
|
|
|
|
|
|
|
import akka.actor.ActorSystem;
|
|
|
|
|
import akka.stream.*;
|
|
|
|
|
import akka.stream.javadsl.*;
|
|
|
|
|
import akka.stream.scaladsl.MergePreferred.MergePreferredShape;
|
|
|
|
|
|
2016-02-11 16:39:25 +01:00
|
|
|
public class GraphCyclesDocTest extends AbstractJavaTest {
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
static ActorSystem system;
|
|
|
|
|
|
|
|
|
|
@BeforeClass
|
|
|
|
|
public static void setup() {
|
|
|
|
|
system = ActorSystem.create("GraphCyclesDocTest");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@AfterClass
|
|
|
|
|
public static void tearDown() {
|
2017-03-17 03:02:47 +08:00
|
|
|
TestKit.shutdownActorSystem(system);
|
2016-01-13 16:25:24 +01:00
|
|
|
system = null;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-12 04:00:53 +08:00
|
|
|
static final SilenceSystemOut.System System = SilenceSystemOut.get();
|
2016-01-13 16:25:24 +01:00
|
|
|
|
2016-01-20 10:00:37 +02:00
|
|
|
final Source<Integer, NotUsed> source = Source.from(Arrays.asList(1, 2, 3, 4, 5));
|
2016-01-13 16:25:24 +01:00
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void demonstrateDeadlockedCycle() {
|
2019-01-12 04:00:53 +08:00
|
|
|
// #deadlocked
|
2016-01-13 16:25:24 +01:00
|
|
|
// WARNING! The graph below deadlocks!
|
2016-01-20 10:00:37 +02:00
|
|
|
final Flow<Integer, Integer, NotUsed> printFlow =
|
2019-01-12 04:00:53 +08:00
|
|
|
Flow.of(Integer.class)
|
|
|
|
|
.map(
|
|
|
|
|
s -> {
|
|
|
|
|
System.out.println(s);
|
|
|
|
|
return s;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
RunnableGraph.fromGraph(
|
|
|
|
|
GraphDSL.create(
|
|
|
|
|
b -> {
|
|
|
|
|
final UniformFanInShape<Integer, Integer> merge = b.add(Merge.create(2));
|
|
|
|
|
final UniformFanOutShape<Integer, Integer> bcast = b.add(Broadcast.create(2));
|
|
|
|
|
final Outlet<Integer> src = b.add(source).out();
|
|
|
|
|
final FlowShape<Integer, Integer> printer = b.add(printFlow);
|
|
|
|
|
final SinkShape<Integer> ignore = b.add(Sink.ignore());
|
|
|
|
|
|
|
|
|
|
b.from(src).viaFanIn(merge).via(printer).viaFanOut(bcast).to(ignore);
|
|
|
|
|
b.to(merge).fromFanOut(bcast);
|
|
|
|
|
return ClosedShape.getInstance();
|
|
|
|
|
}));
|
|
|
|
|
// #deadlocked
|
2016-01-13 16:25:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void demonstrateUnfairCycle() {
|
2016-01-20 10:00:37 +02:00
|
|
|
final Flow<Integer, Integer, NotUsed> printFlow =
|
2019-01-12 04:00:53 +08:00
|
|
|
Flow.of(Integer.class)
|
|
|
|
|
.map(
|
|
|
|
|
s -> {
|
|
|
|
|
System.out.println(s);
|
|
|
|
|
return s;
|
|
|
|
|
});
|
|
|
|
|
// #unfair
|
2016-01-13 16:25:24 +01:00
|
|
|
// WARNING! The graph below stops consuming from "source" after a few steps
|
2019-01-12 04:00:53 +08:00
|
|
|
RunnableGraph.fromGraph(
|
|
|
|
|
GraphDSL.create(
|
|
|
|
|
b -> {
|
|
|
|
|
final MergePreferredShape<Integer> merge = b.add(MergePreferred.create(1));
|
|
|
|
|
final UniformFanOutShape<Integer, Integer> bcast = b.add(Broadcast.create(2));
|
|
|
|
|
final Outlet<Integer> src = b.add(source).out();
|
|
|
|
|
final FlowShape<Integer, Integer> printer = b.add(printFlow);
|
|
|
|
|
final SinkShape<Integer> ignore = b.add(Sink.ignore());
|
|
|
|
|
|
|
|
|
|
b.from(src).viaFanIn(merge).via(printer).viaFanOut(bcast).to(ignore);
|
|
|
|
|
b.to(merge.preferred()).fromFanOut(bcast);
|
|
|
|
|
return ClosedShape.getInstance();
|
|
|
|
|
}));
|
|
|
|
|
// #unfair
|
2016-01-13 16:25:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void demonstrateDroppingCycle() {
|
2016-01-20 10:00:37 +02:00
|
|
|
final Flow<Integer, Integer, NotUsed> printFlow =
|
2019-01-12 04:00:53 +08:00
|
|
|
Flow.of(Integer.class)
|
|
|
|
|
.map(
|
|
|
|
|
s -> {
|
|
|
|
|
System.out.println(s);
|
|
|
|
|
return s;
|
|
|
|
|
});
|
|
|
|
|
// #dropping
|
|
|
|
|
RunnableGraph.fromGraph(
|
|
|
|
|
GraphDSL.create(
|
|
|
|
|
b -> {
|
|
|
|
|
final UniformFanInShape<Integer, Integer> merge = b.add(Merge.create(2));
|
|
|
|
|
final UniformFanOutShape<Integer, Integer> bcast = b.add(Broadcast.create(2));
|
|
|
|
|
final FlowShape<Integer, Integer> droppyFlow =
|
|
|
|
|
b.add(Flow.of(Integer.class).buffer(10, OverflowStrategy.dropHead()));
|
|
|
|
|
final Outlet<Integer> src = b.add(source).out();
|
|
|
|
|
final FlowShape<Integer, Integer> printer = b.add(printFlow);
|
|
|
|
|
final SinkShape<Integer> ignore = b.add(Sink.ignore());
|
|
|
|
|
|
|
|
|
|
b.from(src).viaFanIn(merge).via(printer).viaFanOut(bcast).to(ignore);
|
|
|
|
|
b.to(merge).via(droppyFlow).fromFanOut(bcast);
|
|
|
|
|
return ClosedShape.getInstance();
|
|
|
|
|
}));
|
|
|
|
|
// #dropping
|
2016-01-13 16:25:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void demonstrateZippingCycle() {
|
2016-01-20 10:00:37 +02:00
|
|
|
final Flow<Integer, Integer, NotUsed> printFlow =
|
2019-01-12 04:00:53 +08:00
|
|
|
Flow.of(Integer.class)
|
|
|
|
|
.map(
|
|
|
|
|
s -> {
|
|
|
|
|
System.out.println(s);
|
|
|
|
|
return s;
|
|
|
|
|
});
|
|
|
|
|
// #zipping-dead
|
2016-01-13 16:25:24 +01:00
|
|
|
// WARNING! The graph below never processes any elements
|
2019-01-12 04:00:53 +08:00
|
|
|
RunnableGraph.fromGraph(
|
|
|
|
|
GraphDSL.create(
|
|
|
|
|
b -> {
|
|
|
|
|
final FanInShape2<Integer, Integer, Integer> zip =
|
|
|
|
|
b.add(ZipWith.create((Integer left, Integer right) -> left));
|
|
|
|
|
final UniformFanOutShape<Integer, Integer> bcast = b.add(Broadcast.create(2));
|
|
|
|
|
final FlowShape<Integer, Integer> printer = b.add(printFlow);
|
|
|
|
|
final SinkShape<Integer> ignore = b.add(Sink.ignore());
|
|
|
|
|
|
|
|
|
|
b.from(b.add(source)).toInlet(zip.in0());
|
|
|
|
|
b.from(zip.out()).via(printer).viaFanOut(bcast).to(ignore);
|
|
|
|
|
b.to(zip.in1()).fromFanOut(bcast);
|
|
|
|
|
return ClosedShape.getInstance();
|
|
|
|
|
}));
|
|
|
|
|
// #zipping-dead
|
2016-01-13 16:25:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void demonstrateLiveZippingCycle() {
|
2016-01-20 10:00:37 +02:00
|
|
|
final Flow<Integer, Integer, NotUsed> printFlow =
|
2019-01-12 04:00:53 +08:00
|
|
|
Flow.of(Integer.class)
|
|
|
|
|
.map(
|
|
|
|
|
s -> {
|
|
|
|
|
System.out.println(s);
|
|
|
|
|
return s;
|
|
|
|
|
});
|
|
|
|
|
// #zipping-live
|
|
|
|
|
RunnableGraph.fromGraph(
|
|
|
|
|
GraphDSL.create(
|
|
|
|
|
b -> {
|
|
|
|
|
final FanInShape2<Integer, Integer, Integer> zip =
|
|
|
|
|
b.add(ZipWith.create((Integer left, Integer right) -> left));
|
|
|
|
|
final UniformFanOutShape<Integer, Integer> bcast = b.add(Broadcast.create(2));
|
|
|
|
|
final UniformFanInShape<Integer, Integer> concat = b.add(Concat.create());
|
|
|
|
|
final FlowShape<Integer, Integer> printer = b.add(printFlow);
|
|
|
|
|
final SinkShape<Integer> ignore = b.add(Sink.ignore());
|
|
|
|
|
|
|
|
|
|
b.from(b.add(source)).toInlet(zip.in0());
|
|
|
|
|
b.from(zip.out()).via(printer).viaFanOut(bcast).to(ignore);
|
|
|
|
|
b.to(zip.in1()).viaFanIn(concat).from(b.add(Source.single(1)));
|
|
|
|
|
b.to(concat).fromFanOut(bcast);
|
|
|
|
|
return ClosedShape.getInstance();
|
|
|
|
|
}));
|
|
|
|
|
// #zipping-live
|
2016-01-13 16:25:24 +01:00
|
|
|
}
|
|
|
|
|
}
|