mmtop 0.9.4 → 0.9.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,6 @@
1
+ # I'd like to say that I no longer understand this code.
2
+ # Also, I'd like to say that it's unlikely to work for you, the general public. patches welcome!
3
+
1
4
  module MMTop
2
5
  class Topology
3
6
  def initialize(config)
@@ -10,9 +13,10 @@ module MMTop
10
13
 
11
14
  new_top = create_sort_array(topology)
12
15
 
13
- hosts = @config.hosts.sort_by { |h| new_top.find_index { |t| t[:hostname] == h.name } }
16
+ hosts = @config.hosts.sort_by { |h| new_top.find_index { |t| t[:hostname] == h.name } || 1_000_000 }
14
17
  hosts.each { |h|
15
18
  top = new_top.find { |t| t[:hostname] == h.name }
19
+ next unless top
16
20
  if top[:levels] > 0
17
21
  h.display_name = (" " * top[:levels]) + '\_' + h.name
18
22
  end
@@ -70,7 +74,11 @@ module MMTop
70
74
 
71
75
  def find_master_slave
72
76
  topology = @config.hosts.inject({}) { |accum, h|
73
- hostname = h.query("show global variables where Variable_name='hostname'")[0][:Value]
77
+ rows = h.query("show global variables where Variable_name='hostname'")
78
+ next accum if rows.empty?
79
+
80
+ hostname = rows.first[:Value]
81
+
74
82
  hostname = hostname.split('.')[0]
75
83
  status = h.slave_status
76
84
 
@@ -107,9 +115,18 @@ module MMTop
107
115
  end
108
116
 
109
117
  Filter.add_filter("discover_topology") do |queries, hostinfo, config|
110
- if !config.options['discovered']
111
- config.options['discovered'] = true
118
+ if config.options['discover_topology'] && !config.options['topology.discovered']
119
+ config.options['topology.discovered'] = true
112
120
  config.hosts = MMTop::Topology.new(config).new_hostlist
113
- end
121
+ end
122
+ end
123
+
124
+ MMTop::Command.register do |c|
125
+ c.regexp /map_topology/
126
+ c.usage "map_topology"
127
+ c.explain "Re-Map the slave-chain topology"
128
+ c.command do |cmd, config|
129
+ config.options['discovered'] = false
130
+ end
114
131
  end
115
132
  end
@@ -1,3 +1,5 @@
1
+ require 'mmtop/qps'
2
+
1
3
  module MMTop
2
4
  class Host
3
5
  def initialize(hostname, user, password, options)
@@ -8,20 +10,43 @@ module MMTop
8
10
  m2opts[:socket] = options['socket'] if options['socket']
9
11
  m2opts[:port] = options['port'] if options['port']
10
12
  m2opts[:reconnect] = true
11
- @mysql = Mysql2::Client.new(m2opts)
12
- # rescue connection errors or sumpin
13
13
  @options = options
14
14
  @name = hostname
15
15
  @display_name = @name
16
16
  @comment = options['comment']
17
17
  @last_queries = nil
18
+
19
+ begin
20
+ @mysql = Mysql2::Client.new(m2opts)
21
+ rescue Mysql2::Error => e
22
+ if e.error_number == 2003
23
+ mark_dead!
24
+ else
25
+ raise e
26
+ end
27
+ end
28
+
29
+ # rescue connection errors or sumpin
18
30
  end
19
31
 
20
32
  attr_accessor :display_name, :name, :comment, :options
21
33
 
22
34
  def query(q)
35
+ return [] if dead?
36
+
23
37
  res = []
24
- ret = @mysql.query(q)
38
+ begin
39
+ ret = @mysql.query(q)
40
+ rescue Mysql2::Error => e
41
+ if [2007, 2013, 2003].include?(e.error_number)
42
+ mark_dead!
43
+ return []
44
+ else
45
+ puts "Got error number " + e.error_number.to_s
46
+ raise e
47
+ end
48
+ end
49
+
25
50
  return nil unless ret
26
51
  ret.each(:symbolize_keys => true) do |r|
27
52
  res << r
@@ -29,6 +54,14 @@ module MMTop
29
54
  res
30
55
  end
31
56
 
57
+ def mark_dead!
58
+ @dead = true
59
+ end
60
+
61
+ def dead?
62
+ @dead
63
+ end
64
+
32
65
  def slave_status
33
66
  return nil if @options['expect_slave'] == false
34
67
  res = query("show slave status")[0]
@@ -42,20 +75,15 @@ module MMTop
42
75
 
43
76
  def stats
44
77
  stats = {}
45
- queries = query("show global status like 'Questions'")[0][:Value].to_i
46
-
47
- if @last_queries
48
- elapsed = Time.now.to_i - @last_queries[:time]
49
- if elapsed > 0
50
- qps = (queries - @last_queries[:count]) / elapsed
51
- else
52
- qps = queries - @last_queries[:count]
53
- end
54
- stats[:qps] = qps
55
- end
56
- @last_queries = {}
57
- @last_queries[:count] = queries
58
- @last_queries[:time] = Time.now.to_i
78
+ row = query("show global status like 'Questions'")
79
+ return {} if row.empty?
80
+
81
+ queries = row.first[:Value].to_i
82
+
83
+ @qps ||= MMTop::QPS.new
84
+ @qps.add_sample(queries, Time.now)
85
+ stats[:qps] = @qps.calc.to_i
86
+
59
87
  stats
60
88
  end
61
89
 
@@ -18,12 +18,7 @@ module MMTop
18
18
  h['password'] ||= (pass || config['password'])
19
19
  h['wedge_monitor'] ||= config['wedge_monitor']
20
20
 
21
- begin
22
- Host.new(h['host'], h['user'], h['password'], h)
23
- rescue Mysql2::Error => e
24
- puts e
25
- nil
26
- end
21
+ Host.new(h['host'], h['user'], h['password'], h)
27
22
  end.compact
28
23
 
29
24
  @filters = MMTop::Filter.default_filters
@@ -0,0 +1,46 @@
1
+ module MMTop
2
+ class QPS
3
+ DEFAULT_WINDOW = 20
4
+
5
+ QUERIES = 0
6
+ TIME = 1
7
+ def self.window
8
+ @window || DEFAULT_WINDOW
9
+ end
10
+
11
+ def self.window=(window)
12
+ @window = window
13
+ end
14
+
15
+ def window
16
+ self.class.window
17
+ end
18
+
19
+ def add_sample(queries, time)
20
+ samples.push [queries, time]
21
+ clean_samples
22
+ end
23
+
24
+ def calc
25
+ clean_samples
26
+ return '...' if samples.size == 1
27
+
28
+ queries = samples.last[QUERIES] - samples.first[QUERIES]
29
+ time = samples.last[TIME].to_i - samples.first[TIME].to_i
30
+
31
+ queries / time
32
+ end
33
+
34
+ private
35
+
36
+ def clean_samples
37
+ while samples.first[TIME].to_i < (Time.now.to_i - window)
38
+ samples.shift
39
+ end
40
+ end
41
+
42
+ def samples
43
+ @samples ||= []
44
+ end
45
+ end
46
+ end
@@ -133,14 +133,16 @@ module MMTop
133
133
  str = pipe + " " + column_value(0, p.client, ' ', :right)
134
134
  str += info_sep + column_value(1, p.id ? p.id.to_s : '')
135
135
  str += info_sep + column_value(2, format_time(p.time))
136
- str += info_sep
136
+ str += info_sep
137
137
  str += format_process(p, @x - str.size - 1)
138
138
  str += " " * (@x - str.size - 1) + pipe
139
139
  puts str
140
140
  end
141
141
 
142
142
  def print_host(info)
143
- str = pipe + " " + column_value(0, info.host.display_name + " " + (info.host.comment || ""), "-".dark_gray)
143
+ display_name = info.host.display_name
144
+ display_name = (display_name + "!").red if info.host.dead?
145
+ str = pipe + " " + column_value(0, display_name + " " + (info.host.comment || ""), "-".dark_gray)
144
146
  str += sep_fill + column_fill(1) + sep_fill + column_fill(2)
145
147
  str += info_sep + column_value(3, info.connections.size.to_s)
146
148
  str += info_sep + column_value(4, format_slave_status(info.slave_status))
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mmtop
3
3
  version: !ruby/object:Gem::Version
4
- hash: 51
4
+ hash: 49
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 9
9
- - 4
10
- version: 0.9.4
9
+ - 5
10
+ version: 0.9.5
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ben Osheroff
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-01-18 00:00:00 +00:00
18
+ date: 2012-02-03 00:00:00 +00:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -80,6 +80,7 @@ files:
80
80
  - lib/mmtop/process.rb
81
81
  - lib/mmtop/host.rb
82
82
  - lib/mmtop/term_input.rb
83
+ - lib/mmtop/qps.rb
83
84
  - lib/mmtop/term_printer.rb
84
85
  - lib/mmtop/commands/filters.rb
85
86
  - lib/mmtop/commands/kill.rb