15
15
*/
16
16
package io .lettuce .core .protocol ;
17
17
18
- import java .util .ArrayList ;
19
- import java .util .Collection ;
20
- import java .util .Deque ;
21
- import java .util .HashSet ;
22
- import java .util .List ;
23
- import java .util .Queue ;
24
- import java .util .Set ;
25
- import java .util .concurrent .CompletableFuture ;
26
- import java .util .concurrent .CopyOnWriteArrayList ;
27
- import java .util .concurrent .TimeUnit ;
28
- import java .util .concurrent .atomic .AtomicIntegerFieldUpdater ;
29
- import java .util .concurrent .atomic .AtomicLong ;
30
- import java .util .concurrent .atomic .AtomicReferenceFieldUpdater ;
31
- import java .util .function .Consumer ;
32
-
33
- import javax .annotation .Nonnull ;
34
- import javax .annotation .Nullable ;
35
-
36
18
import io .lettuce .core .ClientOptions ;
37
19
import io .lettuce .core .ConnectionEvents ;
38
20
import io .lettuce .core .ContextualChannel ;
55
37
import io .netty .channel .EventLoop ;
56
38
import io .netty .handler .codec .EncoderException ;
57
39
import io .netty .util .Recycler ;
40
+ import io .netty .util .concurrent .EventExecutor ;
58
41
import io .netty .util .concurrent .Future ;
59
42
import io .netty .util .concurrent .GenericFutureListener ;
60
43
import io .netty .util .internal .logging .InternalLogger ;
61
44
import io .netty .util .internal .logging .InternalLoggerFactory ;
62
45
46
+ import javax .annotation .Nonnull ;
47
+ import javax .annotation .Nullable ;
48
+ import java .util .ArrayList ;
49
+ import java .util .Collection ;
50
+ import java .util .Deque ;
51
+ import java .util .HashSet ;
52
+ import java .util .List ;
53
+ import java .util .Queue ;
54
+ import java .util .Set ;
55
+ import java .util .concurrent .CompletableFuture ;
56
+ import java .util .concurrent .CopyOnWriteArrayList ;
57
+ import java .util .concurrent .TimeUnit ;
58
+ import java .util .concurrent .atomic .AtomicIntegerFieldUpdater ;
59
+ import java .util .concurrent .atomic .AtomicLong ;
60
+ import java .util .concurrent .atomic .AtomicReferenceFieldUpdater ;
61
+ import java .util .function .Consumer ;
62
+
63
63
/**
64
64
* Default {@link Endpoint} implementation.
65
65
*
@@ -161,7 +161,7 @@ protected static void cancelCommandOnEndpointClose(RedisCommand<?, ?, ?> cmd) {
161
161
162
162
private final boolean canFire ;
163
163
164
- private volatile EventLoop lastEventLoop = null ;
164
+ private volatile EventExecutor lastEventExecutor ;
165
165
166
166
private volatile Throwable connectionError ;
167
167
@@ -202,6 +202,7 @@ protected DefaultAutoBatchFlushEndpoint(ClientOptions clientOptions, ClientResou
202
202
this .callbackOnClose = callbackOnClose ;
203
203
this .writeSpinCount = clientOptions .getAutoBatchFlushOptions ().getWriteSpinCount ();
204
204
this .batchSize = clientOptions .getAutoBatchFlushOptions ().getBatchSize ();
205
+ this .lastEventExecutor = clientResources .eventExecutorGroup ().next ();
205
206
}
206
207
207
208
@ Override
@@ -322,7 +323,7 @@ public void notifyChannelActive(Channel channel) {
322
323
return ;
323
324
}
324
325
325
- this .lastEventLoop = channel .eventLoop ();
326
+ this .lastEventExecutor = channel .eventLoop ();
326
327
this .connectionError = null ;
327
328
this .inProtectMode = false ;
328
329
this .logPrefix = null ;
@@ -585,7 +586,7 @@ private void resetInternal() {
585
586
if (chan .context .initialState .isConnected ()) {
586
587
chan .pipeline ().fireUserEventTriggered (new ConnectionEvents .Reset ());
587
588
}
588
- LettuceAssert .assertState (lastEventLoop .inEventLoop (), "must be called in lastEventLoop thread" );
589
+ LettuceAssert .assertState (lastEventExecutor .inEventLoop (), "must be called in lastEventLoop thread" );
589
590
cancelCommands ("resetInternal" );
590
591
}
591
592
@@ -727,22 +728,23 @@ private int pollBatch(final AutoBatchFlushEndPointContext autoBatchFlushEndPoint
727
728
}
728
729
729
730
if (o instanceof RedisCommand <?, ?, ?>) {
731
+ autoBatchFlushEndPointContext .add (1 );
730
732
RedisCommand <?, ?, ?> cmd = (RedisCommand <?, ?, ?>) o ;
731
733
channelWrite (chan , cmd ).addListener (WrittenToChannel .newInstance (this , chan , cmd , false ));
732
734
count ++;
733
735
} else {
734
736
@ SuppressWarnings ("unchecked" )
735
737
Collection <? extends RedisCommand <?, ?, ?>> commands = (Collection <? extends RedisCommand <?, ?, ?>>) o ;
738
+ final int commandsSize = commands .size (); // size() could be expensive for some collections so cache it!
739
+ autoBatchFlushEndPointContext .add (commandsSize );
736
740
for (RedisCommand <?, ?, ?> cmd : commands ) {
737
741
channelWrite (chan , cmd ).addListener (WrittenToChannel .newInstance (this , chan , cmd , false ));
738
742
}
739
- count += commands . size () ;
743
+ count += commandsSize ;
740
744
}
741
745
}
742
746
743
747
if (count > 0 ) {
744
- autoBatchFlushEndPointContext .add (count );
745
-
746
748
channelFlush (chan );
747
749
if (autoBatchFlushEndPointContext .hasRetryableFailedToSendCommands ()) {
748
750
// Wait for onConnectionClose event()
@@ -755,7 +757,7 @@ private int pollBatch(final AutoBatchFlushEndPointContext autoBatchFlushEndPoint
755
757
private void trySetEndpointQuiescence (ContextualChannel chan ) {
756
758
final EventLoop eventLoop = chan .eventLoop ();
757
759
LettuceAssert .isTrue (eventLoop .inEventLoop (), "unexpected: not in event loop" );
758
- LettuceAssert .isTrue (eventLoop == lastEventLoop , "unexpected: lastEventLoop not match" );
760
+ LettuceAssert .isTrue (eventLoop == lastEventExecutor , "unexpected: lastEventLoop not match" );
759
761
760
762
final ConnectionContext connectionContext = chan .context ;
761
763
final @ Nullable ConnectionContext .CloseStatus closeStatus = connectionContext .getCloseStatus ();
@@ -1019,14 +1021,14 @@ private ChannelFuture channelWrite(Channel channel, RedisCommand<?, ?, ?> comman
1019
1021
* is terminated (state is RECONNECT_FAILED/ENDPOINT_CLOSED)
1020
1022
*/
1021
1023
private void syncAfterTerminated (Runnable runnable ) {
1022
- final EventLoop localLastEventLoop = lastEventLoop ;
1023
- LettuceAssert .notNull (localLastEventLoop , "lastEventLoop must not be null after terminated" );
1024
- if (localLastEventLoop .inEventLoop ()) {
1024
+ final EventExecutor localLastEventExecutor = lastEventExecutor ;
1025
+ if (localLastEventExecutor .inEventLoop ()) {
1025
1026
runnable .run ();
1026
1027
} else {
1027
- localLastEventLoop .execute (() -> {
1028
+ localLastEventExecutor .execute (() -> {
1028
1029
runnable .run ();
1029
- LettuceAssert .isTrue (lastEventLoop == localLastEventLoop , "lastEventLoop must not be changed after terminated" );
1030
+ LettuceAssert .isTrue (lastEventExecutor == localLastEventExecutor ,
1031
+ "lastEventLoop must not be changed after terminated" );
1030
1032
});
1031
1033
}
1032
1034
}
0 commit comments