aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--activerecord/CHANGELOG2
-rwxr-xr-xactiverecord/lib/active_record/connection_adapters/abstract_adapter.rb20
-rwxr-xr-xactiverecord/lib/active_record/connection_adapters/mysql_adapter.rb37
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb13
4 files changed, 52 insertions, 20 deletions
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index 2543a2080d..679cdaadf6 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -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>]
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index 7290f2e87e..6b61c92de8 100755
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -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
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index ca410c4add..d58590677b 100755
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -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
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
index adb60cd49f..2c302d7414 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
@@ -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: