master_slave 3.0.0

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.
@@ -0,0 +1,67 @@
1
+ module MasterSlave
2
+ module Base
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ cattr_accessor :slave_connection_names
7
+ self.slave_connection_names = []
8
+
9
+ class << self
10
+ alias_method :connection_without_master_slave, :connection
11
+ alias_method :connection, :connection_with_master_slave
12
+ end
13
+ end
14
+
15
+ module ClassMethods
16
+
17
+ def slave(&block)
18
+ slave_name = select_slave_connection_name
19
+ if slave_name.blank?
20
+ block.call
21
+ else
22
+ with_slave(slave_name) do
23
+ block.call
24
+ end
25
+ end
26
+ end
27
+
28
+ def using(slave_name, &block)
29
+ with_slave(slave_name) do
30
+ block.call
31
+ end
32
+ end
33
+
34
+ def connection_with_master_slave
35
+ slave_block = MasterSlave::RuntimeRegistry.slave_block
36
+ current_slave_name = MasterSlave::RuntimeRegistry.current_slave_name
37
+
38
+ if defined?(Rails) && Rails.env.test?
39
+ connection_without_master_slave
40
+ elsif slave_block && current_slave_name
41
+ pool_name = MasterSlave::ConnectionHandler.connection_pool_name(current_slave_name)
42
+ ar_proxy = MasterSlave::ConnectionHandler::ArProxy.new(pool_name)
43
+ ActiveRecord::Base.connection_handler.retrieve_connection(ar_proxy)
44
+ else
45
+ connection_without_master_slave
46
+ end
47
+ end
48
+
49
+ protected
50
+
51
+ def select_slave_connection_name
52
+ ActiveRecord::Base.slave_connection_names[rand(ActiveRecord::Base.slave_connection_names.size)]
53
+ end
54
+
55
+ def with_slave(slave_name)
56
+ slave_name = slave_name.to_s.strip
57
+ raise "#{slave_name} not exist" unless ActiveRecord::Base.slave_connection_names.include?(slave_name)
58
+ MasterSlave::RuntimeRegistry.current_slave_name = slave_name
59
+ MasterSlave::RuntimeRegistry.slave_block = true
60
+ yield
61
+ ensure
62
+ MasterSlave::RuntimeRegistry.current_slave_name = nil
63
+ MasterSlave::RuntimeRegistry.slave_block = false
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,38 @@
1
+ module MasterSlave
2
+
3
+ def self.config
4
+ @config ||= MasterSlave::Configuration.new
5
+ end
6
+
7
+ class Configuration
8
+ cattr_accessor :config_file
9
+
10
+ def initialize
11
+ @content = load_config
12
+ end
13
+
14
+ def slave_names
15
+ raise "#{Rails.env}'s slave config not exist" if @content.blank?
16
+ @shard_names ||= @content.keys.sort
17
+ end
18
+
19
+ def slave_config(slave_name)
20
+ @content[slave_name]
21
+ end
22
+
23
+ def self.config_file
24
+ @@config_file ||= File.join(Rails.root, 'config', 'shards.yml')
25
+ end
26
+
27
+ private
28
+
29
+ def load_config
30
+ if File.exist?(self.class.config_file)
31
+ hash_config = YAML.load(ERB.new(File.open(self.class.config_file).read).result)
32
+ HashWithIndifferentAccess.new(hash_config)[Rails.env]
33
+ else
34
+ {}
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+ module MasterSlave
3
+ class ConnectionHandler
4
+
5
+ class ArProxy
6
+ attr_reader :name
7
+
8
+ def initialize(name)
9
+ @name = name
10
+ end
11
+ end
12
+
13
+ class << self
14
+
15
+ def setup
16
+ setup_connection
17
+ end
18
+
19
+ def connection_pool_name(slave_name)
20
+ "master_slave_#{slave_name.to_s.strip}"
21
+ end
22
+
23
+ protected
24
+
25
+ def setup_connection
26
+ ActiveRecord::Base.slave_connection_names ||= []
27
+ MasterSlave.config.slave_names.each do |slave_name|
28
+ ActiveRecord::Base.slave_connection_names << slave_name.to_s.strip
29
+ configuration = MasterSlave.config.slave_config(slave_name).symbolize_keys
30
+ unless configuration.key?(:adapter) then raise AdapterNotSpecified, "database configuration does not specify adapter" end
31
+
32
+ adapter_method = "#{configuration[:adapter]}_connection"
33
+ unless ActiveRecord::Base.respond_to?(adapter_method)
34
+ raise AdapterNotFound, "database configuration specifies nonexistent #{spec.config[:adapter]} adapter"
35
+ end
36
+
37
+ # remove_connection 时会调用方法内部 ar_proxy.name
38
+ ar_proxy = ArProxy.new(connection_pool_name(slave_name))
39
+ ActiveRecord::Base.remove_connection(ar_proxy)
40
+
41
+ spec = ActiveRecord::Base::ConnectionSpecification.new(configuration, adapter_method)
42
+ ActiveRecord::Base.connection_handler.establish_connection ar_proxy.name, spec
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,20 @@
1
+ module MasterSlave
2
+ class Railtie < Rails::Railtie # :nodoc:
3
+
4
+ config.after_initialize do
5
+ if File.exist?(MasterSlave::Configuration.config_file)
6
+ puts "\033[32mmaster_slave is on!\033[0m"
7
+ ActiveRecord::Base.send :include, MasterSlave::Base
8
+ MasterSlave::ConnectionHandler.setup
9
+ else
10
+ puts "\033[31mNo such file #{MasterSlave::Configuration.config_file}\033[0m"
11
+ puts "\033[31mPlease execute `rails g master_slave:config`\033[0m"
12
+ puts "\033[31mmaster_slave is off!\033[0m"
13
+ end
14
+ end
15
+
16
+ generators do
17
+ require File.expand_path('../../rails/generators/config_generator', __FILE__)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,32 @@
1
+ begin
2
+ require 'active_support/per_thread_registry'
3
+ rescue LoadError
4
+ module ActiveSupport
5
+ module PerThreadRegistry
6
+ protected
7
+
8
+ def method_missing(name, *args, &block) # :nodoc:
9
+ # Caches the method definition as a singleton method of the receiver.
10
+ define_singleton_method(name) do |*a, &b|
11
+ per_thread_registry_instance.public_send(name, *a, &b)
12
+ end
13
+
14
+ send(name, *args, &block)
15
+ end
16
+
17
+ private
18
+
19
+ def per_thread_registry_instance
20
+ Thread.current[name] ||= new
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ module MasterSlave
27
+ class RuntimeRegistry
28
+ extend ActiveSupport::PerThreadRegistry
29
+
30
+ attr_accessor :slave_block, :current_slave_name
31
+ end
32
+ end
@@ -0,0 +1,3 @@
1
+ module MasterSlave
2
+ VERSION = '3.0.0'
3
+ end
@@ -0,0 +1,6 @@
1
+ require 'master_slave/base'
2
+ require 'master_slave/config'
3
+ require 'master_slave/connection_handler'
4
+ require 'master_slave/runtime_registry'
5
+ require 'master_slave/version'
6
+ require 'master_slave/railtie'
@@ -0,0 +1,34 @@
1
+ require "rails/generators/named_base"
2
+ module MasterSlave
3
+ module Generators
4
+ class ConfigGenerator < Rails::Generators::Base
5
+ desc "Creates a MasterSlave configuration file at config/shards.yml"
6
+
7
+ source_root File.expand_path('../templates', __FILE__)
8
+
9
+ argument :database_name, type: :string, optional: true
10
+
11
+ def app_name
12
+ Rails::Application.subclasses.first.parent.to_s.underscore
13
+ end
14
+
15
+ def create_config_file
16
+ template 'shards.yml', File.join(Rails.root, 'config', "shards.yml")
17
+ end
18
+
19
+ def mysql_socket
20
+ @mysql_socket ||= [
21
+ "/tmp/mysql.sock", # default
22
+ "/var/run/mysqld/mysqld.sock", # debian/gentoo
23
+ "/var/tmp/mysql.sock", # freebsd
24
+ "/var/lib/mysql/mysql.sock", # fedora
25
+ "/opt/local/lib/mysql/mysql.sock", # fedora
26
+ "/opt/local/var/run/mysqld/mysqld.sock", # mac + darwinports + mysql
27
+ "/opt/local/var/run/mysql4/mysqld.sock", # mac + darwinports + mysql4
28
+ "/opt/local/var/run/mysql5/mysqld.sock", # mac + darwinports + mysql5
29
+ "/opt/lampp/var/mysql/mysql.sock" # xampp for linux
30
+ ].find { |f| File.exist?(f) } unless RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,54 @@
1
+ # MySQL. Versions 4.1 and 5.0 are recommended.
2
+ #
3
+ # Install the MYSQL driver
4
+ # gem install mysql2
5
+ #
6
+ # Ensure the MySQL gem is defined in your Gemfile
7
+ # gem 'mysql2'
8
+ #
9
+ # And be sure to use new-style password hashing:
10
+ # http://dev.mysql.com/doc/refman/5.0/en/old-client.html
11
+ development:
12
+ slave:
13
+ adapter: mysql2
14
+ encoding: utf8
15
+ database: <%= database_name || app_name %>_development_slave
16
+ pool: 5
17
+ username: root
18
+ password:
19
+ <% if mysql_socket -%>
20
+ socket: <%= mysql_socket %>
21
+ <% else -%>
22
+ host: localhost
23
+ <% end -%>
24
+
25
+ # Warning: The database defined as "test" will be erased and
26
+ # re-generated from your development database when you run "rake".
27
+ # Do not set this db to the same as development or production.
28
+ test:
29
+ slave:
30
+ adapter: mysql2
31
+ encoding: utf8
32
+ database: <%= database_name || app_name %>_test_slave
33
+ pool: 5
34
+ username: root
35
+ password:
36
+ <% if mysql_socket -%>
37
+ socket: <%= mysql_socket %>
38
+ <% else -%>
39
+ host: localhost
40
+ <% end -%>
41
+
42
+ production:
43
+ slave:
44
+ adapter: mysql2
45
+ encoding: utf8
46
+ database: <%= database_name || app_name %>_production_slave
47
+ pool: 5
48
+ username: root
49
+ password:
50
+ <% if mysql_socket -%>
51
+ socket: <%= mysql_socket %>
52
+ <% else -%>
53
+ host: localhost
54
+ <% end -%>
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: master_slave
3
+ version: !ruby/object:Gem::Version
4
+ version: 3.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Tumayun, Zhangyuan
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-11-22 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 3.0.0
22
+ - - <
23
+ - !ruby/object:Gem::Version
24
+ version: 3.2.0
25
+ type: :runtime
26
+ prerelease: false
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 3.0.0
33
+ - - <
34
+ - !ruby/object:Gem::Version
35
+ version: 3.2.0
36
+ description: mysql separate read and write.
37
+ email: tumayun.2010@gmail.com
38
+ executables: []
39
+ extensions: []
40
+ extra_rdoc_files: []
41
+ files:
42
+ - lib/master_slave.rb
43
+ - lib/rails/generators/templates/shards.yml
44
+ - lib/rails/generators/config_generator.rb
45
+ - lib/master_slave/version.rb
46
+ - lib/master_slave/railtie.rb
47
+ - lib/master_slave/config.rb
48
+ - lib/master_slave/connection_handler.rb
49
+ - lib/master_slave/runtime_registry.rb
50
+ - lib/master_slave/base.rb
51
+ homepage: https://github.com/tumayun/master_slave
52
+ licenses: []
53
+ post_install_message:
54
+ rdoc_options: []
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ requirements: []
70
+ rubyforge_project:
71
+ rubygems_version: 1.8.23
72
+ signing_key:
73
+ specification_version: 3
74
+ summary: master_slave.
75
+ test_files: []