mysql-warmup 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []