Skip to content

Commit 8b7e23b

Browse files
committed
Cluster: Tcl cluster client: get nodes description.
1 parent bc8ea04 commit 8b7e23b

File tree

1 file changed

+60
-6
lines changed

1 file changed

+60
-6
lines changed

tests/support/cluster.tcl

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ package provide redis_cluster 0.1
1414

1515
namespace eval redis_cluster {}
1616
set ::redis_cluster::id 0
17-
array set ::redis_cluster::start_nodes {}
17+
array set ::redis_cluster::startup_nodes {}
1818
array set ::redis_cluster::nodes {}
1919
array set ::redis_cluster::slots {}
2020

@@ -36,14 +36,58 @@ set ::redis_cluster::plain_commands {
3636

3737
proc redis_cluster {nodes} {
3838
set id [incr ::redis_cluster::id]
39-
set ::redis_cluster::start_nodes($id) $nodes
39+
set ::redis_cluster::startup_nodes($id) $nodes
4040
set ::redis_cluster::nodes($id) {}
4141
set ::redis_cluster::slots($id) {}
4242
set handle [interp alias {} ::redis_cluster::instance$id {} ::redis_cluster::__dispatch__ $id]
4343
$handle refresh_nodes_map
4444
return $handle
4545
}
4646

47+
# Totally reset the slots / nodes state for the client, calls
48+
# CLUSTER NODES in the first startup node available, populates the
49+
# list of nodes ::redis_cluster::nodes($id) with an hash mapping node
50+
# ip:port to a representation of the node (another hash), and finally
51+
# maps ::redis_cluster::slots($id) with an hash mapping slot numbers
52+
# to node IDs.
53+
#
54+
# This function is called when a new Redis Cluster client is initialized
55+
# and every time we get a -MOVED redirection error.
56+
proc ::redis_cluster::__method__refresh_nodes_map {id} {
57+
# Contact the first responding startup node.
58+
set idx 0; # Index of the node that will respond.
59+
foreach start_node $::redis_cluster::startup_nodes($id) {
60+
lassign [split $start_node :] host port
61+
if {[catch {
62+
set r [redis $host $port]
63+
set nodes_descr [$r cluster nodes]
64+
$r close
65+
}]} {
66+
incr idx
67+
continue ; # Try next.
68+
} else {
69+
break; # Good node found.
70+
}
71+
}
72+
73+
if {$idx == [llength $::redis_cluster::startup_nodes($id)]} {
74+
error "No good startup node found."
75+
}
76+
77+
# Put the node that responded as first in the list if it is not
78+
# already the first.
79+
if {$idx != 0} {
80+
set l $::redis_cluster::startup_nodes($id)
81+
set left [lrange $l 0 [expr {$idx-1}]]
82+
set right [lrange $l [expr {$idx+1}] end]
83+
set l [concat [lindex $l $idx] $left $right]
84+
set :redis_cluster::startup_nodes($id) $l
85+
}
86+
87+
puts $nodes_descr
88+
exit
89+
}
90+
4791
proc ::redis_cluster::__dispatch__ {id method args} {
4892
if {[info command ::redis_cluster::__method__$method] eq {}} {
4993
# Get the keys from the command.
@@ -59,20 +103,20 @@ proc ::redis_cluster::__dispatch__ {id method args} {
59103
}
60104

61105
# Get the node mapped to this slot.
62-
set node_id [dict get $::redis_cluster::slots($id) $slot]
63-
if {$node_id eq {}} {
106+
set node_addr [dict get $::redis_cluster::slots($id) $slot]
107+
if {$node_addr eq {}} {
64108
error "No mapped node for slot $slot."
65109
}
66110

67111
# Execute the command in the node we think is the slot owner.
68-
set node [dict get $::redis_cluster::nodes($id) $node_id]
112+
set node [dict get $::redis_cluster::nodes($id) $node_addr]
69113
set link [dict get $node link]
70114
if {[catch {$link $method {*}$args} e]} {
71115
# TODO: trap redirection error
72116
}
73117
return $e
74118
} else {
75-
uplevel 1 [list ::redis_cluster::__method__$method $id $fd] $args
119+
uplevel 1 [list ::redis_cluster::__method__$method $id] $args
76120
}
77121
}
78122

@@ -150,4 +194,14 @@ proc ::redis_cluster::hash {key} {
150194
# If the keys hash to multiple slots, an empty string is returned to
151195
# signal that the command can't be run in Redis Cluster.
152196
proc ::redis_cluster::get_slot_from_keys {keys} {
197+
set slot {}
198+
foreach k $keys {
199+
set s [::redis_cluster::hash $k]
200+
if {$slot eq {}} {
201+
set slot $s
202+
} elseif {$slot != $s} {
203+
return {} ; # Error
204+
}
205+
}
206+
return $slot
153207
}

0 commit comments

Comments
 (0)