diff options
Diffstat (limited to 'activerecord/lib/active_record/connection_adapters')
4 files changed, 26 insertions, 19 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb index 4ba8ee2706..f437dafec2 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -298,7 +298,7 @@ module ActiveRecord def run return unless frequency Thread.new(frequency, pool) { |t, p| - while true + loop do sleep t p.reap end @@ -618,7 +618,7 @@ module ActiveRecord timeout_time = Time.now + (@checkout_timeout * 2) @available.with_a_bias_for(Thread.current) do - while true + loop do synchronize do return if collected_conns.size == @connections.size && @now_connecting == 0 remaining_timeout = timeout_time - Time.now @@ -826,9 +826,7 @@ module ActiveRecord # in order to lookup the correct connection pool. class ConnectionHandler def initialize - # These caches are keyed by klass.name, NOT klass. Keying them by klass - # alone would lead to memory leaks in development mode as all previous - # instances of the class would stay in memory. + # These caches are keyed by spec.name (ConnectionSpecification#name). @owner_to_pool = Concurrent::Map.new(:initial_capacity => 2) do |h,k| h[k] = Concurrent::Map.new(:initial_capacity => 2) end @@ -898,17 +896,13 @@ module ActiveRecord end end - # Retrieving the connection pool happens a lot so we cache it in @class_to_pool. + # Retrieving the connection pool happens a lot, so we cache it in @owner_to_pool. # This makes retrieving the connection pool O(1) once the process is warm. # When a connection is established or removed, we invalidate the cache. - # - # Ideally we would use #fetch here, as class_to_pool[klass] may sometimes be nil. - # However, benchmarking (https://gist.github.com/jonleighton/3552829) showed that - # #fetch is significantly slower than #[]. So in the nil case, no caching will - # take place, but that's ok since the nil case is not the common one that we wish - # to optimise for. def retrieve_connection_pool(spec_name) owner_to_pool.fetch(spec_name) do + # Check if a connection was previously established in an ancestor process, + # which may have been forked. if ancestor_pool = pool_from_any_process_for(spec_name) # A connection was established in an ancestor process that must have # subsequently forked. We can't reuse the connection, but we can copy diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index 4eb009c873..44b4b547f3 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -146,11 +146,11 @@ module ActiveRecord end def get_advisory_lock(lock_name, timeout = 0) # :nodoc: - select_value("SELECT GET_LOCK('#{lock_name}', #{timeout});").to_s == '1' + select_value("SELECT GET_LOCK(#{quote(lock_name)}, #{timeout})") == 1 end def release_advisory_lock(lock_name) # :nodoc: - select_value("SELECT RELEASE_LOCK('#{lock_name}')").to_s == '1' + select_value("SELECT RELEASE_LOCK(#{quote(lock_name)})") == 1 end def native_database_types @@ -707,7 +707,7 @@ module ActiveRecord case length when Hash column_names.each {|name| option_strings[name] += "(#{length[name]})" if length.has_key?(name) && length[name].present?} - when Fixnum + when Integer column_names.each {|name| option_strings[name] += "(#{length})"} end end @@ -727,14 +727,22 @@ module ActiveRecord column_names.map {|name| quote_column_name(name) + option_strings[name]} end + # See https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html + ER_DUP_ENTRY = 1062 + ER_NO_REFERENCED_ROW_2 = 1452 + ER_DATA_TOO_LONG = 1406 + ER_LOCK_DEADLOCK = 1213 + def translate_exception(exception, message) case error_number(exception) - when 1062 + when ER_DUP_ENTRY RecordNotUnique.new(message) - when 1452 + when ER_NO_REFERENCED_ROW_2 InvalidForeignKey.new(message) - when 1406 + when ER_DATA_TOO_LONG ValueTooLong.new(message) + when ER_LOCK_DEADLOCK + TransactionSerializationError.new(message) else super end @@ -832,7 +840,7 @@ module ActiveRecord # Increase timeout so the server doesn't disconnect us. wait_timeout = @config[:wait_timeout] - wait_timeout = 2147483 unless wait_timeout.is_a?(Fixnum) + wait_timeout = 2147483 unless wait_timeout.is_a?(Integer) variables['wait_timeout'] = self.class.type_cast_config_to_integer(wait_timeout) defaults = [':default', :default].to_set diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb index 7427a25ad5..4da240edb2 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb @@ -14,6 +14,8 @@ module ActiveRecord def cast(value) case value when ::String + return if value.blank? + if value[0] == '(' && value[-1] == ')' value = value[1...-1] end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index bab80a8890..ddfc560747 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -406,6 +406,7 @@ module ActiveRecord VALUE_LIMIT_VIOLATION = "22001" FOREIGN_KEY_VIOLATION = "23503" UNIQUE_VIOLATION = "23505" + SERIALIZATION_FAILURE = "40001" def translate_exception(exception, message) return exception unless exception.respond_to?(:result) @@ -417,6 +418,8 @@ module ActiveRecord InvalidForeignKey.new(message) when VALUE_LIMIT_VIOLATION ValueTooLong.new(message) + when SERIALIZATION_FAILURE + TransactionSerializationError.new(message) else super end |