Class: SlavePoolsModule::ConnectionProxy

Inherits:
Object
  • Object
show all
Includes:
ActiveRecord::ConnectionAdapters::QueryCache, QueryCacheCompat
Defined in:
lib/slave_pools/connection_proxy.rb

Constant Summary collapse

SAFE_METHODS =

Safe methods are those that should either go to the slave ONLY or go to the current active connection.

Set.new([ :select_all, :select_one, :select_value, :select_values,
:select_rows, :select, :verify!, :raw_connection, :active?, :reconnect!,
:disconnect!, :reset_runtime, :log, :log_info ])
DEFAULT_MASTER_MODELS =

< Rails 2.3

['CGI::Session::ActiveRecordStore::Session']

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from QueryCacheCompat

#delete, #insert, #query_cache_enabled, #select_all, #update

Constructor Details

#initialize(master, slave_pools) ⇒ ConnectionProxy

end class << self



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/slave_pools/connection_proxy.rb', line 83

def initialize(master, slave_pools)
  @slave_pools = {}
  slave_pools.each do |pool_name, slaves|
    @slave_pools[pool_name.to_sym] = SlavePool.new(pool_name, slaves)
  end
  @master    = master
  @reconnect = false
  @current_pool = default_pool
  if self.class.defaults_to_master
    @current = @master
    @master_depth = 1
    @config = master.connection.instance_variable_get(:@config)
  else
    @current = slave
    @master_depth = 0
    @config = @current.config_hash #setting this
  end

end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object

Calls the method on master/slave and dynamically creates a new method on success to speed up subsequent calls



144
145
146
147
148
# File 'lib/slave_pools/connection_proxy.rb', line 144

def method_missing(method, *args, &block)
  send(target_method(method), method, *args, &block).tap do
    create_delegation_method!(method)
  end
end

Class Attribute Details

.configObject

#setting a config instance variable so that thinking sphinx,and other gems that use the connection.instance_variable_get(:@config), work correctly



44
45
46
# File 'lib/slave_pools/connection_proxy.rb', line 44

def config
  @config
end

.defaults_to_masterObject

if master should be the default db



41
42
43
# File 'lib/slave_pools/connection_proxy.rb', line 41

def defaults_to_master
  @defaults_to_master
end

.environmentObject

defaults to Rails.env if multi_db is used with Rails defaults to ‘development’ when used outside Rails



28
29
30
# File 'lib/slave_pools/connection_proxy.rb', line 28

def environment
  @environment
end

.master_modelsObject

a list of models that should always go directly to the master

Example:

SlavePool::ConnectionProxy.master_models = ['MySessionStore', 'PaymentTransaction']


35
36
37
# File 'lib/slave_pools/connection_proxy.rb', line 35

def master_models
  @master_models
end

Instance Attribute Details

#currentObject

Returns the value of attribute current.



22
23
24
# File 'lib/slave_pools/connection_proxy.rb', line 22

def current
  @current
end

#current_poolObject

Returns the value of attribute current_pool.



22
23
24
# File 'lib/slave_pools/connection_proxy.rb', line 22

def current_pool
  @current_pool
end

#masterObject

Returns the value of attribute master.



21
22
23
# File 'lib/slave_pools/connection_proxy.rb', line 21

def master
  @master
end

#master_depthObject

Returns the value of attribute master_depth.



22
23
24
# File 'lib/slave_pools/connection_proxy.rb', line 22

def master_depth
  @master_depth
end

Class Method Details

.setup!Object

Replaces the connection of ActiveRecord::Base with a proxy and establishes the connections to the slaves.



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/slave_pools/connection_proxy.rb', line 48

def setup!
  self.master_models ||= DEFAULT_MASTER_MODELS
  self.environment   ||= (defined?(Rails.env) ? Rails.env : 'development')

  slave_pools = init_slave_pools
  # if there are no slave pools, we just want to silently exit and not edit the ActiveRecord::Base.connection
  if !slave_pools.empty?
    master = ActiveRecord::Base
    master.send :include, SlavePoolsModule::ActiveRecordExtensions
    ActiveRecord::Observer.send :include, SlavePoolsModule::ObserverExtensions

    master.connection_proxy = new(master, slave_pools)
    master.logger.info("** slave_pools with master and #{slave_pools.length} slave_pool#{"s" if slave_pools.length > 1} (#{slave_pools.keys}) loaded.")
  else
    ActiveRecord::Base.logger.info(" No Slave Pools specified for this environment") #this is currently not logging
  end
end

Instance Method Details

#default_poolObject



103
104
105
# File 'lib/slave_pools/connection_proxy.rb', line 103

def default_pool
  @slave_pools[:default] || @slave_pools.values.first #if there is no default specified, use the first pool found
end

#next_slave!Object

Switches to the next slave database for read operations. Fails over to the master database if all slaves are unavailable.



152
153
154
155
156
157
# File 'lib/slave_pools/connection_proxy.rb', line 152

def next_slave!
  return if within_master_block? # don't if in with_master block
  @current = @current_pool.next
rescue
  @current = @master
end

#slaveObject



111
112
113
# File 'lib/slave_pools/connection_proxy.rb', line 111

def slave
  @current_pool.current
end

#slave_poolsObject



107
108
109
# File 'lib/slave_pools/connection_proxy.rb', line 107

def slave_pools
  @slave_pools
end

#transaction(start_db_transaction = true, &block) ⇒ Object



138
139
140
# File 'lib/slave_pools/connection_proxy.rb', line 138

def transaction(start_db_transaction = true, &block)
  with_master { @master.retrieve_connection.transaction(start_db_transaction, &block) }
end

#with_masterObject



124
125
126
127
128
129
130
131
132
# File 'lib/slave_pools/connection_proxy.rb', line 124

def with_master
  @current = @master
  @master_depth += 1
  yield
ensure
  @master_depth -= 1
  @master_depth = 0 if @master_depth < 0 # ensure that master depth never gets below 0
  @current = slave if !within_master_block?
end

#with_pool(pool_name = 'default') ⇒ Object



115
116
117
118
119
120
121
122
# File 'lib/slave_pools/connection_proxy.rb', line 115

def with_pool(pool_name = 'default')
  @current_pool = @slave_pools[pool_name.to_sym] || default_pool
  @current = slave unless within_master_block?
  yield
ensure
  @current_pool = default_pool
  @current = slave unless within_master_block?
end

#within_master_block?Boolean

Returns:

  • (Boolean)


134
135
136
# File 'lib/slave_pools/connection_proxy.rb', line 134

def within_master_block?
  @master_depth > 0
end