-
Notifications
You must be signed in to change notification settings - Fork 1k
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
[UNDERTOW-2072] DefaultByteBufferPool.getBuffer() may return null #1333
Conversation
Hi @baranowb, are you sure this change actually removes the race? If I understand Java Memory Model correctly, referenceCountUpdate.compareAndSet(0,1) will act as a publish and getBuffers reading 0 will act as acquire. This only provides ordering between actions before publish and actions after acquire. The subsequent write to buffer after publish would still race with the read of buffer, before acquire. See for example the section JMM Interpretation: Roach Motel on https://shipilev.net/blog/2014/jmm-pragmatics/, and the subsequent quiz examples. |
core/src/main/java/io/undertow/server/DefaultByteBufferPool.java
Outdated
Show resolved
Hide resolved
@@ -256,20 +256,26 @@ private static class DefaultPooledBuffer implements PooledByteBuffer { | |||
|
|||
@Override | |||
public ByteBuffer getBuffer() { | |||
final ByteBuffer tmp = this.buffer; | |||
if(referenceCount == 0) { |
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.
maybe we should throw exception if tmp is null
Oh, Im fairly sure it does not, the problem here is that this part of code wasnt synced for reason and Im sort of forced to accept some trade off - try to mitigate the problem as best as it can be done. Though Im not 100% happy with even this PR, I will change it a bit. |
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.
There is just a small change pending, other than that it looks very good @baranowb . I'll add it myself to make it possible adding this commit to the 2.3.0.Beta1 release
leakDetector.closed = true; | ||
} | ||
pool.freeInternal(buffer); | ||
this.buffer = null; | ||
if (tmp != null) { |
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.
assert tmp != null
If the referenceCountUpdaters is 1, it means it is not null.
core/src/main/java/io/undertow/server/DefaultByteBufferPool.java
Outdated
Show resolved
Hide resolved
0b6d8bb
to
15a178e
Compare
374984c
to
24bd330
Compare
@baranowb I need to figure out why my proposed commit brokes the tests. I'll update this PR as soon as I'm done with my investigation. |
this PR still breaks CI and it will require further investigation |
The test failure is: |
02bddf2
to
7c9ca9d
Compare
@@ -153,7 +154,6 @@ public PooledByteBuffer allocate() { | |||
local.allocationDepth++; | |||
} | |||
} | |||
buffer.clear(); |
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.
This shouldn't be deleted. E.g. thread local cached buffers will not be cleared anymore.
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.
Great catch @ropalka !
@@ -139,6 +139,7 @@ public PooledByteBuffer allocate() { | |||
buffer = queue.poll(); | |||
if (buffer != null) { | |||
currentQueueLengthUpdater.decrementAndGet(this); | |||
buffer.clear(); |
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.
This doesn't clear all buffers created / reused in this method, see below comment.
01ae7b4
to
f10109b
Compare
…omicIntegerFieldUpdater.addAndGet method by the original volatile read statement, it is more efficient and there is no gain in concurrency safety when using the former, as far as I could find out when investigating this. Also, I removed the check for temp being null before invoking freeInternal, because it must be non-null if referenceCount was 1 when we retrieved it. Signed-off-by: Flavia Rainone <frainone@redhat.com>
I need to see if that fixes the PR so it can be merged. However, it seems that github actions is down, the checks are queued forever. Because I'll be away on PTO until May 2nd, I'm passing the ball to you, @ropalka ! If it passes, it is ready to be merged, unless there are other issues that need to be fixed in the PR. In that case, if someone wants to give it a try, feel free to do so. See you all on the way back! |
https://issues.redhat.com/browse/UNDERTOW-2072