30
30
import com .hivemq .client .internal .mqtt .util .MqttChecks ;
31
31
import com .hivemq .client .internal .util .AsyncRuntimeException ;
32
32
import com .hivemq .client .internal .util .Checks ;
33
+ import com .hivemq .client .internal .util .collections .NodeList ;
33
34
import com .hivemq .client .mqtt .MqttGlobalPublishFilter ;
34
35
import com .hivemq .client .mqtt .mqtt5 .Mqtt5BlockingClient ;
35
36
import com .hivemq .client .mqtt .mqtt5 .exceptions .Mqtt5SubAckException ;
51
52
import org .jetbrains .annotations .Nullable ;
52
53
import org .reactivestreams .Subscription ;
53
54
54
- import java .util .LinkedList ;
55
55
import java .util .Optional ;
56
56
import java .util .concurrent .CancellationException ;
57
57
import java .util .concurrent .CountDownLatch ;
@@ -219,7 +219,7 @@ public void disconnect(final @NotNull Mqtt5Disconnect disconnect) {
219
219
private static class MqttPublishes implements Mqtt5Publishes , FlowableSubscriber <Mqtt5Publish > {
220
220
221
221
private final @ NotNull AtomicReference <@ Nullable Subscription > subscription = new AtomicReference <>();
222
- private final @ NotNull LinkedList <Entry > entries = new LinkedList <>();
222
+ private final @ NotNull NodeList <Entry > entries = new NodeList <>();
223
223
private @ Nullable Mqtt5Publish queuedPublish ;
224
224
private @ Nullable Throwable error ;
225
225
@@ -248,16 +248,15 @@ public void onNext(final @NotNull Mqtt5Publish publish) {
248
248
if (error != null ) {
249
249
return ;
250
250
}
251
- Entry entry ;
252
- while ((entry = entries .poll ()) != null ) {
253
- final boolean success = entry .result .compareAndSet (null , publish );
251
+ final Entry entry = entries .getFirst ();
252
+ if (entry == null ) {
253
+ queuedPublish = publish ;
254
+ } else {
255
+ entries .remove (entry );
256
+ entry .result = publish ;
254
257
entry .latch .countDown ();
255
- if (success ) {
256
- request ();
257
- return ;
258
- }
258
+ request ();
259
259
}
260
- queuedPublish = publish ;
261
260
}
262
261
}
263
262
@@ -273,9 +272,9 @@ public void onError(final @NotNull Throwable t) {
273
272
return ;
274
273
}
275
274
error = t ;
276
- Entry entry ;
277
- while (( entry = entries .poll ()) != null ) {
278
- entry .result . set ( t ) ;
275
+ for ( Entry entry = entries . getFirst (); entry != null ; entry = entry . getNext ()) {
276
+ entries .remove ( entry );
277
+ entry .result = t ;
279
278
entry .latch .countDown ();
280
279
}
281
280
}
@@ -293,26 +292,27 @@ public void onError(final @NotNull Throwable t) {
293
292
return publish ;
294
293
}
295
294
entry = new Entry ();
296
- entries .offer (entry );
295
+ entries .add (entry );
297
296
}
298
297
299
- InterruptedException interruptedException = null ;
298
+ Object result ;
300
299
try {
301
300
entry .latch .await ();
301
+ result = entry .result ;
302
+ assert (result instanceof Mqtt5Publish ) || (result instanceof Throwable );
302
303
} catch (final InterruptedException e ) {
303
- interruptedException = e ;
304
+ result = tryCancel ( entry , e ) ;
304
305
}
305
- final Object result = entry .result .getAndSet (Entry .CANCELLED );
306
306
if (result instanceof Mqtt5Publish ) {
307
307
return (Mqtt5Publish ) result ;
308
308
}
309
309
if (result instanceof Throwable ) {
310
+ if (result instanceof InterruptedException ) {
311
+ throw (InterruptedException ) result ;
312
+ }
310
313
throw handleError ((Throwable ) result );
311
314
}
312
- if (interruptedException != null ) {
313
- throw interruptedException ;
314
- }
315
- throw new InterruptedException ();
315
+ throw new IllegalStateException ("This must not happen and is a bug." );
316
316
}
317
317
318
318
@ Override
@@ -334,25 +334,29 @@ public void onError(final @NotNull Throwable t) {
334
334
return Optional .of (publish );
335
335
}
336
336
entry = new Entry ();
337
- entries .offer (entry );
337
+ entries .add (entry );
338
338
}
339
339
340
- InterruptedException interruptedException = null ;
340
+ Object result ;
341
341
try {
342
- entry .latch .await (timeout , timeUnit );
342
+ if (entry .latch .await (timeout , timeUnit )) {
343
+ result = entry .result ;
344
+ assert (result instanceof Mqtt5Publish ) || (result instanceof Throwable );
345
+ } else {
346
+ result = tryCancel (entry , null );
347
+ }
343
348
} catch (final InterruptedException e ) {
344
- interruptedException = e ;
349
+ result = tryCancel ( entry , e ) ;
345
350
}
346
- final Object result = entry .result .getAndSet (Entry .CANCELLED );
347
351
if (result instanceof Mqtt5Publish ) {
348
352
return Optional .of ((Mqtt5Publish ) result );
349
353
}
350
354
if (result instanceof Throwable ) {
355
+ if (result instanceof InterruptedException ) {
356
+ throw (InterruptedException ) result ;
357
+ }
351
358
throw handleError ((Throwable ) result );
352
359
}
353
- if (interruptedException != null ) {
354
- throw interruptedException ;
355
- }
356
360
return Optional .empty ();
357
361
}
358
362
@@ -369,13 +373,25 @@ public void onError(final @NotNull Throwable t) {
369
373
}
370
374
371
375
private @ Nullable Mqtt5Publish receiveNowUnsafe () {
376
+ final Mqtt5Publish queuedPublish = this .queuedPublish ;
372
377
if (queuedPublish != null ) {
373
- final Mqtt5Publish queuedPublish = this .queuedPublish ;
374
378
this .queuedPublish = null ;
375
379
request ();
376
- return queuedPublish ;
377
380
}
378
- return null ;
381
+ return queuedPublish ;
382
+ }
383
+
384
+ private @ Nullable Object tryCancel (final @ NotNull Entry entry , final @ Nullable Object resultOnCancel ) {
385
+ synchronized (entries ) {
386
+ final Object result = entry .result ;
387
+ if (result == null ) {
388
+ entries .remove (entry );
389
+ return resultOnCancel ;
390
+ } else {
391
+ assert (result instanceof Mqtt5Publish ) || (result instanceof Throwable );
392
+ return result ;
393
+ }
394
+ }
379
395
}
380
396
381
397
@ Override
@@ -389,9 +405,9 @@ public void close() {
389
405
return ;
390
406
}
391
407
error = new CancellationException ();
392
- Entry entry ;
393
- while (( entry = entries .poll ()) != null ) {
394
- entry .result . set ( error ) ;
408
+ for ( Entry entry = entries . getFirst (); entry != null ; entry = entry . getNext ()) {
409
+ entries .remove ( entry );
410
+ entry .result = error ;
395
411
entry .latch .countDown ();
396
412
}
397
413
}
@@ -404,12 +420,10 @@ public void close() {
404
420
throw new RuntimeException (t );
405
421
}
406
422
407
- private static class Entry {
408
-
409
- static final @ NotNull Object CANCELLED = new Object ();
423
+ private static class Entry extends NodeList .Node <Entry > {
410
424
411
425
final @ NotNull CountDownLatch latch = new CountDownLatch (1 );
412
- final @ NotNull AtomicReference < @ Nullable Object > result = new AtomicReference <>() ;
426
+ @ Nullable Object result = null ;
413
427
}
414
428
}
415
429
}
0 commit comments