]> git.saurik.com Git - redis.git/blobdiff - src/redis-trib.rb
redis-trib: all node information into a single hash
[redis.git] / src / redis-trib.rb
index 31fc5230550852a5fe6848d2b0c9064990b4cdc0..9859b16c02b3fca5215475ba29e8e8f8379c4f92 100755 (executable)
@@ -18,20 +18,31 @@ class ClusterNode
             exit 1
         end
         @r = nil
-        @host = s[0]
-        @port = s[1]
-        @slots = {}
-        @dirty = false
+        @info = {}
+        @info[:host] = s[0]
+        @info[:port] = s[1]
+        @info[:slots] = {}
+        @dirty = false # True if we need to flush slots info into node.
+        @friends = []
+    end
+
+    def friends
+        @friends
+    end
+
+    def slots 
+        @info[:slots]
     end
 
     def to_s
-        "#{@host}:#{@port}"
+        "#{@info[:host]}:#{@info[:port]}"
     end
 
     def connect(o={})
+        return if @r
         xputs "Connecting to node #{self}: "
         begin
-            @r = Redis.new(:host => @host, :port => @port)
+            @r = Redis.new(:host => @info[:host], :port => @info[:port])
             @r.ping
         rescue
             puts "ERROR"
@@ -58,9 +69,51 @@ class ClusterNode
         end
     end
 
+    def load_info(o={})
+        self.connect
+        nodes = @r.cluster("nodes").split("\n")
+        nodes.each{|n|
+            # name addr flags role ping_sent ping_recv link_status slots
+            name,addr,flags,role,ping_sent,ping_recv,link_status,slots = n.split(" ")
+            info = {
+                :name => name,
+                :addr => addr,
+                :flags => flags.split(","),
+                :role => role,
+                :ping_sent => ping_sent.to_i,
+                :ping_recv => ping_recv.to_i,
+                :link_status => link_status
+            }
+            if info[:flags].index("myself")
+                @info = @info.merge(info)
+                @info[:slots] = {}
+                slots.split(",").each{|s|
+                    if s.index("-")
+                        start,stop = s.split("-")
+                        self.add_slots((start.to_i)..(stop.to_i))
+                    else
+                        self.add_slots((s.to_i)..(s.to_i))
+                    end
+                }
+                @dirty = false
+                @r.cluster("info").split("\n").each{|e|    
+                    k,v=e.split(":")
+                    k = k.to_sym
+                    if k != :cluster_state
+                        @info[k] = v.to_i
+                    else
+                        @info[k] = v
+                    end
+                }
+            elsif o[:getfriends]
+                @friends << info
+            end
+        }
+    end
+
     def add_slots(slots)
         slots.each{|s|
-            @slots[s] = :new
+            @info[:slots][s] = :new
         }
         @dirty = true
     end
@@ -68,10 +121,10 @@ class ClusterNode
     def flush_node_config
         return if !@dirty
         new = []
-        @slots.each{|s,val|
+        @info[:slots].each{|s,val|
             if val == :new
                 new << s
-                @slots[s] = true
+                @info[:slots][s] = true
             end
         }
         @r.cluster("addslots",*new)
@@ -87,7 +140,7 @@ class ClusterNode
         
         # First step: we want an increasing array of integers
         # for instance: [1,2,3,4,5,8,9,20,21,22,23,24,25,30]
-        slots = @slots.keys.sort
+        slots = @info[:slots].keys.sort
 
         # As we want to aggregate adiacent slots we convert all the
         # slot integers into ranges (with just one element)
@@ -114,12 +167,7 @@ class ClusterNode
     end
 
     def info
-        {
-            :host => @host,
-            :port => @port,
-            :slots => @slots,
-            :dirty => @dirty
-        }
+        @info
     end
     
     def is_dirty?
@@ -151,6 +199,16 @@ class RedisTrib
     def check_cluster
         puts "Performing Cluster Check (using node #{@nodes[0]})"
         show_nodes
+        # Check if all the slots are covered
+        slots = {}
+        @nodes.each{|n|
+            slots = slots.merge(n.slots)
+        }
+        if slots.length == 4096
+            puts "[OK] All 4096 slots covered."
+        else
+            puts "[ERR] Not all 4096 slots are covered by nodes."
+        end
     end
 
     def alloc_slots
@@ -205,7 +263,14 @@ class RedisTrib
         node = ClusterNode.new(ARGV[1])
         node.connect(:abort => true)
         node.assert_cluster
+        node.load_info(:getfriends => true)
         add_node(node)
+        node.friends.each{|f|
+            fnode = ClusterNode.new(f[:addr])
+            fnode.connect()
+            fnode.load_info()
+            add_node(fnode)
+        }
         check_cluster
     end