-
Notifications
You must be signed in to change notification settings - Fork 283
Fix ByteBuf memory leak in PutOperation when operations are aborted #3176
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
base: master
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -578,6 +578,11 @@ void setOperationCompleted() { | |
| */ | ||
| public void cleanupChunks() { | ||
| releaseDataForAllChunks(); | ||
| // At this point, if the channelReadBuf is not null it means it did not get fully read | ||
| // by the ChunkFiller in fillChunks and needs to be released. | ||
| if (channelReadBuf != null) { | ||
| channelReadBuf.release(); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -1642,7 +1647,7 @@ void onFillComplete(boolean updateMetric) { | |
| * @param channelReadBuf the {@link ByteBuf} from which to read data. | ||
| * @return the number of bytes transferred in this operation. | ||
| */ | ||
| synchronized int fillFrom(ByteBuf channelReadBuf) { | ||
| int fillFrom(ByteBuf channelReadBuf) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we still need this function to be synchronized here, it's here to protect race condition.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lets walk through to see if that's the case.
So fillChunks since it's only accessed by a single thread would only needs to be synchronized from concurrent access from error / cleanup threads. What is needed is that any objects used within the fillChunks routine which may also be concurrently accessed by those threads to be either behind a more narrowly scoped lock or declared as volatile. So lets look at that. In PutManager.poll we have: So
Therefore we need to a) make sure anything that happens within In PutManager.completePendingOperations we have: and So lets look at condition a: So for condition A we set the exception, set operation completed, and clear chunks which are provably finished. None of this will involve concurrent modification with fillChunks. Lets looks at condition b: For condition b we can either add synchronized to fillChunks (instead of fillFrom) or we can add a lock around updating the operationCompleted value (and when we need to avoid TOCTOU). The synchronized on fillChunks should cause the least amount of complexity without too large an of an overhead as most of the work in fillChunks happens within an internal loop depending on the operationCompleted value. |
||
| int toWrite; | ||
| ByteBuf slice; | ||
| if (buf == 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.
Nice! This is a better clean fix with unit test than adding synchronized. thank you