mirror of
https://github.com/fluencelabs/redis
synced 2025-04-01 15:21:03 +00:00
Cluster: Tcl cluster client: get nodes description.
This commit is contained in:
parent
bc8ea04a7d
commit
8b7e23bdde
@ -14,7 +14,7 @@ package provide redis_cluster 0.1
|
|||||||
|
|
||||||
namespace eval redis_cluster {}
|
namespace eval redis_cluster {}
|
||||||
set ::redis_cluster::id 0
|
set ::redis_cluster::id 0
|
||||||
array set ::redis_cluster::start_nodes {}
|
array set ::redis_cluster::startup_nodes {}
|
||||||
array set ::redis_cluster::nodes {}
|
array set ::redis_cluster::nodes {}
|
||||||
array set ::redis_cluster::slots {}
|
array set ::redis_cluster::slots {}
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ set ::redis_cluster::plain_commands {
|
|||||||
|
|
||||||
proc redis_cluster {nodes} {
|
proc redis_cluster {nodes} {
|
||||||
set id [incr ::redis_cluster::id]
|
set id [incr ::redis_cluster::id]
|
||||||
set ::redis_cluster::start_nodes($id) $nodes
|
set ::redis_cluster::startup_nodes($id) $nodes
|
||||||
set ::redis_cluster::nodes($id) {}
|
set ::redis_cluster::nodes($id) {}
|
||||||
set ::redis_cluster::slots($id) {}
|
set ::redis_cluster::slots($id) {}
|
||||||
set handle [interp alias {} ::redis_cluster::instance$id {} ::redis_cluster::__dispatch__ $id]
|
set handle [interp alias {} ::redis_cluster::instance$id {} ::redis_cluster::__dispatch__ $id]
|
||||||
@ -44,6 +44,50 @@ proc redis_cluster {nodes} {
|
|||||||
return $handle
|
return $handle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Totally reset the slots / nodes state for the client, calls
|
||||||
|
# CLUSTER NODES in the first startup node available, populates the
|
||||||
|
# list of nodes ::redis_cluster::nodes($id) with an hash mapping node
|
||||||
|
# ip:port to a representation of the node (another hash), and finally
|
||||||
|
# maps ::redis_cluster::slots($id) with an hash mapping slot numbers
|
||||||
|
# to node IDs.
|
||||||
|
#
|
||||||
|
# This function is called when a new Redis Cluster client is initialized
|
||||||
|
# and every time we get a -MOVED redirection error.
|
||||||
|
proc ::redis_cluster::__method__refresh_nodes_map {id} {
|
||||||
|
# Contact the first responding startup node.
|
||||||
|
set idx 0; # Index of the node that will respond.
|
||||||
|
foreach start_node $::redis_cluster::startup_nodes($id) {
|
||||||
|
lassign [split $start_node :] host port
|
||||||
|
if {[catch {
|
||||||
|
set r [redis $host $port]
|
||||||
|
set nodes_descr [$r cluster nodes]
|
||||||
|
$r close
|
||||||
|
}]} {
|
||||||
|
incr idx
|
||||||
|
continue ; # Try next.
|
||||||
|
} else {
|
||||||
|
break; # Good node found.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if {$idx == [llength $::redis_cluster::startup_nodes($id)]} {
|
||||||
|
error "No good startup node found."
|
||||||
|
}
|
||||||
|
|
||||||
|
# Put the node that responded as first in the list if it is not
|
||||||
|
# already the first.
|
||||||
|
if {$idx != 0} {
|
||||||
|
set l $::redis_cluster::startup_nodes($id)
|
||||||
|
set left [lrange $l 0 [expr {$idx-1}]]
|
||||||
|
set right [lrange $l [expr {$idx+1}] end]
|
||||||
|
set l [concat [lindex $l $idx] $left $right]
|
||||||
|
set :redis_cluster::startup_nodes($id) $l
|
||||||
|
}
|
||||||
|
|
||||||
|
puts $nodes_descr
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
proc ::redis_cluster::__dispatch__ {id method args} {
|
proc ::redis_cluster::__dispatch__ {id method args} {
|
||||||
if {[info command ::redis_cluster::__method__$method] eq {}} {
|
if {[info command ::redis_cluster::__method__$method] eq {}} {
|
||||||
# Get the keys from the command.
|
# Get the keys from the command.
|
||||||
@ -59,20 +103,20 @@ proc ::redis_cluster::__dispatch__ {id method args} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Get the node mapped to this slot.
|
# Get the node mapped to this slot.
|
||||||
set node_id [dict get $::redis_cluster::slots($id) $slot]
|
set node_addr [dict get $::redis_cluster::slots($id) $slot]
|
||||||
if {$node_id eq {}} {
|
if {$node_addr eq {}} {
|
||||||
error "No mapped node for slot $slot."
|
error "No mapped node for slot $slot."
|
||||||
}
|
}
|
||||||
|
|
||||||
# Execute the command in the node we think is the slot owner.
|
# Execute the command in the node we think is the slot owner.
|
||||||
set node [dict get $::redis_cluster::nodes($id) $node_id]
|
set node [dict get $::redis_cluster::nodes($id) $node_addr]
|
||||||
set link [dict get $node link]
|
set link [dict get $node link]
|
||||||
if {[catch {$link $method {*}$args} e]} {
|
if {[catch {$link $method {*}$args} e]} {
|
||||||
# TODO: trap redirection error
|
# TODO: trap redirection error
|
||||||
}
|
}
|
||||||
return $e
|
return $e
|
||||||
} else {
|
} else {
|
||||||
uplevel 1 [list ::redis_cluster::__method__$method $id $fd] $args
|
uplevel 1 [list ::redis_cluster::__method__$method $id] $args
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,4 +194,14 @@ proc ::redis_cluster::hash {key} {
|
|||||||
# If the keys hash to multiple slots, an empty string is returned to
|
# If the keys hash to multiple slots, an empty string is returned to
|
||||||
# signal that the command can't be run in Redis Cluster.
|
# signal that the command can't be run in Redis Cluster.
|
||||||
proc ::redis_cluster::get_slot_from_keys {keys} {
|
proc ::redis_cluster::get_slot_from_keys {keys} {
|
||||||
|
set slot {}
|
||||||
|
foreach k $keys {
|
||||||
|
set s [::redis_cluster::hash $k]
|
||||||
|
if {$slot eq {}} {
|
||||||
|
set slot $s
|
||||||
|
} elseif {$slot != $s} {
|
||||||
|
return {} ; # Error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $slot
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user