Commit ed47f779 authored by antirez's avatar antirez
Browse files

redis-trib: initial support to fix "open" slots.

Open slots are slots found in importing or migrating slot when a
cluster check is performed.
parent 1a6df104
......@@ -57,6 +57,10 @@ class ClusterNode
@info[:slots]
end
def has_flag?(flag)
@info[:flags].index(flag)
end
def to_s
"#{@info[:host]}:#{@info[:port]}"
end
......@@ -197,7 +201,7 @@ class ClusterNode
x.count == 1 ? x.first.to_s : "#{x.first}-#{x.last}"
}.join(",")
"[#{@info[:cluster_state].upcase}] #{self.info[:name]} #{self.to_s} slots:#{slots} (#{self.slots.length} slots)"
"[#{@info[:cluster_state].upcase} #{(self.info[:flags]-["myself"]).join(",")}] #{self.info[:name]} #{self.to_s} slots:#{slots} (#{self.slots.length} slots)"
end
# Return a single string representing nodes and associated slots.
......@@ -257,6 +261,7 @@ class RedisTrib
puts "Performing Cluster Check (using node #{@nodes[0]})"
show_nodes
check_config_consistency
check_open_slots
check_slots_coverage
end
......@@ -282,6 +287,26 @@ class RedisTrib
end
end
def check_open_slots
open_slots = []
@nodes.each{|n|
if n.info[:migrating].size > 0
puts "[WARNING] Node #{n} has slots in migrating state."
open_slots += n.info[:migrating].keys
elsif n.info[:importing].size > 0
puts "[WARNING] Node #{n} has slots in importing state."
open_slots += n.info[:importing].keys
end
}
open_slots.uniq!
if open_slots.length
puts "[WARNING] The following slots are open: #{open_slots.join(",")}"
end
if @fix
open_slots.each{|slot| fix_open_slot slot}
end
end
def nodes_with_keys_in_slot(slot)
nodes = []
@nodes.each{|n|
......@@ -351,6 +376,36 @@ class RedisTrib
end
end
# Slot 'slot' was found to be in importing or migrating state in one or
# more nodes. This function fixes this condition by migrating keys where
# it seems more sensible.
def fix_open_slot(slot)
migrating = []
importing = []
@nodes.each{|n|
next if n.has_flag? "slave"
if n.info[:migrating][slot]
migrating << n
elsif n.info[:importing][slot]
importing << n
elsif n.r.cluster("countkeysinslot",slot) > 0
puts "Found keys about slot #{slot} in node #{n}!"
end
}
puts "Fixing open slot 0:"
puts "Set as migrating in: #{migrating.join(",")}"
puts "Set as importing in: #{importing.join(",")}"
# Case 1: The slot is in migrating state in one slot, and in
# importing state in 1 slot. That's trivial to address.
if migrating.length == 1 && importing.length == 1
puts "Moving slot zero to #{importing[1]}"
move_slot(migrating[0],importing[0],0,:verbose=>true)
else
puts "Sorry, Redis-trib can't fix this slot yet (work in progress)"
end
end
# Check if all the nodes agree about the cluster configuration
def check_config_consistency
signatures=[]
......@@ -472,7 +527,7 @@ class RedisTrib
# and the slot as migrating in the target host. Note that the order of
# the operations is important, as otherwise a client may be redirected
# to the target node that does not yet know it is importing this slot.
print "Moving slot #{slot} from #{source.info_string}: "; STDOUT.flush
print "Moving slot #{slot} from #{source} to #{target}: "; STDOUT.flush
target.r.cluster("setslot",slot,"importing",source.info[:name])
source.r.cluster("setslot",slot,"migrating",target.info[:name])
# Migrate all the keys from source to target using the MIGRATE command
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment