!str #16902: Unify stream internal representation
also =str #16912: Fix StreamTcpSpec flakiness
This commit is contained in:
parent
cac9c9f2fb
commit
8d77fa8b29
230 changed files with 7814 additions and 9596 deletions
|
|
@ -3,37 +3,43 @@
|
|||
*/
|
||||
package docs.stream
|
||||
|
||||
import akka.stream.ActorFlowMaterializer
|
||||
import akka.stream._
|
||||
import akka.stream.scaladsl._
|
||||
import akka.stream.testkit.AkkaSpec
|
||||
|
||||
import scala.collection.immutable.IndexedSeq
|
||||
import scala.concurrent.Await
|
||||
import scala.concurrent.duration._
|
||||
import scala.util.control.NoStackTrace
|
||||
|
||||
object FlexiDocSpec {
|
||||
//#fleximerge-zip-states
|
||||
//#fleximerge-zip-readall
|
||||
import akka.stream.FanInShape._
|
||||
class ZipPorts[A, B](_init: Init[(A, B)] = Name("Zip"))
|
||||
extends FanInShape[(A, B)](_init) {
|
||||
val left = newInlet[A]("left")
|
||||
val right = newInlet[B]("right")
|
||||
protected override def construct(i: Init[(A, B)]) = new ZipPorts(i)
|
||||
}
|
||||
//#fleximerge-zip-readall
|
||||
//#fleximerge-zip-states
|
||||
}
|
||||
|
||||
class FlexiDocSpec extends AkkaSpec {
|
||||
import FlexiDocSpec._
|
||||
|
||||
implicit val ec = system.dispatcher
|
||||
implicit val mat = ActorFlowMaterializer()
|
||||
|
||||
"implement zip using readall" in {
|
||||
//#fleximerge-zip-readall
|
||||
class Zip[A, B] extends FlexiMerge[(A, B)] {
|
||||
class Zip[A, B] extends FlexiMerge[(A, B), ZipPorts[A, B]](
|
||||
new ZipPorts, OperationAttributes.name("Zip1State")) {
|
||||
import FlexiMerge._
|
||||
val left = createInputPort[A]()
|
||||
val right = createInputPort[B]()
|
||||
|
||||
def createMergeLogic = new MergeLogic[(A, B)] {
|
||||
override def inputHandles(inputCount: Int) = {
|
||||
require(inputCount == 2, s"Zip must have two connected inputs, was $inputCount")
|
||||
Vector(left, right)
|
||||
}
|
||||
|
||||
override def initialState: State[_] =
|
||||
State[ReadAllInputs](ReadAll(left, right)) { (ctx, _, inputs) =>
|
||||
val a: A = inputs(left)
|
||||
val b: B = inputs(right)
|
||||
override def createMergeLogic(p: PortT) = new MergeLogic[(A, B)] {
|
||||
override def initialState =
|
||||
State(ReadAll(p.left, p.right)) { (ctx, _, inputs) =>
|
||||
val a = inputs(p.left)
|
||||
val b = inputs(p.right)
|
||||
ctx.emit((a, b))
|
||||
SameState
|
||||
}
|
||||
|
|
@ -44,49 +50,40 @@ class FlexiDocSpec extends AkkaSpec {
|
|||
//#fleximerge-zip-readall
|
||||
|
||||
//format: OFF
|
||||
val res =
|
||||
//#fleximerge-zip-connecting
|
||||
val head = Sink.head[(Int, String)]
|
||||
//#fleximerge-zip-connecting
|
||||
FlowGraph.closed(Sink.head[(Int, String)]) { implicit b =>
|
||||
o =>
|
||||
import FlowGraph.Implicits._
|
||||
|
||||
val map =
|
||||
//#fleximerge-zip-connecting
|
||||
FlowGraph { implicit b =>
|
||||
import FlowGraphImplicits._
|
||||
|
||||
val zip = Zip[Int, String]
|
||||
val zip = b.add(new Zip[Int, String])
|
||||
|
||||
Source.single(1) ~> zip.left
|
||||
Source.single("A") ~> zip.right
|
||||
zip.out ~> head
|
||||
Source.single("1") ~> zip.right
|
||||
zip.out ~> o.inlet
|
||||
}
|
||||
//#fleximerge-zip-connecting
|
||||
.run()
|
||||
.run()
|
||||
//format: ON
|
||||
|
||||
Await.result(map.get(head), remaining) should equal((1, "A"))
|
||||
Await.result(res, 300.millis) should equal((1, "1"))
|
||||
}
|
||||
|
||||
"implement zip using two states" in {
|
||||
//#fleximerge-zip-states
|
||||
class Zip[A, B] extends FlexiMerge[(A, B)] {
|
||||
class Zip[A, B] extends FlexiMerge[(A, B), ZipPorts[A, B]](
|
||||
new ZipPorts, OperationAttributes.name("Zip2State")) {
|
||||
import FlexiMerge._
|
||||
val left = createInputPort[A]()
|
||||
val right = createInputPort[B]()
|
||||
|
||||
def createMergeLogic = new MergeLogic[(A, B)] {
|
||||
override def createMergeLogic(p: PortT) = new MergeLogic[(A, B)] {
|
||||
var lastInA: A = _
|
||||
|
||||
override def inputHandles(inputCount: Int) = {
|
||||
require(inputCount == 2, s"Zip must have two connected inputs, was $inputCount")
|
||||
Vector(left, right)
|
||||
}
|
||||
|
||||
val readA: State[A] = State[A](Read(left)) { (ctx, input, element) =>
|
||||
val readA: State[A] = State[A](Read(p.left)) { (ctx, input, element) =>
|
||||
lastInA = element
|
||||
readB
|
||||
}
|
||||
|
||||
val readB: State[B] = State[B](Read(right)) { (ctx, input, element) =>
|
||||
val readB: State[B] = State[B](Read(p.right)) { (ctx, input, element) =>
|
||||
ctx.emit((lastInA, element))
|
||||
readA
|
||||
}
|
||||
|
|
@ -98,37 +95,37 @@ class FlexiDocSpec extends AkkaSpec {
|
|||
}
|
||||
//#fleximerge-zip-states
|
||||
|
||||
val head = Sink.head[(Int, String)]
|
||||
val map = FlowGraph { implicit b =>
|
||||
import akka.stream.scaladsl.FlowGraphImplicits._
|
||||
val res = FlowGraph.closed(Sink.head[(Int, String)]) { implicit b =>
|
||||
o =>
|
||||
import FlowGraph.Implicits._
|
||||
|
||||
val zip = new Zip[Int, String]
|
||||
val zip = b.add(new Zip[Int, String])
|
||||
|
||||
Source(1 to 2) ~> zip.left
|
||||
Source(List("A", "B")) ~> zip.right
|
||||
zip.out ~> head
|
||||
Source(1 to 2) ~> zip.left
|
||||
Source((1 to 2).map(_.toString)) ~> zip.right
|
||||
zip.out ~> o.inlet
|
||||
}.run()
|
||||
|
||||
Await.result(map.get(head), remaining) should equal((1, "A"))
|
||||
Await.result(res, 300.millis) should equal((1, "1"))
|
||||
}
|
||||
|
||||
"fleximerge completion handling" in {
|
||||
import FanInShape._
|
||||
//#fleximerge-completion
|
||||
class ImportantWithBackups[A] extends FlexiMerge[A] {
|
||||
class ImportantWithBackupShape[A](_init: Init[A] = Name("Zip"))
|
||||
extends FanInShape[A](_init) {
|
||||
val important = newInlet[A]("important")
|
||||
val replica1 = newInlet[A]("replica1")
|
||||
val replica2 = newInlet[A]("replica2")
|
||||
protected override def construct(i: Init[A]) =
|
||||
new ImportantWithBackupShape(i)
|
||||
}
|
||||
class ImportantWithBackups[A] extends FlexiMerge[A, ImportantWithBackupShape[A]](
|
||||
new ImportantWithBackupShape, OperationAttributes.name("ImportantWithBackups")) {
|
||||
import FlexiMerge._
|
||||
|
||||
val important = createInputPort[A]()
|
||||
val replica1 = createInputPort[A]()
|
||||
val replica2 = createInputPort[A]()
|
||||
|
||||
def createMergeLogic = new MergeLogic[A] {
|
||||
val inputs = Vector(important, replica1, replica2)
|
||||
|
||||
override def inputHandles(inputCount: Int) = {
|
||||
require(inputCount == 3, s"Must connect 3 inputs, connected only $inputCount")
|
||||
inputs
|
||||
}
|
||||
|
||||
override def createMergeLogic(p: PortT) = new MergeLogic[A] {
|
||||
import p.important
|
||||
override def initialCompletionHandling =
|
||||
CompletionHandling(
|
||||
onUpstreamFinish = (ctx, input) => input match {
|
||||
|
|
@ -159,18 +156,19 @@ class FlexiDocSpec extends AkkaSpec {
|
|||
SameState
|
||||
})
|
||||
|
||||
override def initialState = State[A](ReadAny(inputs)) {
|
||||
(ctx, input, element) =>
|
||||
ctx.emit(element)
|
||||
SameState
|
||||
}
|
||||
override def initialState =
|
||||
State[A](ReadAny(p.important, p.replica1, p.replica2)) {
|
||||
(ctx, input, element) =>
|
||||
ctx.emit(element)
|
||||
SameState
|
||||
}
|
||||
}
|
||||
}
|
||||
//#fleximerge-completion
|
||||
|
||||
FlowGraph { implicit b =>
|
||||
import FlowGraphImplicits._
|
||||
val importantWithBackups = new ImportantWithBackups[Int]
|
||||
FlowGraph.closed() { implicit b =>
|
||||
import FlowGraph.Implicits._
|
||||
val importantWithBackups = b.add(new ImportantWithBackups[Int])
|
||||
Source.single(1) ~> importantWithBackups.important
|
||||
Source.single(2) ~> importantWithBackups.replica1
|
||||
Source.failed[Int](new Exception("Boom!") with NoStackTrace) ~> importantWithBackups.replica2
|
||||
|
|
@ -179,22 +177,22 @@ class FlexiDocSpec extends AkkaSpec {
|
|||
}
|
||||
|
||||
"flexi preferring merge" in {
|
||||
import FanInShape._
|
||||
//#flexi-preferring-merge
|
||||
class PreferringMerge extends FlexiMerge[Int] {
|
||||
class PreferringMergeShape[A](_init: Init[A] = Name("PreferringMerge"))
|
||||
extends FanInShape[A](_init) {
|
||||
val preferred = newInlet[A]("preferred")
|
||||
val secondary1 = newInlet[A]("secondary1")
|
||||
val secondary2 = newInlet[A]("secondary2")
|
||||
protected override def construct(i: Init[A]) = new PreferringMergeShape(i)
|
||||
}
|
||||
class PreferringMerge extends FlexiMerge[Int, PreferringMergeShape[Int]](
|
||||
new PreferringMergeShape, OperationAttributes.name("ImportantWithBackups")) {
|
||||
import akka.stream.scaladsl.FlexiMerge._
|
||||
|
||||
val preferred = createInputPort[Int]()
|
||||
val secondary1 = createInputPort[Int]()
|
||||
val secondary2 = createInputPort[Int]()
|
||||
|
||||
def createMergeLogic = new MergeLogic[Int] {
|
||||
override def inputHandles(inputCount: Int) = {
|
||||
require(inputCount == 3, s"PreferringMerge must have 3 connected inputs, was $inputCount")
|
||||
Vector(preferred, secondary1, secondary2)
|
||||
}
|
||||
|
||||
override def createMergeLogic(p: PortT) = new MergeLogic[Int] {
|
||||
override def initialState =
|
||||
State[Int](ReadPreferred(preferred)(secondary1, secondary2)) {
|
||||
State[Int](ReadPreferred(p.preferred, p.secondary1, p.secondary2)) {
|
||||
(ctx, input, element) =>
|
||||
ctx.emit(element)
|
||||
SameState
|
||||
|
|
@ -204,61 +202,28 @@ class FlexiDocSpec extends AkkaSpec {
|
|||
//#flexi-preferring-merge
|
||||
}
|
||||
|
||||
"flexi read conditions" in {
|
||||
class X extends FlexiMerge[Int] {
|
||||
import FlexiMerge._
|
||||
|
||||
override def createMergeLogic(): MergeLogic[Int] = new MergeLogic[Int] {
|
||||
//#read-conditions
|
||||
val first = createInputPort[Int]()
|
||||
val second = createInputPort[Int]()
|
||||
val third = createInputPort[Int]()
|
||||
//#read-conditions
|
||||
|
||||
//#read-conditions
|
||||
val onlyFirst = Read(first)
|
||||
|
||||
val firstOrThird = ReadAny(first, third)
|
||||
|
||||
val firstAndSecond = ReadAll(first, second)
|
||||
val firstAndThird = ReadAll(first, third)
|
||||
|
||||
val mostlyFirst = ReadPreferred(first)(second, third)
|
||||
|
||||
//#read-conditions
|
||||
|
||||
override def inputHandles(inputCount: Int): IndexedSeq[InputHandle] = Vector()
|
||||
|
||||
override def initialState: State[_] = State[ReadAllInputs](firstAndSecond) {
|
||||
(ctx, input, inputs) =>
|
||||
val in1: Int = inputs(first)
|
||||
SameState
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"flexi route" in {
|
||||
//#flexiroute-unzip
|
||||
class Unzip[A, B] extends FlexiRoute[(A, B)] {
|
||||
import FanOutShape._
|
||||
class UnzipShape[A, B](_init: Init[(A, B)] = Name[(A, B)]("Unzip"))
|
||||
extends FanOutShape[(A, B)](_init) {
|
||||
val outA = newOutlet[A]("outA")
|
||||
val outB = newOutlet[B]("outB")
|
||||
protected override def construct(i: Init[(A, B)]) = new UnzipShape(i)
|
||||
}
|
||||
class Unzip[A, B] extends FlexiRoute[(A, B), UnzipShape[A, B]](
|
||||
new UnzipShape, OperationAttributes.name("Unzip")) {
|
||||
import FlexiRoute._
|
||||
val outA = createOutputPort[A]()
|
||||
val outB = createOutputPort[B]()
|
||||
|
||||
override def createRouteLogic() = new RouteLogic[(A, B)] {
|
||||
|
||||
override def outputHandles(outputCount: Int) = {
|
||||
require(outputCount == 2, s"Unzip must have two connected outputs, was $outputCount")
|
||||
Vector(outA, outB)
|
||||
}
|
||||
|
||||
override def initialState = State[Any](DemandFromAll(outA, outB)) {
|
||||
(ctx, _, element) =>
|
||||
val (a, b) = element
|
||||
ctx.emit(outA, a)
|
||||
ctx.emit(outB, b)
|
||||
SameState
|
||||
}
|
||||
override def createRouteLogic(p: PortT) = new RouteLogic[(A, B)] {
|
||||
override def initialState =
|
||||
State[Any](DemandFromAll(p.outA, p.outB)) {
|
||||
(ctx, _, element) =>
|
||||
val (a, b) = element
|
||||
ctx.emit(p.outA)(a)
|
||||
ctx.emit(p.outB)(b)
|
||||
SameState
|
||||
}
|
||||
|
||||
override def initialCompletionHandling = eagerClose
|
||||
}
|
||||
|
|
@ -267,20 +232,20 @@ class FlexiDocSpec extends AkkaSpec {
|
|||
}
|
||||
|
||||
"flexi route completion handling" in {
|
||||
import FanOutShape._
|
||||
//#flexiroute-completion
|
||||
class ImportantRoute[A] extends FlexiRoute[A] {
|
||||
class ImportantRouteShape[A](_init: Init[A] = Name[A]("ImportantRoute")) extends FanOutShape[A](_init) {
|
||||
val important = newOutlet[A]("important")
|
||||
val additional1 = newOutlet[A]("additional1")
|
||||
val additional2 = newOutlet[A]("additional2")
|
||||
protected override def construct(i: Init[A]) = new ImportantRouteShape(i)
|
||||
}
|
||||
class ImportantRoute[A] extends FlexiRoute[A, ImportantRouteShape[A]](
|
||||
new ImportantRouteShape, OperationAttributes.name("ImportantRoute")) {
|
||||
import FlexiRoute._
|
||||
val important = createOutputPort[A]()
|
||||
val additional1 = createOutputPort[A]()
|
||||
val additional2 = createOutputPort[A]()
|
||||
|
||||
override def createRouteLogic() = new RouteLogic[A] {
|
||||
val outputs = Vector(important, additional1, additional2)
|
||||
|
||||
override def outputHandles(outputCount: Int) = {
|
||||
require(outputCount == 3, s"Must have three connected outputs, was $outputCount")
|
||||
outputs
|
||||
}
|
||||
override def createRouteLogic(p: PortT) = new RouteLogic[A] {
|
||||
import p.important
|
||||
private val select = (p.important | p.additional1 | p.additional2)
|
||||
|
||||
override def initialCompletionHandling =
|
||||
CompletionHandling(
|
||||
|
|
@ -297,18 +262,19 @@ class FlexiDocSpec extends AkkaSpec {
|
|||
SameState
|
||||
})
|
||||
|
||||
override def initialState = State[A](DemandFromAny(outputs)) {
|
||||
(ctx, output, element) =>
|
||||
ctx.emit(output, element)
|
||||
SameState
|
||||
}
|
||||
override def initialState =
|
||||
State(DemandFromAny(p.important, p.additional1, p.additional2)) {
|
||||
(ctx, output, element) =>
|
||||
ctx.emit(select(output))(element)
|
||||
SameState
|
||||
}
|
||||
}
|
||||
}
|
||||
//#flexiroute-completion
|
||||
|
||||
FlowGraph { implicit b =>
|
||||
import FlowGraphImplicits._
|
||||
val route = new ImportantRoute[Int]
|
||||
FlowGraph.closed() { implicit b =>
|
||||
import FlowGraph.Implicits._
|
||||
val route = b.add(new ImportantRoute[Int])
|
||||
Source.single(1) ~> route.in
|
||||
route.important ~> Sink.ignore
|
||||
route.additional1 ~> Sink.ignore
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue