mysql-warmup 0.0.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ef5600e2b1d9462f2e8653caa0ae64a1e373ae4d
4
+ data.tar.gz: aa4a0595091db470b66d079784d4dacadded57ca
5
+ SHA512:
6
+ metadata.gz: ac489f240575c9f49f7e8bc4cb4217e899c29c2282eafffbfe1ad445085f03d806055e632ff204026acfaafdcbff2ebd33ac77e7949c7b99674df434ce789278
7
+ data.tar.gz: 9fcb4721c49c1a29a34e1e7349f4e066f4699a00b338041d924fb7dd9ec48ba5270f4baf25727344a2f8a5186300ae4ee39b9affe67e59552ca1c37cf6414873
data/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # mysql_warmup
2
+ Simple mysql-wamup command tool for warming up mysql server after create/reboot
3
+ [Github](https://github.com/manhdaovan/mysql_warmup)
4
+
5
+ # Background
6
+ With InnoDB storage engine, when you've just created new slave instance,
7
+ first requests to DB will be hit on disk instead of buffer poll. So, the requests will be slow down.
8
+ You can use this tool for warming up buffer poll before the first requests come.
9
+ [Detail](https://www.percona.com/blog/2008/05/01/quickly-preloading-innodb-tables-in-the-buffer-pool/)
10
+
11
+ # Usage
12
+ 1. **When?**
13
+ * You've set up new slave instance (base on Master-Slave model)
14
+ * Your mysql version < 5.6, that not support [Saving and Restoring the Buffer Pool State](https://dev.mysql.com/doc/refman/5.6/en/innodb-preload-buffer-pool.html), and your mysql instance just reboot
15
+ * Your mysql version >= 5.6, but you not config [Saving and Restoring the Buffer Pool State](https://dev.mysql.com/doc/refman/5.6/en/innodb-preload-buffer-pool.html), and your mysql just reboot
16
+ 2. **How?**
17
+ * Install this tool (please see `Install` section below)
18
+ * Usage as below syntax
19
+
20
+ ```
21
+ Usage: mysql-warmup -h host-or-ip -u username <options>
22
+
23
+ Input options:
24
+ -h host : Host or ip of mysql instance
25
+ -u username : Username to access mysql instance
26
+ -d database : Database to warmup.
27
+ Default to all databases exclude information_schema, mysql, performance_schema, sys
28
+ -p port : Port to connect. Default to 3306
29
+ --help : Show help message
30
+ --version : Show mysql-warmup version
31
+ ```
32
+
33
+ # Install
34
+ * Directly with command: `$gem install mysql-warmup`
35
+
36
+ * Or with `Gemfile` by adding line '`gem 'mysql-warmup`' to your `Gemfile` then `$bundle install`
37
+
38
+ # TODO
39
+ * RDoc
40
+
41
+ # Development
42
+ * All PR are welcome.
43
+ * Be sure all test cases are passed by command: `$rake test`
44
+
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << 'test'
5
+ end
6
+
7
+ desc 'Run tests for gmo_payment'
8
+ task default: :test
data/bin/console ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- encoding : utf-8 -*-
3
+ $LOAD_PATH.unshift(File.expand_path('./../lib', File.dirname(__FILE__)))
4
+ # noinspection RubyResolve
5
+ require 'mysql_warmup'
6
+ require 'irb'
7
+ require 'pp'
8
+
9
+ if __FILE__ == $PROGRAM_NAME
10
+ IRB.start(__FILE__)
11
+ else # check -e option
12
+ if /\A-e\z/ =~ $PROGRAM_NAME
13
+ IRB.start(__FILE__)
14
+ else
15
+ IRB.setup(__FILE__)
16
+ end
17
+ end
data/bin/mysql-warmup ADDED
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ $LOAD_PATH.unshift(File.expand_path('../lib', File.dirname(__FILE__)))
5
+ require 'mysql_warmup'
6
+ require 'optparse'
7
+
8
+ def print_help
9
+ puts "mysql-warmup, by ManhDV - version #{MysqlWarmup::VERSION}"
10
+ puts 'Website: https://github.com/manhdaovan/mysql_warmup'
11
+ puts
12
+ puts 'Usage: mysql-warmup -h host-or-ip -u username <options>'
13
+ puts
14
+ puts 'Input options:'
15
+ puts '-h host : Host or ip of mysql instance'
16
+ puts '-u username : Username to access mysql instance'
17
+ puts '-d database : Database to warmup.'
18
+ puts ' Default to all databases exclude information_schema, mysql, performance_schema, sys'
19
+ puts '-p port : Port to connect. Default to 3306'
20
+ puts '--help : Show help message'
21
+ puts '--version : Show mysql-warmup version'
22
+ end
23
+
24
+ def print_error(msg)
25
+ puts
26
+ puts ">>> ERROR: #{msg}"
27
+ end
28
+
29
+ def params_valid?(options)
30
+ required_params = [:host, :username]
31
+ valid = true
32
+ required_params.each do |rp|
33
+ next unless options.fetch(rp, nil).nil?
34
+ print_error("Required #{rp}")
35
+ valid = false
36
+ end
37
+ valid
38
+ end
39
+
40
+ options = { show_version: false, help: false, port: 3306, database: 'all' }
41
+
42
+ begin
43
+ OptionParser.new do |opts|
44
+ opts.banner = 'Usage: mysql-warmup -h host-or-ip -u username <options>'
45
+ opts.on('-h host', String) do |h|
46
+ options[:host] = h
47
+ end
48
+
49
+ opts.on('-u username') do |u|
50
+ options[:username] = u
51
+ end
52
+
53
+ opts.on('-d database') do |d|
54
+ options[:database] = d
55
+ end
56
+
57
+ opts.on('-p port') do |p|
58
+ options[:port] = p
59
+ end
60
+
61
+ opts.on('--help') do |_|
62
+ options[:help] = true
63
+ end
64
+
65
+ opts.on('--version') do |_|
66
+ options[:show_version] = true
67
+ end
68
+ end.parse!
69
+ rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e
70
+ print_error(e.message)
71
+ print_help
72
+ exit(0)
73
+ end
74
+
75
+ # Execute command base on input
76
+ if options[:show_version]
77
+ puts MysqlWarmup::VERSION
78
+ elsif options[:help]
79
+ print_help
80
+ elsif params_valid?(options)
81
+ puts
82
+ puts 'Input the mysql password:'
83
+ password = gets.chomp
84
+ begin
85
+ MysqlWarmup::Warmer.new(options[:host],
86
+ options[:username],
87
+ password,
88
+ options[:port].to_i,
89
+ options[:database]).warmup
90
+ rescue => e
91
+ print_error(e.message)
92
+ end
93
+ else
94
+ print_help
95
+ end
@@ -0,0 +1,51 @@
1
+ module MysqlWarmup
2
+ class Index
3
+ QUERY_TEMPLATE = 'select %s from %s where %s'.freeze
4
+ attr_reader :query_string
5
+
6
+ def initialize(table_name, column_name, column_type, column_key)
7
+ @table_name = table_name
8
+ @column_name = column_name
9
+ @column_type = column_type
10
+ @column_key = column_key
11
+ @query_string = build_query_string(@table_name, @column_name,
12
+ @column_type, @column_key)
13
+ end
14
+
15
+ private
16
+
17
+ def build_query_string(table_name, column_name, column_type, column_key)
18
+ if type_primary?(column_key) && type_integer?(column_type)
19
+ format_query("sum(`#{table_name}`.`#{column_name}`)", "`#{table_name}`", '1')
20
+ elsif type_integer?(column_type)
21
+ format_query('count(*)', "`#{table_name}`", "`#{table_name}`.`#{column_name}` LIKE '%0%'")
22
+ elsif type_var_char?(column_type)
23
+ format_query('count(*)', "`#{table_name}`", "`#{table_name}`.`#{column_name}` LIKE '%0%'")
24
+ elsif type_blob?(column_type)
25
+ format_query('count(*)', "`#{table_name}`", "`#{table_name}`.`#{column_name}` LIKE '%0%'")
26
+ else
27
+ format_query('count(*)', "`#{table_name}`", "`#{table_name}`.`#{column_name}` LIKE '%0%'")
28
+ end
29
+ end
30
+
31
+ def type_primary?(column_key)
32
+ column_key.casecmp('PRI').zero?
33
+ end
34
+
35
+ def type_integer?(column_type)
36
+ !(column_type.downcase =~ /int/).nil?
37
+ end
38
+
39
+ def type_blob?(column_type)
40
+ !(column_type.downcase =~ /blob/).nil?
41
+ end
42
+
43
+ def type_var_char?(column_type)
44
+ !(column_type.downcase =~ /varchar|index/).nil?
45
+ end
46
+
47
+ def format_query(*params)
48
+ format(QUERY_TEMPLATE, *params)
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,9 @@
1
+ module MysqlWarmup
2
+ class Logger
3
+ class << self
4
+ def write(log_msg)
5
+ puts "#{Time.now}: --- #{log_msg}"
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,34 @@
1
+ module MysqlWarmup
2
+ class Table
3
+ DESC_TABLE_STRUCTURE = {
4
+ field: 0,
5
+ type: 1,
6
+ null: 2,
7
+ key: 3,
8
+ default: 4,
9
+ extra: 5
10
+ }.freeze
11
+
12
+ attr_reader :indexes
13
+
14
+ def initialize(table_name, field_infos)
15
+ @table_name = table_name
16
+ @field_infos = field_infos
17
+ @indexes = build_index
18
+ end
19
+
20
+ private
21
+
22
+ def build_index
23
+ indexes_infos = @field_infos.select { |v| !v[DESC_TABLE_STRUCTURE[:key]].empty? }
24
+ indexes = []
25
+ indexes_infos.each do |index_info|
26
+ indexes << MysqlWarmup::Index.new(@table_name,
27
+ index_info[DESC_TABLE_STRUCTURE[:field]],
28
+ index_info[DESC_TABLE_STRUCTURE[:type]],
29
+ index_info[DESC_TABLE_STRUCTURE[:key]])
30
+ end
31
+ indexes
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ module MysqlWarmup
2
+ VERSION = '0.0.1'.freeze
3
+ end
@@ -0,0 +1,95 @@
1
+ require 'mysql'
2
+ module MysqlWarmup
3
+ class Warmer
4
+ ALL_DATABASE = 'all'.freeze
5
+ EXCLUDE_DATABASES = %w(information_schema mysql performance_schema sys).freeze
6
+ PREVENT_VARIABLES = [:@host, :@username, :@password, :@database, :@port].freeze
7
+
8
+ def initialize(host, username, password, port = 3306, database = 'all')
9
+ @host = host
10
+ @username = username
11
+ @password = password
12
+ @database = database
13
+ @port = port
14
+
15
+ @connector = if warmup_all?
16
+ Mysql.new(@host, @username, @password, '', @port)
17
+ else
18
+ Mysql.new(@host, @username, @password, @database, @port)
19
+ end
20
+ end
21
+
22
+ def warmup
23
+ warmup_all? ? warmup_all_dbs : warmup_only
24
+ end
25
+
26
+ # Prevent inspection object
27
+ def inspect
28
+ "#<MysqlWarmup::Warmer:#{object_id}>"
29
+ end
30
+
31
+ def instance_variable_get(*several_variants)
32
+ raise 'Not allow to view this variable' if PREVENT_VARIABLES.include?(several_variants[0])
33
+ super
34
+ end
35
+
36
+ private
37
+
38
+ def warmup_all_dbs
39
+ @connector.list_dbs.each do |db|
40
+ next if EXCLUDE_DATABASES.include?(db)
41
+ MysqlWarmup::Warmer.new(@host, @username, @password, @port, db).warmup
42
+ end
43
+ end
44
+
45
+ def warmup_only
46
+ write_log(">>>>>>> START WARMUP FOR DB: #{@database} <<<<<<")
47
+ tables = @connector.query('show tables')
48
+ table = tables.fetch_row
49
+ while table
50
+ # Fetch fields infos
51
+ fields_infos = fetch_fields_infos(table[0])
52
+
53
+ table_instance = MysqlWarmup::Table.new(table[0], fields_infos)
54
+ write_log("START WARMUP FOR TABLE: `#{@database}`.`#{table[0]}`")
55
+ table_instance.indexes.each do |i|
56
+ touch(i.query_string)
57
+ end
58
+ write_log("SUCCESS WARMUP FOR TABLE: `#{@database}`.`#{table[0]}`\n\n")
59
+
60
+ # Continue fetching table
61
+ table = tables.fetch_row
62
+ end
63
+ write_log("+++++++ SUCCESS WARMUP FOR DB: #{@database} +++++++\n\n")
64
+ rescue Mysql::Error => e
65
+ write_log("ERROR: ----------- #{e.message}")
66
+ write_log("BACKTRACE: ------- #{e.backtrace[0, 5]}")
67
+ ensure
68
+ @connector.close if @connector
69
+ end
70
+
71
+ def fetch_fields_infos(table_name)
72
+ fields_infos = []
73
+ fields = @connector.query("describe `#{table_name}`")
74
+ field = fields.fetch_row
75
+ while field
76
+ fields_infos << field
77
+ field = fields.fetch_row
78
+ end
79
+ fields_infos
80
+ end
81
+
82
+ def touch(query_string)
83
+ # write_log(query_string)
84
+ @connector.query(query_string)
85
+ end
86
+
87
+ def write_log(log_msg)
88
+ MysqlWarmup::Logger.write(log_msg)
89
+ end
90
+
91
+ def warmup_all?
92
+ @database.downcase == ALL_DATABASE
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,7 @@
1
+ module MysqlWarmup; end
2
+
3
+ require 'mysql_warmup/logger'
4
+ require 'mysql_warmup/index'
5
+ require 'mysql_warmup/table'
6
+ require 'mysql_warmup/warmer'
7
+ require 'mysql_warmup/version'
@@ -0,0 +1,35 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'mysql_warmup/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = 'mysql-warmup'
8
+ s.version = MysqlWarmup::VERSION
9
+ s.author = 'Manh Dao Van'
10
+ s.email = 'manhdaovan@gmail.com'
11
+ s.homepage = 'https://github.com/manhdaovan/mysql_warmup'
12
+ s.license = 'MIT'
13
+
14
+ s.summary = 'A command line tool to warm up mysql instance after reboot or startup'
15
+ s.description = <<-eos
16
+ When you've just created new slave instance, first requests to DB (with InnoDB storage engine)
17
+ will be hit on disk instead of buffer poll. So, the requests will be slow down.
18
+ You can use this tool for warming up buffer poll before the first requests come.
19
+ Please see document for other cases.
20
+ eos
21
+
22
+ s.platform = Gem::Platform::RUBY
23
+ s.required_ruby_version = '>= 2.0.0'
24
+
25
+ s.files = `git ls-files`.split("\n")
26
+ s.test_files = `git ls-files -- {test}/*`.split("\n")
27
+ s.require_paths = ['lib']
28
+
29
+ s.executables = s.files.grep(%r{^bin/}).map { |f| File.basename(f) }
30
+ s.default_executable = 'mysql-warmup'
31
+ s.bindir = 'bin'
32
+
33
+ s.add_dependency('mysql')
34
+ s.add_development_dependency('rake')
35
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,7 @@
1
+ def query_template
2
+ 'select %s from %s where %s'.freeze
3
+ end
4
+
5
+ def build_query(*params)
6
+ format(query_template, *params)
7
+ end
@@ -0,0 +1,20 @@
1
+ require 'test/unit'
2
+ require 'mysql_warmup'
3
+ require 'helper'
4
+
5
+ class TestIndex < Test::Unit::TestCase
6
+ def test_query_string
7
+ types = %w(VARCHAR TEXT BLOB INT DATE OTHERS)
8
+ # Index for primary
9
+ index = MysqlWarmup::Index.new('table_name', 'col_name', 'INT', 'PRI')
10
+ assert_equal(build_query('sum(`table_name`.`col_name`)', '`table_name`', '1'),
11
+ index.query_string)
12
+
13
+ # Index for other fields
14
+ types.each do |type|
15
+ index = MysqlWarmup::Index.new('table_name', 'col_name', type, '')
16
+ assert_equal(build_query('count(*)', '`table_name`', "`table_name`.`col_name` LIKE '%0%'"),
17
+ index.query_string)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,13 @@
1
+ require 'test/unit'
2
+ require 'mysql_warmup'
3
+
4
+ class TestLogger < Test::Unit::TestCase
5
+ def test_logger_output
6
+ orig_stdout = $stdout
7
+ $stdout = StringIO.new
8
+ MysqlWarmup::Logger.write('log output')
9
+ assert_equal(true, !($stdout.string =~ /log output/).nil?)
10
+ ensure
11
+ $stdout = orig_stdout
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ require 'test/unit'
2
+ require 'mysql_warmup'
3
+
4
+ class TestMysqlWarmup < Test::Unit::TestCase
5
+ end
@@ -0,0 +1,14 @@
1
+ require 'test/unit'
2
+ require 'mysql_warmup'
3
+
4
+ class TestTable < Test::Unit::TestCase
5
+ def test_indexes_of_table
6
+ table_name = 'table_name'
7
+ fields_info = [%w(field type null key default extra)] * 5
8
+ table = MysqlWarmup::Table.new(table_name, fields_info)
9
+ assert_equal(5, table.indexes.size)
10
+ table.indexes.each do |table_index|
11
+ assert_equal(true, table_index.is_a?(MysqlWarmup::Index))
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ require 'test/unit'
2
+ require 'mysql_warmup'
3
+
4
+ class TestWarmer < Test::Unit::TestCase
5
+ def test_init_and_prevent_variable
6
+ Mysql.class_eval do
7
+ def self.new(*_arg)
8
+ 'Mysql Instance'
9
+ end
10
+ end
11
+ warmer = MysqlWarmup::Warmer.new('localhost', 'db_user', 'db_password')
12
+ MysqlWarmup::Warmer::PREVENT_VARIABLES.each do |p_v|
13
+ begin
14
+ warmer.instance_variable_get(p_v)
15
+ rescue => e
16
+ assert_equal('Not allow to view this variable', e.message)
17
+ end
18
+ end
19
+ assert_equal('Mysql Instance', warmer.instance_variable_get(:@connector))
20
+ end
21
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mysql-warmup
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Manh Dao Van
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-01-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mysql
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: |2
42
+ When you've just created new slave instance, first requests to DB (with InnoDB storage engine)
43
+ will be hit on disk instead of buffer poll. So, the requests will be slow down.
44
+ You can use this tool for warming up buffer poll before the first requests come.
45
+ Please see document for other cases.
46
+ email: manhdaovan@gmail.com
47
+ executables:
48
+ - console
49
+ - mysql-warmup
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - README.md
54
+ - Rakefile
55
+ - bin/console
56
+ - bin/mysql-warmup
57
+ - lib/mysql_warmup.rb
58
+ - lib/mysql_warmup/index.rb
59
+ - lib/mysql_warmup/logger.rb
60
+ - lib/mysql_warmup/table.rb
61
+ - lib/mysql_warmup/version.rb
62
+ - lib/mysql_warmup/warmer.rb
63
+ - mysql-warmup.gemspec
64
+ - test/helper.rb
65
+ - test/test_index.rb
66
+ - test/test_logger.rb
67
+ - test/test_mysql_warmup.rb
68
+ - test/test_table.rb
69
+ - test/test_warmer.rb
70
+ homepage: https://github.com/manhdaovan/mysql_warmup
71
+ licenses:
72
+ - MIT
73
+ metadata: {}
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 2.0.0
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project:
90
+ rubygems_version: 2.6.8
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: A command line tool to warm up mysql instance after reboot or startup
94
+ test_files: []