activerecord 5.1.5 → 5.2.8.1

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.

Files changed (261) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +655 -608
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -5
  5. data/examples/performance.rb +2 -0
  6. data/examples/simple.rb +2 -0
  7. data/lib/active_record/aggregations.rb +6 -5
  8. data/lib/active_record/association_relation.rb +7 -5
  9. data/lib/active_record/associations/alias_tracker.rb +19 -27
  10. data/lib/active_record/associations/association.rb +41 -37
  11. data/lib/active_record/associations/association_scope.rb +38 -50
  12. data/lib/active_record/associations/belongs_to_association.rb +28 -9
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
  14. data/lib/active_record/associations/builder/association.rb +4 -7
  15. data/lib/active_record/associations/builder/belongs_to.rb +14 -5
  16. data/lib/active_record/associations/builder/collection_association.rb +3 -3
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
  18. data/lib/active_record/associations/builder/has_many.rb +2 -0
  19. data/lib/active_record/associations/builder/has_one.rb +2 -0
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  21. data/lib/active_record/associations/collection_association.rb +59 -47
  22. data/lib/active_record/associations/collection_proxy.rb +20 -49
  23. data/lib/active_record/associations/foreign_association.rb +2 -0
  24. data/lib/active_record/associations/has_many_association.rb +12 -1
  25. data/lib/active_record/associations/has_many_through_association.rb +36 -30
  26. data/lib/active_record/associations/has_one_association.rb +12 -1
  27. data/lib/active_record/associations/has_one_through_association.rb +13 -8
  28. data/lib/active_record/associations/join_dependency/join_association.rb +39 -63
  29. data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
  30. data/lib/active_record/associations/join_dependency/join_part.rb +9 -9
  31. data/lib/active_record/associations/join_dependency.rb +48 -93
  32. data/lib/active_record/associations/preloader/association.rb +45 -61
  33. data/lib/active_record/associations/preloader/through_association.rb +71 -79
  34. data/lib/active_record/associations/preloader.rb +18 -38
  35. data/lib/active_record/associations/singular_association.rb +14 -16
  36. data/lib/active_record/associations/through_association.rb +26 -11
  37. data/lib/active_record/associations.rb +40 -63
  38. data/lib/active_record/attribute_assignment.rb +2 -5
  39. data/lib/active_record/attribute_decorators.rb +3 -2
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
  41. data/lib/active_record/attribute_methods/dirty.rb +32 -216
  42. data/lib/active_record/attribute_methods/primary_key.rb +7 -6
  43. data/lib/active_record/attribute_methods/query.rb +2 -0
  44. data/lib/active_record/attribute_methods/read.rb +9 -3
  45. data/lib/active_record/attribute_methods/serialization.rb +23 -0
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
  47. data/lib/active_record/attribute_methods/write.rb +21 -9
  48. data/lib/active_record/attribute_methods.rb +65 -24
  49. data/lib/active_record/attributes.rb +7 -6
  50. data/lib/active_record/autosave_association.rb +35 -19
  51. data/lib/active_record/base.rb +2 -0
  52. data/lib/active_record/callbacks.rb +12 -6
  53. data/lib/active_record/coders/json.rb +2 -0
  54. data/lib/active_record/coders/yaml_column.rb +15 -1
  55. data/lib/active_record/collection_cache_key.rb +12 -8
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +142 -42
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +174 -33
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +15 -5
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -32
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +14 -5
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +64 -6
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +152 -81
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +84 -97
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +110 -173
  69. data/lib/active_record/connection_adapters/column.rb +3 -1
  70. data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +13 -2
  72. data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +47 -2
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -30
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -0
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +13 -1
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -1
  97. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +5 -3
  99. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +8 -2
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +50 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +234 -112
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +3 -1
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +66 -74
  117. data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +24 -1
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +75 -1
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +82 -95
  126. data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
  127. data/lib/active_record/connection_handling.rb +4 -2
  128. data/lib/active_record/core.rb +51 -61
  129. data/lib/active_record/counter_cache.rb +20 -15
  130. data/lib/active_record/define_callbacks.rb +5 -3
  131. data/lib/active_record/dynamic_matchers.rb +9 -9
  132. data/lib/active_record/enum.rb +18 -13
  133. data/lib/active_record/errors.rb +60 -15
  134. data/lib/active_record/explain.rb +3 -1
  135. data/lib/active_record/explain_registry.rb +2 -0
  136. data/lib/active_record/explain_subscriber.rb +2 -0
  137. data/lib/active_record/fixture_set/file.rb +2 -0
  138. data/lib/active_record/fixtures.rb +67 -60
  139. data/lib/active_record/gem_version.rb +5 -3
  140. data/lib/active_record/inheritance.rb +49 -19
  141. data/lib/active_record/integration.rb +58 -19
  142. data/lib/active_record/internal_metadata.rb +2 -0
  143. data/lib/active_record/legacy_yaml_adapter.rb +3 -1
  144. data/lib/active_record/locking/optimistic.rb +30 -42
  145. data/lib/active_record/locking/pessimistic.rb +9 -6
  146. data/lib/active_record/log_subscriber.rb +43 -0
  147. data/lib/active_record/migration/command_recorder.rb +11 -9
  148. data/lib/active_record/migration/compatibility.rb +47 -9
  149. data/lib/active_record/migration/join_table.rb +2 -0
  150. data/lib/active_record/migration.rb +189 -139
  151. data/lib/active_record/model_schema.rb +19 -24
  152. data/lib/active_record/nested_attributes.rb +18 -6
  153. data/lib/active_record/no_touching.rb +3 -1
  154. data/lib/active_record/null_relation.rb +2 -0
  155. data/lib/active_record/persistence.rb +198 -49
  156. data/lib/active_record/query_cache.rb +12 -14
  157. data/lib/active_record/querying.rb +4 -2
  158. data/lib/active_record/railtie.rb +80 -6
  159. data/lib/active_record/railties/console_sandbox.rb +2 -0
  160. data/lib/active_record/railties/controller_runtime.rb +2 -0
  161. data/lib/active_record/railties/databases.rake +46 -36
  162. data/lib/active_record/readonly_attributes.rb +3 -2
  163. data/lib/active_record/reflection.rb +108 -194
  164. data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
  165. data/lib/active_record/relation/batches.rb +20 -5
  166. data/lib/active_record/relation/calculations.rb +46 -20
  167. data/lib/active_record/relation/delegation.rb +45 -27
  168. data/lib/active_record/relation/finder_methods.rb +77 -78
  169. data/lib/active_record/relation/from_clause.rb +2 -8
  170. data/lib/active_record/relation/merger.rb +53 -23
  171. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
  172. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  173. data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
  174. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
  175. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  176. data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
  177. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  178. data/lib/active_record/relation/predicate_builder.rb +60 -79
  179. data/lib/active_record/relation/query_attribute.rb +28 -2
  180. data/lib/active_record/relation/query_methods.rb +129 -100
  181. data/lib/active_record/relation/record_fetch_warning.rb +2 -0
  182. data/lib/active_record/relation/spawn_methods.rb +4 -2
  183. data/lib/active_record/relation/where_clause.rb +65 -68
  184. data/lib/active_record/relation/where_clause_factory.rb +5 -48
  185. data/lib/active_record/relation.rb +120 -214
  186. data/lib/active_record/result.rb +2 -0
  187. data/lib/active_record/runtime_registry.rb +2 -0
  188. data/lib/active_record/sanitization.rb +129 -121
  189. data/lib/active_record/schema.rb +4 -2
  190. data/lib/active_record/schema_dumper.rb +36 -26
  191. data/lib/active_record/schema_migration.rb +2 -0
  192. data/lib/active_record/scoping/default.rb +8 -9
  193. data/lib/active_record/scoping/named.rb +23 -7
  194. data/lib/active_record/scoping.rb +9 -8
  195. data/lib/active_record/secure_token.rb +2 -0
  196. data/lib/active_record/serialization.rb +2 -0
  197. data/lib/active_record/statement_cache.rb +23 -13
  198. data/lib/active_record/store.rb +3 -1
  199. data/lib/active_record/suppressor.rb +2 -0
  200. data/lib/active_record/table_metadata.rb +12 -3
  201. data/lib/active_record/tasks/database_tasks.rb +26 -15
  202. data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
  203. data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
  204. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
  205. data/lib/active_record/timestamp.rb +13 -6
  206. data/lib/active_record/touch_later.rb +2 -0
  207. data/lib/active_record/transactions.rb +33 -28
  208. data/lib/active_record/translation.rb +2 -0
  209. data/lib/active_record/type/adapter_specific_registry.rb +2 -0
  210. data/lib/active_record/type/date.rb +2 -0
  211. data/lib/active_record/type/date_time.rb +2 -0
  212. data/lib/active_record/type/decimal_without_scale.rb +2 -0
  213. data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
  214. data/lib/active_record/type/internal/timezone.rb +2 -0
  215. data/lib/active_record/type/json.rb +30 -0
  216. data/lib/active_record/type/serialized.rb +6 -0
  217. data/lib/active_record/type/text.rb +2 -0
  218. data/lib/active_record/type/time.rb +2 -0
  219. data/lib/active_record/type/type_map.rb +2 -0
  220. data/lib/active_record/type/unsigned_integer.rb +2 -0
  221. data/lib/active_record/type.rb +4 -1
  222. data/lib/active_record/type_caster/connection.rb +2 -0
  223. data/lib/active_record/type_caster/map.rb +3 -1
  224. data/lib/active_record/type_caster.rb +2 -0
  225. data/lib/active_record/validations/absence.rb +2 -0
  226. data/lib/active_record/validations/associated.rb +2 -0
  227. data/lib/active_record/validations/length.rb +2 -0
  228. data/lib/active_record/validations/presence.rb +2 -0
  229. data/lib/active_record/validations/uniqueness.rb +36 -6
  230. data/lib/active_record/validations.rb +2 -0
  231. data/lib/active_record/version.rb +2 -0
  232. data/lib/active_record.rb +11 -4
  233. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  234. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  235. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
  236. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
  237. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
  238. data/lib/rails/generators/active_record/migration.rb +2 -0
  239. data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
  240. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
  241. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  242. data/lib/rails/generators/active_record.rb +3 -1
  243. metadata +26 -40
  244. data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
  245. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  246. data/lib/active_record/associations/preloader/has_many.rb +0 -15
  247. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  248. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  249. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  250. data/lib/active_record/associations/preloader/singular_association.rb +0 -18
  251. data/lib/active_record/attribute/user_provided_default.rb +0 -30
  252. data/lib/active_record/attribute.rb +0 -240
  253. data/lib/active_record/attribute_mutation_tracker.rb +0 -114
  254. data/lib/active_record/attribute_set/builder.rb +0 -124
  255. data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
  256. data/lib/active_record/attribute_set.rb +0 -113
  257. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
  258. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  259. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  260. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
  261. data/lib/active_record/type/internal/abstract_json.rb +0 -37
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module CollectionCacheKey
3
5
  def collection_cache_key(collection = all, timestamp_column = :updated_at) # :nodoc:
4
- query_signature = Digest::MD5.hexdigest(collection.to_sql)
6
+ query_signature = ActiveSupport::Digest.hexdigest(collection.to_sql)
5
7
  key = "#{collection.model_name.cache_key}/query-#{query_signature}"
6
8
 
7
9
  if collection.loaded? || collection.distinct_value
@@ -10,24 +12,26 @@ module ActiveRecord
10
12
  timestamp = collection.max_by(&timestamp_column)._read_attribute(timestamp_column)
11
13
  end
12
14
  else
13
- column_type = type_for_attribute(timestamp_column.to_s)
14
- column = "#{connection.quote_table_name(collection.table_name)}.#{connection.quote_column_name(timestamp_column)}"
15
+ if collection.eager_loading?
16
+ collection = collection.send(:apply_join_dependency)
17
+ end
18
+ column_type = type_for_attribute(timestamp_column)
19
+ column = connection.column_name_from_arel_node(collection.arel_attribute(timestamp_column))
15
20
  select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
16
21
 
17
22
  if collection.has_limit_or_offset?
18
- query = collection.spawn
19
- query.select_values = [column]
23
+ query = collection.select("#{column} AS collection_cache_key_timestamp")
20
24
  subquery_alias = "subquery_for_cache_key"
21
- subquery_column = "#{subquery_alias}.#{timestamp_column}"
25
+ subquery_column = "#{subquery_alias}.collection_cache_key_timestamp"
22
26
  subquery = query.arel.as(subquery_alias)
23
- arel = Arel::SelectManager.new(query.engine).project(select_values % subquery_column).from(subquery)
27
+ arel = Arel::SelectManager.new(subquery).project(select_values % subquery_column)
24
28
  else
25
29
  query = collection.unscope(:order)
26
30
  query.select_values = [select_values % column]
27
31
  arel = query.arel
28
32
  end
29
33
 
30
- result = connection.select_one(arel, nil, query.bound_attributes)
34
+ result = connection.select_one(arel, nil)
31
35
 
32
36
  if result.blank?
33
37
  size = 0
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "thread"
2
4
  require "concurrent/map"
3
5
  require "monitor"
@@ -61,15 +63,13 @@ module ActiveRecord
61
63
  # There are several connection-pooling-related options that you can add to
62
64
  # your database connection configuration:
63
65
  #
64
- # * +pool+: number indicating size of connection pool (default 5)
65
- # * +checkout_timeout+: number of seconds to block and wait for a connection
66
- # before giving up and raising a timeout error (default 5 seconds).
67
- # * +reaping_frequency+: frequency in seconds to periodically run the
68
- # Reaper, which attempts to find and recover connections from dead
69
- # threads, which can occur if a programmer forgets to close a
70
- # connection at the end of a thread or a thread dies unexpectedly.
71
- # Regardless of this setting, the Reaper will be invoked before every
72
- # blocking wait. (Default +nil+, which means don't schedule the Reaper).
66
+ # * +pool+: maximum number of connections the pool may manage (default 5).
67
+ # * +idle_timeout+: number of seconds that a connection will be kept
68
+ # unused in the pool before it is automatically disconnected (default
69
+ # 300 seconds). Set this to zero to keep connections forever.
70
+ # * +checkout_timeout+: number of seconds to wait for a connection to
71
+ # become available before giving up and raising a timeout error (default
72
+ # 5 seconds).
73
73
  #
74
74
  #--
75
75
  # Synchronization policy:
@@ -80,11 +80,8 @@ module ActiveRecord
80
80
  # * private methods that require being called in a +synchronize+ blocks
81
81
  # are now explicitly documented
82
82
  class ConnectionPool
83
- # Threadsafe, fair, FIFO queue. Meant to be used by ConnectionPool
84
- # with which it shares a Monitor. But could be a generic Queue.
85
- #
86
- # The Queue in stdlib's 'thread' could replace this class except
87
- # stdlib's doesn't support waiting with a timeout.
83
+ # Threadsafe, fair, LIFO queue. Meant to be used by ConnectionPool
84
+ # with which it shares a Monitor.
88
85
  class Queue
89
86
  def initialize(lock = Monitor.new)
90
87
  @lock = lock
@@ -173,7 +170,7 @@ module ActiveRecord
173
170
 
174
171
  # Removes and returns the head of the queue if possible, or +nil+.
175
172
  def remove
176
- @queue.shift
173
+ @queue.pop
177
174
  end
178
175
 
179
176
  # Remove and return the head the queue if the number of
@@ -191,7 +188,9 @@ module ActiveRecord
191
188
  t0 = Time.now
192
189
  elapsed = 0
193
190
  loop do
194
- @cond.wait(timeout - elapsed)
191
+ ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
192
+ @cond.wait(timeout - elapsed)
193
+ end
195
194
 
196
195
  return remove if any?
197
196
 
@@ -268,7 +267,7 @@ module ActiveRecord
268
267
  # Connections must be leased while holding the main pool mutex. This is
269
268
  # an internal subclass that also +.leases+ returned connections while
270
269
  # still in queue's critical section (queue synchronizes with the same
271
- # +@lock+ as the main pool) so that a returned connection is already
270
+ # <tt>@lock</tt> as the main pool) so that a returned connection is already
272
271
  # leased and there is no need to re-enter synchronized block.
273
272
  class ConnectionLeasingQueue < Queue # :nodoc:
274
273
  include BiasableQueue
@@ -281,12 +280,12 @@ module ActiveRecord
281
280
  end
282
281
  end
283
282
 
284
- # Every +frequency+ seconds, the reaper will call +reap+ on +pool+.
285
- # A reaper instantiated with a +nil+ frequency will never reap the
286
- # connection pool.
283
+ # Every +frequency+ seconds, the reaper will call +reap+ and +flush+ on
284
+ # +pool+. A reaper instantiated with a zero frequency will never reap
285
+ # the connection pool.
287
286
  #
288
- # Configure the frequency by setting "reaping_frequency" in your
289
- # database yaml file.
287
+ # Configure the frequency by setting +reaping_frequency+ in your database
288
+ # yaml file (default 60 seconds).
290
289
  class Reaper
291
290
  attr_reader :pool, :frequency
292
291
 
@@ -296,11 +295,12 @@ module ActiveRecord
296
295
  end
297
296
 
298
297
  def run
299
- return unless frequency
298
+ return unless frequency && frequency > 0
300
299
  Thread.new(frequency, pool) { |t, p|
301
300
  loop do
302
301
  sleep t
303
302
  p.reap
303
+ p.flush
304
304
  end
305
305
  }
306
306
  end
@@ -310,7 +310,7 @@ module ActiveRecord
310
310
  include QueryCache::ConnectionPoolConfiguration
311
311
 
312
312
  attr_accessor :automatic_reconnect, :checkout_timeout, :schema_cache
313
- attr_reader :spec, :connections, :size, :reaper
313
+ attr_reader :spec, :size, :reaper
314
314
 
315
315
  # Creates a new ConnectionPool object. +spec+ is a ConnectionSpecification
316
316
  # object which describes database connection information (e.g. adapter,
@@ -324,8 +324,10 @@ module ActiveRecord
324
324
  @spec = spec
325
325
 
326
326
  @checkout_timeout = (spec.config[:checkout_timeout] && spec.config[:checkout_timeout].to_f) || 5
327
- @reaper = Reaper.new(self, (spec.config[:reaping_frequency] && spec.config[:reaping_frequency].to_f))
328
- @reaper.run
327
+ if @idle_timeout = spec.config.fetch(:idle_timeout, 300)
328
+ @idle_timeout = @idle_timeout.to_f
329
+ @idle_timeout = nil if @idle_timeout <= 0
330
+ end
329
331
 
330
332
  # default max pool size to 5
331
333
  @size = (spec.config[:pool] && spec.config[:pool].to_i) || 5
@@ -338,7 +340,7 @@ module ActiveRecord
338
340
  # then that +thread+ does indeed own that +conn+. However, an absence of a such
339
341
  # mapping does not mean that the +thread+ doesn't own the said connection. In
340
342
  # that case +conn.owner+ attr should be consulted.
341
- # Access and modification of +@thread_cached_conns+ does not require
343
+ # Access and modification of <tt>@thread_cached_conns</tt> does not require
342
344
  # synchronization.
343
345
  @thread_cached_conns = Concurrent::Map.new(initial_capacity: @size)
344
346
 
@@ -355,6 +357,12 @@ module ActiveRecord
355
357
  @available = ConnectionLeasingQueue.new self
356
358
 
357
359
  @lock_thread = false
360
+
361
+ # +reaping_frequency+ is configurable mostly for historical reasons, but it could
362
+ # also be useful if someone wants a very low +idle_timeout+.
363
+ reaping_frequency = spec.config.fetch(:reaping_frequency, 60)
364
+ @reaper = Reaper.new(self, reaping_frequency && reaping_frequency.to_f)
365
+ @reaper.run
358
366
  end
359
367
 
360
368
  def lock_thread=(lock_thread)
@@ -371,7 +379,7 @@ module ActiveRecord
371
379
  # #connection can be called any number of times; the connection is
372
380
  # held in a cache keyed by a thread.
373
381
  def connection
374
- @thread_cached_conns[connection_cache_key(@lock_thread || Thread.current)] ||= checkout
382
+ @thread_cached_conns[connection_cache_key(current_thread)] ||= checkout
375
383
  end
376
384
 
377
385
  # Returns true if there is an open connection being used for the current thread.
@@ -380,7 +388,7 @@ module ActiveRecord
380
388
  # #connection or #with_connection methods. Connections obtained through
381
389
  # #checkout will not be detected by #active_connection?
382
390
  def active_connection?
383
- @thread_cached_conns[connection_cache_key(Thread.current)]
391
+ @thread_cached_conns[connection_cache_key(current_thread)]
384
392
  end
385
393
 
386
394
  # Signal that the thread is finished with the current connection.
@@ -415,6 +423,21 @@ module ActiveRecord
415
423
  synchronize { @connections.any? }
416
424
  end
417
425
 
426
+ # Returns an array containing the connections currently in the pool.
427
+ # Access to the array does not require synchronization on the pool because
428
+ # the array is newly created and not retained by the pool.
429
+ #
430
+ # However; this method bypasses the ConnectionPool's thread-safe connection
431
+ # access pattern. A returned connection may be owned by another thread,
432
+ # unowned, or by happen-stance owned by the calling thread.
433
+ #
434
+ # Calling methods on a connection without ownership is subject to the
435
+ # thread-safety guarantees of the underlying method. Many of the methods
436
+ # on connection adapter classes are inherently multi-thread unsafe.
437
+ def connections
438
+ synchronize { @connections.dup }
439
+ end
440
+
418
441
  # Disconnects all connections in the pool, and clears the pool.
419
442
  #
420
443
  # Raises:
@@ -447,6 +470,21 @@ module ActiveRecord
447
470
  disconnect(false)
448
471
  end
449
472
 
473
+ # Discards all connections in the pool (even if they're currently
474
+ # leased!), along with the pool itself. Any further interaction with the
475
+ # pool (except #spec and #schema_cache) is undefined.
476
+ #
477
+ # See AbstractAdapter#discard!
478
+ def discard! # :nodoc:
479
+ synchronize do
480
+ return if @connections.nil? # already discarded
481
+ @connections.each do |conn|
482
+ conn.discard!
483
+ end
484
+ @connections = @available = @thread_cached_conns = nil
485
+ end
486
+ end
487
+
450
488
  # Clears the cache which maps classes and re-connects connections that
451
489
  # require reloading.
452
490
  #
@@ -572,6 +610,35 @@ module ActiveRecord
572
610
  end
573
611
  end
574
612
 
613
+ # Disconnect all connections that have been idle for at least
614
+ # +minimum_idle+ seconds. Connections currently checked out, or that were
615
+ # checked in less than +minimum_idle+ seconds ago, are unaffected.
616
+ def flush(minimum_idle = @idle_timeout)
617
+ return if minimum_idle.nil?
618
+
619
+ idle_connections = synchronize do
620
+ @connections.select do |conn|
621
+ !conn.in_use? && conn.seconds_idle >= minimum_idle
622
+ end.each do |conn|
623
+ conn.lease
624
+
625
+ @available.delete conn
626
+ @connections.delete conn
627
+ end
628
+ end
629
+
630
+ idle_connections.each do |conn|
631
+ conn.disconnect!
632
+ end
633
+ end
634
+
635
+ # Disconnect all currently idle connections. Connections currently checked
636
+ # out are unaffected.
637
+ def flush!
638
+ reap
639
+ flush(-1)
640
+ end
641
+
575
642
  def num_waiting_in_queue # :nodoc:
576
643
  @available.num_waiting
577
644
  end
@@ -616,6 +683,10 @@ module ActiveRecord
616
683
  thread
617
684
  end
618
685
 
686
+ def current_thread
687
+ @lock_thread || Thread.current
688
+ end
689
+
619
690
  # Take control of all existing connections so a "group" action such as
620
691
  # reload/disconnect can be performed safely. It is no longer enough to
621
692
  # wrap it in +synchronize+ because some pool's actions are allowed
@@ -679,7 +750,7 @@ module ActiveRecord
679
750
  # this block can't be easily moved into attempt_to_checkout_all_existing_connections's
680
751
  # rescue block, because doing so would put it outside of synchronize section, without
681
752
  # being in a critical section thread_report might become inaccurate
682
- msg = "could not obtain ownership of all database connections in #{checkout_timeout} seconds"
753
+ msg = "could not obtain ownership of all database connections in #{checkout_timeout} seconds".dup
683
754
 
684
755
  thread_report = []
685
756
  @connections.each do |conn|
@@ -734,10 +805,10 @@ module ActiveRecord
734
805
  # Implementation detail: the connection returned by +acquire_connection+
735
806
  # will already be "+connection.lease+ -ed" to the current thread.
736
807
  def acquire_connection(checkout_timeout)
737
- # NOTE: we rely on +@available.poll+ and +try_to_checkout_new_connection+ to
808
+ # NOTE: we rely on <tt>@available.poll</tt> and +try_to_checkout_new_connection+ to
738
809
  # +conn.lease+ the returned connection (and to do this in a +synchronized+
739
810
  # section). This is not the cleanest implementation, as ideally we would
740
- # <tt>synchronize { conn.lease }</tt> in this method, but by leaving it to +@available.poll+
811
+ # <tt>synchronize { conn.lease }</tt> in this method, but by leaving it to <tt>@available.poll</tt>
741
812
  # and +try_to_checkout_new_connection+ we can piggyback on +synchronize+ sections
742
813
  # of the said methods and avoid an additional +synchronize+ overhead.
743
814
  if conn = @available.poll || try_to_checkout_new_connection
@@ -761,7 +832,7 @@ module ActiveRecord
761
832
  end
762
833
  end
763
834
 
764
- # If the pool is not at a +@size+ limit, establish new connection. Connecting
835
+ # If the pool is not at a <tt>@size</tt> limit, establish new connection. Connecting
765
836
  # to the DB is done outside main synchronized section.
766
837
  #--
767
838
  # Implementation constraint: a newly established connection returned by this
@@ -827,7 +898,7 @@ module ActiveRecord
827
898
  # end
828
899
  #
829
900
  # class Book < ActiveRecord::Base
830
- # establish_connection "library_db"
901
+ # establish_connection :library_db
831
902
  # end
832
903
  #
833
904
  # class ScaryBook < Book
@@ -859,17 +930,41 @@ module ActiveRecord
859
930
  # All Active Record models use this handler to determine the connection pool that they
860
931
  # should use.
861
932
  #
862
- # The ConnectionHandler class is not coupled with the Active models, as it has no knowlodge
933
+ # The ConnectionHandler class is not coupled with the Active models, as it has no knowledge
863
934
  # about the model. The model needs to pass a specification name to the handler,
864
- # in order to lookup the correct connection pool.
935
+ # in order to look up the correct connection pool.
865
936
  class ConnectionHandler
866
- def initialize
867
- # These caches are keyed by spec.name (ConnectionSpecification#name).
868
- @owner_to_pool = Concurrent::Map.new(initial_capacity: 2) do |h, k|
937
+ def self.create_owner_to_pool # :nodoc:
938
+ Concurrent::Map.new(initial_capacity: 2) do |h, k|
939
+ # Discard the parent's connection pools immediately; we have no need
940
+ # of them
941
+ discard_unowned_pools(h)
942
+
869
943
  h[k] = Concurrent::Map.new(initial_capacity: 2)
870
944
  end
871
945
  end
872
946
 
947
+ def self.unowned_pool_finalizer(pid_map) # :nodoc:
948
+ lambda do |_|
949
+ discard_unowned_pools(pid_map)
950
+ end
951
+ end
952
+
953
+ def self.discard_unowned_pools(pid_map) # :nodoc:
954
+ pid_map.each do |pid, pools|
955
+ pools.values.compact.each(&:discard!) unless pid == Process.pid
956
+ end
957
+ end
958
+
959
+ def initialize
960
+ # These caches are keyed by spec.name (ConnectionSpecification#name).
961
+ @owner_to_pool = ConnectionHandler.create_owner_to_pool
962
+
963
+ # Backup finalizer: if the forked child never needed a pool, the above
964
+ # early discard has not occurred
965
+ ObjectSpace.define_finalizer self, ConnectionHandler.unowned_pool_finalizer(@owner_to_pool)
966
+ end
967
+
873
968
  def connection_pool_list
874
969
  owner_to_pool.values.compact
875
970
  end
@@ -921,6 +1016,13 @@ module ActiveRecord
921
1016
  connection_pool_list.each(&:disconnect!)
922
1017
  end
923
1018
 
1019
+ # Disconnects all currently idle connections.
1020
+ #
1021
+ # See ConnectionPool#flush! for details.
1022
+ def flush_idle_connections!
1023
+ connection_pool_list.each(&:flush!)
1024
+ end
1025
+
924
1026
  # Locate the connection of the nearest super class. This can be an
925
1027
  # active or defined connection: if it is the latter, it will be
926
1028
  # opened and set as the active connection for the class it was defined
@@ -928,9 +1030,7 @@ module ActiveRecord
928
1030
  def retrieve_connection(spec_name) #:nodoc:
929
1031
  pool = retrieve_connection_pool(spec_name)
930
1032
  raise ConnectionNotEstablished, "No connection pool with '#{spec_name}' found." unless pool
931
- conn = pool.connection
932
- raise ConnectionNotEstablished, "No connection for '#{spec_name}' in connection pool" unless conn
933
- conn
1033
+ pool.connection
934
1034
  end
935
1035
 
936
1036
  # Returns true if a connection that's accessible to this class has
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters # :nodoc:
3
5
  module DatabaseLimits
@@ -60,6 +62,11 @@ module ActiveRecord
60
62
  def joins_per_query
61
63
  256
62
64
  end
65
+
66
+ private
67
+ def bind_params_length
68
+ 65535
69
+ end
63
70
  end
64
71
  end
65
72
  end