@ -239,13 +239,15 @@ public class CommandBatchService extends CommandAsyncService {
return promise ;
}
pr otected void execute ( final Entry entry , final NodeSource source , final RPromise < Void > mainPromise , final AtomicInteger slots ,
pr ivate void execute ( final Entry entry , final NodeSource source , final RPromise < Void > mainPromise , final AtomicInteger slots ,
final int attempt , final boolean noResult , final long responseTimeout , final int retryAttempts , final long retryInterval ) {
if ( mainPromise . isCancelled ( ) ) {
free ( entry ) ;
return ;
}
if ( ! connectionManager . getShutdownLatch ( ) . acquire ( ) ) {
free ( entry ) ;
mainPromise . tryFailure ( new RedissonShutdownException ( "Redisson is shutdown" ) ) ;
return ;
}
@ -260,10 +262,30 @@ public class CommandBatchService extends CommandAsyncService {
} else {
connectionFuture = connectionManager . connectionWriteOp ( source , null ) ;
}
final int attempts ;
if ( retryAttempts > 0 ) {
attempts = retryAttempts ;
} else {
attempts = connectionManager . getConfig ( ) . getRetryAttempts ( ) ;
}
final FutureListener < Void > mainPromiseListener = new FutureListener < Void > ( ) {
@Override
public void operationComplete ( Future < Void > future ) throws Exception {
if ( future . isCancelled ( ) & & connectionFuture . cancel ( false ) ) {
log . debug ( "Connection obtaining canceled for batch" ) ;
details . getTimeout ( ) . cancel ( ) ;
if ( details . getAttemptPromise ( ) . cancel ( false ) ) {
free ( entry ) ;
}
}
}
} ;
final TimerTask retryTimerTask = new TimerTask ( ) {
@Override
public void run ( Timeout timeout ) throws Exception {
public void run ( Timeout t ) throws Exception {
if ( attemptPromise . isDone ( ) ) {
return ;
}
@ -272,22 +294,29 @@ public class CommandBatchService extends CommandAsyncService {
connectionManager . getShutdownLatch ( ) . release ( ) ;
} else {
if ( connectionFuture . isSuccess ( ) ) {
ChannelFuture writeFuture = details . getWriteFuture ( ) ;
if ( writeFuture ! = null & & ! writeFuture . cancel ( false ) & & writeFuture . isSuccess ( ) ) {
if ( details . getWriteFuture ( ) = = null | | ! details . getWriteFuture ( ) . isDone ( ) ) {
if ( details . getAttempt ( ) = = attempts ) {
return ;
}
details . incAttempt ( ) ;
Timeout timeout = connectionManager . newTimeout ( this , connectionManager . getConfig ( ) . getRetryInterval ( ) , TimeUnit . MILLISECONDS ) ;
details . setTimeout ( timeout ) ;
return ;
}
if ( details . getWriteFuture ( ) . isDone ( ) & & details . getWriteFuture ( ) . isSuccess ( ) ) {
return ;
}
}
}
if ( mainPromise . isCancelled ( ) ) {
attemptPromise . cancel ( false ) ;
if ( attemptPromise . cancel ( false ) ) {
free ( entry ) ;
}
return ;
}
int attempts = connectionManager . getConfig ( ) . getRetryAttempts ( ) ;
if ( retryAttempts > 0 ) {
attempts = retryAttempts ;
}
if ( attempt = = attempts ) {
if ( details . getException ( ) = = null ) {
details . setException ( new RedisTimeoutException ( "Batch command execution timeout" ) ) ;
@ -300,6 +329,7 @@ public class CommandBatchService extends CommandAsyncService {
}
int count = attempt + 1 ;
mainPromise . removeListener ( mainPromiseListener ) ;
execute ( entry , source , mainPromise , slots , count , noResult , responseTimeout , retryAttempts , retryInterval ) ;
}
} ;
@ -311,11 +341,12 @@ public class CommandBatchService extends CommandAsyncService {
Timeout timeout = connectionManager . newTimeout ( retryTimerTask , interval , TimeUnit . MILLISECONDS ) ;
details . setTimeout ( timeout ) ;
mainPromise . addListener ( mainPromiseListener ) ;
connectionFuture . addListener ( new FutureListener < RedisConnection > ( ) {
@Override
public void operationComplete ( Future < RedisConnection > connFuture ) throws Exception {
checkConnectionFuture ( entry , source , mainPromise , attemptPromise , details , connectionFuture , noResult , responseTimeout );
checkConnectionFuture ( entry , source , mainPromise , attemptPromise , details , connectionFuture , noResult , responseTimeout , attempts );
}
} ) ;
@ -327,6 +358,8 @@ public class CommandBatchService extends CommandAsyncService {
return ;
}
mainPromise . removeListener ( mainPromiseListener ) ;
if ( future . cause ( ) instanceof RedisMovedException ) {
RedisMovedException ex = ( RedisMovedException ) future . cause ( ) ;
entry . clearErrors ( ) ;
@ -357,7 +390,8 @@ public class CommandBatchService extends CommandAsyncService {
return ;
}
free ( entry ) ;
if ( future . isSuccess ( ) ) {
if ( slots . decrementAndGet ( ) = = 0 ) {
mainPromise . trySuccess ( future . getNow ( ) ) ;
@ -369,36 +403,44 @@ public class CommandBatchService extends CommandAsyncService {
} ) ;
}
private void checkWriteFuture ( final RPromise < Void > attemptPromise , AsyncDetails details ,
final RedisConnection connection , ChannelFuture future , boolean noResult , long responseTimeout ) {
if ( attemptPromise . isDone ( ) | | future . isCancelled ( ) ) {
return ;
protected void free ( final Entry entry ) {
for ( BatchCommandData < ? , ? > command : entry . getCommands ( ) ) {
free ( command . getParams ( ) ) ;
}
}
private void checkWriteFuture ( Entry entry , final RPromise < Void > attemptPromise , AsyncDetails details ,
final RedisConnection connection , ChannelFuture future , boolean noResult , long responseTimeout , int attempts ) {
if ( ! future . isSuccess ( ) ) {
details . setException ( new WriteRedisConnectionException ( "Can't write command batch to channel: " + future . channel ( ) , future . cause ( ) ) ) ;
} else {
details . getTimeout ( ) . cancel ( ) ;
TimerTask timerTask = new TimerTask ( ) {
@Override
public void run ( Timeout timeout ) throws Exception {
attemptPromise . tryFailure (
new RedisTimeoutException ( "Redis server response timeout during command batch execution. Channel: " + connection . getChannel ( ) ) ) ;
}
} ;
long timeout = connectionManager . getConfig ( ) . getTimeout ( ) ;
if ( responseTimeout > 0 ) {
timeout = responseTimeout ;
if ( details . getAttempt ( ) = = attempts ) {
details . getAttemptPromise ( ) . tryFailure ( details . getException ( ) ) ;
free ( entry ) ;
}
return ;
}
details . getTimeout ( ) . cancel ( ) ;
TimerTask timerTask = new TimerTask ( ) {
@Override
public void run ( Timeout timeout ) throws Exception {
attemptPromise . tryFailure (
new RedisTimeoutException ( "Redis server response timeout during command batch execution. Channel: " + connection . getChannel ( ) ) ) ;
}
Timeout timeoutTask = connectionManager . newTimeout ( timerTask , timeout , TimeUnit . MILLISECONDS ) ;
details . setTimeout ( timeoutTask ) ;
} ;
long timeout = connectionManager . getConfig ( ) . getTimeout ( ) ;
if ( responseTimeout > 0 ) {
timeout = responseTimeout ;
}
Timeout timeoutTask = connectionManager . newTimeout ( timerTask , timeout , TimeUnit . MILLISECONDS ) ;
details . setTimeout ( timeoutTask ) ;
}
private void checkConnectionFuture ( final Entry entry , final NodeSource source ,
final RPromise < Void > mainPromise , final RPromise < Void > attemptPromise , final AsyncDetails details ,
RFuture < RedisConnection > connFuture , final boolean noResult , final long responseTimeout ) {
RFuture < RedisConnection > connFuture , final boolean noResult , final long responseTimeout , int attempts ) {
if ( attemptPromise . isDone ( ) | | mainPromise . isCancelled ( ) | | connFuture . isCancelled ( ) ) {
return ;
}
@ -430,7 +472,7 @@ public class CommandBatchService extends CommandAsyncService {
details . getWriteFuture ( ) . addListener ( new ChannelFutureListener ( ) {
@Override
public void operationComplete ( ChannelFuture future ) throws Exception {
checkWriteFuture ( attemptPromise, details , connection , future , noResult , responseTimeout ) ;
checkWriteFuture ( entry, attemptPromise, details , connection , future , noResult , responseTimeout , attempts ) ;
}
} ) ;