Split connection handler into single- and multiple-thread versions.

This commit is contained in:
Nick Sieger
2008-06-07 16:30:56 -05:00
parent ff97e9d029
commit 72d959d9b5
2 changed files with 57 additions and 31 deletions

View File

@@ -134,18 +134,17 @@ module ActiveRecord
end
end
class ConnectionHandler
attr_reader :connection_pools_lock
module ConnectionHandlerMethods
def initialize(pools = {})
@connection_pools = pools
end
def initialize
@connection_pools = {}
@connection_pools_lock = Monitor.new
def connection_pools
@connection_pools ||= {}
end
def establish_connection(name, spec)
connection_pools_lock.synchronize do
@connection_pools[name] = ConnectionAdapters::ConnectionPool.new(spec)
end
@connection_pools[name] = ConnectionAdapters::ConnectionPool.new(spec)
end
# for internal use only and for testing
@@ -168,7 +167,7 @@ module ActiveRecord
end
def clear_all_connections!
clear_cache!(@connection_pools) {|name, pool| pool.disconnect! }
@connection_pools.each_value {|pool| pool.disconnect! }
end
# Verify active connections.
@@ -185,15 +184,6 @@ module ActiveRecord
(pool && pool.connection) or raise ConnectionNotEstablished
end
def retrieve_connection_pool(klass)
loop do
pool = @connection_pools[klass.name]
return pool if pool
return nil if ActiveRecord::Base == klass
klass = klass.superclass
end
end
# Returns true if a connection that's accessible to this class has already been opened.
def connected?(klass)
retrieve_connection_pool(klass).connected?
@@ -210,16 +200,40 @@ module ActiveRecord
pool.spec.config if pool
end
synchronize :retrieve_connection, :retrieve_connection_pool, :connected?,
:remove_connection, :active_connections, :clear_active_connections!,
:clear_reloadable_connections!, :clear_all_connections!,
:verify_active_connections!, :with => :connection_pools_lock
private
def clear_cache!(cache, &block)
cache.each(&block) if block_given?
cache.clear
def retrieve_connection_pool(klass)
loop do
pool = @connection_pools[klass.name]
return pool if pool
return nil if ActiveRecord::Base == klass
klass = klass.superclass
end
end
end
# This connection handler is not thread-safe, as it does not protect access
# to the underlying connection pools.
class SingleThreadConnectionHandler
include ConnectionHandlerMethods
end
# This connection handler is thread-safe. Each access or modification of a thread
# pool is synchronized by an internal monitor.
class MultipleThreadConnectionHandler
attr_reader :connection_pools_lock
include ConnectionHandlerMethods
def initialize(pools = {})
super
@connection_pools_lock = Monitor.new
end
# Apply monitor to all public methods that access the pool.
synchronize :establish_connection, :retrieve_connection,
:connected?, :remove_connection, :active_connections,
:clear_active_connections!, :clear_reloadable_connections!,
:clear_all_connections!, :verify_active_connections!,
:with => :connection_pools_lock
end
end
end

View File

@@ -14,12 +14,24 @@ module ActiveRecord
# The connection handler
cattr_accessor :connection_handler, :instance_writer => false
@@connection_handler = ConnectionAdapters::ConnectionHandler.new
@@connection_handler = ConnectionAdapters::SingleThreadConnectionHandler.new
# Turning on allow_concurrency basically switches a null mutex for a real one, so that
# multi-threaded access of the connection pools hash is synchronized.
# Turning on allow_concurrency changes the single threaded connection handler
# for a multiple threaded one, so that multi-threaded access of the
# connection pools is synchronized.
def self.allow_concurrency=(flag)
@@allow_concurrency = flag
if @@allow_concurrency != flag
@@allow_concurrency = flag
# When switching connection handlers, preserve the existing pools so that
# #establish_connection doesn't need to be called again.
if @@allow_concurrency
self.connection_handler = ConnectionAdapters::MultipleThreadConnectionHandler.new(
self.connection_handler.connection_pools)
else
self.connection_handler = ConnectionAdapters::SingleThreadConnectionHandler.new(
self.connection_handler.connection_pools)
end
end
end
# Returns the connection currently associated with the class. This can
@@ -112,7 +124,7 @@ module ActiveRecord
connection_handler.connected?(self)
end
def remove_connection(klass=self)
def remove_connection(klass = self)
connection_handler.remove_connection(klass)
end