Class: MultiDb::ConnectionProxy

Inherits:
Object
  • Object
show all
Extended by:
ThreadLocalAccessors
Includes:
ActiveRecord::ConnectionAdapters::QueryCache, QueryCacheCompat
Defined in:
lib/multi_db/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.

[ :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

#columns, #delete, #insert, #select_all, #update

Constructor Details

#initialize(master, slaves, scheduler = Scheduler) ⇒ ConnectionProxy

Returns a new instance of ConnectionProxy.



97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/multi_db/connection_proxy.rb', line 97

def initialize(master, slaves, scheduler = Scheduler)
  @slaves    = scheduler.new(slaves)
  @master    = master
  @reconnect = false
  @query_cache = {}
  if self.class.defaults_to_master
    self.current = @master
    self.master_depth = 1
  else
    self.current = @slaves.current
    self.master_depth = 0
  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



145
146
147
148
149
# File 'lib/multi_db/connection_proxy.rb', line 145

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

Class Attribute Details

.defaults_to_masterObject

if master should be the default db



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

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/multi_db/connection_proxy.rb', line 28

def environment
  @environment
end

.master_modelsObject

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

Example:

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


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

def master_models
  @master_models
end

.sticky_slaveObject

decides if we should switch to the next reader automatically. If set to false, an after|before_filter in the ApplicationController has to do this. This will not affect failover if a master is unavailable.



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

def sticky_slave
  @sticky_slave
end

Instance Attribute Details

#masterObject

Returns the value of attribute master.



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

def master
  @master
end

Class Method Details

.setup!(scheduler = Scheduler) ⇒ 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
# File 'lib/multi_db/connection_proxy.rb', line 48

def setup!(scheduler = Scheduler)
  self.master_models ||= DEFAULT_MASTER_MODELS
  self.environment   ||= (defined?(Rails) ? Rails.env : 'development')
  self.sticky_slave  ||= false
  
  master = ActiveRecord::Base
  slaves = init_slaves
  raise "No slaves databases defined for environment: #{self.environment}" if slaves.empty?
  master.send :include, MultiDb::ActiveRecordExtensions
  ActiveRecord::Observer.send :include, MultiDb::ObserverExtensions
  master.connection_proxy = new(master, slaves, scheduler)
  master.logger.info("** multi_db with master and #{slaves.length} slave#{"s" if slaves.length > 1} loaded.")
end

Instance Method Details

#next_reader!Object

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



153
154
155
156
157
158
159
# File 'lib/multi_db/connection_proxy.rb', line 153

def next_reader!
  return if  master_depth > 0  # don't if in with_master block
  self.current = @slaves.next
rescue Scheduler::NoMoreItems
  logger.warn "[MULTIDB] All slaves are blacklisted. Reading from master"
  self.current = @master
end

#schedulerObject



115
116
117
# File 'lib/multi_db/connection_proxy.rb', line 115

def scheduler
  @slaves
end

#slaveObject



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

def slave
  @slaves.current
end

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



139
140
141
# File 'lib/multi_db/connection_proxy.rb', line 139

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

#with_masterObject



120
121
122
123
124
125
126
127
# File 'lib/multi_db/connection_proxy.rb', line 120

def with_master
  self.current = @master
  self.master_depth += 1
  yield
ensure
  self.master_depth -= 1
  self.current = slave if (master_depth <= 0) 
end

#with_slaveObject



130
131
132
133
134
135
136
137
# File 'lib/multi_db/connection_proxy.rb', line 130

def with_slave
  self.current = slave
  self.master_depth -= 1
  yield
ensure
  self.master_depth += 1
  self.current = @master if (master_depth > 0)
end