22
33require 'redis_client'
44require 'redis_client/cluster/errors'
5+ require 'redis_client/middlewares'
6+ require 'redis_client/pooled'
57
68class RedisClient
79 class Cluster
@@ -12,65 +14,70 @@ class Pipeline
1214 def initialize ( router , command_builder , seed : Random . new_seed )
1315 @router = router
1416 @command_builder = command_builder
15- @grouped = { }
16- @size = 0
1717 @seed = seed
18+ @pipelines = @indices = nil
19+ @size = 0
1820 end
1921
2022 def call ( *args , **kwargs , &block )
2123 command = @command_builder . generate ( args , kwargs )
2224 node_key = @router . find_node_key ( command , seed : @seed )
23- add_row ( node_key , [ @size , :call_v , command , block ] )
25+ get_pipeline ( node_key ) . call_v ( command , &block )
26+ index_pipeline ( node_key )
2427 end
2528
2629 def call_v ( args , &block )
2730 command = @command_builder . generate ( args )
2831 node_key = @router . find_node_key ( command , seed : @seed )
29- add_row ( node_key , [ @size , :call_v , command , block ] )
32+ get_pipeline ( node_key ) . call_v ( command , &block )
33+ index_pipeline ( node_key )
3034 end
3135
3236 def call_once ( *args , **kwargs , &block )
3337 command = @command_builder . generate ( args , kwargs )
3438 node_key = @router . find_node_key ( command , seed : @seed )
35- add_row ( node_key , [ @size , :call_once_v , command , block ] )
39+ get_pipeline ( node_key ) . call_once_v ( command , &block )
40+ index_pipeline ( node_key )
3641 end
3742
3843 def call_once_v ( args , &block )
3944 command = @command_builder . generate ( args )
4045 node_key = @router . find_node_key ( command , seed : @seed )
41- add_row ( node_key , [ @size , :call_once_v , command , block ] )
46+ get_pipeline ( node_key ) . call_once_v ( command , &block )
47+ index_pipeline ( node_key )
4248 end
4349
4450 def blocking_call ( timeout , *args , **kwargs , &block )
4551 command = @command_builder . generate ( args , kwargs )
4652 node_key = @router . find_node_key ( command , seed : @seed )
47- add_row ( node_key , [ @size , :blocking_call_v , timeout , command , block ] )
53+ get_pipeline ( node_key ) . blocking_call_v ( timeout , command , &block )
54+ index_pipeline ( node_key )
4855 end
4956
5057 def blocking_call_v ( timeout , args , &block )
5158 command = @command_builder . generate ( args )
5259 node_key = @router . find_node_key ( command , seed : @seed )
53- add_row ( node_key , [ @size , :blocking_call_v , timeout , command , block ] )
60+ get_pipeline ( node_key ) . blocking_call_v ( timeout , command , &block )
61+ index_pipeline ( node_key )
5462 end
5563
5664 def empty?
5765 @size . zero?
5866 end
5967
6068 # TODO: https://github.com/redis-rb/redis-cluster-client/issues/37 handle redirections
61- def execute # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/ PerceivedComplexity
69+ def execute # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
6270 all_replies = errors = nil
63- @grouped . each_slice ( MAX_THREADS ) do |chuncked_grouped |
64- threads = chuncked_grouped . map do |k , v |
65- Thread . new ( @router , k , v ) do |router , node_key , rows |
71+ @pipelines & .each_slice ( MAX_THREADS ) do |chuncked_pipelines |
72+ threads = chuncked_pipelines . map do |node_key , pipeline |
73+ Thread . new ( node_key , pipeline ) do |nk , pl |
6674 Thread . pass
67- replies = do_pipelining ( router . find_node ( node_key ) , rows )
68- raise ReplySizeError , "commands: #{ rows . size } , replies: #{ replies . size } " if rows . size != replies . size
75+ Thread . current . thread_variable_set ( :node_key , nk )
76+ replies = do_pipelining ( @router . find_node ( nk ) , pl )
77+ raise ReplySizeError , "commands: #{ pl . _size } , replies: #{ replies . size } " if pl . _size != replies . size
6978
70- Thread . current . thread_variable_set ( :rows , rows )
7179 Thread . current . thread_variable_set ( :replies , replies )
7280 rescue StandardError => e
73- Thread . current . thread_variable_set ( :node_key , node_key )
7481 Thread . current . thread_variable_set ( :error , e )
7582 end
7683 end
@@ -79,7 +86,7 @@ def execute # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Met
7986 t . join
8087 if t . thread_variable? ( :replies )
8188 all_replies ||= Array . new ( @size )
82- t . thread_variable_get ( :rows ) . each_with_index { |r , i | all_replies [ r . first ] = t . thread_variable_get ( :replies ) [ i ] }
89+ @indices [ t . thread_variable_get ( :node_key ) ] . each_with_index { |gi , i | all_replies [ gi ] = t . thread_variable_get ( :replies ) [ i ] }
8390 elsif t . thread_variable? ( :error )
8491 errors ||= { }
8592 errors [ t . thread_variable_get ( :node_key ) ] = t . thread_variable_get ( :error )
@@ -94,21 +101,35 @@ def execute # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Met
94101
95102 private
96103
97- def add_row ( node_key , row )
98- @grouped [ node_key ] = [ ] unless @grouped . key? ( node_key )
99- @grouped [ node_key ] << row
104+ def get_pipeline ( node_key )
105+ @pipelines ||= { }
106+ @pipelines [ node_key ] ||= ::RedisClient ::Pipeline . new ( @command_builder )
107+ end
108+
109+ def index_pipeline ( node_key )
110+ @indices ||= { }
111+ @indices [ node_key ] ||= [ ]
112+ @indices [ node_key ] << @size
100113 @size += 1
101114 end
102115
103- def do_pipelining ( node , rows )
104- node . pipelined do |pipeline |
105- rows . each do |row |
106- case row . size
107- when 4 then pipeline . send ( row [ 1 ] , row [ 2 ] , &row [ 3 ] )
108- when 5 then pipeline . send ( row [ 1 ] , row [ 2 ] , row [ 3 ] , &row [ 4 ] )
109- end
116+ def do_pipelining ( client , pipeline )
117+ case client
118+ when ::RedisClient then send_pipeline ( client , pipeline )
119+ when ::RedisClient ::Pooled then client . with { |cli | send_pipeline ( cli , pipeline ) }
120+ else raise NotImplementedError , "#{ client . class . name } #pipelined for cluster client"
121+ end
122+ end
123+
124+ def send_pipeline ( client , pipeline )
125+ results = client . send ( :ensure_connected , retryable : pipeline . _retryable? ) do |connection |
126+ commands = pipeline . _commands
127+ ::RedisClient ::Middlewares . call_pipelined ( commands , client . config ) do
128+ connection . call_pipelined ( commands , pipeline . _timeouts )
110129 end
111130 end
131+
132+ pipeline . _coerce! ( results )
112133 end
113134 end
114135 end
0 commit comments