@@ -155,7 +155,7 @@ type clusterNode struct {
155
155
156
156
latency uint32 // atomic
157
157
generation uint32 // atomic
158
- loading uint32 // atomic
158
+ failing uint32 // atomic
159
159
}
160
160
161
161
func newClusterNode (clOpt * ClusterOptions , addr string ) * clusterNode {
@@ -203,21 +203,21 @@ func (n *clusterNode) Latency() time.Duration {
203
203
return time .Duration (latency ) * time .Microsecond
204
204
}
205
205
206
- func (n * clusterNode ) MarkAsLoading () {
207
- atomic .StoreUint32 (& n .loading , uint32 (time .Now ().Unix ()))
206
+ func (n * clusterNode ) MarkAsFailing () {
207
+ atomic .StoreUint32 (& n .failing , uint32 (time .Now ().Unix ()))
208
208
}
209
209
210
- func (n * clusterNode ) Loading () bool {
211
- const minute = int64 ( time . Minute / time . Second )
210
+ func (n * clusterNode ) Failing () bool {
211
+ const timeout = 15 // 15 seconds
212
212
213
- loading := atomic .LoadUint32 (& n .loading )
214
- if loading == 0 {
213
+ failing := atomic .LoadUint32 (& n .failing )
214
+ if failing == 0 {
215
215
return false
216
216
}
217
- if time .Now ().Unix ()- int64 (loading ) < minute {
217
+ if time .Now ().Unix ()- int64 (failing ) < timeout {
218
218
return true
219
219
}
220
- atomic .StoreUint32 (& n .loading , 0 )
220
+ atomic .StoreUint32 (& n .failing , 0 )
221
221
return false
222
222
}
223
223
@@ -522,7 +522,7 @@ func (c *clusterState) slotSlaveNode(slot int) (*clusterNode, error) {
522
522
case 1 :
523
523
return nodes [0 ], nil
524
524
case 2 :
525
- if slave := nodes [1 ]; ! slave .Loading () {
525
+ if slave := nodes [1 ]; ! slave .Failing () {
526
526
return slave , nil
527
527
}
528
528
return nodes [0 ], nil
@@ -531,7 +531,7 @@ func (c *clusterState) slotSlaveNode(slot int) (*clusterNode, error) {
531
531
for i := 0 ; i < 10 ; i ++ {
532
532
n := rand .Intn (len (nodes )- 1 ) + 1
533
533
slave = nodes [n ]
534
- if ! slave .Loading () {
534
+ if ! slave .Failing () {
535
535
return slave , nil
536
536
}
537
537
}
@@ -551,7 +551,7 @@ func (c *clusterState) slotClosestNode(slot int) (*clusterNode, error) {
551
551
552
552
var node * clusterNode
553
553
for _ , n := range nodes {
554
- if n .Loading () {
554
+ if n .Failing () {
555
555
continue
556
556
}
557
557
if node == nil || node .Latency ()- n .Latency () > threshold {
@@ -561,10 +561,13 @@ func (c *clusterState) slotClosestNode(slot int) (*clusterNode, error) {
561
561
return node , nil
562
562
}
563
563
564
- func (c * clusterState ) slotRandomNode (slot int ) * clusterNode {
564
+ func (c * clusterState ) slotRandomNode (slot int ) ( * clusterNode , error ) {
565
565
nodes := c .slotNodes (slot )
566
+ if len (nodes ) == 0 {
567
+ return c .nodes .Random ()
568
+ }
566
569
n := rand .Intn (len (nodes ))
567
- return nodes [n ]
570
+ return nodes [n ], nil
568
571
}
569
572
570
573
func (c * clusterState ) slotNodes (slot int ) []* clusterNode {
@@ -742,23 +745,26 @@ func (c *ClusterClient) ProcessContext(ctx context.Context, cmd Cmder) error {
742
745
}
743
746
744
747
func (c * ClusterClient ) process (ctx context.Context , cmd Cmder ) error {
748
+ cmdInfo := c .cmdInfo (cmd .Name ())
749
+ slot := c .cmdSlot (cmd )
750
+
745
751
var node * clusterNode
746
752
var ask bool
747
753
for attempt := 0 ; attempt <= c .opt .MaxRedirects ; attempt ++ {
754
+ var err error
755
+
748
756
if attempt > 0 {
749
757
time .Sleep (c .retryBackoff (attempt ))
750
758
}
751
759
752
760
if node == nil {
753
- var err error
754
- _ , node , err = c .cmdSlotAndNode (cmd )
761
+ node , err = c .cmdNode (cmdInfo , slot )
755
762
if err != nil {
756
763
cmd .setErr (err )
757
764
break
758
765
}
759
766
}
760
767
761
- var err error
762
768
if ask {
763
769
pipe := node .Client .Pipeline ()
764
770
_ = pipe .Process (NewCmd ("ASKING" ))
@@ -780,7 +786,7 @@ func (c *ClusterClient) process(ctx context.Context, cmd Cmder) error {
780
786
781
787
// If slave is loading - pick another node.
782
788
if c .opt .ReadOnly && internal .IsLoadingError (err ) {
783
- node .MarkAsLoading ()
789
+ node .MarkAsFailing ()
784
790
node = nil
785
791
continue
786
792
}
@@ -807,11 +813,9 @@ func (c *ClusterClient) process(ctx context.Context, cmd Cmder) error {
807
813
continue
808
814
}
809
815
810
- // Second try random node.
811
- node , err = c .nodes .Random ()
812
- if err != nil {
813
- break
814
- }
816
+ // Second try another node.
817
+ node .MarkAsFailing ()
818
+ node = nil
815
819
continue
816
820
}
817
821
@@ -1100,17 +1104,20 @@ func (c *ClusterClient) mapCmdsByNode(cmds []Cmder, cmdsMap *cmdsMap) error {
1100
1104
1101
1105
cmdsAreReadOnly := c .opt .ReadOnly && c .cmdsAreReadOnly (cmds )
1102
1106
for _ , cmd := range cmds {
1107
+ slot := c .cmdSlot (cmd )
1108
+
1103
1109
var node * clusterNode
1104
1110
var err error
1105
1111
if cmdsAreReadOnly {
1106
- _ , node , err = c .cmdSlotAndNode (cmd )
1112
+ cmdInfo := c .cmdInfo (cmd .Name ())
1113
+ node , err = c .cmdNode (cmdInfo , slot )
1107
1114
} else {
1108
- slot := c .cmdSlot (cmd )
1109
1115
node , err = state .slotMasterNode (slot )
1110
1116
}
1111
1117
if err != nil {
1112
1118
return err
1113
1119
}
1120
+
1114
1121
cmdsMap .mu .Lock ()
1115
1122
cmdsMap .m [node ] = append (cmdsMap .m [node ], cmd )
1116
1123
cmdsMap .mu .Unlock ()
@@ -1162,7 +1169,7 @@ func (c *ClusterClient) pipelineReadCmds(
1162
1169
}
1163
1170
1164
1171
if c .opt .ReadOnly && internal .IsLoadingError (err ) {
1165
- node .MarkAsLoading ()
1172
+ node .MarkAsFailing ()
1166
1173
} else if internal .IsRedisError (err ) {
1167
1174
continue
1168
1175
}
@@ -1529,14 +1536,6 @@ func (c *ClusterClient) cmdInfo(name string) *CommandInfo {
1529
1536
return info
1530
1537
}
1531
1538
1532
- func cmdSlot (cmd Cmder , pos int ) int {
1533
- if pos == 0 {
1534
- return hashtag .RandomSlot ()
1535
- }
1536
- firstKey := cmd .stringArg (pos )
1537
- return hashtag .Slot (firstKey )
1538
- }
1539
-
1540
1539
func (c * ClusterClient ) cmdSlot (cmd Cmder ) int {
1541
1540
args := cmd .Args ()
1542
1541
if args [0 ] == "cluster" && args [1 ] == "getkeysinslot" {
@@ -1547,32 +1546,31 @@ func (c *ClusterClient) cmdSlot(cmd Cmder) int {
1547
1546
return cmdSlot (cmd , cmdFirstKeyPos (cmd , cmdInfo ))
1548
1547
}
1549
1548
1550
- func (c * ClusterClient ) cmdSlotAndNode (cmd Cmder ) (int , * clusterNode , error ) {
1549
+ func cmdSlot (cmd Cmder , pos int ) int {
1550
+ if pos == 0 {
1551
+ return hashtag .RandomSlot ()
1552
+ }
1553
+ firstKey := cmd .stringArg (pos )
1554
+ return hashtag .Slot (firstKey )
1555
+ }
1556
+
1557
+ func (c * ClusterClient ) cmdNode (cmdInfo * CommandInfo , slot int ) (* clusterNode , error ) {
1551
1558
state , err := c .state .Get ()
1552
1559
if err != nil {
1553
- return 0 , nil , err
1560
+ return nil , err
1554
1561
}
1555
1562
1556
- cmdInfo := c .cmdInfo (cmd .Name ())
1557
- slot := c .cmdSlot (cmd )
1558
-
1559
1563
if c .opt .ReadOnly && cmdInfo != nil && cmdInfo .ReadOnly {
1560
1564
if c .opt .RouteByLatency {
1561
- node , err := state .slotClosestNode (slot )
1562
- return slot , node , err
1565
+ return state .slotClosestNode (slot )
1563
1566
}
1564
-
1565
1567
if c .opt .RouteRandomly {
1566
- node := state .slotRandomNode (slot )
1567
- return slot , node , nil
1568
+ return state .slotRandomNode (slot )
1568
1569
}
1569
-
1570
- node , err := state .slotSlaveNode (slot )
1571
- return slot , node , err
1570
+ return state .slotSlaveNode (slot )
1572
1571
}
1573
1572
1574
- node , err := state .slotMasterNode (slot )
1575
- return slot , node , err
1573
+ return state .slotMasterNode (slot )
1576
1574
}
1577
1575
1578
1576
func (c * ClusterClient ) slotMasterNode (slot int ) (* clusterNode , error ) {
0 commit comments