poolboy 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,15 +1,24 @@
1
1
  # Poolboy
2
2
 
3
- Poolboy is a command line tool that allows you to see the indexes
3
+ Poolboy is a command line tool that allows you to see information about the MySQL buffer pool as well as the buffered indexes.
4
+ Understanding how your data fits in memory helps discover why some queries are IO bound.
5
+
6
+ By default MySQL doesn't provide the stats necessary to get this information so Poolboy only works with Percona Server.
7
+
8
+ Poolboy in action:
9
+ ![Poolboy](http://samlambert.com/images/poolboy.png)
10
+
11
+ This is my first Ruby project so if you have any comments/constructive criticism please create an issue or submit a pull request :thumbsup:
4
12
 
5
13
  ## Installation
6
14
 
7
15
  $ gem install poolboy
8
16
 
17
+ Poolboy requires process privileges from MySQL
9
18
 
10
19
  ## Usage
11
20
 
12
- Command line options are in the style of the Mysql Client:
21
+ The command line options are in the style of the Mysql Client:
13
22
 
14
23
  $ poolboy -h localhost -u root -p password
15
24
  Help can be found with --help:
@@ -36,10 +45,17 @@ The configuration file needs to be in YAML format like so:
36
45
  $ cat ~/.poolboy.yaml
37
46
  :host: 127.0.0.1
38
47
  :username: root
39
- :password: kraken123
48
+ :password: password123
40
49
  :refresh: 5
41
50
  :force: false
42
51
 
52
+ ## Quirks/Bugs
53
+ Some versions of Percona Server such as the one installed by brew don't have the 'version_comment' server variable which Poolboy uses to check version compatibility. If you want to skip this check just specify the option '-f' or ':force: true' in your config file.
54
+
55
+ Sometimes the Server reports slightly inaccurate page counts causing % to go over 100%
56
+
57
+ Older versions of Percona Server may not report all the values needed by Poolboy
58
+
43
59
  ## TODO
44
60
 
45
61
  Add more stats
@@ -48,7 +64,6 @@ Add tests!
48
64
 
49
65
  Move option parsing into a class
50
66
 
51
- ## Quirks/Bugs
52
67
 
53
68
  ## Contributing
54
69
 
@@ -57,3 +72,9 @@ Move option parsing into a class
57
72
  3. Commit your changes (`git commit -am 'Add some feature'`)
58
73
  4. Push to the branch (`git push origin my-new-feature`)
59
74
  5. Create new Pull Request
75
+
76
+
77
+ ## Thanks
78
+ [Philip Poots](https://github.com/pootsbook) for helping me out and answering my questions about Ruby.
79
+
80
+ Peter Zaitsev for inspiring me to build Poolboy with this [post.](http://www.mysqlperformanceblog.com/2010/12/09/how-well-does-your-table-fits-in-innodb-buffer-pool/)
@@ -3,5 +3,4 @@
3
3
  $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
4
4
 
5
5
  require 'poolboy'
6
-
7
6
  Poolboy.execute
@@ -0,0 +1,42 @@
1
+ class FiveFive
2
+
3
+ def self.get_stats(mysql_conn)
4
+ results ={}
5
+ results['stats'] = mysql_conn.query("
6
+ SELECT a.psize buffer_pool_mb, b.pageda pages_data, c.pagem pages_misc,
7
+ d.pagef pages_free, e.pagesi page_size
8
+ FROM (SELECT variable_value / 1024 / 1024 psize FROM GLOBAL_VARIABLES WHERE VARIABLE_NAME = 'INNODB_BUFFER_POOL_SIZE') a,
9
+ (SELECT variable_value pageda FROM GLOBAL_STATUS WHERE VARIABLE_NAME = 'INNODB_BUFFER_POOL_PAGES_DATA') b,
10
+ (SELECT variable_value pagem FROM GLOBAL_STATUS WHERE VARIABLE_NAME = 'INNODB_BUFFER_POOL_PAGES_MISC') c,
11
+ (SELECT variable_value pagef FROM GLOBAL_STATUS WHERE VARIABLE_NAME = 'INNODB_BUFFER_POOL_PAGES_FREE') d,
12
+ (SELECT variable_value pagesi FROM GLOBAL_VARIABLES WHERE VARIABLE_NAME = 'INNODB_PAGE_SIZE') e")
13
+
14
+ results['bp'] = mysql_conn.query("
15
+ SELECT `schema` AS db,
16
+ innodb_sys_tables.name AS table_n,
17
+ innodb_sys_indexes.name AS i_name,
18
+ cnt,
19
+ dirty,
20
+ hashed,
21
+ IFNULL(ROUND(cnt * 100 / index_size, 2),0) pct
22
+ FROM (SELECT index_id,
23
+ COUNT(*) cnt,
24
+ SUM(dirty = 1) dirty,
25
+ SUM(hashed = 1) hashed,
26
+ data_size index_size
27
+ FROM innodb_buffer_pool_pages_index
28
+ GROUP BY index_id) bp
29
+ JOIN innodb_sys_indexes
30
+ ON bp.index_id = innodb_sys_indexes.index_id
31
+ JOIN innodb_sys_tables
32
+ ON innodb_sys_indexes.table_id = innodb_sys_tables.table_id
33
+ JOIN innodb_index_stats
34
+ ON innodb_index_stats.table_name = innodb_sys_tables.name
35
+ AND innodb_sys_indexes.name = innodb_index_stats.index_name
36
+ AND innodb_index_stats.table_schema = innodb_sys_tables.SCHEMA
37
+ ORDER BY cnt DESC
38
+ ")
39
+ return results
40
+ end
41
+
42
+ end
@@ -0,0 +1,38 @@
1
+
2
+ class FiveOne
3
+
4
+ def self.get_stats(mysql_conn)
5
+ results ={}
6
+ results['stats'] = mysql_conn.query("
7
+ SELECT a.psize buffer_pool_mb, b.pageda pages_data,
8
+ c.pagem pages_misc, d.pagef pages_free, e.pagesi page_size
9
+ FROM (SELECT variable_value / 1024 / 1024 psize FROM GLOBAL_VARIABLES WHERE VARIABLE_NAME = 'INNODB_BUFFER_POOL_SIZE') a,
10
+ (SELECT variable_value pageda FROM GLOBAL_STATUS WHERE VARIABLE_NAME = 'INNODB_BUFFER_POOL_PAGES_DATA') b,
11
+ (SELECT variable_value pagem FROM GLOBAL_STATUS WHERE VARIABLE_NAME = 'INNODB_BUFFER_POOL_PAGES_MISC') c,
12
+ (SELECT variable_value pagef FROM GLOBAL_STATUS WHERE VARIABLE_NAME = 'INNODB_BUFFER_POOL_PAGES_FREE') d,
13
+ (SELECT variable_value pagesi FROM GLOBAL_VARIABLES WHERE VARIABLE_NAME = 'INNODB_PAGE_SIZE') e")
14
+
15
+ results['bp'] = mysql_conn.query("
16
+ SELECT `schema` AS db,
17
+ innodb_sys_tables.name AS table_n,
18
+ innodb_sys_indexes.name AS i_name,
19
+ cnt,
20
+ dirty,
21
+ hashed,
22
+ IFNULL(ROUND(cnt * 100 / index_s, 2),0) pct
23
+ FROM (SELECT index_id,
24
+ COUNT(*) cnt,
25
+ SUM(dirty = 1) dirty, SUM(hashed = 1) hashed,
26
+ data_size index_s
27
+ FROM innodb_buffer_pool_pages_index
28
+ GROUP BY index_id) bp
29
+ JOIN innodb_sys_indexes ON bp.index_id = innodb_sys_indexes.id
30
+ JOIN innodb_sys_tables ON innodb_sys_indexes.table_id = innodb_sys_tables.id
31
+ JOIN innodb_index_stats ON innodb_index_stats.table_name = innodb_sys_tables.name
32
+ AND innodb_sys_indexes.name = innodb_index_stats.index_name
33
+ AND innodb_index_stats.table_schema = innodb_sys_tables.SCHEMA ORDER BY cnt DESC
34
+ ")
35
+ return results
36
+ end
37
+
38
+ end
@@ -0,0 +1,36 @@
1
+ require 'mysql2'
2
+
3
+ class MysqlConnection
4
+
5
+ def initialize(options)
6
+ begin
7
+ @mysql = Mysql2::Client.new(options.merge({:database => 'information_schema', :connect_timeout => 2, :symbolize_keys => true}))
8
+ rescue Mysql2::Error => e
9
+ puts e
10
+ exit 1
11
+ end
12
+ end
13
+
14
+ def version
15
+ version = query("SHOW VARIABLES LIKE 'version'")
16
+ return version.first[:Value]
17
+ end
18
+
19
+ def percona
20
+ xtra = query("show variables like 'version_comment'")
21
+ return (xtra.first[:Value].include? "Percona") ? true : false
22
+ end
23
+
24
+ def query(query)
25
+ begin
26
+ @mysql.query(query)
27
+ rescue Mysql2::Error => e
28
+ puts e
29
+ exit 1
30
+ end
31
+ end
32
+
33
+ def disconnect
34
+ @mysql.close
35
+ end
36
+ end
@@ -0,0 +1,42 @@
1
+
2
+ class Screen
3
+
4
+ def initialize(window)
5
+ @win = window
6
+ @width = @win.maxx
7
+ @hight = @win.maxy
8
+ end
9
+
10
+ def show_message(message)
11
+ @win.setpos(0, 0)
12
+ message['stats'].each do |s|
13
+ pool_size = (s.fetch(:pages_misc).to_i + s.fetch(:pages_data).to_i * s.fetch(:page_size).to_i / 1024 / 1024)
14
+ stats = "Buffer Pool: %s/%sMB Data pages: %s Misc Pages: %s Free pages: %s\n" % [pool_size, s.fetch(:buffer_pool_mb), s.fetch(:pages_data), s.fetch(:pages_misc), s.fetch(:pages_free)]
15
+ @win.addstr(stats)
16
+ end
17
+ names = (@width * 0.23).round()
18
+ stats = (@width * 0.07).round()
19
+ title = "%-#{names}.#{names}s" % "Database" + "%-#{names}.#{names}s" % "Table" + "%-#{names}.#{names}s" % "Index" + "%-#{stats}.#{stats}s" % "Pages" + "%-#{stats}.#{stats}s" % "Dirty" + "%-#{stats}.#{stats}s" % "Hashed" + "%-#{stats}.#{stats}s\n" % "%"
20
+ @win.addstr("-" * @win.maxx)
21
+ @win.addstr(title)
22
+ @win.addstr("-" * @win.maxx)
23
+ row_max = @win.maxy - 2
24
+ rows = 2
25
+ message['bp'].each do |row|
26
+ row[:db] = "%-#{names}.#{names}s" % row.fetch(:db)
27
+ row[:table_n] = "%-#{names}.#{names}s" % row.fetch(:table_n)
28
+ row[:i_name] = "%-#{names}.#{names}s" % row.fetch(:i_name)
29
+ row[:cnt] = "%-#{stats}.#{stats}s" % row.fetch(:cnt)
30
+ row[:dirty] = "%-#{stats}.f" % row.fetch(:dirty)
31
+ row[:hashed] = "%-#{stats}.f" % row.fetch(:hashed)
32
+ row[:pct] = "%-#{stats}.2f" % row.fetch(:pct)
33
+
34
+ template = "#{row[:db]}#{row[:table_n]}#{row[:i_name]}#{row[:cnt]}#{row[:dirty]}#{row[:hashed]}#{row[:pct]}\n"
35
+ @win.addstr(template)
36
+ rows += 1
37
+ break if rows >= row_max
38
+ end
39
+ @win.refresh
40
+ end
41
+
42
+ end
@@ -0,0 +1,3 @@
1
+ module Poolboy
2
+ VERSION = "0.1.4"
3
+ end
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+
2
3
  lib = File.expand_path('../lib', __FILE__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
5
  require 'poolboy/version'
@@ -10,7 +11,7 @@ Gem::Specification.new do |spec|
10
11
  spec.email = ["sam@ninjapanda.co.uk"]
11
12
  spec.description = %q{See the status of your Percona Server buffer pool}
12
13
  spec.summary = %q{Poolboy lets you view the data in your buffer pool}
13
- spec.homepage = "http://www.samlambert.com"
14
+ spec.homepage = "https://github.com/samlambert/poolboy/issues"
14
15
  spec.license = "MIT"
15
16
 
16
17
  spec.files = `git ls-files`.split($/)
@@ -19,6 +20,8 @@ Gem::Specification.new do |spec|
19
20
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
21
  spec.require_paths = ["lib"]
21
22
 
23
+ spec.required_ruby_version = '>= 1.8.7'
24
+
22
25
  spec.add_dependency "mysql2"
23
26
  spec.add_development_dependency "bundler", "~> 1.3"
24
27
  spec.add_development_dependency "rake"
metadata CHANGED
@@ -1,73 +1,76 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: poolboy
3
- version: !ruby/object:Gem::Version
4
- version: 0.1.3
3
+ version: !ruby/object:Gem::Version
4
+ hash: 19
5
5
  prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 4
10
+ version: 0.1.4
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Sam
9
14
  autorequire:
10
15
  bindir: bin
11
16
  cert_chain: []
12
- date: 2013-06-09 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
17
+
18
+ date: 2013-06-28 00:00:00 -07:00
19
+ default_executable: poolboy
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
15
22
  name: mysql2
16
- requirement: !ruby/object:Gem::Requirement
17
- none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
21
- version: '0'
22
- type: :runtime
23
23
  prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
25
  none: false
26
- requirements:
27
- - - ! '>='
28
- - !ruby/object:Gem::Version
29
- version: '0'
30
- - !ruby/object:Gem::Dependency
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
31
36
  name: bundler
32
- requirement: !ruby/object:Gem::Requirement
33
- none: false
34
- requirements:
35
- - - ~>
36
- - !ruby/object:Gem::Version
37
- version: '1.3'
38
- type: :development
39
37
  prerelease: false
40
- version_requirements: !ruby/object:Gem::Requirement
38
+ requirement: &id002 !ruby/object:Gem::Requirement
41
39
  none: false
42
- requirements:
40
+ requirements:
43
41
  - - ~>
44
- - !ruby/object:Gem::Version
45
- version: '1.3'
46
- - !ruby/object:Gem::Dependency
47
- name: rake
48
- requirement: !ruby/object:Gem::Requirement
49
- none: false
50
- requirements:
51
- - - ! '>='
52
- - !ruby/object:Gem::Version
53
- version: '0'
42
+ - !ruby/object:Gem::Version
43
+ hash: 9
44
+ segments:
45
+ - 1
46
+ - 3
47
+ version: "1.3"
54
48
  type: :development
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: rake
55
52
  prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
53
+ requirement: &id003 !ruby/object:Gem::Requirement
57
54
  none: false
58
- requirements:
59
- - - ! '>='
60
- - !ruby/object:Gem::Version
61
- version: '0'
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ type: :development
63
+ version_requirements: *id003
62
64
  description: See the status of your Percona Server buffer pool
63
- email:
65
+ email:
64
66
  - sam@ninjapanda.co.uk
65
- executables:
67
+ executables:
66
68
  - poolboy
67
69
  extensions: []
70
+
68
71
  extra_rdoc_files: []
69
- files:
70
- - .gitignore
72
+
73
+ files:
71
74
  - Gemfile
72
75
  - LICENSE.txt
73
76
  - README.md
@@ -80,29 +83,41 @@ files:
80
83
  - lib/poolboy/screen.rb
81
84
  - lib/poolboy/version.rb
82
85
  - poolboy.gemspec
83
- homepage: http://www.samlambert.com
84
- licenses:
86
+ has_rdoc: true
87
+ homepage: https://github.com/samlambert/poolboy/issues
88
+ licenses:
85
89
  - MIT
86
90
  post_install_message:
87
91
  rdoc_options: []
88
- require_paths:
92
+
93
+ require_paths:
89
94
  - lib
90
- required_ruby_version: !ruby/object:Gem::Requirement
95
+ required_ruby_version: !ruby/object:Gem::Requirement
91
96
  none: false
92
- requirements:
93
- - - ! '>='
94
- - !ruby/object:Gem::Version
95
- version: '0'
96
- required_rubygems_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ hash: 57
101
+ segments:
102
+ - 1
103
+ - 8
104
+ - 7
105
+ version: 1.8.7
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
107
  none: false
98
- requirements:
99
- - - ! '>='
100
- - !ruby/object:Gem::Version
101
- version: '0'
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ hash: 3
112
+ segments:
113
+ - 0
114
+ version: "0"
102
115
  requirements: []
116
+
103
117
  rubyforge_project:
104
- rubygems_version: 1.8.24
118
+ rubygems_version: 1.6.2
105
119
  signing_key:
106
120
  specification_version: 3
107
121
  summary: Poolboy lets you view the data in your buffer pool
108
122
  test_files: []
123
+
data/.gitignore DELETED
@@ -1,24 +0,0 @@
1
- *.gem
2
- *.rbc
3
- .bundle
4
- .config
5
- .yardoc
6
- Gemfile.lock
7
- InstalledFiles
8
- _yardoc
9
- coverage
10
- doc/
11
- coverage
12
- InstalledFiles
13
- lib/bundler/man
14
- pkg
15
- rdoc
16
- spec/reports
17
- test/tmp
18
- test/version_tmp
19
- tmp
20
- poolboy/
21
- # YARD artifacts
22
- .yardoc
23
- _yardoc
24
- doc/