Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid boxing in ScopedResource.State internals #3140

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
36 changes: 19 additions & 17 deletions core/shared/src/main/scala/fs2/internal/ScopedResource.scala
Original file line number Diff line number Diff line change
Expand Up @@ -108,15 +108,17 @@ private[internal] object ScopedResource {
*/
private[this] final case class State[+F[_]](
open: Boolean,
finalizer: Option[Resource.ExitCase => F[Either[Throwable, Unit]]],
finalizer: Resource.ExitCase => F[
Either[Throwable, Unit]
], // or null which is used as an Optional type to avoid boxing
leases: Int
) {
/* The `isFinished` predicate indicates that the finalizer can be run at the present state:
which happens IF it is closed, AND there are no acquired leases pending to be released. */
@inline def isFinished: Boolean = !open && leases == 0
}

private[this] val initial = State(open = true, finalizer = None, leases = 0)
private[this] val initial = State(open = true, finalizer = null, leases = 0)

def create[F[_]](implicit F: Compiler.Target[F]): F[ScopedResource[F]] =
for {
Expand All @@ -129,17 +131,20 @@ private[internal] object ScopedResource {
private[this] val pru: F[Either[Throwable, Unit]] =
(Right(()): Either[Throwable, Unit]).pure[F]

private[this] val prtrue: F[Either[Throwable, Boolean]] =
F.pure(Right(true))

def release(ec: Resource.ExitCase): F[Either[Throwable, Unit]] =
state
.modify { s =>
if (s.leases != 0)
// do not allow to run finalizer if there are leases open
(s.copy(open = false), None)
(s.copy(open = false), null)
else
// reset finalizer to None, will be run, it available, otherwise the acquire will take care of it
(s.copy(open = false, finalizer = None), s.finalizer)
// reset finalizer to null, will be run, it available, otherwise the acquire will take care of it
(s.copy(open = false, finalizer = null), s.finalizer)
}
.flatMap(finalizer => finalizer.map(_(ec)).getOrElse(pru))
.flatMap(finalizer => if (finalizer ne null) finalizer(ec) else pru)

def acquired(finalizer: Resource.ExitCase => F[Unit]): F[Either[Throwable, Boolean]] =
state.modify { s =>
Expand All @@ -149,10 +154,7 @@ private[internal] object ScopedResource {
else {
val attemptFinalizer = (ec: Resource.ExitCase) => finalizer(ec).attempt
// either state is open, or leases are present, either release or `Lease#cancel` will run the finalizer
s.copy(finalizer = Some(attemptFinalizer)) -> (Right(true): Either[
Throwable,
Boolean
]).pure[F]
s.copy(finalizer = attemptFinalizer) -> prtrue
}
}.flatten

Expand All @@ -171,17 +173,17 @@ private[internal] object ScopedResource {
val now = s.copy(leases = s.leases - 1)
now -> now
}
.flatMap { now =>
if (now.isFinished)
.flatMap {
case now if now.isFinished =>
state.modify { s =>
// Scope is closed and this is last lease, assure finalizer is removed from the state and run
// previous finalizer shall be always present at this point, this shall invoke it
s.copy(finalizer = None) -> (s.finalizer match {
case Some(ff) => ff(Resource.ExitCase.Succeeded)
case None => pru
})
s.copy(finalizer = null) ->
(if (s.finalizer ne null)
s.finalizer(Resource.ExitCase.Succeeded)
else pru)
}.flatten
else
case _ =>
pru
}
}
Expand Down