activerecord 5.0.0.1 → 5.0.1.rc1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +196 -2
- data/README.rdoc +1 -1
- data/lib/active_record.rb +1 -1
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/association_relation.rb +4 -1
- data/lib/active_record/associations.rb +5 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +4 -2
- data/lib/active_record/associations/builder/singular_association.rb +10 -1
- data/lib/active_record/associations/collection_association.rb +22 -17
- data/lib/active_record/associations/collection_proxy.rb +20 -7
- data/lib/active_record/associations/has_many_through_association.rb +4 -0
- data/lib/active_record/associations/join_dependency.rb +10 -4
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader/association.rb +18 -4
- data/lib/active_record/associations/preloader/collection_association.rb +0 -1
- data/lib/active_record/associations/preloader/singular_association.rb +0 -1
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/attribute.rb +3 -3
- data/lib/active_record/attribute_methods.rb +3 -7
- data/lib/active_record/attribute_methods/primary_key.rb +14 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
- data/lib/active_record/attribute_set.rb +2 -0
- data/lib/active_record/attribute_set/builder.rb +29 -7
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +15 -11
- data/lib/active_record/base.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +40 -32
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +29 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +8 -7
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +37 -33
- data/lib/active_record/connection_adapters/abstract_adapter.rb +28 -5
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +42 -45
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +6 -23
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -5
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +12 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +7 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +6 -2
- data/lib/active_record/core.rb +3 -1
- data/lib/active_record/enum.rb +6 -5
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/integration.rb +13 -10
- data/lib/active_record/migration.rb +6 -5
- data/lib/active_record/model_schema.rb +134 -47
- data/lib/active_record/no_touching.rb +4 -0
- data/lib/active_record/persistence.rb +10 -4
- data/lib/active_record/query_cache.rb +13 -15
- data/lib/active_record/querying.rb +3 -3
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/reflection.rb +8 -0
- data/lib/active_record/relation.rb +7 -4
- data/lib/active_record/relation/calculations.rb +11 -11
- data/lib/active_record/relation/delegation.rb +1 -1
- data/lib/active_record/relation/finder_methods.rb +11 -9
- data/lib/active_record/relation/query_methods.rb +3 -3
- data/lib/active_record/result.rb +7 -1
- data/lib/active_record/sanitization.rb +11 -1
- data/lib/active_record/schema_dumper.rb +10 -17
- data/lib/active_record/scoping/named.rb +1 -1
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/table_metadata.rb +4 -3
- data/lib/active_record/touch_later.rb +6 -1
- data/lib/active_record/type/internal/abstract_json.rb +5 -1
- data/lib/active_record/validations/uniqueness.rb +3 -4
- metadata +9 -10
@@ -272,7 +272,11 @@ module ActiveRecord
|
|
272
272
|
construct(model, node, row, rs, seen, model_cache, aliases)
|
273
273
|
else
|
274
274
|
model = construct_model(ar_parent, node, row, model_cache, id, aliases)
|
275
|
-
|
275
|
+
|
276
|
+
if node.reflection.scope_for(node.base_klass).readonly_value
|
277
|
+
model.readonly!
|
278
|
+
end
|
279
|
+
|
276
280
|
seen[ar_parent.object_id][node.base_klass][id] = model
|
277
281
|
construct(model, node, row, rs, seen, model_cache, aliases)
|
278
282
|
end
|
@@ -280,17 +284,19 @@ module ActiveRecord
|
|
280
284
|
end
|
281
285
|
|
282
286
|
def construct_model(record, node, row, model_cache, id, aliases)
|
283
|
-
model = model_cache[node][id] ||= node.instantiate(row,
|
284
|
-
aliases.column_aliases(node))
|
285
287
|
other = record.association(node.reflection.name)
|
286
288
|
|
289
|
+
model = model_cache[node][id] ||=
|
290
|
+
node.instantiate(row, aliases.column_aliases(node)) do |m|
|
291
|
+
other.set_inverse_instance(m)
|
292
|
+
end
|
293
|
+
|
287
294
|
if node.reflection.collection?
|
288
295
|
other.target.push(model)
|
289
296
|
else
|
290
297
|
other.target = model
|
291
298
|
end
|
292
299
|
|
293
|
-
other.set_inverse_instance(model)
|
294
300
|
model
|
295
301
|
end
|
296
302
|
end
|
@@ -62,7 +62,12 @@ module ActiveRecord
|
|
62
62
|
private
|
63
63
|
|
64
64
|
def associated_records_by_owner(preloader)
|
65
|
-
records = load_records
|
65
|
+
records = load_records do |record|
|
66
|
+
owner = owners_by_key[convert_key(record[association_key_name])]
|
67
|
+
association = owner.association(reflection.name)
|
68
|
+
association.set_inverse_instance(record)
|
69
|
+
end
|
70
|
+
|
66
71
|
owners.each_with_object({}) do |owner, result|
|
67
72
|
result[owner] = records[convert_key(owner[owner_key_name])] || []
|
68
73
|
end
|
@@ -79,6 +84,15 @@ module ActiveRecord
|
|
79
84
|
@owner_keys
|
80
85
|
end
|
81
86
|
|
87
|
+
def owners_by_key
|
88
|
+
unless defined?(@owners_by_key)
|
89
|
+
@owners_by_key = owners.each_with_object({}) do |owner, h|
|
90
|
+
h[convert_key(owner[owner_key_name])] = owner
|
91
|
+
end
|
92
|
+
end
|
93
|
+
@owners_by_key
|
94
|
+
end
|
95
|
+
|
82
96
|
def key_conversion_required?
|
83
97
|
@key_conversion_required ||= association_key_type != owner_key_type
|
84
98
|
end
|
@@ -99,13 +113,13 @@ module ActiveRecord
|
|
99
113
|
@model.type_for_attribute(owner_key_name.to_s).type
|
100
114
|
end
|
101
115
|
|
102
|
-
def load_records
|
116
|
+
def load_records(&block)
|
103
117
|
return {} if owner_keys.empty?
|
104
118
|
# Some databases impose a limit on the number of ids in a list (in Oracle it's 1000)
|
105
119
|
# Make several smaller queries if necessary or make one query if the adapter supports it
|
106
120
|
slices = owner_keys.each_slice(klass.connection.in_clause_length || owner_keys.size)
|
107
121
|
@preloaded_records = slices.flat_map do |slice|
|
108
|
-
records_for(slice)
|
122
|
+
records_for(slice).load(&block)
|
109
123
|
end
|
110
124
|
@preloaded_records.group_by do |record|
|
111
125
|
convert_key(record[association_key_name])
|
@@ -113,7 +127,7 @@ module ActiveRecord
|
|
113
127
|
end
|
114
128
|
|
115
129
|
def reflection_scope
|
116
|
-
@reflection_scope ||= reflection.
|
130
|
+
@reflection_scope ||= reflection.scope_for(klass)
|
117
131
|
end
|
118
132
|
|
119
133
|
def build_scope
|
@@ -6,8 +6,7 @@ module ActiveRecord
|
|
6
6
|
if force_reload && klass
|
7
7
|
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
8
8
|
Passing an argument to force an association to reload is now
|
9
|
-
deprecated and will be removed in Rails 5.1. Please call `
|
10
|
-
on the parent object instead.
|
9
|
+
deprecated and will be removed in Rails 5.1. Please call `reload_#{reflection.name}` instead.
|
11
10
|
MSG
|
12
11
|
|
13
12
|
klass.uncached { reload }
|
@@ -38,6 +37,13 @@ module ActiveRecord
|
|
38
37
|
record
|
39
38
|
end
|
40
39
|
|
40
|
+
# Implements the reload reader method, e.g. foo.reload_bar for
|
41
|
+
# Foo.has_one :bar
|
42
|
+
def force_reload_reader
|
43
|
+
klass.uncached { reload }
|
44
|
+
target
|
45
|
+
end
|
46
|
+
|
41
47
|
private
|
42
48
|
|
43
49
|
def create_scope
|
@@ -65,7 +65,7 @@ module ActiveRecord
|
|
65
65
|
|
66
66
|
def with_value_from_user(value)
|
67
67
|
type.assert_valid_value(value)
|
68
|
-
self.class.from_user(name, value, type, self)
|
68
|
+
self.class.from_user(name, value, type, original_attribute || self)
|
69
69
|
end
|
70
70
|
|
71
71
|
def with_value_from_database(value)
|
@@ -132,7 +132,7 @@ module ActiveRecord
|
|
132
132
|
end
|
133
133
|
|
134
134
|
def _original_value_for_database
|
135
|
-
|
135
|
+
type.serialize(original_value)
|
136
136
|
end
|
137
137
|
|
138
138
|
class FromDatabase < Attribute # :nodoc:
|
@@ -160,7 +160,7 @@ module ActiveRecord
|
|
160
160
|
value
|
161
161
|
end
|
162
162
|
|
163
|
-
def
|
163
|
+
def changed_in_place?
|
164
164
|
false
|
165
165
|
end
|
166
166
|
end
|
@@ -279,9 +279,8 @@ module ActiveRecord
|
|
279
279
|
# Returns an <tt>#inspect</tt>-like string for the value of the
|
280
280
|
# attribute +attr_name+. String attributes are truncated up to 50
|
281
281
|
# characters, Date and Time attributes are returned in the
|
282
|
-
# <tt>:db</tt> format
|
283
|
-
#
|
284
|
-
# modification.
|
282
|
+
# <tt>:db</tt> format. Other attributes return the value of
|
283
|
+
# <tt>#inspect</tt> without modification.
|
285
284
|
#
|
286
285
|
# person = Person.create!(name: 'David Heinemeier Hansson ' * 3)
|
287
286
|
#
|
@@ -292,7 +291,7 @@ module ActiveRecord
|
|
292
291
|
# # => "\"2012-10-22 00:15:07\""
|
293
292
|
#
|
294
293
|
# person.attribute_for_inspect(:tag_ids)
|
295
|
-
# # => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
294
|
+
# # => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]"
|
296
295
|
def attribute_for_inspect(attr_name)
|
297
296
|
value = read_attribute(attr_name)
|
298
297
|
|
@@ -300,9 +299,6 @@ module ActiveRecord
|
|
300
299
|
"#{value[0, 50]}...".inspect
|
301
300
|
elsif value.is_a?(Date) || value.is_a?(Time)
|
302
301
|
%("#{value.to_s(:db)}")
|
303
|
-
elsif value.is_a?(Array) && value.size > 10
|
304
|
-
inspected = value.first(10).inspect
|
305
|
-
%(#{inspected[0...-1]}, ...])
|
306
302
|
else
|
307
303
|
value.inspect
|
308
304
|
end
|
@@ -95,7 +95,8 @@ module ActiveRecord
|
|
95
95
|
base_name.foreign_key
|
96
96
|
else
|
97
97
|
if ActiveRecord::Base != self && table_exists?
|
98
|
-
connection.schema_cache.primary_keys(table_name)
|
98
|
+
pk = connection.schema_cache.primary_keys(table_name)
|
99
|
+
suppress_composite_primary_key(pk)
|
99
100
|
else
|
100
101
|
'id'
|
101
102
|
end
|
@@ -122,6 +123,18 @@ module ActiveRecord
|
|
122
123
|
@quoted_primary_key = nil
|
123
124
|
@attributes_builder = nil
|
124
125
|
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
def suppress_composite_primary_key(pk)
|
130
|
+
return pk unless pk.is_a?(Array)
|
131
|
+
|
132
|
+
warn <<-WARNING.strip_heredoc
|
133
|
+
WARNING: Active Record does not support composite primary key.
|
134
|
+
|
135
|
+
#{table_name} has composite primary key. Composite primary key is ignored.
|
136
|
+
WARNING
|
137
|
+
end
|
125
138
|
end
|
126
139
|
end
|
127
140
|
end
|
@@ -3,11 +3,12 @@ require 'active_record/attribute'
|
|
3
3
|
module ActiveRecord
|
4
4
|
class AttributeSet # :nodoc:
|
5
5
|
class Builder # :nodoc:
|
6
|
-
attr_reader :types, :always_initialized
|
6
|
+
attr_reader :types, :always_initialized, :default
|
7
7
|
|
8
|
-
def initialize(types, always_initialized = nil)
|
8
|
+
def initialize(types, always_initialized = nil, &default)
|
9
9
|
@types = types
|
10
10
|
@always_initialized = always_initialized
|
11
|
+
@default = default
|
11
12
|
end
|
12
13
|
|
13
14
|
def build_from_database(values = {}, additional_types = {})
|
@@ -15,21 +16,22 @@ module ActiveRecord
|
|
15
16
|
values[always_initialized] = nil
|
16
17
|
end
|
17
18
|
|
18
|
-
attributes = LazyAttributeHash.new(types, values, additional_types)
|
19
|
+
attributes = LazyAttributeHash.new(types, values, additional_types, &default)
|
19
20
|
AttributeSet.new(attributes)
|
20
21
|
end
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
24
25
|
class LazyAttributeHash # :nodoc:
|
25
|
-
delegate :transform_values, :each_key, to: :materialize
|
26
|
+
delegate :transform_values, :each_key, :fetch, to: :materialize
|
26
27
|
|
27
|
-
def initialize(types, values, additional_types)
|
28
|
+
def initialize(types, values, additional_types, &default)
|
28
29
|
@types = types
|
29
30
|
@values = values
|
30
31
|
@additional_types = additional_types
|
31
32
|
@materialized = false
|
32
33
|
@delegate_hash = {}
|
34
|
+
@default = default || proc {}
|
33
35
|
end
|
34
36
|
|
35
37
|
def key?(key)
|
@@ -76,9 +78,29 @@ module ActiveRecord
|
|
76
78
|
end
|
77
79
|
end
|
78
80
|
|
81
|
+
def marshal_dump
|
82
|
+
materialize
|
83
|
+
end
|
84
|
+
|
85
|
+
def marshal_load(delegate_hash)
|
86
|
+
@delegate_hash = delegate_hash
|
87
|
+
@types = {}
|
88
|
+
@values = {}
|
89
|
+
@additional_types = {}
|
90
|
+
@materialized = true
|
91
|
+
end
|
92
|
+
|
93
|
+
def encode_with(coder)
|
94
|
+
coder["delegate_hash"] = materialize
|
95
|
+
end
|
96
|
+
|
97
|
+
def init_with(coder)
|
98
|
+
marshal_load(coder["delegate_hash"])
|
99
|
+
end
|
100
|
+
|
79
101
|
protected
|
80
102
|
|
81
|
-
attr_reader :types, :values, :additional_types, :delegate_hash
|
103
|
+
attr_reader :types, :values, :additional_types, :delegate_hash, :default
|
82
104
|
|
83
105
|
def materialize
|
84
106
|
unless @materialized
|
@@ -101,7 +123,7 @@ module ActiveRecord
|
|
101
123
|
if value_present
|
102
124
|
delegate_hash[name] = Attribute.from_database(name, value, type)
|
103
125
|
elsif types.key?(name)
|
104
|
-
delegate_hash[name] = Attribute.uninitialized(name, type)
|
126
|
+
delegate_hash[name] = default.call(name) || Attribute.uninitialized(name, type)
|
105
127
|
end
|
106
128
|
end
|
107
129
|
end
|
@@ -34,10 +34,10 @@ module ActiveRecord
|
|
34
34
|
# is not passed, the previous default value (if any) will be used.
|
35
35
|
# Otherwise, the default will be +nil+.
|
36
36
|
#
|
37
|
-
# +array+ (
|
37
|
+
# +array+ (PostgreSQL only) specifies that the type should be an array (see the
|
38
38
|
# examples below).
|
39
39
|
#
|
40
|
-
# +range+ (
|
40
|
+
# +range+ (PostgreSQL only) specifies that the type should be a range (see the
|
41
41
|
# examples below).
|
42
42
|
#
|
43
43
|
# ==== Examples
|
@@ -253,7 +253,7 @@ module ActiveRecord
|
|
253
253
|
name,
|
254
254
|
value,
|
255
255
|
type,
|
256
|
-
_default_attributes
|
256
|
+
_default_attributes.fetch(name.to_s) { nil },
|
257
257
|
)
|
258
258
|
else
|
259
259
|
default_attribute = Attribute.from_database(name, value, type)
|
@@ -329,26 +329,20 @@ module ActiveRecord
|
|
329
329
|
return true if record.destroyed? || (reflection.options[:autosave] && record.marked_for_destruction?)
|
330
330
|
|
331
331
|
validation_context = self.validation_context unless [:create, :update].include?(self.validation_context)
|
332
|
+
|
332
333
|
unless valid = record.valid?(validation_context)
|
333
334
|
if reflection.options[:autosave]
|
334
335
|
indexed_attribute = !index.nil? && (reflection.options[:index_errors] || ActiveRecord::Base.index_nested_attribute_errors)
|
335
336
|
|
336
337
|
record.errors.each do |attribute, message|
|
337
|
-
|
338
|
-
attribute = "#{reflection.name}[#{index}].#{attribute}"
|
339
|
-
else
|
340
|
-
attribute = "#{reflection.name}.#{attribute}"
|
341
|
-
end
|
338
|
+
attribute = normalize_reflection_attribute(indexed_attribute, reflection, index, attribute)
|
342
339
|
errors[attribute] << message
|
343
340
|
errors[attribute].uniq!
|
344
341
|
end
|
345
342
|
|
346
343
|
record.errors.details.each_key do |attribute|
|
347
|
-
|
348
|
-
|
349
|
-
else
|
350
|
-
reflection_attribute = "#{reflection.name}.#{attribute}"
|
351
|
-
end
|
344
|
+
reflection_attribute =
|
345
|
+
normalize_reflection_attribute(indexed_attribute, reflection, index, attribute).to_sym
|
352
346
|
|
353
347
|
record.errors.details[attribute].each do |error|
|
354
348
|
errors.details[reflection_attribute] << error
|
@@ -362,6 +356,14 @@ module ActiveRecord
|
|
362
356
|
valid
|
363
357
|
end
|
364
358
|
|
359
|
+
def normalize_reflection_attribute(indexed_attribute, reflection, index, attribute)
|
360
|
+
if indexed_attribute
|
361
|
+
"#{reflection.name}[#{index}].#{attribute}"
|
362
|
+
else
|
363
|
+
"#{reflection.name}.#{attribute}"
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
365
367
|
# Is used as a before_save callback to check while saving a collection
|
366
368
|
# association whether or not the parent was a new record before saving.
|
367
369
|
def before_save_collection_association
|
@@ -457,7 +459,9 @@ module ActiveRecord
|
|
457
459
|
# In addition, it will destroy the association if it was marked for destruction.
|
458
460
|
def save_belongs_to_association(reflection)
|
459
461
|
association = association_instance_get(reflection.name)
|
460
|
-
|
462
|
+
return unless association && association.loaded? && !association.stale_target?
|
463
|
+
|
464
|
+
record = association.load_target
|
461
465
|
if record && !record.destroyed?
|
462
466
|
autosave = reflection.options[:autosave]
|
463
467
|
|
data/lib/active_record/base.rb
CHANGED
@@ -307,6 +307,7 @@ module ActiveRecord
|
|
307
307
|
end
|
308
308
|
|
309
309
|
include MonitorMixin
|
310
|
+
include QueryCache::ConnectionPoolConfiguration
|
310
311
|
|
311
312
|
attr_accessor :automatic_reconnect, :checkout_timeout, :schema_cache
|
312
313
|
attr_reader :spec, :connections, :size, :reaper
|
@@ -349,8 +350,7 @@ module ActiveRecord
|
|
349
350
|
# currently in the process of independently establishing connections to the DB.
|
350
351
|
@now_connecting = 0
|
351
352
|
|
352
|
-
|
353
|
-
@new_cons_enabled = true
|
353
|
+
@threads_blocking_new_connections = 0
|
354
354
|
|
355
355
|
@available = ConnectionLeasingQueue.new self
|
356
356
|
end
|
@@ -415,7 +415,10 @@ module ActiveRecord
|
|
415
415
|
with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
|
416
416
|
synchronize do
|
417
417
|
@connections.each do |conn|
|
418
|
-
|
418
|
+
if conn.in_use?
|
419
|
+
conn.steal!
|
420
|
+
checkin conn
|
421
|
+
end
|
419
422
|
conn.disconnect!
|
420
423
|
end
|
421
424
|
@connections = []
|
@@ -442,33 +445,19 @@ module ActiveRecord
|
|
442
445
|
# connections in the pool within a timeout interval (default duration is
|
443
446
|
# <tt>spec.config[:checkout_timeout] * 2</tt> seconds).
|
444
447
|
def clear_reloadable_connections(raise_on_acquisition_timeout = true)
|
445
|
-
num_new_conns_required = 0
|
446
|
-
|
447
448
|
with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
|
448
449
|
synchronize do
|
449
450
|
@connections.each do |conn|
|
450
|
-
|
451
|
+
if conn.in_use?
|
452
|
+
conn.steal!
|
453
|
+
checkin conn
|
454
|
+
end
|
451
455
|
conn.disconnect! if conn.requires_reloading?
|
452
456
|
end
|
453
457
|
@connections.delete_if(&:requires_reloading?)
|
454
|
-
|
455
458
|
@available.clear
|
456
|
-
|
457
|
-
if @connections.size < @size
|
458
|
-
# because of the pruning done by this method, we might be running
|
459
|
-
# low on connections, while threads stuck in queue are helpless
|
460
|
-
# (not being able to establish new connections for themselves),
|
461
|
-
# see also more detailed explanation in +remove+
|
462
|
-
num_new_conns_required = num_waiting_in_queue - @connections.size
|
463
|
-
end
|
464
|
-
|
465
|
-
@connections.each do |conn|
|
466
|
-
@available.add conn
|
467
|
-
end
|
468
459
|
end
|
469
460
|
end
|
470
|
-
|
471
|
-
bulk_make_new_connections(num_new_conns_required) if num_new_conns_required > 0
|
472
461
|
end
|
473
462
|
|
474
463
|
# Clears the cache which maps classes and re-connects connections that
|
@@ -556,17 +545,17 @@ module ActiveRecord
|
|
556
545
|
stale_connections = synchronize do
|
557
546
|
@connections.select do |conn|
|
558
547
|
conn.in_use? && !conn.owner.alive?
|
548
|
+
end.each do |conn|
|
549
|
+
conn.steal!
|
559
550
|
end
|
560
551
|
end
|
561
552
|
|
562
553
|
stale_connections.each do |conn|
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
remove conn
|
569
|
-
end
|
554
|
+
if conn.active?
|
555
|
+
conn.reset!
|
556
|
+
checkin conn
|
557
|
+
else
|
558
|
+
remove conn
|
570
559
|
end
|
571
560
|
end
|
572
561
|
end
|
@@ -675,13 +664,32 @@ module ActiveRecord
|
|
675
664
|
end
|
676
665
|
|
677
666
|
def with_new_connections_blocked
|
678
|
-
previous_value = nil
|
679
667
|
synchronize do
|
680
|
-
|
668
|
+
@threads_blocking_new_connections += 1
|
681
669
|
end
|
670
|
+
|
682
671
|
yield
|
683
672
|
ensure
|
684
|
-
|
673
|
+
num_new_conns_required = 0
|
674
|
+
|
675
|
+
synchronize do
|
676
|
+
@threads_blocking_new_connections -= 1
|
677
|
+
|
678
|
+
if @threads_blocking_new_connections.zero?
|
679
|
+
@available.clear
|
680
|
+
|
681
|
+
num_new_conns_required = num_waiting_in_queue
|
682
|
+
|
683
|
+
@connections.each do |conn|
|
684
|
+
next if conn.in_use?
|
685
|
+
|
686
|
+
@available.add conn
|
687
|
+
num_new_conns_required -= 1
|
688
|
+
end
|
689
|
+
end
|
690
|
+
end
|
691
|
+
|
692
|
+
bulk_make_new_connections(num_new_conns_required) if num_new_conns_required > 0
|
685
693
|
end
|
686
694
|
|
687
695
|
# Acquire a connection by one of 1) immediately removing one
|
@@ -733,7 +741,7 @@ module ActiveRecord
|
|
733
741
|
# and increment @now_connecting, to prevent overstepping this pool's @size
|
734
742
|
# constraint
|
735
743
|
do_checkout = synchronize do
|
736
|
-
if @
|
744
|
+
if @threads_blocking_new_connections.zero? && (@connections.size + @now_connecting) < @size
|
737
745
|
@now_connecting += 1
|
738
746
|
end
|
739
747
|
end
|