Skip to content

Commit 4e4b0cb

Browse files
Merge pull request #1507 from zsxwing/backpressure-bufferWithSize
BufferWithSize with Backpressure Support
2 parents 54c222c + e89a39f commit 4e4b0cb

File tree

2 files changed

+275
-0
lines changed

2 files changed

+275
-0
lines changed

rxjava-core/src/main/java/rx/internal/operators/OperatorBufferWithSize.java

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919
import java.util.Iterator;
2020
import java.util.LinkedList;
2121
import java.util.List;
22+
2223
import rx.Observable;
2324
import rx.Observable.Operator;
25+
import rx.Producer;
2426
import rx.Subscriber;
2527

2628
/**
@@ -51,6 +53,12 @@ public final class OperatorBufferWithSize<T> implements Operator<List<T>, T> {
5153
* into a buffer at all!
5254
*/
5355
public OperatorBufferWithSize(int count, int skip) {
56+
if (count <= 0) {
57+
throw new IllegalArgumentException("count must be greater than 0");
58+
}
59+
if (skip <= 0) {
60+
throw new IllegalArgumentException("skip must be greater than 0");
61+
}
5462
this.count = count;
5563
this.skip = skip;
5664
}
@@ -60,6 +68,29 @@ public Subscriber<? super T> call(final Subscriber<? super List<T>> child) {
6068
if (count == skip) {
6169
return new Subscriber<T>(child) {
6270
List<T> buffer;
71+
72+
@Override
73+
public void setProducer(final Producer producer) {
74+
child.setProducer(new Producer() {
75+
76+
private volatile boolean infinite = false;
77+
78+
@Override
79+
public void request(long n) {
80+
if (infinite) {
81+
return;
82+
}
83+
if (n >= Long.MAX_VALUE / count) {
84+
// n == Long.MAX_VALUE or n * count >= Long.MAX_VALUE
85+
infinite = true;
86+
producer.request(Long.MAX_VALUE);
87+
} else {
88+
producer.request(n * count);
89+
}
90+
}
91+
});
92+
}
93+
6394
@Override
6495
public void onNext(T t) {
6596
if (buffer == null) {
@@ -98,6 +129,60 @@ public void onCompleted() {
98129
return new Subscriber<T>(child) {
99130
final List<List<T>> chunks = new LinkedList<List<T>>();
100131
int index;
132+
133+
@Override
134+
public void setProducer(final Producer producer) {
135+
child.setProducer(new Producer() {
136+
137+
private volatile boolean firstRequest = true;
138+
private volatile boolean infinite = false;
139+
140+
private void requestInfinite() {
141+
infinite = true;
142+
producer.request(Long.MAX_VALUE);
143+
}
144+
145+
@Override
146+
public void request(long n) {
147+
if (infinite) {
148+
return;
149+
}
150+
if (n == Long.MAX_VALUE) {
151+
requestInfinite();
152+
return;
153+
} else {
154+
if (firstRequest) {
155+
firstRequest = false;
156+
if (n - 1 >= (Long.MAX_VALUE - count) / skip) {
157+
// count + skip * (n - 1) >= Long.MAX_VALUE
158+
requestInfinite();
159+
return;
160+
}
161+
// count = 5, skip = 2, n = 3
162+
// * * * * *
163+
// * * * * *
164+
// * * * * *
165+
// request = 5 + 2 * ( 3 - 1)
166+
producer.request(count + skip * (n - 1));
167+
} else {
168+
if (n >= Long.MAX_VALUE / skip) {
169+
// skip * n >= Long.MAX_VALUE
170+
requestInfinite();
171+
return;
172+
}
173+
// count = 5, skip = 2, n = 3
174+
// (* * *) * *
175+
// ( *) * * * *
176+
// * * * * *
177+
// request = skip * n
178+
// "()" means the items already emitted before this request
179+
producer.request(skip * n);
180+
}
181+
}
182+
}
183+
});
184+
}
185+
101186
@Override
102187
public void onNext(T t) {
103188
if (index++ % skip == 0) {

rxjava-core/src/test/java/rx/internal/operators/OperatorBufferTest.java

Lines changed: 190 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.assertEquals;
1819
import static org.junit.Assert.assertFalse;
1920
import static org.mockito.Matchers.any;
2021
import static org.mockito.Mockito.inOrder;
@@ -28,6 +29,7 @@
2829
import java.util.List;
2930
import java.util.concurrent.CountDownLatch;
3031
import java.util.concurrent.TimeUnit;
32+
import java.util.concurrent.atomic.AtomicLong;
3133

3234
import org.junit.Before;
3335
import org.junit.Test;
@@ -36,6 +38,7 @@
3638

3739
import rx.Observable;
3840
import rx.Observer;
41+
import rx.Producer;
3942
import rx.Scheduler;
4043
import rx.Subscriber;
4144
import rx.Subscription;
@@ -44,6 +47,7 @@
4447
import rx.functions.Action1;
4548
import rx.functions.Func0;
4649
import rx.functions.Func1;
50+
import rx.observers.TestSubscriber;
4751
import rx.schedulers.TestScheduler;
4852
import rx.subjects.PublishSubject;
4953

@@ -791,4 +795,190 @@ public Observable<Integer> call(Integer t1) {
791795
verify(o, never()).onCompleted();
792796
verify(o).onError(any(TestException.class));
793797
}
798+
799+
@Test
800+
public void testProducerRequestThroughBufferWithSize1() {
801+
TestSubscriber<List<Integer>> ts = new TestSubscriber<List<Integer>>();
802+
ts.requestMore(3);
803+
final AtomicLong requested = new AtomicLong();
804+
Observable.create(new Observable.OnSubscribe<Integer>() {
805+
806+
@Override
807+
public void call(Subscriber<? super Integer> s) {
808+
s.setProducer(new Producer() {
809+
810+
@Override
811+
public void request(long n) {
812+
requested.set(n);
813+
}
814+
815+
});
816+
}
817+
818+
}).buffer(5, 5).subscribe(ts);
819+
assertEquals(15, requested.get());
820+
821+
ts.requestMore(4);
822+
assertEquals(20, requested.get());
823+
}
824+
825+
@Test
826+
public void testProducerRequestThroughBufferWithSize2() {
827+
TestSubscriber<List<Integer>> ts = new TestSubscriber<List<Integer>>();
828+
final AtomicLong requested = new AtomicLong();
829+
Observable.create(new Observable.OnSubscribe<Integer>() {
830+
831+
@Override
832+
public void call(Subscriber<? super Integer> s) {
833+
s.setProducer(new Producer() {
834+
835+
@Override
836+
public void request(long n) {
837+
requested.set(n);
838+
}
839+
840+
});
841+
}
842+
843+
}).buffer(5, 5).subscribe(ts);
844+
assertEquals(Long.MAX_VALUE, requested.get());
845+
}
846+
847+
@Test
848+
public void testProducerRequestThroughBufferWithSize3() {
849+
TestSubscriber<List<Integer>> ts = new TestSubscriber<List<Integer>>();
850+
ts.requestMore(3);
851+
final AtomicLong requested = new AtomicLong();
852+
Observable.create(new Observable.OnSubscribe<Integer>() {
853+
854+
@Override
855+
public void call(Subscriber<? super Integer> s) {
856+
s.setProducer(new Producer() {
857+
858+
@Override
859+
public void request(long n) {
860+
requested.set(n);
861+
}
862+
863+
});
864+
}
865+
866+
}).buffer(5, 2).subscribe(ts);
867+
assertEquals(9, requested.get());
868+
ts.requestMore(3);
869+
assertEquals(6, requested.get());
870+
}
871+
872+
@Test
873+
public void testProducerRequestThroughBufferWithSize4() {
874+
TestSubscriber<List<Integer>> ts = new TestSubscriber<List<Integer>>();
875+
final AtomicLong requested = new AtomicLong();
876+
Observable.create(new Observable.OnSubscribe<Integer>() {
877+
878+
@Override
879+
public void call(Subscriber<? super Integer> s) {
880+
s.setProducer(new Producer() {
881+
882+
@Override
883+
public void request(long n) {
884+
requested.set(n);
885+
}
886+
887+
});
888+
}
889+
890+
}).buffer(5, 2).subscribe(ts);
891+
assertEquals(Long.MAX_VALUE, requested.get());
892+
}
893+
894+
895+
@Test
896+
public void testProducerRequestOverflowThroughBufferWithSize1() {
897+
TestSubscriber<List<Integer>> ts = new TestSubscriber<List<Integer>>();
898+
ts.requestMore(Long.MAX_VALUE / 2);
899+
final AtomicLong requested = new AtomicLong();
900+
Observable.create(new Observable.OnSubscribe<Integer>() {
901+
902+
@Override
903+
public void call(Subscriber<? super Integer> s) {
904+
s.setProducer(new Producer() {
905+
906+
@Override
907+
public void request(long n) {
908+
requested.set(n);
909+
}
910+
911+
});
912+
}
913+
914+
}).buffer(3, 3).subscribe(ts);
915+
assertEquals(Long.MAX_VALUE, requested.get());
916+
}
917+
918+
@Test
919+
public void testProducerRequestOverflowThroughBufferWithSize2() {
920+
TestSubscriber<List<Integer>> ts = new TestSubscriber<List<Integer>>();
921+
ts.requestMore(Long.MAX_VALUE / 2);
922+
final AtomicLong requested = new AtomicLong();
923+
Observable.create(new Observable.OnSubscribe<Integer>() {
924+
925+
@Override
926+
public void call(Subscriber<? super Integer> s) {
927+
s.setProducer(new Producer() {
928+
929+
@Override
930+
public void request(long n) {
931+
requested.set(n);
932+
}
933+
934+
});
935+
}
936+
937+
}).buffer(3, 2).subscribe(ts);
938+
assertEquals(Long.MAX_VALUE, requested.get());
939+
}
940+
941+
@Test
942+
public void testProducerRequestOverflowThroughBufferWithSize3() {
943+
final AtomicLong requested = new AtomicLong();
944+
Observable.create(new Observable.OnSubscribe<Integer>() {
945+
946+
@Override
947+
public void call(final Subscriber<? super Integer> s) {
948+
s.setProducer(new Producer() {
949+
950+
@Override
951+
public void request(long n) {
952+
requested.set(n);
953+
s.onNext(1);
954+
s.onNext(2);
955+
s.onNext(3);
956+
}
957+
958+
});
959+
}
960+
961+
}).buffer(3, 2).subscribe(new Subscriber<List<Integer>>() {
962+
963+
@Override
964+
public void onStart() {
965+
request(Long.MAX_VALUE / 2 - 4);
966+
}
967+
968+
@Override
969+
public void onCompleted() {
970+
}
971+
972+
@Override
973+
public void onError(Throwable e) {
974+
}
975+
976+
@Override
977+
public void onNext(List<Integer> t) {
978+
request(Long.MAX_VALUE / 2);
979+
}
980+
981+
});
982+
assertEquals(Long.MAX_VALUE, requested.get());
983+
}
794984
}

0 commit comments

Comments
 (0)