-
Notifications
You must be signed in to change notification settings - Fork 952
Consider outstanding demand in ByteBufferStoringSubscriber before requesting more #6549
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?
Conversation
.../java/software/amazon/awssdk/services/s3/internal/crt/S3CrtRequestBodyStreamAdapterTest.java
Fixed
Show fixed
Hide fixed
utils/src/main/java/software/amazon/awssdk/utils/async/ByteBufferStoringSubscriber.java
Outdated
Show resolved
Hide resolved
| if (maximumOutstandingDemand.isPresent() && outstandingDemand.get() >= maximumOutstandingDemand.get()) { | ||
| return; | ||
| } | ||
|
|
||
| if (currentDataBuffered < minimumBytesBuffered) { |
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.
Instead of enforcing maximumOutstandingDemand, can we use byteBuffer.remaining() as a hint and check outstandingDemand.get() * buffer hints + currentDataBuffered < minimumBytesBuffered?
Because this class is used else where like https://github.com/aws/aws-sdk-java-v2/blob/master/utils/src/main/java/software/amazon/awssdk/utils/async/InputStreamSubscriber.java#L44 and it'd address the issue there as well
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.
Yeah - thats a great idea - I've updated the approach to use a sizeHint
| @@ -28,14 +28,16 @@ | |||
| @SdkInternalApi | |||
| public final class S3CrtRequestBodyStreamAdapter implements HttpRequestBodyStream { | |||
| private static final long MINIMUM_BYTES_BUFFERED = 1024 * 1024L; | |||
| // for 16 kb chunks, this limits to about 16 MB (2x the standard crt provided buffer size) | |||
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.
Where does the 16KB come from? Is it related to #6542?
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 was removed based on the sizeHint approach, but I've updated the MINIMUM_BYTES_BUFFERED to what it was prior to #3800
utils/src/main/java/software/amazon/awssdk/utils/async/ByteBufferStoringSubscriber.java
Show resolved
Hide resolved
|



Considers the outstanding demand (in flight request to the subscription) in ByteBufferStoringSubscriber before requesting more.
Motivation and Context
Fixes #3726
The ByteBufferStoringSubscriber requests more data from its subscription in two cases:
transferTois called.onNext.In both cases, it will only request more when the amount of buffered data is less than its limit. However, it was not considering unfulfilled requests (ie, requests that have been made to the subscription, but which have not yet been fulfilled) - it is possible then for the ByteBufferStoringSubscriber to queue up a large number of requests and once those are finally fulfilled, end up with a large number of events that are buffered. This can lead to OutOfMemory issues, in particularly when using a bursty Publisher/Subscription (ie, one that will fulfill a large number of requests quickly and then wait for awhile to build up more outstanding requests - an example of this is the FileAsyncRequestBody)
Modifications
byteBufferSizeHintwhenonNextis called.minimumBytesBufferedMINIMUM_BYTES_BUFFEREDback to 16 MB as it was before Fixed the issue where CRT-based S3 client was using excessive memory #3800 - the lower limit was required when outstanding demand wasn't considered.A note on the use of
AtomicIntegerfor trackingoutstandingDemandvsvolatile longfor trackingbyteBufferSizeHint-outstandingDemandis a counter and requires atomic updates (since we are incrementing/decrementing it).byteBufferSizeHinton the other hand is simply set to whatever the latest size is. It should be volatile so that whatever thread is accessing it gets the latest values, but its updates do not need to be atomic.Testing
Added new unit tests. Manual testing with a large file upload and small max heap size - before the change, hit OOM, with the change, memory usage is much lower (200 mb -> 40 mb max usage for a 2 GB file).
Screenshots (if appropriate)
Types of changes
Checklist
mvn installsucceedsscripts/new-changescript and following the instructions. Commit the new file created by the script in.changes/next-releasewith your changes.License