22
22
import io .rsocket .frame .FrameHeaderFlyweight ;
23
23
import java .nio .channels .ClosedChannelException ;
24
24
import java .time .Duration ;
25
+ import java .util .Queue ;
25
26
import java .util .concurrent .atomic .AtomicBoolean ;
27
+ import java .util .concurrent .atomic .AtomicInteger ;
26
28
import java .util .function .Function ;
27
29
import org .reactivestreams .Publisher ;
28
30
import org .slf4j .Logger ;
29
31
import org .slf4j .LoggerFactory ;
30
32
import reactor .core .Disposable ;
31
33
import reactor .core .Disposables ;
32
34
import reactor .core .publisher .*;
35
+ import reactor .util .concurrent .Queues ;
33
36
34
37
class ResumableDuplexConnection implements DuplexConnection , ResumeStateHolder {
35
38
private static final Logger logger = LoggerFactory .getLogger (ResumableDuplexConnection .class );
@@ -45,7 +48,8 @@ class ResumableDuplexConnection implements DuplexConnection, ResumeStateHolder {
45
48
private final FluxProcessor <ByteBuf , ByteBuf > downStreamFrames = ReplayProcessor .create (0 );
46
49
private final FluxProcessor <ByteBuf , ByteBuf > resumeSaveFrames = EmitterProcessor .create ();
47
50
private final MonoProcessor <Void > resumeSaveCompleted = MonoProcessor .create ();
48
- private final FluxProcessor <Object , Object > actions = UnicastProcessor .create ().serialize ();
51
+ private final Queue <Object > actions = Queues .unboundedMultiproducer ().get ();
52
+ private final AtomicInteger actionsWip = new AtomicInteger ();
49
53
50
54
private final Mono <Void > framesSent ;
51
55
private final RequestListener downStreamRequestListener = new RequestListener ();
@@ -56,7 +60,7 @@ class ResumableDuplexConnection implements DuplexConnection, ResumeStateHolder {
56
60
128 ,
57
61
downStreamRequestListener .requests (),
58
62
resumeSaveStreamRequestListener .requests (),
59
- actions :: onNext );
63
+ this :: dispatch );
60
64
61
65
private volatile State state ;
62
66
private volatile Disposable resumedStreamDisposable = Disposables .disposed ();
@@ -92,7 +96,6 @@ class ResumableDuplexConnection implements DuplexConnection, ResumeStateHolder {
92
96
.then ()
93
97
.cache ();
94
98
95
- dispatch (actions );
96
99
reconnect (duplexConnection );
97
100
}
98
101
@@ -109,7 +112,7 @@ public void reconnect(ResumePositionsConnection connection) {
109
112
"{} Resumable duplex connection reconnected with connection: {}" , tag , connection );
110
113
/*race between sendFrame and doResumeStart may lead to ongoing upstream frames
111
114
written before resume complete*/
112
- actions . onNext (new ResumeStart (connection ));
115
+ dispatch (new ResumeStart (connection ));
113
116
}
114
117
}
115
118
@@ -118,7 +121,7 @@ public void reconnect(ResumePositionsConnection connection) {
118
121
public void resume (
119
122
long remotePos , long remoteImpliedPos , Function <Mono <Long >, Mono <Void >> resumeFrameSent ) {
120
123
/*race between sendFrame and doResume may lead to duplicate frames on resume store*/
121
- actions . onNext (new Resume (remotePos , remoteImpliedPos , resumeFrameSent ));
124
+ dispatch (new Resume (remotePos , remoteImpliedPos , resumeFrameSent ));
122
125
}
123
126
124
127
@ Override
@@ -214,15 +217,18 @@ Flux<Throwable> connectionErrors() {
214
217
return connectionErrors ;
215
218
}
216
219
217
- private void dispatch (Flux <?> f ) {
218
- f .subscribe (
219
- o -> {
220
- if (o instanceof ByteBuf ) {
221
- sendFrame ((ByteBuf ) o );
222
- } else {
223
- ((Runnable ) o ).run ();
224
- }
225
- });
220
+ private void dispatch (Object action ) {
221
+ actions .offer (action );
222
+ if (actionsWip .getAndIncrement () == 0 ) {
223
+ do {
224
+ Object a = actions .poll ();
225
+ if (a instanceof ByteBuf ) {
226
+ sendFrame ((ByteBuf ) a );
227
+ } else {
228
+ ((Runnable ) a ).run ();
229
+ }
230
+ } while (actionsWip .decrementAndGet () != 0 );
231
+ }
226
232
}
227
233
228
234
private void doResumeStart (ResumePositionsConnection connection ) {
@@ -272,7 +278,7 @@ private void doResume(
272
278
resumableFramesStore
273
279
.resumeStream ()
274
280
.timeout (resumeStreamTimeout )
275
- .doFinally (s -> actions . onNext (new ResumeComplete ())))
281
+ .doFinally (s -> dispatch (new ResumeComplete ())))
276
282
.doOnError (err -> dispose ()))
277
283
.onErrorResume (err -> Mono .empty ())
278
284
.subscribe ();
@@ -299,7 +305,7 @@ private Mono<Void> streamResumedFrames(Flux<ByteBuf> frames) {
299
305
s -> {
300
306
ResumeFramesSubscriber subscriber =
301
307
new ResumeFramesSubscriber (
302
- downStreamRequestListener .requests (), actions :: onNext , s ::error , s ::success );
308
+ downStreamRequestListener .requests (), this :: dispatch , s ::error , s ::success );
303
309
s .onDispose (subscriber );
304
310
resumedStreamDisposable = subscriber ;
305
311
frames .subscribe (subscriber );
0 commit comments