-
Notifications
You must be signed in to change notification settings - Fork 96
Lock-free BlockingIdentifierGenerator LoHi #1610
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
base: main
Are you sure you want to change the base?
Conversation
9e838df
to
5a58382
Compare
private volatile LoHi loHi; | ||
|
||
public long hi(long hi) { | ||
loHi = new LoHi(hi); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Sanne
This could be made much more strict and based on the previous value while failing if it happens concurrently too (by using a compareAndSet
)
@Sanne see final long next = next();
if ( next != -1 ) {
return CompletionStages.completedFuture( next );
}
if ( getBlockSize() <= 1 ) {
return nextHiValue( connectionSupplier )
.thenApply( i -> next( i ) );
} What happen if 2 concurrent threads both see And the same can happen with a combiner as well: while within the combiner you can have more then one updates in flights, each one competing to both hit the DB and refresh the new |
5a58382
to
ad2d5b8
Compare
|
||
private static final AtomicIntegerFieldUpdater<LoHi> LO_UPDATER = AtomicIntegerFieldUpdater.newUpdater(LoHi.class, "lo"); | ||
private final long hi; | ||
private volatile long lo; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this be an int
? Especially as you're using a AtomicIntegerFieldUpdater
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's for 2 reasons: it won't change based on JOL and will make life easier due to the "blind" getAndIncrement
(which scale much buffer then a compare and set loop).
I'd challenge you in ever noticing the current |
eheh I know, but it won't cost anything to make it lock free like this I think, I'm more concerned instead by this -> #1610 (comment) |
To quote myself of the future (and @Sanne ) re #1610 (comment) this is not a "real" problem leading to break anything, but just an efficiency one; in short, if more then one concurrently try to increase the sequence due to exhaustion and succeed, but update |
@Sanne undrafting, but feel free to pick what you like for next works on this bud ;) |
This is a version that pay a single allocation cost per each
blockSize
to save any synchronized to happen.It can be made gc-free by playing some bit tricks packing both lo/hi into a
long
(and assuming there are no negative values for both, likely) - or with some more complex coordination mechanism (yet to be designed).I don't know few things yet before un-drafting:
state.next(hi)
happen do we need to enforce validation of (hi,lo) based on existing values? new hi > old hi (or diff by blockSize?) && old low >= blockSize.state.next(hi)
happen do we need to ensure some ordering of updates? eg concurrentnext(10), next(20),next(30)
updates in this pr are not yet guaranteed to be set in any specific order and I cannot see any ordering enforced in the original code, but better be safe then sorry with concurrency