poolboy 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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/