lib/gizzard/commands.rb in gizzmo-0.11.4 vs lib/gizzard/commands.rb in gizzmo-0.12.0
- old
+ new
@@ -890,6 +890,112 @@
base_name,
transformations,
scheduler_options
end
end
+
+
+ class CreateTableCommand < Command
+
+ DEFAULT_NUM_SHARDS = 1024
+ DEFAULT_BASE_NAME = "shard"
+
+ FORWARDING_SPACE = 2 ** 60
+ FORWARDING_SPACE_MIN = 0
+ FORWARDING_SPACE_MAX = 2 ** 60 - 1
+
+ def generate_base_ids(num_shards, min_id, max_id)
+ srand(42) # consistent randomization
+
+ id_space = max_id - min_id + 1
+ step_size = id_space / num_shards
+
+ enums = (0...num_shards).to_a
+ ids = enums.map {|i| min_id + (i * step_size) }.sort_by { rand }
+
+ enums.zip(ids)
+ end
+
+ def parse_templates_and_weights(arr)
+ templates_and_weights = {}
+
+ arr.each_slice(2) do |(weight_s, to_template_s)|
+ to = ShardTemplate.parse(to_template_s)
+ weight = weight_s.to_i
+
+ templates_and_weights[to] = weight
+ end
+
+ templates_and_weights
+ end
+
+ # This is all super hacky but I don't have time to generalize right now
+
+ def run
+ help!("must have an even number of arguments") unless @argv.length % 2 == 0
+
+ base_name = command_options.base_name || DEFAULT_BASE_NAME
+ num_shards = (command_options.shards || DEFAULT_NUM_SHARDS).to_i
+ max_id = (command_options.max_id || FORWARDING_SPACE_MAX).to_i
+ min_id = (command_options.min_id || FORWARDING_SPACE_MIN).to_i
+
+ be_quiet = global_options.force && command_options.quiet
+
+ templates_and_weights = parse_templates_and_weights(@argv)
+ total_weight = templates_and_weights.values.inject {|a,b| a + b }
+ templates = templates_and_weights.keys
+
+ base_ids = generate_base_ids(num_shards, min_id, max_id)
+
+ templates_and_base_ids = templates_and_weights.inject({}) do |h, (template, weight)|
+ share = (weight.to_f / total_weight * num_shards).floor
+ ids = []
+ share.times { ids << base_ids.pop }
+
+ h.update template => ids
+ end
+
+ # divvy up the remainder across all templates.
+ base_ids.each_with_index do |base, idx|
+ templates_and_base_ids.values[idx % templates_and_base_ids.length] << base
+ end
+
+ proto = templates.first
+ transform = Transformation.new(proto, proto)
+
+ op_sets = templates.inject({}) do |h, template|
+ ops = transform.create_tree(template).sort
+ h.update template => ops
+ end
+
+ unless be_quiet
+ puts "Create tables #{global_options.tables.join(", ")}:"
+ templates_and_base_ids.each do |template, base_ids|
+ puts " #{template.inspect}"
+ puts " for #{base_ids.length} base ids:"
+ base_ids.each {|(enum, base_id)| puts " #{base_id}" }
+ end
+ puts ""
+ end
+
+ unless global_options.force
+ print "Continue? (y/n) "; $stdout.flush
+ exit unless $stdin.gets.chomp == "y"
+ puts ""
+ end
+
+ global_options.tables.each do |table_id|
+ templates_and_base_ids.each do |template, base_ids|
+ ops = op_sets[template]
+
+ base_ids.each do |(enum, base_id)|
+ table_prefix = Shard.canonical_table_prefix(enum, table_id, base_name)
+ ops.each do |op|
+ puts "#{op.inspect}: #{table_prefix}"
+ op.apply(manager, table_id, base_id, table_prefix, {})
+ end
+ end
+ end
+ end
+ end
+ end
end