@ -63,6 +63,7 @@ import org.redisson.misc.RedissonObjectFactory;
import org.slf4j.Logger ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
import org.slf4j.LoggerFactory ;
import io.netty.buffer.ByteBuf ;
import io.netty.channel.Channel ;
import io.netty.channel.Channel ;
import io.netty.channel.ChannelFuture ;
import io.netty.channel.ChannelFuture ;
import io.netty.channel.ChannelFutureListener ;
import io.netty.channel.ChannelFutureListener ;
@ -470,10 +471,12 @@ public class CommandAsyncService implements CommandAsyncExecutor {
protected < V , R > void async ( final boolean readOnlyMode , final NodeSource source , final Codec codec ,
protected < V , R > void async ( final boolean readOnlyMode , final NodeSource source , final Codec codec ,
final RedisCommand < V > command , final Object [ ] params , final RPromise < R > mainPromise , final int attempt ) {
final RedisCommand < V > command , final Object [ ] params , final RPromise < R > mainPromise , final int attempt ) {
if ( mainPromise . isCancelled ( ) ) {
if ( mainPromise . isCancelled ( ) ) {
free ( params ) ;
return ;
return ;
}
}
if ( ! connectionManager . getShutdownLatch ( ) . acquire ( ) ) {
if ( ! connectionManager . getShutdownLatch ( ) . acquire ( ) ) {
free ( params ) ;
mainPromise . tryFailure ( new RedissonShutdownException ( "Redisson is shutdown" ) ) ;
mainPromise . tryFailure ( new RedissonShutdownException ( "Redisson is shutdown" ) ) ;
return ;
return ;
}
}
@ -490,6 +493,7 @@ public class CommandAsyncService implements CommandAsyncExecutor {
}
}
} catch ( Exception e ) {
} catch ( Exception e ) {
connectionManager . getShutdownLatch ( ) . release ( ) ;
connectionManager . getShutdownLatch ( ) . release ( ) ;
free ( params ) ;
mainPromise . tryFailure ( e ) ;
mainPromise . tryFailure ( e ) ;
return ;
return ;
}
}
@ -518,8 +522,17 @@ public class CommandAsyncService implements CommandAsyncExecutor {
connectionManager . getShutdownLatch ( ) . release ( ) ;
connectionManager . getShutdownLatch ( ) . release ( ) ;
} else {
} else {
if ( details . getConnectionFuture ( ) . isSuccess ( ) ) {
if ( details . getConnectionFuture ( ) . isSuccess ( ) ) {
ChannelFuture writeFuture = details . getWriteFuture ( ) ;
if ( details . getWriteFuture ( ) = = null | | ! details . getWriteFuture ( ) . isDone ( ) ) {
if ( writeFuture ! = null & & ! writeFuture . cancel ( false ) & & writeFuture . isSuccess ( ) ) {
if ( details . getAttempt ( ) = = connectionManager . getConfig ( ) . getRetryAttempts ( ) ) {
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 ;
return ;
}
}
}
}
@ -529,6 +542,7 @@ public class CommandAsyncService implements CommandAsyncExecutor {
if ( details . getAttemptPromise ( ) . cancel ( false ) ) {
if ( details . getAttemptPromise ( ) . cancel ( false ) ) {
AsyncDetails . release ( details ) ;
AsyncDetails . release ( details ) ;
}
}
free ( details ) ;
return ;
return ;
}
}
@ -537,6 +551,7 @@ public class CommandAsyncService implements CommandAsyncExecutor {
details . setException ( new RedisTimeoutException ( "Command execution timeout for command: " + command + " with params: " + LogHelper . toString ( details . getParams ( ) ) ) ) ;
details . setException ( new RedisTimeoutException ( "Command execution timeout for command: " + command + " with params: " + LogHelper . toString ( details . getParams ( ) ) ) ) ;
}
}
details . getAttemptPromise ( ) . tryFailure ( details . getException ( ) ) ;
details . getAttemptPromise ( ) . tryFailure ( details . getException ( ) ) ;
free ( details ) ;
return ;
return ;
}
}
if ( ! details . getAttemptPromise ( ) . cancel ( false ) ) {
if ( ! details . getAttemptPromise ( ) . cancel ( false ) ) {
@ -551,6 +566,7 @@ public class CommandAsyncService implements CommandAsyncExecutor {
async ( details . isReadOnlyMode ( ) , details . getSource ( ) , details . getCodec ( ) , details . getCommand ( ) , details . getParams ( ) , details . getMainPromise ( ) , count ) ;
async ( details . isReadOnlyMode ( ) , details . getSource ( ) , details . getCodec ( ) , details . getCommand ( ) , details . getParams ( ) , details . getMainPromise ( ) , count ) ;
AsyncDetails . release ( details ) ;
AsyncDetails . release ( details ) ;
}
}
} ;
} ;
Timeout timeout = connectionManager . newTimeout ( retryTimerTask , connectionManager . getConfig ( ) . getRetryInterval ( ) , TimeUnit . MILLISECONDS ) ;
Timeout timeout = connectionManager . newTimeout ( retryTimerTask , connectionManager . getConfig ( ) . getRetryInterval ( ) , TimeUnit . MILLISECONDS ) ;
@ -562,13 +578,13 @@ public class CommandAsyncService implements CommandAsyncExecutor {
if ( connFuture . isCancelled ( ) ) {
if ( connFuture . isCancelled ( ) ) {
return ;
return ;
}
}
if ( ! connFuture . isSuccess ( ) ) {
if ( ! connFuture . isSuccess ( ) ) {
connectionManager . getShutdownLatch ( ) . release ( ) ;
connectionManager . getShutdownLatch ( ) . release ( ) ;
details . setException ( convertException ( connectionFuture ) ) ;
details . setException ( convertException ( connectionFuture ) ) ;
return ;
return ;
}
}
if ( details . getAttemptPromise ( ) . isDone ( ) | | details . getMainPromise ( ) . isDone ( ) ) {
if ( details . getAttemptPromise ( ) . isDone ( ) | | details . getMainPromise ( ) . isDone ( ) ) {
releaseConnection ( source , connectionFuture , details . isReadOnlyMode ( ) , details . getAttemptPromise ( ) , details ) ;
releaseConnection ( source , connectionFuture , details . isReadOnlyMode ( ) , details . getAttemptPromise ( ) , details ) ;
return ;
return ;
@ -611,12 +627,24 @@ public class CommandAsyncService implements CommandAsyncExecutor {
} ) ;
} ) ;
}
}
private < V , R > void checkWriteFuture ( final AsyncDetails < V , R > details , final RedisConnection connection ) {
protected void free ( final Object [ ] params ) {
ChannelFuture future = details . getWriteFuture ( ) ;
for ( Object obj : params ) {
if ( details . getAttemptPromise ( ) . isDone ( ) | | future . isCancelled ( ) ) {
if ( obj instanceof ByteBuf ) {
return ;
( ( ByteBuf ) obj ) . release ( ) ;
}
}
}
}
protected < V , R > void free ( final AsyncDetails < V , R > details ) {
for ( Object obj : details . getParams ( ) ) {
if ( obj instanceof ByteBuf ) {
( ( ByteBuf ) obj ) . release ( ) ;
}
}
}
private < V , R > void checkWriteFuture ( final AsyncDetails < V , R > details , final RedisConnection connection ) {
ChannelFuture future = details . getWriteFuture ( ) ;
if ( ! future . isSuccess ( ) ) {
if ( ! future . isSuccess ( ) ) {
details . setException ( new WriteRedisConnectionException (
details . setException ( new WriteRedisConnectionException (
"Can't write command: " + details . getCommand ( ) + ", params: " + LogHelper . toString ( details . getParams ( ) ) + " to channel: " + future . channel ( ) , future . cause ( ) ) ) ;
"Can't write command: " + details . getCommand ( ) + ", params: " + LogHelper . toString ( details . getParams ( ) ) + " to channel: " + future . channel ( ) , future . cause ( ) ) ) ;
@ -624,7 +652,8 @@ public class CommandAsyncService implements CommandAsyncExecutor {
}
}
details . getTimeout ( ) . cancel ( ) ;
details . getTimeout ( ) . cancel ( ) ;
free ( details ) ;
long timeoutTime = connectionManager . getConfig ( ) . getTimeout ( ) ;
long timeoutTime = connectionManager . getConfig ( ) . getTimeout ( ) ;
if ( RedisCommands . BLOCKING_COMMANDS . contains ( details . getCommand ( ) . getName ( ) ) ) {
if ( RedisCommands . BLOCKING_COMMANDS . contains ( details . getCommand ( ) . getName ( ) ) ) {
Long popTimeout = Long . valueOf ( details . getParams ( ) [ details . getParams ( ) . length - 1 ] . toString ( ) ) ;
Long popTimeout = Long . valueOf ( details . getParams ( ) [ details . getParams ( ) . length - 1 ] . toString ( ) ) ;
@ -725,7 +754,7 @@ public class CommandAsyncService implements CommandAsyncExecutor {
if ( ! connectionFuture . isSuccess ( ) ) {
if ( ! connectionFuture . isSuccess ( ) ) {
return ;
return ;
}
}
RedisConnection connection = connectionFuture . getNow ( ) ;
RedisConnection connection = connectionFuture . getNow ( ) ;
connectionManager . getShutdownLatch ( ) . release ( ) ;
connectionManager . getShutdownLatch ( ) . release ( ) ;
if ( isReadOnly ) {
if ( isReadOnly ) {
@ -803,6 +832,7 @@ public class CommandAsyncService implements CommandAsyncExecutor {
} else {
} else {
details . getMainPromise ( ) . tryFailure ( future . cause ( ) ) ;
details . getMainPromise ( ) . tryFailure ( future . cause ( ) ) ;
}
}
AsyncDetails . release ( details ) ;
AsyncDetails . release ( details ) ;
}
}