r3042@asus: jeremy | 2005-11-13 01:51:08 -0800

MySQL active? and reconnect!  References #428.
 r3043@asus:  jeremy | 2005-11-13 01:58:28 -0800
 SQLite active? and reconnect!  References #428.
 r3044@asus:  jeremy | 2005-11-13 02:02:27 -0800
 Update CHANGELOG with admonishment regarding avoidance of the log method.


git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@3001 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
Jeremy Kemper 2005-11-13 10:03:03 +00:00
parent 44b64704dd
commit 680e4742be
4 changed files with 52 additions and 20 deletions

View File

@ -1,6 +1,6 @@
*SVN*
* When AbstractAdapter#log rescues an exception, attempt to detect and reconnect to an inactive database connection. Connection adapter must respond to the active? and reconnect! instance methods. Initial support for PostgreSQL. [Jeremy Kemper]
* When AbstractAdapter#log rescues an exception, attempt to detect and reconnect to an inactive database connection. Connection adapter must respond to the active? and reconnect! instance methods. Initial support for PostgreSQL, MySQL, and SQLite. Make certain that all statements which may need reconnection are performed within a logged block: for example, this means no avoiding log(sql, name) { } if @logger.nil? [Jeremy Kemper]
* Much faster Oracle column reflection. #2848 [Michael Schoen <schoenm@earthlink.net>]

View File

@ -22,6 +22,12 @@ module ActiveRecord
include Quoting, DatabaseStatements, SchemaStatements
@@row_even = true
@@reconnect_success = 0
@@reconnect_failure = 0
def self.reconnect_success_rate
@@reconnect_success.to_f / (@@reconnect_success + @@reconnect_failure)
end
def initialize(connection, logger = nil) #:nodoc:
@connection, @logger = connection, logger
@runtime = 0
@ -40,9 +46,8 @@ module ActiveRecord
end
def reset_runtime #:nodoc:
rt = @runtime
@runtime = 0
return rt
rt, @runtime = @runtime, 0
rt
end
protected
@ -100,7 +105,14 @@ module ActiveRecord
def reconnect_if_inactive!
if respond_to?(:active?) and respond_to?(:reconnect!)
reconnect! unless active?
raise ActiveRecord::ConnectionFailed unless active?
if active?
@@reconnect_success += 1
@logger.info "#{adapter_name} automatically reconnected. Success rate: #{'%.2f' % self.class.reconnect_success_rate}%" if @logger
else
@@reconnect_failure += 1
@logger.warn "#{adapter_name} automatic reconnection failed. Success rate: #{'%.2f' % self.class.reconnect_success_rate}%" if @logger
raise ActiveRecord::ConnectionFailed
end
else
@logger.warn "#{adapter_name} does not yet support automatic reconnection." if @logger
end

View File

@ -136,6 +136,25 @@ module ActiveRecord
end
# CONNECTION MANAGEMENT ====================================
def active?
@connection.stat if @connection.respond_to?(:stat)
true
rescue Mysql::Error
false
end
def reconnect!
if @connection.respond_to?(:ping)
@connection.ping
else
@connection.close rescue nil
@connection.real_connect(*@connection_options)
end
end
# DATABASE STATEMENTS ======================================
def select_all(sql, name = nil) #:nodoc:
@ -148,22 +167,10 @@ module ActiveRecord
end
def execute(sql, name = nil, retries = 2) #:nodoc:
unless @logger
@connection.query(sql)
else
log(sql, name) { @connection.query(sql) }
end
log(sql, name) { @connection.query(sql) }
rescue ActiveRecord::StatementInvalid => exception
if LOST_CONNECTION_ERROR_MESSAGES.any? { |msg| exception.message.split(":").first =~ /^#{msg}/ }
@connection.real_connect(*@connection_options)
unless @logger
@connection.query(sql)
else
@logger.info "Retrying invalid statement with reopened connection"
log(sql, name) { @connection.query(sql) }
end
elsif exception.message.split(":").first =~ /Packets out of order/
raise ActiveRecord::StatementInvalid, "'Packets out of order' error was received from the database. Please update your mysql bindings (gem update mysql) and read http://dev.mysql.com/doc/mysql/en/password-hashing.html for more information."
if exception.message.split(":").first =~ /Packets out of order/
raise ActiveRecord::StatementInvalid, "'Packets out of order' error was received from the database. Please update your mysql bindings (gem install mysql) and read http://dev.mysql.com/doc/mysql/en/password-hashing.html for more information. If you're on Windows, use the Instant Rails installer to get the updated mysql bindings."
else
raise
end

View File

@ -127,6 +127,19 @@ module ActiveRecord
end
# CONNECTION MANAGEMENT ====================================
def active?
# TODO: SQLite is an embedded db, it doesn't lose connections,
# but perhaps some of its exceptions merit a retry, such as
# LockedException.
true
end
def reconnect!
end
# DATABASE STATEMENTS ======================================
def execute(sql, name = nil) #:nodoc: