@Override public long requestedFromDownstream() { return sink.requestedFromDownstream(); }
/** * Fast-path emission that emits items directly without using an intermediate buffer. Only overflow (more items * available than requested) is stored in the buffer. * * @param iterable */ void emitDirect(Iterable<T> iterable) { long demand = sink.requestedFromDownstream(); long sent = 0; for (T value : iterable) { if (canceled) { break; } if (demand <= sent) { buffer.add(value); continue; } sent++; next(value); } }
/** * Buffer-based emission polling items from the buffer and emitting until the demand is satisfied or the buffer is * exhausted. */ void emitFromBuffer() { long demand = sink.requestedFromDownstream(); long sent = 0; if (demand > 0) { T value; while ((value = buffer.poll()) != null) { if (canceled) { break; } sent++; next(value); if (demand <= sent) { break; } } } }
public void pushToSink() { while (sink.requestedFromDownstream() > 0) { Integer item = queue.poll(); if (item != null) { sink.next(item); } else { break; } } }
void onDemand(long n) { if (this.canceled) { return; } ScanSubscriber<T, C> current = getCurrentSubscriber(); if (current == null) { current = new ScanSubscriber<>(this, sink, context, manyMapper); if (SUBSCRIBER.compareAndSet(this, null, current)) { initial.subscribe(current); } return; } ScanCursor cursor = current.getCursor(); if (cursor == null) { return; } current.emitFromBuffer(); if (!current.isExhausted() || current.canceled || sink.requestedFromDownstream() == 0) { return; } if (cursor.isFinished()) { chunkCompleted(); return; } Mono<C> next = scanFunction.apply(cursor); ScanSubscriber<T, C> nextSubscriber = new ScanSubscriber<>(this, sink, context, manyMapper); if (SUBSCRIBER.compareAndSet(this, current, nextSubscriber)) { next.subscribe(nextSubscriber); } }
@Test public void fluxCreateDropBackpressured() { Flux<String> created = Flux.create(s -> { assertThat(s.requestedFromDownstream()).isEqualTo(1); s.next("test1"); s.next("test2"); s.next("test3"); s.complete(); }, FluxSink.OverflowStrategy.DROP); StepVerifier.create(created, 1) .expectNext("test1") .thenAwait() .thenRequest(2) .verifyComplete(); }
@Test public void fluxCreateErrorBackpressured() { Flux<String> created = Flux.create(s -> { assertThat(s.requestedFromDownstream()).isEqualTo(1); s.next("test1"); s.next("test2"); s.next("test3"); s.complete(); }, FluxSink.OverflowStrategy.ERROR); StepVerifier.create(created, 1) .expectNext("test1") .thenAwait() .thenRequest(2) .verifyErrorMatches(Exceptions::isOverflow); }
@Test public void fluxCreateLatestBackpressured() { Flux<String> created = Flux.create(s -> { assertThat(s.requestedFromDownstream()).isEqualTo(1); s.next("test1"); s.next("test2"); s.next("test3"); s.complete(); }, FluxSink.OverflowStrategy.LATEST); StepVerifier.create(created, 1) .expectNext("test1") .thenAwait() .thenRequest(2) .expectNext("test3") .verifyComplete(); }
@Test public void normalBuffered() { AssertSubscriber<Integer> ts = AssertSubscriber.create(); Flux<Integer> source = Flux.<Signal<Integer>>create(e -> { e.next(Signal.next(1)); e.next(Signal.next(2)); e.next(Signal.next(3)); e.next(Signal.complete()); System.out.println(e.isCancelled()); System.out.println(e.requestedFromDownstream()); }).dematerialize(); source.subscribe(ts); ts.assertValues(1, 2, 3) .assertNoError() .assertComplete(); }
@Test public void fluxCreateBufferedBackpressured() { Flux<String> created = Flux.create(s -> { assertThat(s.requestedFromDownstream()).isEqualTo(1); s.next("test1"); s.next("test2"); s.next("test3"); s.complete(); }); StepVerifier.create(created, 1) .expectNext("test1") .thenAwait() .thenRequest(2) .expectNext("test2", "test3") .verifyComplete(); }
@Test public void fluxCreateSerializedBackpressured() { Flux<String> created = Flux.create(s -> { assertThat(s.requestedFromDownstream()).isEqualTo(1); s.next("test1"); s.next("test2"); s.next("test3"); s.complete(); }); StepVerifier.create(created, 1) .expectNext("test1") .thenAwait() .thenRequest(2) .expectNext("test2", "test3") .verifyComplete(); }
@Test public void fluxCreateIgnoreBackpressured() { Flux<String> created = Flux.create(s -> { assertThat(s.requestedFromDownstream()).isEqualTo(1); s.next("test1"); s.next("test2"); s.next("test3"); s.complete(); }, FluxSink.OverflowStrategy.IGNORE); try { StepVerifier.create(created, 1) .expectNext("test1") .thenAwait() .thenRequest(2) .verifyComplete(); Assert.fail(); } catch (AssertionError error){ assertThat(error).hasMessageContaining( "request overflow (expected production of at most 1; produced: 2; request overflown by signal: onNext(test2))"); } }
@Override public long requestedFromDownstream() { return sink.requestedFromDownstream(); }
@Override public boolean emit(CoreEvent event) { onEventConsumer.accept(event); // Optimization to avoid using synchronized block for all emissions. // See: https://github.com/reactor/reactor-core/issues/1037 if (fluxSink.requestedFromDownstream() == 0) { return false; } else if (fluxSink.requestedFromDownstream() > (bufferSize > CORES * 4 ? CORES : 0)) { // If there is sufficient room in buffer to significantly reduce change of concurrent emission when buffer is full then // emit without synchronized block. fluxSink.next(event); return true; } else { // If there is very little room in buffer also emit but synchronized. synchronized (fluxSink) { if (fluxSink.requestedFromDownstream() > 0) { fluxSink.next(event); return true; } else { return false; } } } }
/** * Fast-path emission that emits items directly without using an intermediate buffer. Only overflow (more items * available than requested) is stored in the buffer. * * @param iterable */ void emitDirect(Iterable<T> iterable) { long demand = sink.requestedFromDownstream(); long sent = 0; for (T value : iterable) { if (canceled) { break; } if (demand <= sent) { buffer.add(value); continue; } sent++; next(value); } }
/** * Buffer-based emission polling items from the buffer and emitting until the demand is satisfied or the buffer is * exhausted. */ void emitFromBuffer() { long demand = sink.requestedFromDownstream(); long sent = 0; if (demand > 0) { T value; while ((value = buffer.poll()) != null) { if (canceled) { break; } sent++; next(value); if (demand <= sent) { break; } } } }
void onDemand(long n) { if (this.canceled) { return; } ScanSubscriber<T, C> current = getCurrentSubscriber(); if (current == null) { current = new ScanSubscriber<>(this, sink, context, manyMapper); if (SUBSCRIBER.compareAndSet(this, null, current)) { initial.subscribe(current); } return; } ScanCursor cursor = current.getCursor(); if (cursor == null) { return; } current.emitFromBuffer(); if (!current.isExhausted() || current.canceled || sink.requestedFromDownstream() == 0) { return; } if (cursor.isFinished()) { chunkCompleted(); return; } Mono<C> next = scanFunction.apply(cursor); ScanSubscriber<T, C> nextSubscriber = new ScanSubscriber<>(this, sink, context, manyMapper); if (SUBSCRIBER.compareAndSet(this, current, nextSubscriber)) { next.subscribe(nextSubscriber); } }