seamless_database_pool 1.0.5 → 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'rake'
3
3
  require 'rake/rdoctask'
4
+ require 'yaml'
4
5
 
5
6
  desc 'Default: run unit tests.'
6
7
  task :default => :test
@@ -11,17 +12,61 @@ begin
11
12
  Spec::Rake::SpecTask.new(:test) do |t|
12
13
  t.spec_files = FileList.new('spec/**/*_spec.rb')
13
14
  end
15
+
16
+ namespace :test do
17
+ desc "Run all tests including for all database adapters"
18
+ task :all do
19
+ save_val = ENV['TEST_ADAPTERS']
20
+ begin
21
+ ENV['TEST_ADAPTERS'] = YAML.load_file(File.expand_path("../spec/database.yml", __FILE__)).keys.join(' ')
22
+ Rake::Task["test"].execute
23
+ ensure
24
+ ENV['TEST_ADAPTERS'] = save_val
25
+ end
26
+ end
27
+
28
+ desc "Test all database adapters defined in database.yml or just the one specified in TEST_ADAPTERS"
29
+ task :adapters do
30
+ save_val = ENV['TEST_ADAPTERS']
31
+ begin
32
+ ENV['TEST_ADAPTERS'] ||= YAML.load_file(File.expand_path("../spec/database.yml", __FILE__)).keys.join(' ')
33
+ Rake::Task["test:adapters:specified"].execute
34
+ ensure
35
+ ENV['TEST_ADAPTERS'] = save_val
36
+ end
37
+ end
38
+
39
+ namespace :adapters do
40
+ desc "Internal task to run database adapter tests"
41
+ Spec::Rake::SpecTask.new(:specified) do |t|
42
+ t.spec_files = FileList.new('spec/connection_adapters_spec.rb')
43
+ end
44
+
45
+ YAML.load_file(File.expand_path("../spec/database.yml", __FILE__)).keys.each do |adapter_name|
46
+ desc "Test the #{adapter_name} database adapter"
47
+ task adapter_name do
48
+ save_val = ENV['TEST_ADAPTERS']
49
+ begin
50
+ ENV['TEST_ADAPTERS'] = adapter_name
51
+ Rake::Task["test:adapters:specified"].execute
52
+ ensure
53
+ ENV['TEST_ADAPTERS'] = save_val
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
14
59
  rescue LoadError
15
- tast :test do
16
- STDERR.puts "You must have rspec >= 1.2.9 to run the tests"
60
+ task :test do
61
+ STDERR.puts "You must have rspec >= 1.3.0 to run the tests"
17
62
  end
18
63
  end
19
64
 
20
65
  desc 'Generate documentation for seamless_database_pool.'
21
66
  Rake::RDocTask.new(:rdoc) do |rdoc|
22
67
  rdoc.rdoc_dir = 'rdoc'
23
- rdoc.options << '--title' << 'Seamless Database Pool' << '--line-numbers' << '--inline-source' << '--main' << 'README'
24
- rdoc.rdoc_files.include('README')
68
+ rdoc.options << '--title' << 'Seamless Database Pool' << '--line-numbers' << '--inline-source' << '--main' << 'README.rdoc'
69
+ rdoc.rdoc_files.include('README.rdoc')
25
70
  rdoc.rdoc_files.include('lib/**/*.rb')
26
71
  end
27
72
 
@@ -33,6 +78,9 @@ begin
33
78
  gem.email = "brian@embellishedvisions.com"
34
79
  gem.homepage = "http://github.com/bdurand/seamless_database_pool"
35
80
  gem.authors = ["Brian Durand"]
81
+ gem.files = FileList["lib/**/*", "spec/**/*", "README.rdoc", "Rakefile"].to_a
82
+ gem.has_rdoc = true
83
+ gem.extra_rdoc_files = ["README.rdoc"]
36
84
 
37
85
  gem.add_dependency('activerecord', '>= 2.2.2')
38
86
  gem.add_development_dependency('rspec', '>= 1.2.9')
@@ -1,73 +1,83 @@
1
1
  module ActiveRecord
2
2
  class Base
3
- def self.seamless_database_pool_connection (config)
4
- pool_weights = {}
5
-
6
- default_config = {:pool_weight => 1}.merge(config.merge(:adapter => config[:pool_adapter]))
7
- default_config.delete(:master)
8
- default_config.delete(:read_pool)
9
- default_config.delete(:pool_adapter)
10
-
11
- master_config = default_config.merge(config[:master].symbolize_keys)
12
- establish_adapter(master_config[:adapter])
13
- master_connection = send("#{master_config[:adapter]}_connection".to_sym, master_config)
14
- master_connection.class.send(:include, SeamlessDatabasePool::ConnectTimeout) unless master_connection.class.include?(SeamlessDatabasePool::ConnectTimeout)
15
- master_connection.connect_timeout = master_config[:connect_timeout]
16
- pool_weights[master_connection] = master_config[:pool_weight].to_i if master_config[:pool_weight].to_i > 0
17
-
18
- read_connections = []
19
- config[:read_pool].each do |read_config|
20
- read_config = default_config.merge(read_config.symbolize_keys)
21
- read_config[:pool_weight] = read_config[:pool_weight].to_i
22
- if read_config[:pool_weight] > 0
23
- establish_adapter(read_config[:adapter])
24
- conn = send("#{read_config[:adapter]}_connection".to_sym, read_config)
25
- conn.class.send(:include, SeamlessDatabasePool::ConnectTimeout) unless conn.class.include?(SeamlessDatabasePool::ConnectTimeout)
26
- conn.connect_timeout = read_config[:connect_timeout]
27
- read_connections << conn
28
- pool_weights[conn] = read_config[:pool_weight]
3
+ class << self
4
+ def seamless_database_pool_connection (config)
5
+ pool_weights = {}
6
+
7
+ config = config.with_indifferent_access
8
+ default_config = {:pool_weight => 1}.merge(config.merge(:adapter => config[:pool_adapter])).with_indifferent_access
9
+ default_config.delete(:master)
10
+ default_config.delete(:read_pool)
11
+ default_config.delete(:pool_adapter)
12
+
13
+ master_config = default_config.merge(config[:master]).with_indifferent_access
14
+ establish_adapter(master_config[:adapter])
15
+ master_connection = send("#{master_config[:adapter]}_connection".to_sym, master_config)
16
+ master_connection.class.send(:include, SeamlessDatabasePool::ConnectTimeout) unless master_connection.class.include?(SeamlessDatabasePool::ConnectTimeout)
17
+ master_connection.connect_timeout = master_config[:connect_timeout]
18
+ pool_weights[master_connection] = master_config[:pool_weight].to_i if master_config[:pool_weight].to_i > 0
19
+
20
+ read_connections = []
21
+ config[:read_pool].each do |read_config|
22
+ read_config = default_config.merge(read_config).with_indifferent_access
23
+ read_config[:pool_weight] = read_config[:pool_weight].to_i
24
+ if read_config[:pool_weight] > 0
25
+ establish_adapter(read_config[:adapter])
26
+ conn = send("#{read_config[:adapter]}_connection".to_sym, read_config)
27
+ conn.class.send(:include, SeamlessDatabasePool::ConnectTimeout) unless conn.class.include?(SeamlessDatabasePool::ConnectTimeout)
28
+ conn.connect_timeout = read_config[:connect_timeout]
29
+ read_connections << conn
30
+ pool_weights[conn] = read_config[:pool_weight]
31
+ end
32
+ end if config[:read_pool]
33
+
34
+ @seamless_database_pool_classes ||= {}
35
+ klass = @seamless_database_pool_classes[master_connection.class]
36
+ unless klass
37
+ klass = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter.adapter_class(master_connection)
38
+ @seamless_database_pool_classes[master_connection.class] = klass
29
39
  end
30
- end if config[:read_pool]
31
40
 
32
- @seamless_database_pool_classes ||= {}
33
- klass = @seamless_database_pool_classes[master_connection.class]
34
- unless klass
35
- klass = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter.adapter_class(master_connection)
36
- @seamless_database_pool_classes[master_connection.class] = klass
41
+ return klass.new(nil, logger, master_connection, read_connections, pool_weights)
37
42
  end
38
-
39
- return klass.new(nil, logger, master_connection, read_connections, pool_weights)
40
- end
41
43
 
42
- def self.establish_adapter (adapter)
43
- unless adapter then raise AdapterNotSpecified, "database configuration does not specify adapter" end
44
- raise AdapterNotFound, "database pool must specify adapters" if adapter == 'seamless_database_pool'
45
-
46
- begin
47
- require 'rubygems'
48
- gem "activerecord-#{adapter}-adapter"
49
- require "active_record/connection_adapters/#{adapter}_adapter"
50
- rescue LoadError
44
+ def establish_adapter (adapter)
45
+ raise AdapterNotSpecified.new("database configuration does not specify adapter") unless adapter
46
+ raise AdapterNotFound.new("database pool must specify adapters") if adapter == 'seamless_database_pool'
47
+
51
48
  begin
49
+ require 'rubygems'
50
+ gem "activerecord-#{adapter}-adapter"
52
51
  require "active_record/connection_adapters/#{adapter}_adapter"
53
52
  rescue LoadError
54
- raise "Please install the #{adapter} adapter: `gem install activerecord-#{adapter}-adapter` (#{$!})"
53
+ begin
54
+ require "active_record/connection_adapters/#{adapter}_adapter"
55
+ rescue LoadError
56
+ raise "Please install the #{adapter} adapter: `gem install activerecord-#{adapter}-adapter` (#{$!})"
57
+ end
55
58
  end
56
- end
57
59
 
58
- adapter_method = "#{adapter}_connection"
59
- if !respond_to?(adapter_method)
60
- raise AdapterNotFound, "database configuration specifies nonexistent #{adapter} adapter"
60
+ adapter_method = "#{adapter}_connection"
61
+ if !respond_to?(adapter_method)
62
+ raise AdapterNotFound, "database configuration specifies nonexistent #{adapter} adapter"
63
+ end
61
64
  end
62
65
  end
63
-
64
- # Force reload to use the master connection since it's probably being called for a reason.
65
- def reload_with_seamless_database_pool (options = nil)
66
- SeamlessDatabasePool.use_master_connection do
67
- reload_without_seamless_database_pool(options)
66
+
67
+ module SeamlessDatabasePoolBehavior
68
+ def self.included (base)
69
+ base.alias_method_chain(:reload, :seamless_database_pool)
70
+ end
71
+
72
+ # Force reload to use the master connection since it's probably being called for a reason.
73
+ def reload_with_seamless_database_pool (*args)
74
+ SeamlessDatabasePool.use_master_connection do
75
+ reload_without_seamless_database_pool(*args)
76
+ end
68
77
  end
69
78
  end
70
- alias_method_chain(:reload, :seamless_database_pool)
79
+
80
+ include(SeamlessDatabasePoolBehavior) unless include?(SeamlessDatabasePoolBehavior)
71
81
  end
72
82
 
73
83
  module ConnectionAdapters
@@ -78,25 +88,45 @@ module ActiveRecord
78
88
  # Create an anonymous class that extends this one and proxies methods to the pool connections.
79
89
  def self.adapter_class (master_connection)
80
90
  # Define methods to proxy to the appropriate pool
81
- read_only_methods = [:select_one, :select_all, :select_value, :select_values, :select_rows]
82
- master_methods = master_connection.public_methods(false) + master_connection.protected_methods(false) + master_connection.private_methods(false)
91
+ read_only_methods = [:select_one, :select_all, :select_value, :select_values, :select, :select_rows, :execute, :tables, :columns]
92
+ master_methods = []
93
+ master_connection_classes = [AbstractAdapter, Quoting, DatabaseStatements, SchemaStatements]
94
+ master_connection_classes << DatabaseLimits if const_defined?(:DatabaseLimits)
95
+ master_connection_class = master_connection.class
96
+ while ![Object, AbstractAdapter].include?(master_connection_class) do
97
+ master_connection_classes << master_connection_class
98
+ master_connection_class = master_connection_class.superclass
99
+ end
100
+ master_connection_classes.each do |connection_class|
101
+ master_methods.concat(connection_class.public_instance_methods(false))
102
+ master_methods.concat(connection_class.protected_instance_methods(false))
103
+ #master_methods.concat(connection_class.private_instance_methods(false))
104
+ end
105
+ master_methods.uniq!
83
106
  master_methods -= public_instance_methods(false) + protected_instance_methods(false) + private_instance_methods(false)
84
107
  master_methods = master_methods.collect{|m| m.to_sym}
85
108
  master_methods -= read_only_methods
86
- master_methods.delete(:transaction)
87
109
 
88
110
  klass = Class.new(self)
89
111
  master_methods.each do |method_name|
90
- klass.class_eval(%Q(
112
+ klass.class_eval %Q(
91
113
  def #{method_name}(*args, &block)
92
- begin
93
- proxy_connection_method(master_connection, :#{method_name}, :master, *args, &block)
94
- rescue DatabaseConnectionError => e
95
- raise e.wrapped_exception
114
+ use_master_connection do
115
+ return proxy_connection_method(master_connection, :#{method_name}, :master, *args, &block)
96
116
  end
97
117
  end
98
- ))
118
+ )
119
+ end
120
+
121
+ read_only_methods.each do |method_name|
122
+ klass.class_eval %Q(
123
+ def #{method_name}(*args, &block)
124
+ connection = @use_master ? master_connection : current_read_connection
125
+ proxy_connection_method(connection, :#{method_name}, :read, *args, &block)
126
+ end
127
+ )
99
128
  end
129
+ klass.send :protected, :select
100
130
 
101
131
  return klass
102
132
  end
@@ -115,7 +145,7 @@ module ActiveRecord
115
145
  end
116
146
 
117
147
  def adapter_name #:nodoc:
118
- 'Seamless Database Pool'
148
+ 'Seamless_Database_Pool'
119
149
  end
120
150
 
121
151
  # Returns an array of the master connection and the read pool connections
@@ -174,37 +204,6 @@ module ActiveRecord
174
204
  return SeamlessDatabasePool.read_only_connection(self)
175
205
  end
176
206
 
177
- def transaction(start_db_transaction = true)
178
- use_master_connection do
179
- master_connection.transaction(start_db_transaction) do
180
- yield if block_given?
181
- end
182
- end
183
- end
184
-
185
- # Returns the last auto-generated ID from the affected table.
186
- def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
187
- master_connection.insert(sql, name, pk, id_value, sequence_name)
188
- end
189
-
190
- # Executes the update statement and returns the number of rows affected.
191
- def update(sql, name = nil)
192
- master_connection.update(sql, name)
193
- end
194
-
195
- # Executes the delete statement and returns the number of rows affected.
196
- def delete(sql, name = nil)
197
- master_connection.delete(sql, name)
198
- end
199
-
200
- def execute (*args)
201
- proxy_connection_method(current_read_connection, :execute, :read, *args)
202
- end
203
-
204
- def select_rows(*args)
205
- proxy_connection_method(current_read_connection, :select_rows, :read, *args)
206
- end
207
-
208
207
  def using_master_connection?
209
208
  !!@use_master
210
209
  end
@@ -221,7 +220,6 @@ module ActiveRecord
221
220
  end
222
221
 
223
222
  class DatabaseConnectionError < StandardError
224
- attr_accessor :wrapped_exception
225
223
  end
226
224
 
227
225
  # This simple class puts an expire time on an array of connections. It is used so the a connection
@@ -237,7 +235,7 @@ module ActiveRecord
237
235
  end
238
236
 
239
237
  def expired?
240
- @expires < Time.now if @expires
238
+ @expires <= Time.now if @expires
241
239
  end
242
240
 
243
241
  def reconnect!
@@ -253,7 +251,7 @@ module ActiveRecord
253
251
  available = @available_read_connections.last
254
252
  if available.expired?
255
253
  begin
256
- available.reconnect!
254
+ available.reconnect!# unless available.active?
257
255
  rescue
258
256
  # Couldn't reconnect so try again in a little bit
259
257
  available.expires = 30.seconds.from_now
@@ -266,6 +264,15 @@ module ActiveRecord
266
264
  end
267
265
  end
268
266
 
267
+ def reset_available_read_connections
268
+ @available_read_connections.slice!(1, @available_read_connections.length)
269
+ @available_read_connections.first.connections.each do |connection|
270
+ unless connection.active?
271
+ connection.reconnect! rescue nil
272
+ end
273
+ end
274
+ end
275
+
269
276
  # Temporarily remove a connection from the read pool.
270
277
  def suppress_read_connection (conn, expire)
271
278
  available = available_read_connections
@@ -276,47 +283,31 @@ module ActiveRecord
276
283
 
277
284
  if connections.empty?
278
285
  # No connections available so we might as well try them all again
279
- @available_read_connections.slice!(1, @available_read_connections.length)
286
+ reset_available_read_connections
280
287
  else
281
288
  # Available connections will now not include the suppressed connection for a while
282
289
  @available_read_connections.push(AvailableConnections.new(connections, conn, expire.seconds.from_now))
283
290
  end
284
291
  end
285
292
 
286
- protected
293
+ private
287
294
 
288
- def select (*args)
289
- connection = current_read_connection
295
+ def proxy_connection_method (connection, method, proxy_type, *args, &block)
290
296
  begin
291
- proxy_connection_method(connection, :select, :read, *args)
292
- rescue DatabaseConnectionError => e
293
- unless using_master_connection?
294
- # Try again with a different connection if needed unless it could have a side effect
297
+ connection.send(method, *args, &block)
298
+ rescue => e
299
+ # If the statement was a read statement and it wasn't forced against the master connection
300
+ # try to reconnect if the connection is dead and then re-run the statement.
301
+ if proxy_type == :read and !using_master_connection?
295
302
  unless connection.active?
296
303
  suppress_read_connection(connection, 30)
297
304
  connection = current_read_connection
298
305
  SeamlessDatabasePool.set_persistent_read_connection(self, connection)
299
306
  end
300
- proxy_connection_method(connection, :select, :retry, *args)
307
+ proxy_connection_method(connection, method, :retry, *args, &block)
301
308
  else
302
- raise e.wrapped_exception
303
- end
304
- end
305
- end
306
-
307
- private
308
-
309
- def proxy_connection_method (connection, method, proxy_type, *args, &block)
310
- begin
311
- connection.send(method, *args, &block)
312
- rescue => e
313
- unless proxy_type == :retry or connection.active?
314
- connection.reconnect! rescue nil
315
- connection_error = DatabaseConnectionError.new
316
- connection_error.wrapped_exception = e
317
- raise connection_error
309
+ raise e
318
310
  end
319
- raise e
320
311
  end
321
312
  end
322
313
 
@@ -0,0 +1,27 @@
1
+ module Arel
2
+ module SqlCompiler
3
+ # Hook into arel to use the compiler used by the master connection.
4
+ class Seamless_Database_PoolCompiler < GenericCompiler
5
+ def self.new (relation)
6
+ @compiler_classes ||= {}
7
+ master_adapter = relation.engine.connection.master_connection.adapter_name
8
+ compiler_class = @compiler_classes[master_adapter]
9
+ unless compiler_class
10
+ begin
11
+ require "arel/engines/sql/compilers/#{master_adapter.downcase}_compiler"
12
+ rescue LoadError
13
+ begin
14
+ # try to load an externally defined compiler, in case this adapter has defined the compiler on its own.
15
+ require "#{master_adapter.downcase}/arel_compiler"
16
+ rescue LoadError
17
+ raise "#{master_adapter} is not supported by Arel."
18
+ end
19
+ end
20
+ compiler_class = Arel::SqlCompiler.const_get("#{master_adapter}Compiler")
21
+ @compiler_classes[master_adapter] = compiler_class
22
+ end
23
+ compiler_class.new(relation)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -2,6 +2,7 @@ require File.join(File.dirname(__FILE__), 'seamless_database_pool', 'connect_tim
2
2
  require File.join(File.dirname(__FILE__), 'seamless_database_pool', 'connection_statistics')
3
3
  require File.join(File.dirname(__FILE__), 'seamless_database_pool', 'controller_filter')
4
4
  require File.join(File.dirname(__FILE__), 'active_record', 'connection_adapters', 'seamless_database_pool_adapter')
5
+ $LOAD_PATH << File.dirname(__FILE__) unless $LOAD_PATH.include?(File.dirname(__FILE__))
5
6
 
6
7
  # This module allows setting the read pool connection type. Generally you will use one of
7
8
  #
@@ -17,97 +18,99 @@ module SeamlessDatabasePool
17
18
 
18
19
  READ_CONNECTION_METHODS = [:master, :persistent, :random]
19
20
 
20
- # Call this method to use a random connection from the read pool for every select statement.
21
- # This method is good if your replication is very fast. Otherwise there is a chance you could
22
- # get inconsistent results from one request to the next. This can result in mysterious failures
23
- # if your code selects a value in one statement and then uses in another statement. You can wind
24
- # up trying to use a value from one server that hasn't been replicated to another one yet.
25
- # This method is best if you have few processes which generate a lot of queries and you have
26
- # fast replication.
27
- def self.use_random_read_connection
28
- if block_given?
29
- set_read_only_connection_type(:random){yield}
30
- else
31
- Thread.current[:read_only_connection] = :random
21
+ class << self
22
+ # Call this method to use a random connection from the read pool for every select statement.
23
+ # This method is good if your replication is very fast. Otherwise there is a chance you could
24
+ # get inconsistent results from one request to the next. This can result in mysterious failures
25
+ # if your code selects a value in one statement and then uses in another statement. You can wind
26
+ # up trying to use a value from one server that hasn't been replicated to another one yet.
27
+ # This method is best if you have few processes which generate a lot of queries and you have
28
+ # fast replication.
29
+ def use_random_read_connection
30
+ if block_given?
31
+ set_read_only_connection_type(:random){yield}
32
+ else
33
+ Thread.current[:read_only_connection] = :random
34
+ end
32
35
  end
33
- end
34
36
 
35
- # Call this method to pick a random connection from the read pool and use it for all subsequent
36
- # select statements. This provides consistency from one select statement to the next. This
37
- # method should always be called with a block otherwise you can end up with an imbalanced read
38
- # pool. This method is best if you have lots of processes which have a relatively few select
39
- # statements or a slow replication mechanism. Generally this is the best method to use for web
40
- # applications.
41
- def self.use_persistent_read_connection
42
- if block_given?
43
- set_read_only_connection_type(:persistent){yield}
44
- else
45
- Thread.current[:read_only_connection] = {}
37
+ # Call this method to pick a random connection from the read pool and use it for all subsequent
38
+ # select statements. This provides consistency from one select statement to the next. This
39
+ # method should always be called with a block otherwise you can end up with an imbalanced read
40
+ # pool. This method is best if you have lots of processes which have a relatively few select
41
+ # statements or a slow replication mechanism. Generally this is the best method to use for web
42
+ # applications.
43
+ def use_persistent_read_connection
44
+ if block_given?
45
+ set_read_only_connection_type(:persistent){yield}
46
+ else
47
+ Thread.current[:read_only_connection] = {}
48
+ end
46
49
  end
47
- end
48
50
 
49
- # Call this method to use the master connection for all subsequent select statements. This
50
- # method is most useful when you are doing lots of updates since it guarantees consistency
51
- # if you do a select immediately after an update or insert.
52
- #
53
- # The master connection will also be used for selects inside any transaction blocks. It will
54
- # also be used if you pass :readonly => false to any ActiveRecord.find method.
55
- def self.use_master_connection
56
- if block_given?
57
- set_read_only_connection_type(:master){yield}
58
- else
59
- Thread.current[:read_only_connection] = :master
51
+ # Call this method to use the master connection for all subsequent select statements. This
52
+ # method is most useful when you are doing lots of updates since it guarantees consistency
53
+ # if you do a select immediately after an update or insert.
54
+ #
55
+ # The master connection will also be used for selects inside any transaction blocks. It will
56
+ # also be used if you pass :readonly => false to any ActiveRecord.find method.
57
+ def use_master_connection
58
+ if block_given?
59
+ set_read_only_connection_type(:master){yield}
60
+ else
61
+ Thread.current[:read_only_connection] = :master
62
+ end
60
63
  end
61
- end
62
64
 
63
- # Set the read only connection type to either :master, :random, or :persistent.
64
- def self.set_read_only_connection_type (connection_type)
65
- saved_connection = Thread.current[:read_only_connection]
66
- retval = nil
67
- begin
68
- connection_type = {} if connection_type == :persistent
69
- Thread.current[:read_only_connection] = connection_type
70
- retval = yield if block_given?
71
- ensure
72
- Thread.current[:read_only_connection] = saved_connection
65
+ # Set the read only connection type to either :master, :random, or :persistent.
66
+ def set_read_only_connection_type (connection_type)
67
+ saved_connection = Thread.current[:read_only_connection]
68
+ retval = nil
69
+ begin
70
+ connection_type = {} if connection_type == :persistent
71
+ Thread.current[:read_only_connection] = connection_type
72
+ retval = yield if block_given?
73
+ ensure
74
+ Thread.current[:read_only_connection] = saved_connection
75
+ end
76
+ return retval
73
77
  end
74
- return retval
75
- end
76
78
 
77
- # Get the read only connection type currently in use. Will be one of :master, :random, or :persistent.
78
- def self.read_only_connection_type (default = :master)
79
- connection_type = Thread.current[:read_only_connection] || default
80
- connection_type = :persistent if connection_type.kind_of?(Hash)
81
- return connection_type
82
- end
79
+ # Get the read only connection type currently in use. Will be one of :master, :random, or :persistent.
80
+ def read_only_connection_type (default = :master)
81
+ connection_type = Thread.current[:read_only_connection] || default
82
+ connection_type = :persistent if connection_type.kind_of?(Hash)
83
+ return connection_type
84
+ end
83
85
 
84
- # Get a read only connection from a connection pool.
85
- def self.read_only_connection (pool_connection)
86
- return pool_connection.master_connection if pool_connection.using_master_connection?
87
- connection_type = Thread.current[:read_only_connection]
86
+ # Get a read only connection from a connection pool.
87
+ def read_only_connection (pool_connection)
88
+ return pool_connection.master_connection if pool_connection.using_master_connection?
89
+ connection_type = Thread.current[:read_only_connection]
88
90
 
89
- if connection_type.kind_of?(Hash)
90
- connection = connection_type[pool_connection]
91
- unless connection
92
- connection = pool_connection.random_read_connection
93
- connection_type[pool_connection] = connection
91
+ if connection_type.kind_of?(Hash)
92
+ connection = connection_type[pool_connection]
93
+ unless connection
94
+ connection = pool_connection.random_read_connection
95
+ connection_type[pool_connection] = connection
96
+ end
97
+ return connection
98
+ elsif connection_type == :random
99
+ return pool_connection.random_read_connection
100
+ else
101
+ return pool_connection.master_connection
94
102
  end
95
- return connection
96
- elsif connection_type == :random
97
- return pool_connection.random_read_connection
98
- else
99
- return pool_connection.master_connection
100
103
  end
101
- end
102
104
 
103
- # This method is provided as a way to change the persistent connection when it fails and a new one is substituted.
104
- def self.set_persistent_read_connection (pool_connection, read_connection)
105
- connection_type = Thread.current[:read_only_connection]
106
- connection_type[pool_connection] = read_connection if connection_type.kind_of?(Hash)
107
- end
105
+ # This method is provided as a way to change the persistent connection when it fails and a new one is substituted.
106
+ def set_persistent_read_connection (pool_connection, read_connection)
107
+ connection_type = Thread.current[:read_only_connection]
108
+ connection_type[pool_connection] = read_connection if connection_type.kind_of?(Hash)
109
+ end
108
110
 
109
- def self.clear_read_only_connection
110
- Thread.current[:read_only_connection] = nil
111
+ def clear_read_only_connection
112
+ Thread.current[:read_only_connection] = nil
113
+ end
111
114
  end
112
115
 
113
116
  end