@@ -247,90 +247,113 @@ var rr, rs = func() ([32]uint32, [32]uint32) {
247247
248248// connForSlot returns established connection for slot, if it exists.
249249func (c * Cluster ) connForSlot (slot uint16 , policy ReplicaPolicyEnum , seen []* redisconn.Connection ) (* redisconn.Connection , * errorx.Error ) {
250- var conn * redisconn.Connection
251250 cfg := c .getConfig ()
252251 shard := cfg .slot2shard (slot )
253- nodes := cfg .nodes
254252
255253 if shard == nil {
256254 return nil , c .err (ErrClusterConfigEmpty ).WithProperty (redis .EKSlot , slot )
257255 }
258256
259- var addr string
257+ conn := c .connForPolicy (policy , seen , shard , cfg )
258+ if conn == nil {
259+ c .ForceReloading ()
260+ return nil , c .err (ErrNoAliveConnection ).WithProperty (redis .EKSlot , slot ).WithProperty (EKPolicy , policy )
261+ }
262+ return conn , nil
263+ }
264+
265+ func (c * Cluster ) connForPolicy (policy ReplicaPolicyEnum , seen []* redisconn.Connection , shard * shard , cfg * clusterConfig ) * redisconn.Connection {
260266 switch policy {
261267 case MasterOnly :
262- addr = shard .addr [0 ]
263- node := nodes [addr ]
264- if node == nil {
265- break /*switch*/
266- }
267- conn = node .getConn (c .opts .ConnHostPolicy , preferConnected , seen )
268+ return c .connForPolicyMaster (seen , shard , cfg )
268269 case MasterAndSlaves , PreferSlaves :
269- var ws [32 ]uint32
270- if atomic .LoadUint32 (& c .latencyAwareness ) == 0 {
271- ws = rr
272- if policy == PreferSlaves {
273- ws = rs
274- }
275- } else {
276- for i := range shard .weights {
277- ws [i ] = atomic .LoadUint32 (& shard .weights [i ])
278- }
279- }
280- weights := ws [:len (shard .weights )]
270+ return c .connForPolicySlaves (policy , seen , shard , cfg )
271+ default :
272+ panic ("unknown policy" )
273+ }
274+ }
281275
282- health := atomic .LoadUint32 (& shard .good ) // load health information
283- healthWeight := uint32 (0 )
284- for i , w := range weights {
285- if health & (1 << uint (i )) == 0 {
286- continue
287- }
288- healthWeight += w
289- }
276+ func (c * Cluster ) connForPolicyMaster (seen []* redisconn.Connection , shard * shard , cfg * clusterConfig ) * redisconn.Connection {
277+ nodes := cfg .nodes
290278
291- off := c .opts .RoundRobinSeed .Current ()
292-
293- // First, we try already established connections.
294- // If no one found, then connections thar are connecting at the moment are tried.
295- for _ , needState := range []int {needConnected , mayBeConnected } {
296- mask , maskWeight := health , healthWeight
297- // a bit of quadratic algorithms
298- for mask != 0 && conn == nil {
299- r := nextRng (& off , maskWeight )
300- k := uint (0 )
301- for i , w := range weights {
302- if mask & (1 << uint (i )) == 0 {
303- continue
304- }
305- if r < w {
306- k = uint (i )
307- break
308- }
309- r -= w
310- }
279+ addr := shard .addr [0 ]
280+ node := nodes [addr ]
281+ if node == nil {
282+ return nil
283+ }
284+ return node .getConn (c .opts .ConnHostPolicy , preferConnected , seen )
285+ }
286+
287+ func (c * Cluster ) connForPolicySlaves (policy ReplicaPolicyEnum , seen []* redisconn.Connection , shard * shard , cfg * clusterConfig ) * redisconn.Connection {
288+ weights := c .weightsForPolicySlaves (policy , shard )
311289
312- mask &^= 1 << k
313- maskWeight -= weights [k ]
314- addr = shard .addr [k ]
315- node := nodes [addr ]
316- if node == nil {
317- // it is strange a bit, but lets ignore
290+ health := atomic .LoadUint32 (& shard .good ) // load health information
291+ healthWeight := c .getHealthWeight (weights , health )
292+ off := c .opts .RoundRobinSeed .Current ()
293+
294+ // First, we try already established connections.
295+ // If no one found, then connections thar are connecting at the moment are tried.
296+ for _ , needState := range []int {needConnected , mayBeConnected } {
297+ mask , maskWeight := health , healthWeight
298+
299+ for mask != 0 {
300+ r := nextRng (& off , maskWeight )
301+ k := uint (0 )
302+ for i , w := range weights {
303+ if mask & (1 << uint (i )) == 0 { // not healthy
318304 continue
319305 }
320- conn = node .getConn (c .opts .ConnHostPolicy , needState , seen )
306+ if r < w {
307+ k = uint (i )
308+ break
309+ }
310+ r -= w
311+ }
312+
313+ mask &^= 1 << k
314+ maskWeight -= weights [k ]
315+ addr := shard .addr [k ]
316+ nodes := cfg .nodes
317+ node := nodes [addr ]
318+ if node == nil {
319+ // it is strange a bit, but lets ignore
320+ continue
321321 }
322- if conn != nil {
323- break
322+
323+ if conn := node .getConn (c .opts .ConnHostPolicy , needState , seen ); conn != nil {
324+ return conn
324325 }
325326 }
326- default :
327- panic ("unknown policy" )
328327 }
329- if conn == nil {
330- c .ForceReloading ()
331- return nil , c .err (ErrNoAliveConnection ).WithProperty (redis .EKSlot , slot ).WithProperty (EKPolicy , policy )
328+
329+ return nil
330+ }
331+
332+ func (* Cluster ) getHealthWeight (weights []uint32 , health uint32 ) uint32 {
333+ healthWeight := uint32 (0 )
334+ for i , w := range weights {
335+ if health & (1 << uint (i )) == 0 {
336+ continue
337+ }
338+ healthWeight += w
332339 }
333- return conn , nil
340+ return healthWeight
341+ }
342+
343+ func (c * Cluster ) weightsForPolicySlaves (policy ReplicaPolicyEnum , shard * shard ) []uint32 {
344+ var ws []uint32
345+ if atomic .LoadUint32 (& c .latencyAwareness ) == disabled {
346+ ws = rr [:]
347+ if policy == PreferSlaves {
348+ ws = rs [:]
349+ }
350+ } else {
351+ ws = make ([]uint32 , len (shard .pingWeights ))
352+ for i := range shard .pingWeights {
353+ ws [i ] = atomic .LoadUint32 (& shard .pingWeights [i ])
354+ }
355+ }
356+ return ws [:len (shard .pingWeights )]
334357}
335358
336359func (c * Cluster ) connForAddress (addr string ) * redisconn.Connection {
0 commit comments