-
Notifications
You must be signed in to change notification settings - Fork 975
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
Changes from 2 commits
975e1f2
326e615
3c8d84b
75eb291
43044d6
997f254
4510e2f
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 |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| { | ||
| "type": "bugfix", | ||
| "category": "Amazon S3", | ||
| "contributor": "", | ||
| "description": "Fix OutOfMemory issues when using S3CrtRequestBodyStreamAdapter on streams that produce data faster than they can be consumed." | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,6 +21,7 @@ | |
| import java.util.Optional; | ||
| import java.util.concurrent.CountDownLatch; | ||
| import java.util.concurrent.Phaser; | ||
| import java.util.concurrent.atomic.AtomicInteger; | ||
| import java.util.concurrent.atomic.AtomicLong; | ||
| import org.reactivestreams.Subscriber; | ||
| import org.reactivestreams.Subscription; | ||
|
|
@@ -56,6 +57,10 @@ public class ByteBufferStoringSubscriber implements Subscriber<ByteBuffer> { | |
|
|
||
| private final Phaser phaser = new Phaser(1); | ||
|
|
||
| private final AtomicInteger outstandingDemand = new AtomicInteger(0); | ||
|
|
||
| private final Optional<Integer> maximumOutstandingDemand; | ||
alextwoods marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| /** | ||
| * The active subscription. Set when {@link #onSubscribe(Subscription)} is invoked. | ||
| */ | ||
|
|
@@ -67,6 +72,19 @@ public class ByteBufferStoringSubscriber implements Subscriber<ByteBuffer> { | |
| public ByteBufferStoringSubscriber(long minimumBytesBuffered) { | ||
| this.minimumBytesBuffered = Validate.isPositive(minimumBytesBuffered, "Data buffer minimum must be positive"); | ||
| this.storingSubscriber = new StoringSubscriber<>(Integer.MAX_VALUE); | ||
| this.maximumOutstandingDemand = Optional.empty(); | ||
| } | ||
|
|
||
| /** | ||
| * Create a subscriber that stores at least {@code minimumBytesBuffered} in memory for retrieval and which limits the | ||
| * maximum outstanding demand (requests) to its subscription. | ||
| */ | ||
| public ByteBufferStoringSubscriber(long minimumBytesBuffered, int maximumOutstandingDemand) { | ||
| this.minimumBytesBuffered = Validate.isPositive(minimumBytesBuffered, "Data buffer minimum must be positive"); | ||
| this.maximumOutstandingDemand = Optional.of(Validate.isPositive(maximumOutstandingDemand, | ||
| "maximumOutstandingDemand must be positive")); | ||
|
|
||
| this.storingSubscriber = new StoringSubscriber<>(Integer.MAX_VALUE); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -175,12 +193,14 @@ public void onSubscribe(Subscription s) { | |
| storingSubscriber.onSubscribe(new DemandIgnoringSubscription(s)); | ||
| subscription = s; | ||
| subscription.request(1); | ||
| outstandingDemand.incrementAndGet(); | ||
alextwoods marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| subscriptionLatch.countDown(); | ||
| } | ||
|
|
||
| @Override | ||
| public void onNext(ByteBuffer byteBuffer) { | ||
| int remaining = byteBuffer.remaining(); | ||
| outstandingDemand.decrementAndGet(); | ||
| storingSubscriber.onNext(byteBuffer.duplicate()); | ||
| addBufferedDataAmount(remaining); | ||
| phaser.arrive(); | ||
|
|
@@ -204,7 +224,13 @@ private void addBufferedDataAmount(long amountToAdd) { | |
| } | ||
|
|
||
| private void maybeRequestMore(long currentDataBuffered) { | ||
| // if we have too many outstanding requests, no need to make more requests | ||
| if (maximumOutstandingDemand.isPresent() && outstandingDemand.get() >= maximumOutstandingDemand.get()) { | ||
| return; | ||
| } | ||
|
|
||
| if (currentDataBuffered < minimumBytesBuffered) { | ||
|
||
| outstandingDemand.incrementAndGet(); | ||
| subscription.request(1); | ||
| } | ||
| } | ||
|
|
||
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