gizzmo 0.4.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/gizzmo.gemspec +2 -2
- data/lib/gizzard/commands.rb +125 -5
- data/lib/gizzard/thrift.rb +4 -0
- data/lib/gizzmo.rb +15 -3
- metadata +4 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.5.0
|
data/gizzmo.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{gizzmo}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.5.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Kyle Maxwell"]
|
12
|
-
s.date = %q{2010-08-
|
12
|
+
s.date = %q{2010-08-23}
|
13
13
|
s.default_executable = %q{gizzmo}
|
14
14
|
s.description = %q{Gizzmo is a command-line client for managing gizzard clusters.}
|
15
15
|
s.email = %q{kmaxwell@twitter.com}
|
data/lib/gizzard/commands.rb
CHANGED
@@ -78,7 +78,7 @@ module Gizzard
|
|
78
78
|
end
|
79
79
|
end
|
80
80
|
end
|
81
|
-
|
81
|
+
|
82
82
|
class ForwardingsCommand < ShardCommand
|
83
83
|
def run
|
84
84
|
service.get_forwardings().sort_by do |f|
|
@@ -257,12 +257,132 @@ module Gizzard
|
|
257
257
|
end
|
258
258
|
end
|
259
259
|
|
260
|
+
class RebalanceCommand < ShardCommand
|
261
|
+
|
262
|
+
class NamedArray < Array
|
263
|
+
attr_reader :name
|
264
|
+
def initialize(name)
|
265
|
+
@name = name
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def run
|
270
|
+
ids = @argv.map{|arg| ShardId.new(*arg.split("/")) rescue nil }.compact
|
271
|
+
by_host = ids.inject({}) do |memo, id|
|
272
|
+
memo[id.hostname] ||= NamedArray.new(id.hostname)
|
273
|
+
memo[id.hostname] << id
|
274
|
+
memo
|
275
|
+
end
|
276
|
+
|
277
|
+
sets = by_host.values
|
278
|
+
|
279
|
+
begin
|
280
|
+
sorted = sets.sort_by{|s| s.length }
|
281
|
+
longest = sorted.last
|
282
|
+
shortest = sorted.first
|
283
|
+
shortest.push longest.pop
|
284
|
+
end while longest.length > shortest.length + 1
|
285
|
+
|
286
|
+
shard_info = nil
|
287
|
+
sets.each do |set|
|
288
|
+
host = set.name
|
289
|
+
set.each do |id|
|
290
|
+
if id.hostname != host
|
291
|
+
shard_info ||= service.get_shard(id)
|
292
|
+
old = id.to_unix
|
293
|
+
id.hostname = host
|
294
|
+
puts "gizzmo create #{shard_info.class_name} -s '#{shard_info.source_type}' -d '#{shard_info.destination_type}' #{old}"
|
295
|
+
puts "gizzmo copy #{old} #{id.to_unix}"
|
296
|
+
puts "gizzmo delete #{old}"
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
class PairCommand < ShardCommand
|
304
|
+
def run
|
305
|
+
ids = []
|
306
|
+
@argv.map do |host|
|
307
|
+
service.shards_for_hostname(host).each do |shard|
|
308
|
+
ids << shard.id
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
ids_by_table = {}
|
313
|
+
ids.map do |id|
|
314
|
+
ids_by_table[id.table_prefix] ||= []
|
315
|
+
ids_by_table[id.table_prefix] << id
|
316
|
+
end
|
317
|
+
|
318
|
+
ids_by_host = {}
|
319
|
+
ids.map do |id|
|
320
|
+
ids_by_host[id.hostname] ||= []
|
321
|
+
ids_by_host[id.hostname] << id
|
322
|
+
end
|
323
|
+
|
324
|
+
overlaps = {}
|
325
|
+
ids_by_table.values.each do |arr|
|
326
|
+
key = arr.map{|id| id.hostname }.sort
|
327
|
+
overlaps[key] ||= 0
|
328
|
+
overlaps[key] += 1
|
329
|
+
end
|
330
|
+
|
331
|
+
displayed = {}
|
332
|
+
overlaps.sort_by{|hosts, count| count }.reverse.each do |(host_a, host_b), count|
|
333
|
+
next if !host_a || !host_b || displayed[host_a] || displayed[host_b]
|
334
|
+
id_a = ids_by_host[host_a].first
|
335
|
+
id_b = ids_by_host[host_b].first
|
336
|
+
weight_a = service.list_upward_links(id_a).first.weight
|
337
|
+
weight_b = service.list_upward_links(id_b).first.weight
|
338
|
+
if weight_a > weight_b
|
339
|
+
puts "#{host_a}\t#{host_b}"
|
340
|
+
else
|
341
|
+
puts "#{host_b}\t#{host_a}"
|
342
|
+
end
|
343
|
+
displayed[host_a] = true
|
344
|
+
displayed[host_b] = true
|
345
|
+
end
|
346
|
+
remaining = @argv - displayed.keys
|
347
|
+
loop do
|
348
|
+
a = remaining.shift
|
349
|
+
b = remaining.shift
|
350
|
+
break unless a && b
|
351
|
+
puts "#{a}\t#{b}"
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
class ReportCommand < ShardCommand
|
357
|
+
def run
|
358
|
+
regex = @argv.first
|
359
|
+
help!("regex is a required option") unless regex
|
360
|
+
regex = Regexp.compile(regex)
|
361
|
+
service.list_hostnames.map do |host|
|
362
|
+
puts host
|
363
|
+
counts = {}
|
364
|
+
service.shards_for_hostname(host).each do |shard|
|
365
|
+
id = shard.id.to_unix
|
366
|
+
if key = id[regex, 1] || id[regex, 0]
|
367
|
+
counts[key] ||= 0
|
368
|
+
counts[key] += 1
|
369
|
+
end
|
370
|
+
end
|
371
|
+
counts.sort.each do |k, v|
|
372
|
+
puts " %3d %s" % [v, k]
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
260
378
|
class FindCommand < ShardCommand
|
261
379
|
def run
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
380
|
+
hosts = @argv << command_options.shard_host
|
381
|
+
hosts.compact.each do |host|
|
382
|
+
service.shards_for_hostname(host).each do |shard|
|
383
|
+
next if command_options.shard_type && shard.class_name !~ Regexp.new(command_options.shard_type)
|
384
|
+
output shard.id.to_unix
|
385
|
+
end
|
266
386
|
end
|
267
387
|
end
|
268
388
|
end
|
data/lib/gizzard/thrift.rb
CHANGED
data/lib/gizzmo.rb
CHANGED
@@ -63,7 +63,7 @@ subcommands = {
|
|
63
63
|
'create' => OptionParser.new do |opts|
|
64
64
|
opts.banner = "Usage: #{zero} create [options] CLASS_NAME SHARD_ID [MORE SHARD_IDS...]"
|
65
65
|
separators(opts, DOC_STRINGS["create"])
|
66
|
-
|
66
|
+
|
67
67
|
opts.on("-s", "--source-type=TYPE") do |s|
|
68
68
|
subcommand_options.source_type = s
|
69
69
|
end
|
@@ -76,6 +76,18 @@ subcommands = {
|
|
76
76
|
opts.banner = "Usage: #{zero} wrap CLASS_NAME SHARD_ID_TO_WRAP [MORE SHARD_IDS...]"
|
77
77
|
separators(opts, DOC_STRINGS["wrap"])
|
78
78
|
end,
|
79
|
+
'report' => OptionParser.new do |opts|
|
80
|
+
opts.banner = "Usage: #{zero} report RUBY_REGEX"
|
81
|
+
separators(opts, DOC_STRINGS["report"])
|
82
|
+
end,
|
83
|
+
'rebalance' => OptionParser.new do |opts|
|
84
|
+
opts.banner = "Usage: #{zero} rebalance RUBY_REGEX"
|
85
|
+
separators(opts, DOC_STRINGS["rebalance"])
|
86
|
+
end,
|
87
|
+
'pair' => OptionParser.new do |opts|
|
88
|
+
opts.banner = "Usage: #{zero} pair"
|
89
|
+
separators(opts, DOC_STRINGS["pair"])
|
90
|
+
end,
|
79
91
|
'subtree' => OptionParser.new do |opts|
|
80
92
|
opts.banner = "Usage: #{zero} subtree SHARD_ID"
|
81
93
|
separators(opts, DOC_STRINGS["subtree"])
|
@@ -209,11 +221,11 @@ global = OptionParser.new do |opts|
|
|
209
221
|
opts.on("-P", "--port=PORT", "PORT of remote thrift service") do |port|
|
210
222
|
global_options.port = port
|
211
223
|
end
|
212
|
-
|
224
|
+
|
213
225
|
opts.on("--subtree", "Render in subtree mode") do
|
214
226
|
global_options.render << "subtree"
|
215
227
|
end
|
216
|
-
|
228
|
+
|
217
229
|
opts.on("--info", "Render in info mode") do
|
218
230
|
global_options.render << "info"
|
219
231
|
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 5
|
8
|
+
- 0
|
9
|
+
version: 0.5.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Kyle Maxwell
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-08-
|
17
|
+
date: 2010-08-23 00:00:00 -07:00
|
18
18
|
default_executable: gizzmo
|
19
19
|
dependencies: []
|
20
20
|
|