1
1
/*
2
- * Copyright 2002-2017 the original author or authors.
2
+ * Copyright 2002-2018 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
@@ -75,6 +75,33 @@ public void subscribe(CoreSubscriber<? super Void> actual) {
75
75
}
76
76
77
77
78
+ private enum State {
79
+
80
+ /** No emissions from the upstream source yet */
81
+ NEW ,
82
+
83
+ /**
84
+ * At least one signal of any kind has been received; we're ready to
85
+ * call the write function and proceed with actual writing.
86
+ */
87
+ FIRST_SIGNAL_RECEIVED ,
88
+
89
+ /**
90
+ * The write subscriber has subscribed and requested; we're going to
91
+ * emit the cached signals.
92
+ */
93
+ EMITTING_CACHED_SIGNALS ,
94
+
95
+ /**
96
+ * The write subscriber has subscribed, and cached signals have been
97
+ * emitted to it; we're ready to switch to a simple pass-through mode
98
+ * for all remaining signals.
99
+ **/
100
+ READY_TO_WRITE
101
+
102
+ }
103
+
104
+
78
105
/**
79
106
* A barrier inserted between the write source and the write subscriber
80
107
* (i.e. the HTTP server adapter) that pre-fetches and waits for the first
@@ -99,27 +126,23 @@ private class WriteBarrier implements CoreSubscriber<T>, Subscription, Publisher
99
126
@ Nullable
100
127
private Subscription subscription ;
101
128
102
- /**
103
- * We've at at least one emission, we've called the write function, the write
104
- * subscriber has subscribed and cached signals have been emitted to it.
105
- * We're now simply passing data through to the write subscriber.
106
- **/
107
- private boolean readyToWrite = false ;
108
-
109
- /** No emission from upstream yet */
110
- private boolean beforeFirstEmission = true ;
111
-
112
- /** Cached signal before readyToWrite */
129
+ /** Cached data item before readyToWrite */
113
130
@ Nullable
114
131
private T item ;
115
132
116
- /** Cached 1st/2nd signal before readyToWrite */
133
+ /** Cached error signal before readyToWrite */
117
134
@ Nullable
118
135
private Throwable error ;
119
136
120
- /** Cached 1st/2nd signal before readyToWrite */
137
+ /** Cached onComplete signal before readyToWrite */
121
138
private boolean completed = false ;
122
139
140
+ /** Recursive demand while emitting cached signals */
141
+ private long demandBeforeReadyToWrite ;
142
+
143
+ /** Current state */
144
+ private State state = State .NEW ;
145
+
123
146
/** The actual writeSubscriber from the HTTP server adapter */
124
147
@ Nullable
125
148
private Subscriber <? super T > writeSubscriber ;
@@ -143,18 +166,18 @@ public final void onSubscribe(Subscription s) {
143
166
144
167
@ Override
145
168
public final void onNext (T item ) {
146
- if (this .readyToWrite ) {
169
+ if (this .state == State . READY_TO_WRITE ) {
147
170
requiredWriteSubscriber ().onNext (item );
148
171
return ;
149
172
}
150
173
//FIXME revisit in case of reentrant sync deadlock
151
174
synchronized (this ) {
152
- if (this .readyToWrite ) {
175
+ if (this .state == State . READY_TO_WRITE ) {
153
176
requiredWriteSubscriber ().onNext (item );
154
177
}
155
- else if (this .beforeFirstEmission ) {
178
+ else if (this .state == State . NEW ) {
156
179
this .item = item ;
157
- this .beforeFirstEmission = false ;
180
+ this .state = State . FIRST_SIGNAL_RECEIVED ;
158
181
writeFunction .apply (this ).subscribe (this .writeCompletionBarrier );
159
182
}
160
183
else {
@@ -173,16 +196,16 @@ private Subscriber<? super T> requiredWriteSubscriber() {
173
196
174
197
@ Override
175
198
public final void onError (Throwable ex ) {
176
- if (this .readyToWrite ) {
199
+ if (this .state == State . READY_TO_WRITE ) {
177
200
requiredWriteSubscriber ().onError (ex );
178
201
return ;
179
202
}
180
203
synchronized (this ) {
181
- if (this .readyToWrite ) {
204
+ if (this .state == State . READY_TO_WRITE ) {
182
205
requiredWriteSubscriber ().onError (ex );
183
206
}
184
- else if (this .beforeFirstEmission ) {
185
- this .beforeFirstEmission = false ;
207
+ else if (this .state == State . NEW ) {
208
+ this .state = State . FIRST_SIGNAL_RECEIVED ;
186
209
this .writeCompletionBarrier .onError (ex );
187
210
}
188
211
else {
@@ -193,17 +216,17 @@ else if (this.beforeFirstEmission) {
193
216
194
217
@ Override
195
218
public final void onComplete () {
196
- if (this .readyToWrite ) {
219
+ if (this .state == State . READY_TO_WRITE ) {
197
220
requiredWriteSubscriber ().onComplete ();
198
221
return ;
199
222
}
200
223
synchronized (this ) {
201
- if (this .readyToWrite ) {
224
+ if (this .state == State . READY_TO_WRITE ) {
202
225
requiredWriteSubscriber ().onComplete ();
203
226
}
204
- else if (this .beforeFirstEmission ) {
227
+ else if (this .state == State . NEW ) {
205
228
this .completed = true ;
206
- this .beforeFirstEmission = false ;
229
+ this .state = State . FIRST_SIGNAL_RECEIVED ;
207
230
writeFunction .apply (this ).subscribe (this .writeCompletionBarrier );
208
231
}
209
232
else {
@@ -226,19 +249,28 @@ public void request(long n) {
226
249
if (s == null ) {
227
250
return ;
228
251
}
229
- if (this .readyToWrite ) {
252
+ if (this .state == State . READY_TO_WRITE ) {
230
253
s .request (n );
231
254
return ;
232
255
}
233
256
synchronized (this ) {
234
257
if (this .writeSubscriber != null ) {
235
- this .readyToWrite = true ;
236
- if ( emitCachedSignals ()) {
258
+ if ( this .state == State . EMITTING_CACHED_SIGNALS ) {
259
+ this . demandBeforeReadyToWrite = n ;
237
260
return ;
238
261
}
239
- n --;
240
- if (n == 0 ) {
241
- return ;
262
+ try {
263
+ this .state = State .EMITTING_CACHED_SIGNALS ;
264
+ if (emitCachedSignals ()) {
265
+ return ;
266
+ }
267
+ n = n + this .demandBeforeReadyToWrite - 1 ;
268
+ if (n == 0 ) {
269
+ return ;
270
+ }
271
+ }
272
+ finally {
273
+ this .state = State .READY_TO_WRITE ;
242
274
}
243
275
}
244
276
}
0 commit comments