Skip to content

Commit 6a53f24

Browse files
committed
Feature/perf tunning 3 (#726)
* provides improved `UnicastMonoEmpty` Signed-off-by: Oleh Dokuka <[email protected]> * provides built-in lifecycle handler for UnicastMonoProcessor Signed-off-by: Oleh Dokuka <[email protected]>
1 parent aedea7a commit 6a53f24

File tree

7 files changed

+709
-118
lines changed

7 files changed

+709
-118
lines changed

rsocket-core/src/main/java/io/rsocket/RSocketRequester.java

Lines changed: 57 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,28 @@
2525
import io.netty.util.collection.IntObjectMap;
2626
import io.rsocket.exceptions.ConnectionErrorException;
2727
import io.rsocket.exceptions.Exceptions;
28-
import io.rsocket.frame.*;
28+
import io.rsocket.frame.CancelFrameFlyweight;
29+
import io.rsocket.frame.ErrorFrameFlyweight;
30+
import io.rsocket.frame.FrameHeaderFlyweight;
31+
import io.rsocket.frame.FrameType;
32+
import io.rsocket.frame.MetadataPushFrameFlyweight;
33+
import io.rsocket.frame.PayloadFrameFlyweight;
34+
import io.rsocket.frame.RequestChannelFrameFlyweight;
35+
import io.rsocket.frame.RequestFireAndForgetFrameFlyweight;
36+
import io.rsocket.frame.RequestNFrameFlyweight;
37+
import io.rsocket.frame.RequestResponseFrameFlyweight;
38+
import io.rsocket.frame.RequestStreamFrameFlyweight;
2939
import io.rsocket.frame.decoder.PayloadDecoder;
3040
import io.rsocket.internal.RateLimitableRequestPublisher;
3141
import io.rsocket.internal.SynchronizedIntObjectHashMap;
3242
import io.rsocket.internal.UnboundedProcessor;
43+
import io.rsocket.internal.UnicastMonoEmpty;
3344
import io.rsocket.internal.UnicastMonoProcessor;
3445
import io.rsocket.keepalive.KeepAliveFramesAcceptor;
3546
import io.rsocket.keepalive.KeepAliveHandler;
3647
import io.rsocket.keepalive.KeepAliveSupport;
3748
import io.rsocket.lease.RequesterLeaseHandler;
38-
import io.rsocket.util.OnceConsumer;
49+
import io.rsocket.util.MonoLifecycleHandler;
3950
import java.nio.channels.ClosedChannelException;
4051
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
4152
import java.util.function.Consumer;
@@ -46,8 +57,11 @@
4657
import org.reactivestreams.Processor;
4758
import org.reactivestreams.Publisher;
4859
import org.reactivestreams.Subscriber;
49-
import org.reactivestreams.Subscription;
50-
import reactor.core.publisher.*;
60+
import reactor.core.publisher.BaseSubscriber;
61+
import reactor.core.publisher.Flux;
62+
import reactor.core.publisher.Mono;
63+
import reactor.core.publisher.SignalType;
64+
import reactor.core.publisher.UnicastProcessor;
5165
import reactor.util.concurrent.Queues;
5266

5367
/**
@@ -170,23 +184,19 @@ private Mono<Void> handleFireAndForget(Payload payload) {
170184

171185
final int streamId = streamIdSupplier.nextStreamId(receivers);
172186

173-
return emptyUnicastMono()
174-
.doOnSubscribe(
175-
new OnceConsumer<Subscription>() {
176-
@Override
177-
public void acceptOnce(@Nonnull Subscription subscription) {
178-
ByteBuf requestFrame =
179-
RequestFireAndForgetFrameFlyweight.encode(
180-
allocator,
181-
streamId,
182-
false,
183-
payload.hasMetadata() ? payload.sliceMetadata().retain() : null,
184-
payload.sliceData().retain());
185-
payload.release();
186-
187-
sendProcessor.onNext(requestFrame);
188-
}
189-
});
187+
return UnicastMonoEmpty.newInstance(
188+
() -> {
189+
ByteBuf requestFrame =
190+
RequestFireAndForgetFrameFlyweight.encode(
191+
allocator,
192+
streamId,
193+
false,
194+
payload.hasMetadata() ? payload.sliceMetadata().retain() : null,
195+
payload.sliceData().retain());
196+
payload.release();
197+
198+
sendProcessor.onNext(requestFrame);
199+
});
190200
}
191201

192202
private Mono<Payload> handleRequestResponse(final Payload payload) {
@@ -199,14 +209,11 @@ private Mono<Payload> handleRequestResponse(final Payload payload) {
199209
int streamId = streamIdSupplier.nextStreamId(receivers);
200210
final UnboundedProcessor<ByteBuf> sendProcessor = this.sendProcessor;
201211

202-
UnicastMonoProcessor<Payload> receiver = UnicastMonoProcessor.create();
203-
receivers.put(streamId, receiver);
204-
205-
return receiver
206-
.doOnSubscribe(
207-
new OnceConsumer<Subscription>() {
212+
UnicastMonoProcessor<Payload> receiver =
213+
UnicastMonoProcessor.create(
214+
new MonoLifecycleHandler<Payload>() {
208215
@Override
209-
public void acceptOnce(@Nonnull Subscription subscription) {
216+
public void doOnSubscribe() {
210217
final ByteBuf requestFrame =
211218
RequestResponseFrameFlyweight.encode(
212219
allocator,
@@ -218,15 +225,23 @@ public void acceptOnce(@Nonnull Subscription subscription) {
218225

219226
sendProcessor.onNext(requestFrame);
220227
}
221-
})
222-
.doOnError(t -> sendProcessor.onNext(ErrorFrameFlyweight.encode(allocator, streamId, t)))
223-
.doFinally(
224-
s -> {
225-
if (s == SignalType.CANCEL) {
226-
sendProcessor.onNext(CancelFrameFlyweight.encode(allocator, streamId));
228+
229+
@Override
230+
public void doOnTerminal(
231+
@Nonnull SignalType signalType,
232+
@Nullable Payload element,
233+
@Nullable Throwable e) {
234+
if (signalType == SignalType.ON_ERROR) {
235+
sendProcessor.onNext(ErrorFrameFlyweight.encode(allocator, streamId, e));
236+
} else if (signalType == SignalType.CANCEL) {
237+
sendProcessor.onNext(CancelFrameFlyweight.encode(allocator, streamId));
238+
}
239+
removeStreamReceiver(streamId);
227240
}
228-
removeStreamReceiver(streamId);
229241
});
242+
receivers.put(streamId, receiver);
243+
244+
return receiver;
230245
}
231246

232247
private Flux<Payload> handleRequestStream(final Payload payload) {
@@ -390,24 +405,14 @@ private Mono<Void> handleMetadataPush(Payload payload) {
390405
return Mono.error(err);
391406
}
392407

393-
return emptyUnicastMono()
394-
.doOnSubscribe(
395-
new OnceConsumer<Subscription>() {
396-
@Override
397-
public void acceptOnce(@Nonnull Subscription subscription) {
398-
ByteBuf metadataPushFrame =
399-
MetadataPushFrameFlyweight.encode(allocator, payload.sliceMetadata().retain());
400-
payload.release();
401-
402-
sendProcessor.onNext(metadataPushFrame);
403-
}
404-
});
405-
}
408+
return UnicastMonoEmpty.newInstance(
409+
() -> {
410+
ByteBuf metadataPushFrame =
411+
MetadataPushFrameFlyweight.encode(allocator, payload.sliceMetadata().retain());
412+
payload.release();
406413

407-
private static UnicastMonoProcessor<Void> emptyUnicastMono() {
408-
UnicastMonoProcessor<Void> result = UnicastMonoProcessor.create();
409-
result.onComplete();
410-
return result;
414+
sendProcessor.onNext(metadataPushFrame);
415+
});
411416
}
412417

413418
private Throwable checkAvailable() {
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package io.rsocket.internal;
2+
3+
import java.time.Duration;
4+
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
5+
import reactor.core.CoreSubscriber;
6+
import reactor.core.Scannable;
7+
import reactor.core.publisher.Mono;
8+
import reactor.core.publisher.Operators;
9+
import reactor.util.annotation.Nullable;
10+
11+
/**
12+
* Represents an empty publisher which only calls onSubscribe and onComplete.
13+
*
14+
* <p>This Publisher is effectively stateless and only a single instance exists. Use the {@link
15+
* #instance()} method to obtain a properly type-parametrized view of it.
16+
*
17+
* @see <a href="https://github.com/reactor/reactive-streams-commons">Reactive-Streams-Commons</a>
18+
*/
19+
public final class UnicastMonoEmpty extends Mono<Object> implements Scannable {
20+
21+
final Runnable onSubscribe;
22+
23+
volatile int once;
24+
25+
@SuppressWarnings("rawtypes")
26+
static final AtomicIntegerFieldUpdater<UnicastMonoEmpty> ONCE =
27+
AtomicIntegerFieldUpdater.newUpdater(UnicastMonoEmpty.class, "once");
28+
29+
UnicastMonoEmpty(Runnable onSubscribe) {
30+
this.onSubscribe = onSubscribe;
31+
}
32+
33+
@Override
34+
public void subscribe(CoreSubscriber<? super Object> actual) {
35+
if (once == 0 && ONCE.compareAndSet(this, 0, 1)) {
36+
onSubscribe.run();
37+
Operators.complete(actual);
38+
} else {
39+
Operators.error(
40+
actual, new IllegalStateException("UnicastMonoEmpty allows only a single Subscriber"));
41+
}
42+
}
43+
44+
/**
45+
* Returns a properly parametrized instance of this empty Publisher.
46+
*
47+
* @param <T> the output type
48+
* @return a properly parametrized instance of this empty Publisher
49+
*/
50+
@SuppressWarnings("unchecked")
51+
public static <T> Mono<T> newInstance(Runnable onSubscribe) {
52+
return (Mono<T>) new UnicastMonoEmpty(onSubscribe);
53+
}
54+
55+
@Override
56+
@Nullable
57+
public Object block(Duration m) {
58+
if (once == 0 && ONCE.compareAndSet(this, 0, 1)) {
59+
onSubscribe.run();
60+
return null;
61+
} else {
62+
throw new IllegalStateException("UnicastMonoEmpty allows only a single Subscriber");
63+
}
64+
}
65+
66+
@Override
67+
@Nullable
68+
public Object block() {
69+
if (once == 0 && ONCE.compareAndSet(this, 0, 1)) {
70+
onSubscribe.run();
71+
return null;
72+
} else {
73+
throw new IllegalStateException("UnicastMonoEmpty allows only a single Subscriber");
74+
}
75+
}
76+
77+
@Override
78+
public Object scanUnsafe(Attr key) {
79+
return null; // no particular key to be represented, still useful in hooks
80+
}
81+
82+
@Override
83+
public String stepName() {
84+
return "source(UnicastMonoEmpty)";
85+
}
86+
}

0 commit comments

Comments
 (0)