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

Skip to content

Conversation

@IgorDorokhov
Copy link
Contributor

@IgorDorokhov IgorDorokhov commented Feb 14, 2025

In this PR I have added tryAcquire and tryAcquireN functions to Semaphore and TSemaphore as per following enhancement request #9390

The functions I added are non-blocking, they check if there are available permits and if yes it decreases the amount of permits and return true. If not, then a false is returned and a fiber is not queued.

Open questions:

  • If tryAcquire is decreasing the amount of permits, should the algorithm increase amount of permits back once it is done with them?
    If we take a look at the Semaphore implementation we will see that functions that can do that (reserve, restore, releaseN) are not part of the Semaphore trait and cannot be called directly by the user to release permits manually.

On the other hand, if use TSemaphore as an example, it has acquireBetween function which does not release permits as well.
Or should something like following be added for tryAcquire?

  def withPermitsBetween[R, E, A](min: Long, max: Long)(zio: Long => ZIO[R, E, A])(implicit
    trace: Trace
  ): ZIO[R, E, A] =
    ZSTM.acquireReleaseWith(acquireBetween(min, max))((actualN: Long) => releaseN(actualN).commit)(zio)

Need a feedback from more experienced engineers.

Links for reference:
Semaphore -

sealed trait Semaphore extends Serializable {

TSemaphore -
final class TSemaphore private (val permits: TRef[Long]) extends Serializable {

Copy link
Contributor

@kyri-petrou kyri-petrou left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution, and sorry for taking this long to review this! Looks good to me, just some minor comments

Co-authored-by: kyri-petrou <[email protected]>
@CLAassistant
Copy link

CLAassistant commented Mar 28, 2025

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
2 out of 3 committers have signed the CLA.

✅ hearnadam
✅ IgorDorokhov
❌ Igor Dorokhov


Igor Dorokhov seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@hearnadam
Copy link
Collaborator

@IgorDorokhov is it possible to get this to the finish line? I have no other feedback aside from my last comments.

@IgorDorokhov
Copy link
Contributor Author

IgorDorokhov commented Apr 13, 2025 via email

@IgorDorokhov IgorDorokhov requested a review from hearnadam April 15, 2025 00:43
private[zio] val zero = Reservation(ZIO.unit, ZIO.unit)
}

def tryReserve(n: Long)(implicit trace: Trace): UIO[Option[Reservation]] =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized this method doesn't need to return a Reservation since it's only used internally. Sorry for missing this in the previous passes.

Can it just return Option[UIO[Unit]]?

Copy link
Contributor Author

@IgorDorokhov IgorDorokhov Apr 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tryReserve follows the same pattern as reserve. reserve is used only internally as well.
I would keep current implementation as it is aligns with the reserve and it is easy to use in ZIO.acquireReleaseWith(tryReserve(n))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

def reserve(n: Long)(implicit trace: Trace): UIO[Reservation] =
if (n < 0)
ZIO.die(new IllegalArgumentException(s"Unexpected negative `$n` permits requested."))
else if (n == 0L)
ZIO.succeed(Reservation.zero)
else
Promise.make[Nothing, Unit].flatMap { promise =>
ref.modify {
case Right(permits) if permits >= n =>
Reservation(ZIO.unit, releaseN(n)) -> Right(permits - n)
case Right(permits) =>
Reservation(promise.await, restore(promise, n)) -> Left(ScalaQueue(promise -> (n - permits)))
case Left(queue) =>
Reservation(promise.await, restore(promise, n)) -> Left(queue.enqueue(promise -> n))
}
}

@IgorDorokhov IgorDorokhov requested a review from hearnadam April 23, 2025 21:06
@IgorDorokhov
Copy link
Contributor Author

Closing this PR due to commits which were made from the default account which is not CLA signed.
Instead of rebasing I decided to open a new PR #9825
@hearnadam

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants