cluster.tcl 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. # Cluster-specific test functions.
  2. #
  3. # Copyright (C) 2014 Salvatore Sanfilippo antirez@gmail.com
  4. # This software is released under the BSD License. See the COPYING file for
  5. # more information.
  6. # Returns a parsed CLUSTER NODES output as a list of dictionaries.
  7. proc get_cluster_nodes id {
  8. set lines [split [R $id cluster nodes] "\r\n"]
  9. set nodes {}
  10. foreach l $lines {
  11. set l [string trim $l]
  12. if {$l eq {}} continue
  13. set args [split $l]
  14. set node [dict create \
  15. id [lindex $args 0] \
  16. addr [lindex $args 1] \
  17. flags [split [lindex $args 2] ,] \
  18. slaveof [lindex $args 3] \
  19. ping_sent [lindex $args 4] \
  20. pong_recv [lindex $args 5] \
  21. config_epoch [lindex $args 6] \
  22. linkstate [lindex $args 7] \
  23. slots [lrange $args 8 -1] \
  24. ]
  25. lappend nodes $node
  26. }
  27. return $nodes
  28. }
  29. # Test node for flag.
  30. proc has_flag {node flag} {
  31. expr {[lsearch -exact [dict get $node flags] $flag] != -1}
  32. }
  33. # Returns the parsed myself node entry as a dictionary.
  34. proc get_myself id {
  35. set nodes [get_cluster_nodes $id]
  36. foreach n $nodes {
  37. if {[has_flag $n myself]} {return $n}
  38. }
  39. return {}
  40. }
  41. # Return the value of the specified CLUSTER INFO field.
  42. proc CI {n field} {
  43. get_info_field [R $n cluster info] $field
  44. }
  45. # Assuming nodes are reest, this function performs slots allocation.
  46. # Only the first 'n' nodes are used.
  47. proc cluster_allocate_slots {n} {
  48. set slot 16383
  49. while {$slot >= 0} {
  50. # Allocate successive slots to random nodes.
  51. set node [randomInt $n]
  52. lappend slots_$node $slot
  53. incr slot -1
  54. }
  55. for {set j 0} {$j < $n} {incr j} {
  56. R $j cluster addslots {*}[set slots_${j}]
  57. }
  58. }
  59. # Check that cluster nodes agree about "state", or raise an error.
  60. proc assert_cluster_state {state} {
  61. foreach_redis_id id {
  62. if {[instance_is_killed redis $id]} continue
  63. wait_for_condition 1000 50 {
  64. [CI $id cluster_state] eq $state
  65. } else {
  66. fail "Cluster node $id cluster_state:[CI $id cluster_state]"
  67. }
  68. }
  69. }
  70. # Search the first node starting from ID $first that is not
  71. # already configured as a slave.
  72. proc cluster_find_available_slave {first} {
  73. foreach_redis_id id {
  74. if {$id < $first} continue
  75. if {[instance_is_killed redis $id]} continue
  76. set me [get_myself $id]
  77. if {[dict get $me slaveof] eq {-}} {return $id}
  78. }
  79. fail "No available slaves"
  80. }
  81. # Add 'slaves' slaves to a cluster composed of 'masters' masters.
  82. # It assumes that masters are allocated sequentially from instance ID 0
  83. # to N-1.
  84. proc cluster_allocate_slaves {masters slaves} {
  85. for {set j 0} {$j < $slaves} {incr j} {
  86. set master_id [expr {$j % $masters}]
  87. set slave_id [cluster_find_available_slave $masters]
  88. set master_myself [get_myself $master_id]
  89. R $slave_id cluster replicate [dict get $master_myself id]
  90. }
  91. }
  92. # Create a cluster composed of the specified number of masters and slaves.
  93. proc create_cluster {masters slaves} {
  94. cluster_allocate_slots $masters
  95. if {$slaves} {
  96. cluster_allocate_slaves $masters $slaves
  97. }
  98. assert_cluster_state ok
  99. }
  100. # Set the cluster node-timeout to all the reachalbe nodes.
  101. proc set_cluster_node_timeout {to} {
  102. foreach_redis_id id {
  103. catch {R $id CONFIG SET cluster-node-timeout $to}
  104. }
  105. }
  106. # Check if the cluster is writable and readable. Use node "id"
  107. # as a starting point to talk with the cluster.
  108. proc cluster_write_test {id} {
  109. set prefix [randstring 20 20 alpha]
  110. set port [get_instance_attrib redis $id port]
  111. set cluster [redis_cluster 127.0.0.1:$port]
  112. for {set j 0} {$j < 100} {incr j} {
  113. $cluster set key.$j $prefix.$j
  114. }
  115. for {set j 0} {$j < 100} {incr j} {
  116. assert {[$cluster get key.$j] eq "$prefix.$j"}
  117. }
  118. $cluster close
  119. }