+ def assert_empty
+ if !(@r.cluster("info").split("\r\n").index("cluster_known_nodes:1")) ||
+ (@r.info['db0'])
+ puts "Error: Node #{self} is not empty. Either the node already knows other nodes (check with nodes-info) or contains some key in database 0."
+ exit 1
+ end
+ end
+
+ def add_slots(slots)
+ slots.each{|s|
+ @slots[s] = :new
+ }
+ @dirty = true
+ end
+
+ def flush_node_config
+ return if !@dirty
+ new = []
+ @slots.each{|s,val|
+ if val == :new
+ new << s
+ @slots[s] = true
+ end
+ }
+ @r.cluster("addslots",*new)
+ @dirty = false
+ end
+
+ def info_string
+ # We want to display the hash slots assigned to this node
+ # as ranges, like in: "1-5,8-9,20-25,30"
+ #
+ # Note: this could be easily written without side effects,
+ # we use 'slots' just to split the computation into steps.
+
+ # 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
+
+ # As we want to aggregate adiacent slots we convert all the
+ # slot integers into ranges (with just one element)
+ # So we have something like [1..1,2..2, ... and so forth.
+ slots.map!{|x| x..x}
+
+ # Finally we group ranges with adiacent elements.
+ slots = slots.reduce([]) {|a,b|
+ if !a.empty? && b.first == (a[-1].last)+1
+ a[0..-2] + [(a[-1].first)..(b.last)]
+ else
+ a + [b]
+ end
+ }
+
+ # Now our task is easy, we just convert ranges with just one
+ # element into a number, and a real range into a start-end format.
+ # Finally we join the array using the comma as separator.
+ slots = slots.map{|x|
+ x.count == 1 ? x.first.to_s : "#{x.first}-#{x.last}"
+ }.join(",")
+
+ "#{self.to_s.ljust(25)} slots:#{slots}"
+ end
+
+ def info
+ {
+ :host => @host,
+ :port => @port,
+ :slots => @slots,
+ :dirty => @dirty
+ }
+ end
+
+ def is_dirty?
+ @dirty
+ end
+