Skip to content

Commit 9a2a311

Browse files
committed
add request overflow check for OnSubscribeFromIterable
1 parent dda25e6 commit 9a2a311

File tree

4 files changed

+85
-11
lines changed

4 files changed

+85
-11
lines changed

src/main/java/rx/internal/operators/OnSubscribeFromIterable.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public void request(long n) {
8080
}
8181
} else if(n > 0) {
8282
// backpressure is requested
83-
long _c = REQUESTED_UPDATER.getAndAdd(this, n);
83+
long _c = Util.getAndAddRequest(REQUESTED_UPDATER, this, n);
8484
if (_c == 0) {
8585
while (true) {
8686
/*

src/main/java/rx/internal/operators/OperatorMerge.java

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -545,16 +545,7 @@ public void request(long n) {
545545
if (n == Long.MAX_VALUE) {
546546
requested = Long.MAX_VALUE;
547547
} else {
548-
// add n to requested but check for overflow
549-
while (true) {
550-
long current = REQUESTED.get(this);
551-
long next = current + n;
552-
//check for overflow
553-
if (next < 0)
554-
next = Long.MAX_VALUE;
555-
if (REQUESTED.compareAndSet(this, current, next))
556-
break;
557-
}
548+
Util.getAndAddRequest(REQUESTED, this, n);
558549
if (ms.drainQueuesIfNeeded()) {
559550
boolean sendComplete = false;
560551
synchronized (ms) {
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* Copyright 2014 Netflix, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package rx.internal.operators;
17+
18+
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
19+
20+
/**
21+
* Utility functions for use with Operators.
22+
*
23+
*/
24+
final class Util {
25+
26+
/**
27+
* Adds n to requested field and returns the value prior to addition once the addition
28+
* is successful (uses CAS semantics). If overflows then sets requested field to Long.MAX_VALUE.
29+
*
30+
* @param requested atomic field updater for a request count
31+
* @param object contains the field updated by the updater
32+
* @param n the number of requests to add to the requested count
33+
* @return requested value just prior to successful addition
34+
*/
35+
static <T> long getAndAddRequest(AtomicLongFieldUpdater<T> requested, T object, long n) {
36+
// add n to field but check for overflow
37+
while (true) {
38+
long current = requested.get(object);
39+
long next = current + n;
40+
//check for overflow
41+
if (next < 0)
42+
next = Long.MAX_VALUE;
43+
if (requested.compareAndSet(object, current, next))
44+
return current;
45+
}
46+
}
47+
}

src/test/java/rx/internal/operators/OnSubscribeFromIterableTest.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package rx.internal.operators;
1717

18+
import static org.junit.Assert.assertTrue;
1819
import static org.mockito.Matchers.any;
1920
import static org.mockito.Mockito.mock;
2021
import static org.mockito.Mockito.times;
@@ -24,14 +25,18 @@
2425
import java.util.Arrays;
2526
import java.util.Collections;
2627
import java.util.Iterator;
28+
import java.util.concurrent.CountDownLatch;
29+
import java.util.concurrent.TimeUnit;
2730

2831
import org.junit.Test;
2932
import org.mockito.Mockito;
3033

3134
import rx.Observable;
3235
import rx.Observer;
36+
import rx.Subscriber;
3337
import rx.internal.util.RxRingBuffer;
3438
import rx.observers.TestSubscriber;
39+
import rx.schedulers.Schedulers;
3540

3641
public class OnSubscribeFromIterableTest {
3742

@@ -157,5 +162,36 @@ public void testSubscribeMultipleTimes() {
157162
o.call(ts);
158163
ts.assertReceivedOnNext(Arrays.asList(1, 2, 3));
159164
}
165+
166+
@Test
167+
public void testFromIterableRequestOverflow() throws InterruptedException {
168+
Observable<Integer> o = Observable.from(Arrays.asList(1,2,3,4));
169+
final int expectedCount = 4;
170+
final CountDownLatch latch = new CountDownLatch(expectedCount);
171+
o.subscribeOn(Schedulers.computation()).subscribe(new Subscriber<Integer>() {
172+
173+
@Override
174+
public void onStart() {
175+
request(2);
176+
}
177+
178+
@Override
179+
public void onCompleted() {
180+
//ignore
181+
}
182+
183+
@Override
184+
public void onError(Throwable e) {
185+
throw new RuntimeException(e);
186+
}
187+
188+
@Override
189+
public void onNext(Integer t) {
190+
latch.countDown();
191+
request(Long.MAX_VALUE-1);
192+
}});
193+
assertTrue(latch.await(10, TimeUnit.SECONDS));
194+
}
195+
160196

161197
}

0 commit comments

Comments
 (0)