Skip to content

Commit d5e8a45

Browse files
authored
Fixes possible elements' leaks occurrence (#799)
1 parent 00acd1e commit d5e8a45

File tree

2 files changed

+70
-34
lines changed

2 files changed

+70
-34
lines changed

rsocket-core/src/main/java/io/rsocket/internal/UnboundedProcessor.java

Lines changed: 66 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -43,28 +43,43 @@
4343
public final class UnboundedProcessor<T> extends FluxProcessor<T, T>
4444
implements Fuseable.QueueSubscription<T>, Fuseable {
4545

46+
final Queue<T> queue;
47+
final Queue<T> priorityQueue;
48+
49+
volatile boolean done;
50+
Throwable error;
51+
// important to not loose the downstream too early and miss discard hook, while
52+
// having relevant hasDownstreams()
53+
boolean hasDownstream;
54+
volatile CoreSubscriber<? super T> actual;
55+
56+
volatile boolean cancelled;
57+
58+
volatile int once;
59+
4660
@SuppressWarnings("rawtypes")
4761
static final AtomicIntegerFieldUpdater<UnboundedProcessor> ONCE =
4862
AtomicIntegerFieldUpdater.newUpdater(UnboundedProcessor.class, "once");
4963

64+
volatile int wip;
65+
5066
@SuppressWarnings("rawtypes")
5167
static final AtomicIntegerFieldUpdater<UnboundedProcessor> WIP =
5268
AtomicIntegerFieldUpdater.newUpdater(UnboundedProcessor.class, "wip");
5369

70+
volatile int discardGuard;
71+
72+
@SuppressWarnings("rawtypes")
73+
static final AtomicIntegerFieldUpdater<UnboundedProcessor> DISCARD_GUARD =
74+
AtomicIntegerFieldUpdater.newUpdater(UnboundedProcessor.class, "discardGuard");
75+
76+
volatile long requested;
77+
5478
@SuppressWarnings("rawtypes")
5579
static final AtomicLongFieldUpdater<UnboundedProcessor> REQUESTED =
5680
AtomicLongFieldUpdater.newUpdater(UnboundedProcessor.class, "requested");
5781

58-
final Queue<T> queue;
59-
final Queue<T> priorityQueue;
60-
volatile boolean done;
61-
Throwable error;
62-
volatile CoreSubscriber<? super T> actual;
63-
volatile boolean cancelled;
64-
volatile int once;
65-
volatile int wip;
66-
volatile long requested;
67-
volatile boolean outputFused;
82+
boolean outputFused;
6883

6984
public UnboundedProcessor() {
7085
this.queue = new MpscUnboundedArrayQueue<>(Queues.SMALL_BUFFER_SIZE);
@@ -79,6 +94,7 @@ public int getBufferSize() {
7994
@Override
8095
public Object scanUnsafe(Attr key) {
8196
if (Attr.BUFFERED == key) return queue.size();
97+
if (Attr.PREFETCH == key) return Integer.MAX_VALUE;
8298
return super.scanUnsafe(key);
8399
}
84100

@@ -143,8 +159,8 @@ void drainFused(Subscriber<? super T> a) {
143159
for (; ; ) {
144160

145161
if (cancelled) {
146-
clear();
147-
actual = null;
162+
this.clear();
163+
hasDownstream = false;
148164
return;
149165
}
150166

@@ -153,7 +169,7 @@ void drainFused(Subscriber<? super T> a) {
153169
a.onNext(null);
154170

155171
if (d) {
156-
actual = null;
172+
hasDownstream = false;
157173

158174
Throwable ex = error;
159175
if (ex != null) {
@@ -173,6 +189,9 @@ void drainFused(Subscriber<? super T> a) {
173189

174190
public void drain() {
175191
if (WIP.getAndIncrement(this) != 0) {
192+
if (cancelled) {
193+
this.clear();
194+
}
176195
return;
177196
}
178197

@@ -199,13 +218,13 @@ public void drain() {
199218

200219
boolean checkTerminated(boolean d, boolean empty, Subscriber<? super T> a) {
201220
if (cancelled) {
202-
clear();
203-
actual = null;
221+
this.clear();
222+
hasDownstream = false;
204223
return true;
205224
}
206225
if (d && empty) {
207226
Throwable e = error;
208-
actual = null;
227+
hasDownstream = false;
209228
if (e != null) {
210229
a.onError(e);
211230
} else {
@@ -226,10 +245,6 @@ public void onSubscribe(Subscription s) {
226245
}
227246
}
228247

229-
public long available() {
230-
return requested;
231-
}
232-
233248
@Override
234249
public int getPrefetch() {
235250
return Integer.MAX_VALUE;
@@ -308,7 +323,7 @@ public void subscribe(CoreSubscriber<? super T> actual) {
308323
actual.onSubscribe(this);
309324
this.actual = actual;
310325
if (cancelled) {
311-
this.actual = null;
326+
this.hasDownstream = false;
312327
} else {
313328
drain();
314329
}
@@ -335,8 +350,8 @@ public void cancel() {
335350
cancelled = true;
336351

337352
if (WIP.getAndIncrement(this) == 0) {
338-
clear();
339-
actual = null;
353+
this.clear();
354+
hasDownstream = false;
340355
}
341356
}
342357

@@ -362,16 +377,29 @@ public boolean isEmpty() {
362377

363378
@Override
364379
public void clear() {
365-
while (!queue.isEmpty()) {
366-
T t = queue.poll();
367-
if (t != null) {
368-
release(t);
369-
}
380+
if (DISCARD_GUARD.getAndIncrement(this) != 0) {
381+
return;
370382
}
371-
while (!priorityQueue.isEmpty()) {
372-
T t = priorityQueue.poll();
373-
if (t != null) {
374-
release(t);
383+
384+
int missed = 1;
385+
386+
for (; ; ) {
387+
while (!queue.isEmpty()) {
388+
T t = queue.poll();
389+
if (t != null) {
390+
release(t);
391+
}
392+
}
393+
while (!priorityQueue.isEmpty()) {
394+
T t = priorityQueue.poll();
395+
if (t != null) {
396+
release(t);
397+
}
398+
}
399+
400+
missed = DISCARD_GUARD.addAndGet(this, -missed);
401+
if (missed == 0) {
402+
break;
375403
}
376404
}
377405
}
@@ -413,14 +441,18 @@ public long downstreamCount() {
413441

414442
@Override
415443
public boolean hasDownstreams() {
416-
return actual != null;
444+
return hasDownstream;
417445
}
418446

419447
void release(T t) {
420448
if (t instanceof ReferenceCounted) {
421449
ReferenceCounted refCounted = (ReferenceCounted) t;
422450
if (refCounted.refCnt() > 0) {
423-
refCounted.release();
451+
try {
452+
refCounted.release();
453+
} catch (Throwable ex) {
454+
// no ops
455+
}
424456
}
425457
}
426458
}

rsocket-core/src/main/java/io/rsocket/resume/ResumableDuplexConnection.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,10 @@ public boolean isDisposed() {
223223
}
224224

225225
private void sendFrame(ByteBuf f) {
226+
if (disposed.get()) {
227+
f.release();
228+
return;
229+
}
226230
/*resuming from store so no need to save again*/
227231
if (state != State.RESUME && isResumableFrame(f)) {
228232
resumeSaveFrames.onNext(f);

0 commit comments

Comments
 (0)