Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 50 additions & 9 deletions core-tests/shared/src/test/scala/zio/ZManagedSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,6 @@ object ZManagedSpec extends ZIOBaseSpec {
values <- program.use_(ZIO.unit) *> effects.get
} yield assert(values)(equalTo(List(1, 2, 3, 3, 2, 1)))
},
testM("Properly performs parallel acquire and release") {
for {
log <- Ref.make[List[String]](Nil)
a = ZManaged.make(UIO.succeed("A"))(_ => log.update("A" :: _))
b = ZManaged.make(UIO.succeed("B"))(_ => log.update("B" :: _))
result <- a.zipWithPar(b)(_ + _).use(ZIO.succeed(_))
cleanups <- log.get
} yield assert(result.length)(equalTo(2)) && assert(cleanups)(hasSize(equalTo(2)))
},
testM("Constructs an uninterruptible Managed value") {
doInterrupt(io => ZManaged.make(io)(_ => IO.unit), _ => None)
},
Expand Down Expand Up @@ -126,6 +117,32 @@ object ZManagedSpec extends ZIOBaseSpec {
} yield assert(result)(equalTo(List[Exit[Any, Any]](Exit.Failure(Cause.Die(acquireEx)))))
}
) @@ zioTag(errors),
suite("zipWithPar")(
testM("Properly performs parallel acquire and release") {
for {
log <- Ref.make[List[String]](Nil)
a = ZManaged.make(UIO.succeed("A"))(_ => log.update("A" :: _))
b = ZManaged.make(UIO.succeed("B"))(_ => log.update("B" :: _))
result <- a.zipWithPar(b)(_ + _).use(ZIO.succeed(_))
cleanups <- log.get
} yield assert(result.length)(equalTo(2)) && assert(cleanups)(hasSize(equalTo(2)))
},
testM("preserves ordering of nested finalizers") {
val inner = Ref.make(List[Int]()).toManaged_.flatMap { ref =>
ZManaged.finalizer(ref.update(1 :: _)) *>
ZManaged.finalizer(ref.update(2 :: _)) *>
ZManaged.finalizer(ref.update(3 :: _)).as(ref)
}

(inner <&> inner).useNow.flatMap {
case (l, r) => l.get <*> r.get
}.map {
case (l, r) =>
assert(l)(equalTo(List(1, 2, 3))) &&
assert(r)(equalTo(List(1, 2, 3)))
}
} @@ TestAspect.nonFlaky
),
suite("fromEffect")(
testM("Performed interruptibly") {
assertM(ZManaged.fromEffect(ZIO.checkInterruptible(ZIO.succeed(_))).use(ZIO.succeed(_)))(
Expand Down Expand Up @@ -337,6 +354,9 @@ object ZManagedSpec extends ZIOBaseSpec {
},
testM("Runs acquisitions in parallel") {
testAcquirePar(4, res => ZManaged.foreachPar(List(1, 2, 3, 4))(_ => res))
},
testM("Maintains finalizer ordering in inner ZManaged values") {
checkM(Gen.int(5, 100))(l => testParallelNestedFinalizerOrdering(l, ZManaged.foreachPar(_)(identity)))
}
),
suite("foreachParN")(
Expand All @@ -355,6 +375,11 @@ object ZManagedSpec extends ZIOBaseSpec {
},
testM("Runs finalizers") {
testAcquirePar(2, res => ZManaged.foreachParN(2)(List(1, 2, 3, 4))(_ => res))
},
testM("Maintains finalizer ordering in inner ZManaged values") {
checkM(Gen.int(4, 10), Gen.int(5, 100)) { (n, l) =>
testParallelNestedFinalizerOrdering(l, ZManaged.foreachParN(n)(_)(identity))
}
}
),
suite("foreach_")(
Expand Down Expand Up @@ -1649,4 +1674,20 @@ object ZManagedSpec extends ZIOBaseSpec {
count <- effects.get
_ <- reserveLatch.succeed(())
} yield assert(count)(equalTo(n))

def testParallelNestedFinalizerOrdering(
listLength: Int,
f: List[ZManaged[Any, Nothing, Ref[List[Int]]]] => ZManaged[Any, Nothing, List[Ref[List[Int]]]]
) = {
val inner = Ref.make(List[Int]()).toManaged_.flatMap { ref =>
ZManaged.finalizer(ref.update(1 :: _)) *>
ZManaged.finalizer(ref.update(2 :: _)) *>
ZManaged.finalizer(ref.update(3 :: _)).as(ref)
}

f(List.fill(listLength)(inner)).useNow
.flatMap(refs => ZIO.foreach(refs)(_.get))
.map(results => assert(results)(forall(equalTo(List(1, 2, 3)))))
}

}
51 changes: 36 additions & 15 deletions core/shared/src/main/scala/zio/ZManaged.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1114,15 +1114,22 @@ abstract class ZManaged[-R, +E, +A] extends Serializable { self =>
*/
def zipWithPar[R1 <: R, E1 >: E, A1, A2](that: ZManaged[R1, E1, A1])(f: (A, A1) => A2): ZManaged[R1, E1, A2] =
ZManaged.ReleaseMap.makeManaged(ExecutionStrategy.Parallel).mapM { parallelReleaseMap =>
self.zio
.zipWithPar(that.zio) {
// We can safely discard the finalizers here because the resulting ZManaged's early
// release will trigger the ReleaseMap, which would release both finalizers in
// parallel.
case ((_, a), (_, b)) =>
f(a, b)
}
.provideSome[R1]((_, parallelReleaseMap))
val innerMap =
ZManaged.ReleaseMap.makeManaged(ExecutionStrategy.Sequential).zio.provideSome[R1]((_, parallelReleaseMap))

(innerMap zip innerMap) flatMap {
case ((_, l), (_, r)) =>
self.zio
.provideSome[R1]((_, l))
.zipWithPar(that.zio.provideSome[R1]((_, r))) {
// We can safely discard the finalizers here because the resulting ZManaged's early
// release will trigger the ReleaseMap, which would release both finalizers in
// parallel.
case ((_, a), (_, b)) =>
f(a, b)
}

}
}
}

Expand Down Expand Up @@ -1649,10 +1656,14 @@ object ZManaged extends ZManagedPlatformSpecific {
ReleaseMap
.makeManaged(ExecutionStrategy.Parallel)
.mapM { parallelReleaseMap =>
val makeInnerMap =
ReleaseMap.makeManaged(ExecutionStrategy.Sequential).zio.map(_._2).provideSome[Any]((_, parallelReleaseMap))

ZIO
.foreachPar(as.toIterable)(f(_).zio.map(_._2))
.foreachPar(as.toIterable)(a =>
makeInnerMap.flatMap(innerMap => f(a).zio.map(_._2).provideSome[R]((_, innerMap)))
)
.map(bf.fromSpecific(as))
.provideSome[R]((_, parallelReleaseMap))
}

/**
Expand All @@ -1668,10 +1679,14 @@ object ZManaged extends ZManagedPlatformSpecific {
ReleaseMap
.makeManaged(ExecutionStrategy.ParallelN(n))
.mapM { parallelReleaseMap =>
val makeInnerMap =
ReleaseMap.makeManaged(ExecutionStrategy.Sequential).zio.map(_._2).provideSome[Any]((_, parallelReleaseMap))

ZIO
.foreachParN(n)(as.toIterable)(f(_).zio.map(_._2))
.foreachParN(n)(as.toIterable)(a =>
makeInnerMap.flatMap(innerMap => f(a).zio.map(_._2).provideSome[R]((_, innerMap)))
)
.map(bf.fromSpecific(as))
.provideSome[R]((_, parallelReleaseMap))
}

/**
Expand All @@ -1695,7 +1710,10 @@ object ZManaged extends ZManagedPlatformSpecific {
*/
def foreachPar_[R, E, A](as: Iterable[A])(f: A => ZManaged[R, E, Any]): ZManaged[R, E, Unit] =
ReleaseMap.makeManaged(ExecutionStrategy.Parallel).mapM { parallelReleaseMap =>
ZIO.foreachPar_(as)(f(_).zio.map(_._2)).provideSome[R]((_, parallelReleaseMap))
val makeInnerMap =
ReleaseMap.makeManaged(ExecutionStrategy.Sequential).zio.map(_._2).provideSome[Any]((_, parallelReleaseMap))

ZIO.foreachPar_(as)(a => makeInnerMap.flatMap(innerMap => f(a).zio.map(_._2).provideSome[R]((_, innerMap))))
}

/**
Expand All @@ -1712,7 +1730,10 @@ object ZManaged extends ZManagedPlatformSpecific {
f: A => ZManaged[R, E, Any]
): ZManaged[R, E, Unit] =
ReleaseMap.makeManaged(ExecutionStrategy.ParallelN(n)).mapM { parallelReleaseMap =>
ZIO.foreachParN_(n)(as)(f(_).zio.map(_._2)).provideSome[R]((_, parallelReleaseMap))
val makeInnerMap =
ReleaseMap.makeManaged(ExecutionStrategy.Sequential).zio.map(_._2).provideSome[Any]((_, parallelReleaseMap))

ZIO.foreachParN_(n)(as)(a => makeInnerMap.flatMap(innerMap => f(a).zio.map(_._2).provideSome[R]((_, innerMap))))
}

/**
Expand Down