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

Fixed resource leak in Semaphore#withPermit and acquire(N) #403

Merged
merged 4 commits into from
Nov 9, 2018

Conversation

mpilquist
Copy link
Member

Addresses a leak in withPermit discussed in #382. Also addresses a leak of permits when acquire(N) is cancelled after receiving some but not all of its permits.

@codecov-io
Copy link

codecov-io commented Oct 30, 2018

Codecov Report

Merging #403 into master will increase coverage by 4.36%.
The diff coverage is 84.61%.

@@            Coverage Diff             @@
##           master     #403      +/-   ##
==========================================
+ Coverage   84.19%   88.56%   +4.36%     
==========================================
  Files          69       69              
  Lines        1898     1801      -97     
  Branches      187      188       +1     
==========================================
- Hits         1598     1595       -3     
+ Misses        300      206      -94

case None => (Left(waiting), releaseN(n))
case Some(m) => (Left(waiting.filterNot(_._2 eq gate)), releaseN(n - m))
}
case Right(m) => (Right(m + n), F.unit)
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand how this cleanup routine remembers that the acquire actually happened or not.

First of all we can have a Right(m) in that state without acquire ever happening, which means n permits will get re-added to the pool that were never acquired.

Copy link
Member Author

Choose a reason for hiding this comment

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

First of all we can have a Right(m) in that state without acquire ever happening, which means n permits will get re-added to the pool that were never acquired.

No, if we have a Right(m) in state when cleanup runs, it means that acquire happened. Note this cleanup is only used when we've put a new entry in Left(waiting) for this particular acquire call. We know there was an entry in the state and we know it's no longer there, therefore we know acquire completed.

Copy link
Member

Choose a reason for hiding this comment

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

Ah, you might be right, I was thinking of another constraint that you don't have.

alexandru added a commit to alexandru/monix that referenced this pull request Nov 2, 2018
@alexandru
Copy link
Member

I think this works, but you have to prove it with some tests.

You can use count to notice the effect of a cancellation.

alexandru added a commit to monix/monix that referenced this pull request Nov 2, 2018
* Fix issue typelevel/cats-effect#403

* Optimize acquireAsyncN

* Add more tests

* Fix JS tests

* Optimize Semaphore.withPermit

* Add credits
@mpilquist
Copy link
Member Author

Added two tests -- prior to the fixes in this PR, the first test fails and the second test hangs. With this PR, both tests pass.

@mpilquist
Copy link
Member Author

Any objections to exposing acquireNInternal publicly, suitably renamed (I can do so with a new subtype of Semaphore to preserve backwards compatibility)?

@alexandru
Copy link
Member

I thought about it too, but I don’t think it’s user friendly. How do you explain it?

@mpilquist
Copy link
Member Author

What about this instead? Passing false for releaseOnCompletion would give us resource safe equivalents of acquire.

def withPermit[A](fa: F[A], releaseOnCompletion: Boolean): F[A]
def withPermitN[A](fa: F[A], n: Long, releaseOnCompletion: Boolean): F[A]

@mpilquist
Copy link
Member Author

@alexandru Bump -- I can propose the overloaded withPermit in a separate issue to unblock this one.

@alexandru
Copy link
Member

@mpilquist we can talk on a separate thread. This PR is good to go IMO.

@mpilquist mpilquist merged commit 1c11c5b into typelevel:master Nov 9, 2018
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