activerecord 5.2.8 → 7.0.2

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 (364) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1393 -587
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +7 -5
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/aggregations.rb +10 -9
  7. data/lib/active_record/association_relation.rb +22 -12
  8. data/lib/active_record/associations/alias_tracker.rb +19 -16
  9. data/lib/active_record/associations/association.rb +122 -47
  10. data/lib/active_record/associations/association_scope.rb +24 -24
  11. data/lib/active_record/associations/belongs_to_association.rb +67 -49
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +16 -7
  13. data/lib/active_record/associations/builder/association.rb +52 -23
  14. data/lib/active_record/associations/builder/belongs_to.rb +44 -61
  15. data/lib/active_record/associations/builder/collection_association.rb +17 -19
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
  17. data/lib/active_record/associations/builder/has_many.rb +10 -3
  18. data/lib/active_record/associations/builder/has_one.rb +35 -3
  19. data/lib/active_record/associations/builder/singular_association.rb +5 -3
  20. data/lib/active_record/associations/collection_association.rb +59 -50
  21. data/lib/active_record/associations/collection_proxy.rb +32 -23
  22. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  23. data/lib/active_record/associations/foreign_association.rb +20 -0
  24. data/lib/active_record/associations/has_many_association.rb +27 -14
  25. data/lib/active_record/associations/has_many_through_association.rb +26 -19
  26. data/lib/active_record/associations/has_one_association.rb +52 -37
  27. data/lib/active_record/associations/has_one_through_association.rb +6 -6
  28. data/lib/active_record/associations/join_dependency/join_association.rb +44 -22
  29. data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
  30. data/lib/active_record/associations/join_dependency.rb +97 -62
  31. data/lib/active_record/associations/preloader/association.rb +220 -60
  32. data/lib/active_record/associations/preloader/batch.rb +48 -0
  33. data/lib/active_record/associations/preloader/branch.rb +147 -0
  34. data/lib/active_record/associations/preloader/through_association.rb +85 -40
  35. data/lib/active_record/associations/preloader.rb +44 -105
  36. data/lib/active_record/associations/singular_association.rb +9 -17
  37. data/lib/active_record/associations/through_association.rb +4 -4
  38. data/lib/active_record/associations.rb +207 -66
  39. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  40. data/lib/active_record/attribute_assignment.rb +17 -19
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +19 -8
  42. data/lib/active_record/attribute_methods/dirty.rb +141 -47
  43. data/lib/active_record/attribute_methods/primary_key.rb +22 -27
  44. data/lib/active_record/attribute_methods/query.rb +6 -10
  45. data/lib/active_record/attribute_methods/read.rb +15 -55
  46. data/lib/active_record/attribute_methods/serialization.rb +77 -18
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +16 -18
  48. data/lib/active_record/attribute_methods/write.rb +18 -37
  49. data/lib/active_record/attribute_methods.rb +90 -153
  50. data/lib/active_record/attributes.rb +38 -12
  51. data/lib/active_record/autosave_association.rb +50 -50
  52. data/lib/active_record/base.rb +23 -18
  53. data/lib/active_record/callbacks.rb +159 -44
  54. data/lib/active_record/coders/yaml_column.rb +12 -3
  55. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
  57. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
  58. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +92 -464
  59. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -51
  60. data/lib/active_record/connection_adapters/abstract/database_statements.rb +209 -164
  61. data/lib/active_record/connection_adapters/abstract/query_cache.rb +38 -22
  62. data/lib/active_record/connection_adapters/abstract/quoting.rb +103 -82
  63. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  64. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +140 -110
  65. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -94
  66. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +16 -5
  67. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +456 -159
  68. data/lib/active_record/connection_adapters/abstract/transaction.rb +169 -78
  69. data/lib/active_record/connection_adapters/abstract_adapter.rb +367 -162
  70. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +311 -327
  71. data/lib/active_record/connection_adapters/column.rb +33 -11
  72. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  73. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  74. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  75. data/lib/active_record/connection_adapters/mysql/database_statements.rb +113 -45
  76. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  77. data/lib/active_record/connection_adapters/mysql/quoting.rb +71 -5
  78. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
  79. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
  80. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +25 -8
  81. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +143 -19
  82. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
  83. data/lib/active_record/connection_adapters/mysql2_adapter.rb +63 -22
  84. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  85. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  86. data/lib/active_record/connection_adapters/postgresql/column.rb +53 -28
  87. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +56 -63
  88. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  90. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  91. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +10 -2
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +15 -2
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +54 -16
  95. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
  97. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  102. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +26 -12
  105. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
  106. data/lib/active_record/connection_adapters/postgresql/oid.rb +4 -0
  107. data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -52
  108. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +34 -2
  109. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +39 -4
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +128 -91
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -1
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +149 -113
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +386 -182
  116. data/lib/active_record/connection_adapters/schema_cache.rb +161 -22
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +17 -6
  118. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +152 -0
  119. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +65 -18
  120. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  121. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +92 -26
  122. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +251 -204
  123. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  124. data/lib/active_record/connection_adapters.rb +53 -0
  125. data/lib/active_record/connection_handling.rb +292 -38
  126. data/lib/active_record/core.rb +385 -158
  127. data/lib/active_record/counter_cache.rb +8 -30
  128. data/lib/active_record/database_configurations/connection_url_resolver.rb +100 -0
  129. data/lib/active_record/database_configurations/database_config.rb +83 -0
  130. data/lib/active_record/database_configurations/hash_config.rb +154 -0
  131. data/lib/active_record/database_configurations/url_config.rb +53 -0
  132. data/lib/active_record/database_configurations.rb +256 -0
  133. data/lib/active_record/delegated_type.rb +250 -0
  134. data/lib/active_record/destroy_association_async_job.rb +36 -0
  135. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  136. data/lib/active_record/dynamic_matchers.rb +4 -5
  137. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  138. data/lib/active_record/encryption/cipher.rb +53 -0
  139. data/lib/active_record/encryption/config.rb +44 -0
  140. data/lib/active_record/encryption/configurable.rb +61 -0
  141. data/lib/active_record/encryption/context.rb +35 -0
  142. data/lib/active_record/encryption/contexts.rb +72 -0
  143. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  144. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  145. data/lib/active_record/encryption/encryptable_record.rb +208 -0
  146. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  147. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  148. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  149. data/lib/active_record/encryption/encryptor.rb +155 -0
  150. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  151. data/lib/active_record/encryption/errors.rb +15 -0
  152. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  153. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  154. data/lib/active_record/encryption/key.rb +28 -0
  155. data/lib/active_record/encryption/key_generator.rb +42 -0
  156. data/lib/active_record/encryption/key_provider.rb +46 -0
  157. data/lib/active_record/encryption/message.rb +33 -0
  158. data/lib/active_record/encryption/message_serializer.rb +90 -0
  159. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  160. data/lib/active_record/encryption/properties.rb +76 -0
  161. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  162. data/lib/active_record/encryption/scheme.rb +99 -0
  163. data/lib/active_record/encryption.rb +55 -0
  164. data/lib/active_record/enum.rb +130 -51
  165. data/lib/active_record/errors.rb +129 -23
  166. data/lib/active_record/explain.rb +10 -6
  167. data/lib/active_record/explain_registry.rb +11 -6
  168. data/lib/active_record/explain_subscriber.rb +1 -1
  169. data/lib/active_record/fixture_set/file.rb +22 -15
  170. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  171. data/lib/active_record/fixture_set/render_context.rb +17 -0
  172. data/lib/active_record/fixture_set/table_row.rb +187 -0
  173. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  174. data/lib/active_record/fixtures.rb +206 -490
  175. data/lib/active_record/future_result.rb +139 -0
  176. data/lib/active_record/gem_version.rb +3 -3
  177. data/lib/active_record/inheritance.rb +104 -37
  178. data/lib/active_record/insert_all.rb +278 -0
  179. data/lib/active_record/integration.rb +69 -18
  180. data/lib/active_record/internal_metadata.rb +24 -9
  181. data/lib/active_record/legacy_yaml_adapter.rb +3 -36
  182. data/lib/active_record/locking/optimistic.rb +41 -26
  183. data/lib/active_record/locking/pessimistic.rb +18 -8
  184. data/lib/active_record/log_subscriber.rb +46 -35
  185. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  186. data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
  187. data/lib/active_record/middleware/database_selector.rb +82 -0
  188. data/lib/active_record/middleware/shard_selector.rb +60 -0
  189. data/lib/active_record/migration/command_recorder.rb +96 -44
  190. data/lib/active_record/migration/compatibility.rb +246 -64
  191. data/lib/active_record/migration/join_table.rb +1 -2
  192. data/lib/active_record/migration.rb +266 -187
  193. data/lib/active_record/model_schema.rb +165 -52
  194. data/lib/active_record/nested_attributes.rb +17 -19
  195. data/lib/active_record/no_touching.rb +11 -4
  196. data/lib/active_record/null_relation.rb +2 -7
  197. data/lib/active_record/persistence.rb +467 -92
  198. data/lib/active_record/query_cache.rb +21 -4
  199. data/lib/active_record/query_logs.rb +138 -0
  200. data/lib/active_record/querying.rb +51 -24
  201. data/lib/active_record/railtie.rb +224 -57
  202. data/lib/active_record/railties/console_sandbox.rb +2 -4
  203. data/lib/active_record/railties/controller_runtime.rb +31 -36
  204. data/lib/active_record/railties/databases.rake +369 -101
  205. data/lib/active_record/readonly_attributes.rb +15 -0
  206. data/lib/active_record/reflection.rb +170 -137
  207. data/lib/active_record/relation/batches/batch_enumerator.rb +44 -14
  208. data/lib/active_record/relation/batches.rb +46 -37
  209. data/lib/active_record/relation/calculations.rb +168 -96
  210. data/lib/active_record/relation/delegation.rb +37 -52
  211. data/lib/active_record/relation/finder_methods.rb +79 -58
  212. data/lib/active_record/relation/from_clause.rb +5 -1
  213. data/lib/active_record/relation/merger.rb +50 -51
  214. data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
  215. data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
  216. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  217. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +11 -10
  218. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  219. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  220. data/lib/active_record/relation/predicate_builder.rb +58 -46
  221. data/lib/active_record/relation/query_attribute.rb +9 -10
  222. data/lib/active_record/relation/query_methods.rb +685 -208
  223. data/lib/active_record/relation/record_fetch_warning.rb +9 -11
  224. data/lib/active_record/relation/spawn_methods.rb +10 -10
  225. data/lib/active_record/relation/where_clause.rb +108 -64
  226. data/lib/active_record/relation.rb +515 -151
  227. data/lib/active_record/result.rb +78 -42
  228. data/lib/active_record/runtime_registry.rb +9 -13
  229. data/lib/active_record/sanitization.rb +29 -44
  230. data/lib/active_record/schema.rb +37 -31
  231. data/lib/active_record/schema_dumper.rb +74 -23
  232. data/lib/active_record/schema_migration.rb +7 -9
  233. data/lib/active_record/scoping/default.rb +62 -17
  234. data/lib/active_record/scoping/named.rb +17 -32
  235. data/lib/active_record/scoping.rb +70 -41
  236. data/lib/active_record/secure_token.rb +16 -8
  237. data/lib/active_record/serialization.rb +6 -4
  238. data/lib/active_record/signed_id.rb +116 -0
  239. data/lib/active_record/statement_cache.rb +49 -6
  240. data/lib/active_record/store.rb +88 -9
  241. data/lib/active_record/suppressor.rb +13 -17
  242. data/lib/active_record/table_metadata.rb +42 -43
  243. data/lib/active_record/tasks/database_tasks.rb +352 -94
  244. data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
  245. data/lib/active_record/tasks/postgresql_database_tasks.rb +41 -39
  246. data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
  247. data/lib/active_record/test_databases.rb +24 -0
  248. data/lib/active_record/test_fixtures.rb +287 -0
  249. data/lib/active_record/timestamp.rb +44 -34
  250. data/lib/active_record/touch_later.rb +23 -22
  251. data/lib/active_record/transactions.rb +67 -128
  252. data/lib/active_record/translation.rb +3 -3
  253. data/lib/active_record/type/adapter_specific_registry.rb +34 -19
  254. data/lib/active_record/type/hash_lookup_type_map.rb +34 -2
  255. data/lib/active_record/type/internal/timezone.rb +2 -2
  256. data/lib/active_record/type/serialized.rb +7 -4
  257. data/lib/active_record/type/time.rb +10 -0
  258. data/lib/active_record/type/type_map.rb +17 -21
  259. data/lib/active_record/type/unsigned_integer.rb +0 -1
  260. data/lib/active_record/type.rb +9 -5
  261. data/lib/active_record/type_caster/connection.rb +15 -15
  262. data/lib/active_record/type_caster/map.rb +8 -8
  263. data/lib/active_record/validations/associated.rb +2 -3
  264. data/lib/active_record/validations/numericality.rb +35 -0
  265. data/lib/active_record/validations/uniqueness.rb +39 -31
  266. data/lib/active_record/validations.rb +4 -3
  267. data/lib/active_record.rb +209 -32
  268. data/lib/arel/alias_predication.rb +9 -0
  269. data/lib/arel/attributes/attribute.rb +33 -0
  270. data/lib/arel/collectors/bind.rb +29 -0
  271. data/lib/arel/collectors/composite.rb +39 -0
  272. data/lib/arel/collectors/plain_string.rb +20 -0
  273. data/lib/arel/collectors/sql_string.rb +27 -0
  274. data/lib/arel/collectors/substitute_binds.rb +35 -0
  275. data/lib/arel/crud.rb +48 -0
  276. data/lib/arel/delete_manager.rb +32 -0
  277. data/lib/arel/errors.rb +9 -0
  278. data/lib/arel/expressions.rb +29 -0
  279. data/lib/arel/factory_methods.rb +49 -0
  280. data/lib/arel/filter_predications.rb +9 -0
  281. data/lib/arel/insert_manager.rb +48 -0
  282. data/lib/arel/math.rb +45 -0
  283. data/lib/arel/nodes/and.rb +32 -0
  284. data/lib/arel/nodes/ascending.rb +23 -0
  285. data/lib/arel/nodes/binary.rb +126 -0
  286. data/lib/arel/nodes/bind_param.rb +44 -0
  287. data/lib/arel/nodes/case.rb +55 -0
  288. data/lib/arel/nodes/casted.rb +62 -0
  289. data/lib/arel/nodes/comment.rb +29 -0
  290. data/lib/arel/nodes/count.rb +12 -0
  291. data/lib/arel/nodes/delete_statement.rb +44 -0
  292. data/lib/arel/nodes/descending.rb +23 -0
  293. data/lib/arel/nodes/equality.rb +15 -0
  294. data/lib/arel/nodes/extract.rb +24 -0
  295. data/lib/arel/nodes/false.rb +16 -0
  296. data/lib/arel/nodes/filter.rb +10 -0
  297. data/lib/arel/nodes/full_outer_join.rb +8 -0
  298. data/lib/arel/nodes/function.rb +45 -0
  299. data/lib/arel/nodes/grouping.rb +11 -0
  300. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  301. data/lib/arel/nodes/in.rb +15 -0
  302. data/lib/arel/nodes/infix_operation.rb +92 -0
  303. data/lib/arel/nodes/inner_join.rb +8 -0
  304. data/lib/arel/nodes/insert_statement.rb +37 -0
  305. data/lib/arel/nodes/join_source.rb +20 -0
  306. data/lib/arel/nodes/matches.rb +18 -0
  307. data/lib/arel/nodes/named_function.rb +23 -0
  308. data/lib/arel/nodes/node.rb +51 -0
  309. data/lib/arel/nodes/node_expression.rb +13 -0
  310. data/lib/arel/nodes/ordering.rb +27 -0
  311. data/lib/arel/nodes/outer_join.rb +8 -0
  312. data/lib/arel/nodes/over.rb +15 -0
  313. data/lib/arel/nodes/regexp.rb +16 -0
  314. data/lib/arel/nodes/right_outer_join.rb +8 -0
  315. data/lib/arel/nodes/select_core.rb +67 -0
  316. data/lib/arel/nodes/select_statement.rb +41 -0
  317. data/lib/arel/nodes/sql_literal.rb +19 -0
  318. data/lib/arel/nodes/string_join.rb +11 -0
  319. data/lib/arel/nodes/table_alias.rb +31 -0
  320. data/lib/arel/nodes/terminal.rb +16 -0
  321. data/lib/arel/nodes/true.rb +16 -0
  322. data/lib/arel/nodes/unary.rb +44 -0
  323. data/lib/arel/nodes/unary_operation.rb +20 -0
  324. data/lib/arel/nodes/unqualified_column.rb +22 -0
  325. data/lib/arel/nodes/update_statement.rb +46 -0
  326. data/lib/arel/nodes/values_list.rb +9 -0
  327. data/lib/arel/nodes/window.rb +126 -0
  328. data/lib/arel/nodes/with.rb +11 -0
  329. data/lib/arel/nodes.rb +71 -0
  330. data/lib/arel/order_predications.rb +13 -0
  331. data/lib/arel/predications.rb +258 -0
  332. data/lib/arel/select_manager.rb +276 -0
  333. data/lib/arel/table.rb +117 -0
  334. data/lib/arel/tree_manager.rb +60 -0
  335. data/lib/arel/update_manager.rb +48 -0
  336. data/lib/arel/visitors/dot.rb +298 -0
  337. data/lib/arel/visitors/mysql.rb +99 -0
  338. data/lib/arel/visitors/postgresql.rb +110 -0
  339. data/lib/arel/visitors/sqlite.rb +38 -0
  340. data/lib/arel/visitors/to_sql.rb +955 -0
  341. data/lib/arel/visitors/visitor.rb +45 -0
  342. data/lib/arel/visitors.rb +13 -0
  343. data/lib/arel/window_predications.rb +9 -0
  344. data/lib/arel.rb +55 -0
  345. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  346. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  347. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
  348. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
  349. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
  350. data/lib/rails/generators/active_record/migration.rb +19 -2
  351. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  352. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  353. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  354. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  355. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  356. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  357. metadata +162 -32
  358. data/lib/active_record/attribute_decorators.rb +0 -90
  359. data/lib/active_record/collection_cache_key.rb +0 -53
  360. data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
  361. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
  362. data/lib/active_record/define_callbacks.rb +0 -22
  363. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
  364. data/lib/active_record/relation/where_clause_factory.rb +0 -34
@@ -4,21 +4,41 @@ require "thread"
4
4
  require "concurrent/map"
5
5
  require "monitor"
6
6
 
7
+ require "active_record/connection_adapters/abstract/connection_pool/queue"
8
+ require "active_record/connection_adapters/abstract/connection_pool/reaper"
9
+
7
10
  module ActiveRecord
8
- # Raised when a connection could not be obtained within the connection
9
- # acquisition timeout period: because max connections in pool
10
- # are in use.
11
- class ConnectionTimeoutError < ConnectionNotEstablished
12
- end
11
+ module ConnectionAdapters
12
+ module AbstractPool # :nodoc:
13
+ def get_schema_cache(connection)
14
+ self.schema_cache ||= SchemaCache.new(connection)
15
+ schema_cache.connection = connection
16
+ schema_cache
17
+ end
13
18
 
14
- # Raised when a pool was unable to get ahold of all its connections
15
- # to perform a "group" action such as
16
- # {ActiveRecord::Base.connection_pool.disconnect!}[rdoc-ref:ConnectionAdapters::ConnectionPool#disconnect!]
17
- # or {ActiveRecord::Base.clear_reloadable_connections!}[rdoc-ref:ConnectionAdapters::ConnectionHandler#clear_reloadable_connections!].
18
- class ExclusiveConnectionTimeoutError < ConnectionTimeoutError
19
- end
19
+ def set_schema_cache(cache)
20
+ self.schema_cache = cache
21
+ end
22
+
23
+ def lazily_set_schema_cache
24
+ return unless ActiveRecord.lazily_load_schema_cache
25
+
26
+ cache = SchemaCache.load_from(db_config.lazy_schema_cache_path)
27
+ set_schema_cache(cache)
28
+ end
29
+ end
30
+
31
+ class NullPool # :nodoc:
32
+ include ConnectionAdapters::AbstractPool
33
+
34
+ attr_accessor :schema_cache
35
+
36
+ def connection_class; end
37
+ def checkin(_); end
38
+ def remove(_); end
39
+ def async_executor; end
40
+ end
20
41
 
21
- module ConnectionAdapters
22
42
  # Connection pool base class for managing Active Record database
23
43
  # connections.
24
44
  #
@@ -80,264 +100,42 @@ module ActiveRecord
80
100
  # * private methods that require being called in a +synchronize+ blocks
81
101
  # are now explicitly documented
82
102
  class ConnectionPool
83
- # Threadsafe, fair, LIFO queue. Meant to be used by ConnectionPool
84
- # with which it shares a Monitor.
85
- class Queue
86
- def initialize(lock = Monitor.new)
87
- @lock = lock
88
- @cond = @lock.new_cond
89
- @num_waiting = 0
90
- @queue = []
91
- end
92
-
93
- # Test if any threads are currently waiting on the queue.
94
- def any_waiting?
95
- synchronize do
96
- @num_waiting > 0
97
- end
98
- end
99
-
100
- # Returns the number of threads currently waiting on this
101
- # queue.
102
- def num_waiting
103
- synchronize do
104
- @num_waiting
105
- end
106
- end
107
-
108
- # Add +element+ to the queue. Never blocks.
109
- def add(element)
110
- synchronize do
111
- @queue.push element
112
- @cond.signal
113
- end
114
- end
115
-
116
- # If +element+ is in the queue, remove and return it, or +nil+.
117
- def delete(element)
118
- synchronize do
119
- @queue.delete(element)
120
- end
121
- end
122
-
123
- # Remove all elements from the queue.
124
- def clear
125
- synchronize do
126
- @queue.clear
127
- end
128
- end
129
-
130
- # Remove the head of the queue.
131
- #
132
- # If +timeout+ is not given, remove and return the head the
133
- # queue if the number of available elements is strictly
134
- # greater than the number of threads currently waiting (that
135
- # is, don't jump ahead in line). Otherwise, return +nil+.
136
- #
137
- # If +timeout+ is given, block if there is no element
138
- # available, waiting up to +timeout+ seconds for an element to
139
- # become available.
140
- #
141
- # Raises:
142
- # - ActiveRecord::ConnectionTimeoutError if +timeout+ is given and no element
143
- # becomes available within +timeout+ seconds,
144
- def poll(timeout = nil)
145
- synchronize { internal_poll(timeout) }
146
- end
147
-
148
- private
149
-
150
- def internal_poll(timeout)
151
- no_wait_poll || (timeout && wait_poll(timeout))
152
- end
153
-
154
- def synchronize(&block)
155
- @lock.synchronize(&block)
156
- end
157
-
158
- # Test if the queue currently contains any elements.
159
- def any?
160
- !@queue.empty?
161
- end
162
-
163
- # A thread can remove an element from the queue without
164
- # waiting if and only if the number of currently available
165
- # connections is strictly greater than the number of waiting
166
- # threads.
167
- def can_remove_no_wait?
168
- @queue.size > @num_waiting
169
- end
170
-
171
- # Removes and returns the head of the queue if possible, or +nil+.
172
- def remove
173
- @queue.pop
174
- end
175
-
176
- # Remove and return the head the queue if the number of
177
- # available elements is strictly greater than the number of
178
- # threads currently waiting. Otherwise, return +nil+.
179
- def no_wait_poll
180
- remove if can_remove_no_wait?
181
- end
182
-
183
- # Waits on the queue up to +timeout+ seconds, then removes and
184
- # returns the head of the queue.
185
- def wait_poll(timeout)
186
- @num_waiting += 1
187
-
188
- t0 = Time.now
189
- elapsed = 0
190
- loop do
191
- ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
192
- @cond.wait(timeout - elapsed)
193
- end
194
-
195
- return remove if any?
196
-
197
- elapsed = Time.now - t0
198
- if elapsed >= timeout
199
- msg = "could not obtain a connection from the pool within %0.3f seconds (waited %0.3f seconds); all pooled connections were in use" %
200
- [timeout, elapsed]
201
- raise ConnectionTimeoutError, msg
202
- end
203
- end
204
- ensure
205
- @num_waiting -= 1
206
- end
207
- end
208
-
209
- # Adds the ability to turn a basic fair FIFO queue into one
210
- # biased to some thread.
211
- module BiasableQueue # :nodoc:
212
- class BiasedConditionVariable # :nodoc:
213
- # semantics of condition variables guarantee that +broadcast+, +broadcast_on_biased+,
214
- # +signal+ and +wait+ methods are only called while holding a lock
215
- def initialize(lock, other_cond, preferred_thread)
216
- @real_cond = lock.new_cond
217
- @other_cond = other_cond
218
- @preferred_thread = preferred_thread
219
- @num_waiting_on_real_cond = 0
220
- end
221
-
222
- def broadcast
223
- broadcast_on_biased
224
- @other_cond.broadcast
225
- end
226
-
227
- def broadcast_on_biased
228
- @num_waiting_on_real_cond = 0
229
- @real_cond.broadcast
230
- end
231
-
232
- def signal
233
- if @num_waiting_on_real_cond > 0
234
- @num_waiting_on_real_cond -= 1
235
- @real_cond
236
- else
237
- @other_cond
238
- end.signal
239
- end
240
-
241
- def wait(timeout)
242
- if Thread.current == @preferred_thread
243
- @num_waiting_on_real_cond += 1
244
- @real_cond
245
- else
246
- @other_cond
247
- end.wait(timeout)
248
- end
249
- end
250
-
251
- def with_a_bias_for(thread)
252
- previous_cond = nil
253
- new_cond = nil
254
- synchronize do
255
- previous_cond = @cond
256
- @cond = new_cond = BiasedConditionVariable.new(@lock, @cond, thread)
257
- end
258
- yield
259
- ensure
260
- synchronize do
261
- @cond = previous_cond if previous_cond
262
- new_cond.broadcast_on_biased if new_cond # wake up any remaining sleepers
263
- end
264
- end
265
- end
266
-
267
- # Connections must be leased while holding the main pool mutex. This is
268
- # an internal subclass that also +.leases+ returned connections while
269
- # still in queue's critical section (queue synchronizes with the same
270
- # <tt>@lock</tt> as the main pool) so that a returned connection is already
271
- # leased and there is no need to re-enter synchronized block.
272
- class ConnectionLeasingQueue < Queue # :nodoc:
273
- include BiasableQueue
274
-
275
- private
276
- def internal_poll(timeout)
277
- conn = super
278
- conn.lease if conn
279
- conn
280
- end
281
- end
282
-
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.
286
- #
287
- # Configure the frequency by setting +reaping_frequency+ in your database
288
- # yaml file (default 60 seconds).
289
- class Reaper
290
- attr_reader :pool, :frequency
291
-
292
- def initialize(pool, frequency)
293
- @pool = pool
294
- @frequency = frequency
295
- end
296
-
297
- def run
298
- return unless frequency && frequency > 0
299
- Thread.new(frequency, pool) { |t, p|
300
- loop do
301
- sleep t
302
- p.reap
303
- p.flush
304
- end
305
- }
306
- end
307
- end
308
-
309
103
  include MonitorMixin
310
104
  include QueryCache::ConnectionPoolConfiguration
105
+ include ConnectionAdapters::AbstractPool
311
106
 
312
- attr_accessor :automatic_reconnect, :checkout_timeout, :schema_cache
313
- attr_reader :spec, :size, :reaper
107
+ attr_accessor :automatic_reconnect, :checkout_timeout
108
+ attr_reader :db_config, :size, :reaper, :pool_config, :connection_class, :async_executor, :role, :shard
314
109
 
315
- # Creates a new ConnectionPool object. +spec+ is a ConnectionSpecification
110
+ alias_method :connection_klass, :connection_class
111
+ deprecate :connection_klass
112
+ delegate :schema_cache, :schema_cache=, to: :pool_config
113
+
114
+ # Creates a new ConnectionPool object. +pool_config+ is a PoolConfig
316
115
  # object which describes database connection information (e.g. adapter,
317
116
  # host name, username, password, etc), as well as the maximum size for
318
117
  # this ConnectionPool.
319
118
  #
320
119
  # The default ConnectionPool maximum size is 5.
321
- def initialize(spec)
120
+ def initialize(pool_config)
322
121
  super()
323
122
 
324
- @spec = spec
325
-
326
- @checkout_timeout = (spec.config[:checkout_timeout] && spec.config[:checkout_timeout].to_f) || 5
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
123
+ @pool_config = pool_config
124
+ @db_config = pool_config.db_config
125
+ @connection_class = pool_config.connection_class
126
+ @role = pool_config.role
127
+ @shard = pool_config.shard
331
128
 
332
- # default max pool size to 5
333
- @size = (spec.config[:pool] && spec.config[:pool].to_i) || 5
129
+ @checkout_timeout = db_config.checkout_timeout
130
+ @idle_timeout = db_config.idle_timeout
131
+ @size = db_config.pool
334
132
 
335
133
  # This variable tracks the cache of threads mapped to reserved connections, with the
336
134
  # sole purpose of speeding up the +connection+ method. It is not the authoritative
337
135
  # registry of which thread owns which connection. Connection ownership is tracked by
338
136
  # the +connection.owner+ attr on each +connection+ instance.
339
137
  # The invariant works like this: if there is mapping of <tt>thread => conn</tt>,
340
- # then that +thread+ does indeed own that +conn+. However, an absence of a such
138
+ # then that +thread+ does indeed own that +conn+. However, an absence of such
341
139
  # mapping does not mean that the +thread+ doesn't own the said connection. In
342
140
  # that case +conn.owner+ attr should be consulted.
343
141
  # Access and modification of <tt>@thread_cached_conns</tt> does not require
@@ -358,10 +156,11 @@ module ActiveRecord
358
156
 
359
157
  @lock_thread = false
360
158
 
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)
159
+ @async_executor = build_async_executor
160
+
161
+ lazily_set_schema_cache
162
+
163
+ @reaper = Reaper.new(self, db_config.reaping_frequency)
365
164
  @reaper.run
366
165
  end
367
166
 
@@ -443,7 +242,7 @@ module ActiveRecord
443
242
  # Raises:
444
243
  # - ActiveRecord::ExclusiveConnectionTimeoutError if unable to gain ownership of all
445
244
  # connections in the pool within a timeout interval (default duration is
446
- # <tt>spec.config[:checkout_timeout] * 2</tt> seconds).
245
+ # <tt>spec.db_config.checkout_timeout * 2</tt> seconds).
447
246
  def disconnect(raise_on_acquisition_timeout = true)
448
247
  with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
449
248
  synchronize do
@@ -464,7 +263,7 @@ module ActiveRecord
464
263
  #
465
264
  # The pool first tries to gain ownership of all connections. If unable to
466
265
  # do so within a timeout interval (default duration is
467
- # <tt>spec.config[:checkout_timeout] * 2</tt> seconds), then the pool is forcefully
266
+ # <tt>spec.db_config.checkout_timeout * 2</tt> seconds), then the pool is forcefully
468
267
  # disconnected without any regard for other connection owning threads.
469
268
  def disconnect!
470
269
  disconnect(false)
@@ -477,7 +276,7 @@ module ActiveRecord
477
276
  # See AbstractAdapter#discard!
478
277
  def discard! # :nodoc:
479
278
  synchronize do
480
- return if @connections.nil? # already discarded
279
+ return if self.discarded?
481
280
  @connections.each do |conn|
482
281
  conn.discard!
483
282
  end
@@ -485,13 +284,17 @@ module ActiveRecord
485
284
  end
486
285
  end
487
286
 
287
+ def discarded? # :nodoc:
288
+ @connections.nil?
289
+ end
290
+
488
291
  # Clears the cache which maps classes and re-connects connections that
489
292
  # require reloading.
490
293
  #
491
294
  # Raises:
492
295
  # - ActiveRecord::ExclusiveConnectionTimeoutError if unable to gain ownership of all
493
296
  # connections in the pool within a timeout interval (default duration is
494
- # <tt>spec.config[:checkout_timeout] * 2</tt> seconds).
297
+ # <tt>spec.db_config.checkout_timeout * 2</tt> seconds).
495
298
  def clear_reloadable_connections(raise_on_acquisition_timeout = true)
496
299
  with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
497
300
  synchronize do
@@ -513,7 +316,7 @@ module ActiveRecord
513
316
  #
514
317
  # The pool first tries to gain ownership of all connections. If unable to
515
318
  # do so within a timeout interval (default duration is
516
- # <tt>spec.config[:checkout_timeout] * 2</tt> seconds), then the pool forcefully
319
+ # <tt>spec.db_config.checkout_timeout * 2</tt> seconds), then the pool forcefully
517
320
  # clears the cache and reloads connections without any regard for other
518
321
  # connection owning threads.
519
322
  def clear_reloadable_connections!
@@ -593,6 +396,7 @@ module ActiveRecord
593
396
  # or a thread dies unexpectedly.
594
397
  def reap
595
398
  stale_connections = synchronize do
399
+ return if self.discarded?
596
400
  @connections.select do |conn|
597
401
  conn.in_use? && !conn.owner.alive?
598
402
  end.each do |conn|
@@ -617,6 +421,7 @@ module ActiveRecord
617
421
  return if minimum_idle.nil?
618
422
 
619
423
  idle_connections = synchronize do
424
+ return if self.discarded?
620
425
  @connections.select do |conn|
621
426
  !conn.in_use? && conn.seconds_idle >= minimum_idle
622
427
  end.each do |conn|
@@ -661,7 +466,28 @@ module ActiveRecord
661
466
  end
662
467
  end
663
468
 
469
+ def schedule_query(future_result) # :nodoc:
470
+ @async_executor.post { future_result.execute_or_skip }
471
+ Thread.pass
472
+ end
473
+
664
474
  private
475
+ def build_async_executor
476
+ case ActiveRecord.async_query_executor
477
+ when :multi_thread_pool
478
+ if @db_config.max_threads > 0
479
+ Concurrent::ThreadPoolExecutor.new(
480
+ min_threads: @db_config.min_threads,
481
+ max_threads: @db_config.max_threads,
482
+ max_queue: @db_config.max_queue,
483
+ fallback_policy: :caller_runs
484
+ )
485
+ end
486
+ when :global_thread_pool
487
+ ActiveRecord.global_thread_pool_async_query_executor
488
+ end
489
+ end
490
+
665
491
  #--
666
492
  # this is unfortunately not concurrent
667
493
  def bulk_make_new_connections(num_new_conns_needed)
@@ -705,13 +531,13 @@ module ActiveRecord
705
531
  end
706
532
 
707
533
  newly_checked_out = []
708
- timeout_time = Time.now + (@checkout_timeout * 2)
534
+ timeout_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) + (@checkout_timeout * 2)
709
535
 
710
536
  @available.with_a_bias_for(Thread.current) do
711
537
  loop do
712
538
  synchronize do
713
539
  return if collected_conns.size == @connections.size && @now_connecting == 0
714
- remaining_timeout = timeout_time - Time.now
540
+ remaining_timeout = timeout_time - Process.clock_gettime(Process::CLOCK_MONOTONIC)
715
541
  remaining_timeout = 0 if remaining_timeout < 0
716
542
  conn = checkout_for_exclusive_access(remaining_timeout)
717
543
  collected_conns << conn
@@ -750,7 +576,7 @@ module ActiveRecord
750
576
  # this block can't be easily moved into attempt_to_checkout_all_existing_connections's
751
577
  # rescue block, because doing so would put it outside of synchronize section, without
752
578
  # being in a critical section thread_report might become inaccurate
753
- msg = "could not obtain ownership of all database connections in #{checkout_timeout} seconds".dup
579
+ msg = +"could not obtain ownership of all database connections in #{checkout_timeout} seconds"
754
580
 
755
581
  thread_report = []
756
582
  @connections.each do |conn|
@@ -827,8 +653,8 @@ module ActiveRecord
827
653
  alias_method :release, :remove_connection_from_thread_cache
828
654
 
829
655
  def new_connection
830
- Base.send(spec.adapter_method, spec.config).tap do |conn|
831
- conn.schema_cache = schema_cache.dup if schema_cache
656
+ Base.public_send(db_config.adapter_method, db_config.configuration_hash).tap do |conn|
657
+ conn.check_version
832
658
  end
833
659
  end
834
660
 
@@ -885,203 +711,5 @@ module ActiveRecord
885
711
  raise
886
712
  end
887
713
  end
888
-
889
- # ConnectionHandler is a collection of ConnectionPool objects. It is used
890
- # for keeping separate connection pools that connect to different databases.
891
- #
892
- # For example, suppose that you have 5 models, with the following hierarchy:
893
- #
894
- # class Author < ActiveRecord::Base
895
- # end
896
- #
897
- # class BankAccount < ActiveRecord::Base
898
- # end
899
- #
900
- # class Book < ActiveRecord::Base
901
- # establish_connection :library_db
902
- # end
903
- #
904
- # class ScaryBook < Book
905
- # end
906
- #
907
- # class GoodBook < Book
908
- # end
909
- #
910
- # And a database.yml that looked like this:
911
- #
912
- # development:
913
- # database: my_application
914
- # host: localhost
915
- #
916
- # library_db:
917
- # database: library
918
- # host: some.library.org
919
- #
920
- # Your primary database in the development environment is "my_application"
921
- # but the Book model connects to a separate database called "library_db"
922
- # (this can even be a database on a different machine).
923
- #
924
- # Book, ScaryBook and GoodBook will all use the same connection pool to
925
- # "library_db" while Author, BankAccount, and any other models you create
926
- # will use the default connection pool to "my_application".
927
- #
928
- # The various connection pools are managed by a single instance of
929
- # ConnectionHandler accessible via ActiveRecord::Base.connection_handler.
930
- # All Active Record models use this handler to determine the connection pool that they
931
- # should use.
932
- #
933
- # The ConnectionHandler class is not coupled with the Active models, as it has no knowledge
934
- # about the model. The model needs to pass a specification name to the handler,
935
- # in order to look up the correct connection pool.
936
- class ConnectionHandler
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
-
943
- h[k] = Concurrent::Map.new(initial_capacity: 2)
944
- end
945
- end
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
-
968
- def connection_pool_list
969
- owner_to_pool.values.compact
970
- end
971
- alias :connection_pools :connection_pool_list
972
-
973
- def establish_connection(config)
974
- resolver = ConnectionSpecification::Resolver.new(Base.configurations)
975
- spec = resolver.spec(config)
976
-
977
- remove_connection(spec.name)
978
-
979
- message_bus = ActiveSupport::Notifications.instrumenter
980
- payload = {
981
- connection_id: object_id
982
- }
983
- if spec
984
- payload[:spec_name] = spec.name
985
- payload[:config] = spec.config
986
- end
987
-
988
- message_bus.instrument("!connection.active_record", payload) do
989
- owner_to_pool[spec.name] = ConnectionAdapters::ConnectionPool.new(spec)
990
- end
991
-
992
- owner_to_pool[spec.name]
993
- end
994
-
995
- # Returns true if there are any active connections among the connection
996
- # pools that the ConnectionHandler is managing.
997
- def active_connections?
998
- connection_pool_list.any?(&:active_connection?)
999
- end
1000
-
1001
- # Returns any connections in use by the current thread back to the pool,
1002
- # and also returns connections to the pool cached by threads that are no
1003
- # longer alive.
1004
- def clear_active_connections!
1005
- connection_pool_list.each(&:release_connection)
1006
- end
1007
-
1008
- # Clears the cache which maps classes.
1009
- #
1010
- # See ConnectionPool#clear_reloadable_connections! for details.
1011
- def clear_reloadable_connections!
1012
- connection_pool_list.each(&:clear_reloadable_connections!)
1013
- end
1014
-
1015
- def clear_all_connections!
1016
- connection_pool_list.each(&:disconnect!)
1017
- end
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
-
1026
- # Locate the connection of the nearest super class. This can be an
1027
- # active or defined connection: if it is the latter, it will be
1028
- # opened and set as the active connection for the class it was defined
1029
- # for (not necessarily the current class).
1030
- def retrieve_connection(spec_name) #:nodoc:
1031
- pool = retrieve_connection_pool(spec_name)
1032
- raise ConnectionNotEstablished, "No connection pool with '#{spec_name}' found." unless pool
1033
- pool.connection
1034
- end
1035
-
1036
- # Returns true if a connection that's accessible to this class has
1037
- # already been opened.
1038
- def connected?(spec_name)
1039
- conn = retrieve_connection_pool(spec_name)
1040
- conn && conn.connected?
1041
- end
1042
-
1043
- # Remove the connection for this class. This will close the active
1044
- # connection and the defined connection (if they exist). The result
1045
- # can be used as an argument for #establish_connection, for easily
1046
- # re-establishing the connection.
1047
- def remove_connection(spec_name)
1048
- if pool = owner_to_pool.delete(spec_name)
1049
- pool.automatic_reconnect = false
1050
- pool.disconnect!
1051
- pool.spec.config
1052
- end
1053
- end
1054
-
1055
- # Retrieving the connection pool happens a lot, so we cache it in @owner_to_pool.
1056
- # This makes retrieving the connection pool O(1) once the process is warm.
1057
- # When a connection is established or removed, we invalidate the cache.
1058
- def retrieve_connection_pool(spec_name)
1059
- owner_to_pool.fetch(spec_name) do
1060
- # Check if a connection was previously established in an ancestor process,
1061
- # which may have been forked.
1062
- if ancestor_pool = pool_from_any_process_for(spec_name)
1063
- # A connection was established in an ancestor process that must have
1064
- # subsequently forked. We can't reuse the connection, but we can copy
1065
- # the specification and establish a new connection with it.
1066
- establish_connection(ancestor_pool.spec.to_hash).tap do |pool|
1067
- pool.schema_cache = ancestor_pool.schema_cache if ancestor_pool.schema_cache
1068
- end
1069
- else
1070
- owner_to_pool[spec_name] = nil
1071
- end
1072
- end
1073
- end
1074
-
1075
- private
1076
-
1077
- def owner_to_pool
1078
- @owner_to_pool[Process.pid]
1079
- end
1080
-
1081
- def pool_from_any_process_for(spec_name)
1082
- owner_to_pool = @owner_to_pool.values.reverse.find { |v| v[spec_name] }
1083
- owner_to_pool && owner_to_pool[spec_name]
1084
- end
1085
- end
1086
714
  end
1087
715
  end