Skip to content
This repository has been archived by the owner on Sep 26, 2023. It is now read-only.

implement lock-free semaphore #407

Merged
merged 6 commits into from
Jan 17, 2018
Merged

implement lock-free semaphore #407

merged 6 commits into from
Jan 17, 2018

Conversation

pongad
Copy link
Contributor

@pongad pongad commented Nov 2, 2017

Previous implementation of Semaphore64 allows two ways to acquire
permits:

  1. acquire() - the method will eventually return after it has acquired
    permits.
  2. tryAcquire() - the method returns immediately, reporting whether or
    not it have acquired the permits.

Pubsub implements its own work queue and use tryAcquire exclusively.

The problem:
To implement acquire(), we must use a lock
(I do not know of a better way)
and all users must pay for the lock, even if they never use acquire().
In particular, we call notifyAll() when releasing permits;
these calls are quite expensive.

This commit splits Semaphore64 into two implementations,
one exclusively blocks and the other exclusively not.
In this way the non-blocking implementation needs not pay for the cost
the lock.

This reduces CPU usage of pubsub client lib by about 10%.

Previous implementation of Semaphore64 allows two ways to acquire
permits:

1. acquire() -  the method will eventually return after it has acquired
   permits.
2. tryAcquire() - the method returns immediately, reporting whether or
   not it have acquired the permits.

Pubsub implements its own work queue and use tryAcquire exclusively.

The problem:
To implement acquire(), we must use a lock
(I do not know of a better way)
and all users must pay for the lock, even if they never use acquire().
In particular, we call notifyAll() when releasing permits;
these calls are quite expensive.

This commit splits Semaphore64 into two implementations,
one exclusively blocks and the other exclusively not.
In this way the non-blocking implementation needs not pay for the cost
the lock.

This reduces CPU usage of pubsub client lib by about 10%.
@codecov-io
Copy link

codecov-io commented Nov 2, 2017

Codecov Report

Merging #407 into master will decrease coverage by 0.01%.
The diff coverage is 85.71%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master     #407      +/-   ##
============================================
- Coverage      71.7%   71.69%   -0.02%     
- Complexity      751      753       +2     
============================================
  Files           155      156       +1     
  Lines          3354     3363       +9     
  Branches        261      262       +1     
============================================
+ Hits           2405     2411       +6     
- Misses          847      848       +1     
- Partials        102      104       +2
Impacted Files Coverage Δ Complexity Δ
...va/com/google/api/gax/batching/FlowController.java 78.12% <100%> (-0.67%) 17 <0> (-1)
...com/google/api/gax/batching/BlockingSemaphore.java 80.95% <80.95%> (ø) 6 <6> (?)
.../google/api/gax/batching/NonBlockingSemaphore.java 81.25% <81.25%> (ø) 5 <5> (?)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update bdcd4d8...433dc8a. Read the comment docs.

return false;
}

static final class Returning extends Semaphore64 {

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

@pongad
Copy link
Contributor Author

pongad commented Nov 3, 2017

I'll hold off on this a bit. Depending on how pubsub simplification goes, this might not add much value. In that case, we might as well not complicate this.

@pongad
Copy link
Contributor Author

pongad commented Jan 9, 2018

@garrettjonesgoogle Looks like this will be useful after all. PTAL

class ReturningSemaphore implements Semaphore64 {
private final AtomicLong currentPermits;

private static void notNegative(long l) {

This comment was marked as spam.

This comment was marked as spam.

import java.util.concurrent.atomic.AtomicLong;

/** A {@link Sempahore64} that immediately returns with failure if permits are not available. */
class ReturningSemaphore implements Semaphore64 {

This comment was marked as spam.

This comment was marked as spam.

@pongad
Copy link
Contributor Author

pongad commented Jan 17, 2018

@garrettjonesgoogle PTAL

@garrettjonesgoogle
Copy link
Member

LGTM

@pongad pongad merged commit d0b60bc into googleapis:master Jan 17, 2018
@pongad pongad deleted the lock-free-sema branch January 17, 2018 22:32
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants