summaryrefslogtreecommitdiff
path: root/src/redis-trib.rb
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2014-01-17 11:48:42 +0100
committerantirez <antirez@gmail.com>2014-01-17 11:48:42 +0100
commitb4511767342b18335faaf37e5780711e57f88616 (patch)
tree619e92b18faa5b60229c0c4ffe4212fca3606799 /src/redis-trib.rb
parent30d9c1dc32f9028ed80b0e20237ba201d7bfcbb5 (diff)
downloadredis-b4511767342b18335faaf37e5780711e57f88616.tar.gz
Cluster: redis-trib addnode is now able to add replicas.
Diffstat (limited to 'src/redis-trib.rb')
-rwxr-xr-xsrc/redis-trib.rb62
1 files changed, 60 insertions, 2 deletions
diff --git a/src/redis-trib.rb b/src/redis-trib.rb
index d4a0d6fe5..5d266ef0a 100755
--- a/src/redis-trib.rb
+++ b/src/redis-trib.rb
@@ -304,6 +304,17 @@ class RedisTrib
return nil
end
+ # This function returns the master that has the least number of replicas
+ # in the cluster. If there are multiple masters with the same smaller
+ # number of replicas, one at random is returned.
+ def get_master_with_least_replicas
+ masters = @nodes.select{|n| n.has_flag? "master"}
+ sorted = masters.sort{|a,b|
+ a.info[:replicas].length <=> b.info[:replicas].length
+ }
+ sorted[0]
+ end
+
def check_cluster
xputs ">>> Performing Cluster Check (using node #{@nodes[0]})"
show_nodes
@@ -596,6 +607,29 @@ class RedisTrib
fnode.load_info()
add_node(fnode)
}
+ populate_nodes_replicas_info
+ end
+
+ # This function is called by load_cluster_info_from_node in order to
+ # add additional information to every node as a list of replicas.
+ def populate_nodes_replicas_info
+ # Start adding the new field to every node.
+ @nodes.each{|n|
+ n.info[:replicas] = []
+ }
+
+ # Populate the replicas field using the replicate field of slave
+ # nodes.
+ @nodes.each{|n|
+ if n.info[:replicate]
+ master = get_node_by_name(n.info[:replicate])
+ if !master
+ xputs "*** WARNING: #{n} claims to be slave of unknown node ID #{n.info[:replicate]}."
+ else
+ master.info[:replicas] << n
+ end
+ end
+ }
end
# Given a list of source nodes return a "resharding plan"
@@ -795,6 +829,20 @@ class RedisTrib
load_cluster_info_from_node(argv[1])
check_cluster
+ # If --master-id was specified, try to resolve it now so that we
+ # abort before starting with the node configuration.
+ if opt['slave']
+ if opt['master-id']
+ master = get_node_by_name(opt['master-id'])
+ if !master
+ xputs "[ERR] No such master ID #{opt['master-id']}"
+ end
+ else
+ master = get_master_with_least_replicas
+ xputs "Automatically selected master #{master}"
+ end
+ end
+
# Add the new node
new = ClusterNode.new(argv[0])
new.connect(:abort => true)
@@ -802,10 +850,20 @@ class RedisTrib
new.load_info
new.assert_empty
first = @nodes.first.info
+ add_node(new)
# Send CLUSTER MEET command to the new node
xputs ">>> Send CLUSTER MEET to node #{new} to make it join the cluster."
new.r.cluster("meet",first[:host],first[:port])
+
+ # Additional configuration is needed if the node is added as
+ # a slave.
+ if opt['slave']
+ wait_cluster_join
+ xputs ">>> Configure node as replica of #{master}."
+ new.r.cluster("replicate",master.info[:name])
+ end
+ xputs "[OK] New node added correctly."
end
def delnode_cluster_cmd(argv,opt)
@@ -835,7 +893,6 @@ class RedisTrib
if n.info[:replicate] && n.info[:replicate].downcase == node_id
# Reconfigure the slave to replicate with some other node
xputs ">>> #{n} as replica of #{master}"
- # TODO: implement get_master_with_least_replicas
master = get_master_with_least_replicas
n.r.cluster("replicate",master.info[:name])
end
@@ -893,7 +950,8 @@ COMMANDS={
}
ALLOWED_OPTIONS={
- "create" => {"replicas" => true}
+ "create" => {"replicas" => true},
+ "addnode" => {"slave" => false, "master-id" => true}
}
def show_help