omg-activerecord 8.0.0.alpha1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (412) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +355 -0
  3. data/MIT-LICENSE +22 -0
  4. data/README.rdoc +219 -0
  5. data/examples/performance.rb +185 -0
  6. data/examples/simple.rb +15 -0
  7. data/lib/active_record/aggregations.rb +287 -0
  8. data/lib/active_record/association_relation.rb +50 -0
  9. data/lib/active_record/associations/alias_tracker.rb +90 -0
  10. data/lib/active_record/associations/association.rb +417 -0
  11. data/lib/active_record/associations/association_scope.rb +175 -0
  12. data/lib/active_record/associations/belongs_to_association.rb +163 -0
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
  14. data/lib/active_record/associations/builder/association.rb +170 -0
  15. data/lib/active_record/associations/builder/belongs_to.rb +160 -0
  16. data/lib/active_record/associations/builder/collection_association.rb +80 -0
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +107 -0
  18. data/lib/active_record/associations/builder/has_many.rb +23 -0
  19. data/lib/active_record/associations/builder/has_one.rb +61 -0
  20. data/lib/active_record/associations/builder/singular_association.rb +48 -0
  21. data/lib/active_record/associations/collection_association.rb +535 -0
  22. data/lib/active_record/associations/collection_proxy.rb +1163 -0
  23. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  24. data/lib/active_record/associations/errors.rb +265 -0
  25. data/lib/active_record/associations/foreign_association.rb +40 -0
  26. data/lib/active_record/associations/has_many_association.rb +167 -0
  27. data/lib/active_record/associations/has_many_through_association.rb +232 -0
  28. data/lib/active_record/associations/has_one_association.rb +142 -0
  29. data/lib/active_record/associations/has_one_through_association.rb +45 -0
  30. data/lib/active_record/associations/join_dependency/join_association.rb +106 -0
  31. data/lib/active_record/associations/join_dependency/join_base.rb +23 -0
  32. data/lib/active_record/associations/join_dependency/join_part.rb +71 -0
  33. data/lib/active_record/associations/join_dependency.rb +301 -0
  34. data/lib/active_record/associations/nested_error.rb +47 -0
  35. data/lib/active_record/associations/preloader/association.rb +316 -0
  36. data/lib/active_record/associations/preloader/batch.rb +48 -0
  37. data/lib/active_record/associations/preloader/branch.rb +153 -0
  38. data/lib/active_record/associations/preloader/through_association.rb +150 -0
  39. data/lib/active_record/associations/preloader.rb +135 -0
  40. data/lib/active_record/associations/singular_association.rb +76 -0
  41. data/lib/active_record/associations/through_association.rb +132 -0
  42. data/lib/active_record/associations.rb +1897 -0
  43. data/lib/active_record/asynchronous_queries_tracker.rb +64 -0
  44. data/lib/active_record/attribute_assignment.rb +82 -0
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +106 -0
  46. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  47. data/lib/active_record/attribute_methods/dirty.rb +262 -0
  48. data/lib/active_record/attribute_methods/primary_key.rb +158 -0
  49. data/lib/active_record/attribute_methods/query.rb +50 -0
  50. data/lib/active_record/attribute_methods/read.rb +46 -0
  51. data/lib/active_record/attribute_methods/serialization.rb +232 -0
  52. data/lib/active_record/attribute_methods/time_zone_conversion.rb +94 -0
  53. data/lib/active_record/attribute_methods/write.rb +49 -0
  54. data/lib/active_record/attribute_methods.rb +542 -0
  55. data/lib/active_record/attributes.rb +307 -0
  56. data/lib/active_record/autosave_association.rb +586 -0
  57. data/lib/active_record/base.rb +338 -0
  58. data/lib/active_record/callbacks.rb +452 -0
  59. data/lib/active_record/coders/column_serializer.rb +61 -0
  60. data/lib/active_record/coders/json.rb +15 -0
  61. data/lib/active_record/coders/yaml_column.rb +95 -0
  62. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +290 -0
  63. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +210 -0
  64. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
  65. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +923 -0
  66. data/lib/active_record/connection_adapters/abstract/database_limits.rb +31 -0
  67. data/lib/active_record/connection_adapters/abstract/database_statements.rb +747 -0
  68. data/lib/active_record/connection_adapters/abstract/query_cache.rb +319 -0
  69. data/lib/active_record/connection_adapters/abstract/quoting.rb +239 -0
  70. data/lib/active_record/connection_adapters/abstract/savepoints.rb +24 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +190 -0
  72. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +961 -0
  73. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +106 -0
  74. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1883 -0
  75. data/lib/active_record/connection_adapters/abstract/transaction.rb +676 -0
  76. data/lib/active_record/connection_adapters/abstract_adapter.rb +1218 -0
  77. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +1016 -0
  78. data/lib/active_record/connection_adapters/column.rb +122 -0
  79. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  80. data/lib/active_record/connection_adapters/mysql/column.rb +28 -0
  81. data/lib/active_record/connection_adapters/mysql/database_statements.rb +95 -0
  82. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
  83. data/lib/active_record/connection_adapters/mysql/quoting.rb +114 -0
  84. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +106 -0
  85. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +106 -0
  86. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +97 -0
  87. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +300 -0
  88. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +40 -0
  89. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +96 -0
  90. data/lib/active_record/connection_adapters/mysql2_adapter.rb +196 -0
  91. data/lib/active_record/connection_adapters/pool_config.rb +83 -0
  92. data/lib/active_record/connection_adapters/pool_manager.rb +57 -0
  93. data/lib/active_record/connection_adapters/postgresql/column.rb +82 -0
  94. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +231 -0
  95. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +91 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +53 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +54 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +31 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +20 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +109 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
  109. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
  110. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  111. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +42 -0
  112. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
  113. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +74 -0
  114. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +124 -0
  115. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
  116. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  117. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  118. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +125 -0
  119. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +45 -0
  120. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
  121. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
  122. data/lib/active_record/connection_adapters/postgresql/oid.rb +38 -0
  123. data/lib/active_record/connection_adapters/postgresql/quoting.rb +238 -0
  124. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +71 -0
  125. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +169 -0
  126. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +392 -0
  127. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +127 -0
  128. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +1162 -0
  129. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +44 -0
  130. data/lib/active_record/connection_adapters/postgresql/utils.rb +79 -0
  131. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1182 -0
  132. data/lib/active_record/connection_adapters/schema_cache.rb +478 -0
  133. data/lib/active_record/connection_adapters/sql_type_metadata.rb +45 -0
  134. data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
  135. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +145 -0
  136. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  137. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +116 -0
  138. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +37 -0
  139. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +39 -0
  140. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +47 -0
  141. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +221 -0
  142. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +843 -0
  143. data/lib/active_record/connection_adapters/statement_pool.rb +67 -0
  144. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +69 -0
  145. data/lib/active_record/connection_adapters/trilogy_adapter.rb +212 -0
  146. data/lib/active_record/connection_adapters.rb +176 -0
  147. data/lib/active_record/connection_handling.rb +413 -0
  148. data/lib/active_record/core.rb +836 -0
  149. data/lib/active_record/counter_cache.rb +230 -0
  150. data/lib/active_record/database_configurations/connection_url_resolver.rb +105 -0
  151. data/lib/active_record/database_configurations/database_config.rb +104 -0
  152. data/lib/active_record/database_configurations/hash_config.rb +172 -0
  153. data/lib/active_record/database_configurations/url_config.rb +78 -0
  154. data/lib/active_record/database_configurations.rb +309 -0
  155. data/lib/active_record/delegated_type.rb +289 -0
  156. data/lib/active_record/deprecator.rb +7 -0
  157. data/lib/active_record/destroy_association_async_job.rb +38 -0
  158. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  159. data/lib/active_record/dynamic_matchers.rb +121 -0
  160. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  161. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  162. data/lib/active_record/encryption/cipher.rb +53 -0
  163. data/lib/active_record/encryption/config.rb +70 -0
  164. data/lib/active_record/encryption/configurable.rb +60 -0
  165. data/lib/active_record/encryption/context.rb +42 -0
  166. data/lib/active_record/encryption/contexts.rb +76 -0
  167. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  168. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  169. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  170. data/lib/active_record/encryption/encrypted_attribute_type.rb +184 -0
  171. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  172. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  173. data/lib/active_record/encryption/encryptor.rb +177 -0
  174. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  175. data/lib/active_record/encryption/errors.rb +15 -0
  176. data/lib/active_record/encryption/extended_deterministic_queries.rb +159 -0
  177. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  178. data/lib/active_record/encryption/key.rb +28 -0
  179. data/lib/active_record/encryption/key_generator.rb +53 -0
  180. data/lib/active_record/encryption/key_provider.rb +46 -0
  181. data/lib/active_record/encryption/message.rb +33 -0
  182. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  183. data/lib/active_record/encryption/message_serializer.rb +96 -0
  184. data/lib/active_record/encryption/null_encryptor.rb +25 -0
  185. data/lib/active_record/encryption/properties.rb +76 -0
  186. data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
  187. data/lib/active_record/encryption/scheme.rb +107 -0
  188. data/lib/active_record/encryption.rb +58 -0
  189. data/lib/active_record/enum.rb +424 -0
  190. data/lib/active_record/errors.rb +614 -0
  191. data/lib/active_record/explain.rb +63 -0
  192. data/lib/active_record/explain_registry.rb +37 -0
  193. data/lib/active_record/explain_subscriber.rb +34 -0
  194. data/lib/active_record/fixture_set/file.rb +89 -0
  195. data/lib/active_record/fixture_set/model_metadata.rb +42 -0
  196. data/lib/active_record/fixture_set/render_context.rb +19 -0
  197. data/lib/active_record/fixture_set/table_row.rb +208 -0
  198. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  199. data/lib/active_record/fixtures.rb +850 -0
  200. data/lib/active_record/future_result.rb +182 -0
  201. data/lib/active_record/gem_version.rb +17 -0
  202. data/lib/active_record/inheritance.rb +366 -0
  203. data/lib/active_record/insert_all.rb +328 -0
  204. data/lib/active_record/integration.rb +209 -0
  205. data/lib/active_record/internal_metadata.rb +164 -0
  206. data/lib/active_record/legacy_yaml_adapter.rb +15 -0
  207. data/lib/active_record/locale/en.yml +48 -0
  208. data/lib/active_record/locking/optimistic.rb +228 -0
  209. data/lib/active_record/locking/pessimistic.rb +102 -0
  210. data/lib/active_record/log_subscriber.rb +149 -0
  211. data/lib/active_record/marshalling.rb +56 -0
  212. data/lib/active_record/message_pack.rb +124 -0
  213. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  214. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  215. data/lib/active_record/middleware/database_selector.rb +87 -0
  216. data/lib/active_record/middleware/shard_selector.rb +62 -0
  217. data/lib/active_record/migration/command_recorder.rb +406 -0
  218. data/lib/active_record/migration/compatibility.rb +490 -0
  219. data/lib/active_record/migration/default_strategy.rb +22 -0
  220. data/lib/active_record/migration/execution_strategy.rb +19 -0
  221. data/lib/active_record/migration/join_table.rb +16 -0
  222. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  223. data/lib/active_record/migration.rb +1626 -0
  224. data/lib/active_record/model_schema.rb +635 -0
  225. data/lib/active_record/nested_attributes.rb +633 -0
  226. data/lib/active_record/no_touching.rb +65 -0
  227. data/lib/active_record/normalization.rb +163 -0
  228. data/lib/active_record/persistence.rb +968 -0
  229. data/lib/active_record/promise.rb +84 -0
  230. data/lib/active_record/query_cache.rb +56 -0
  231. data/lib/active_record/query_logs.rb +247 -0
  232. data/lib/active_record/query_logs_formatter.rb +30 -0
  233. data/lib/active_record/querying.rb +122 -0
  234. data/lib/active_record/railtie.rb +440 -0
  235. data/lib/active_record/railties/console_sandbox.rb +5 -0
  236. data/lib/active_record/railties/controller_runtime.rb +65 -0
  237. data/lib/active_record/railties/databases.rake +641 -0
  238. data/lib/active_record/railties/job_runtime.rb +23 -0
  239. data/lib/active_record/readonly_attributes.rb +66 -0
  240. data/lib/active_record/reflection.rb +1287 -0
  241. data/lib/active_record/relation/batches/batch_enumerator.rb +115 -0
  242. data/lib/active_record/relation/batches.rb +491 -0
  243. data/lib/active_record/relation/calculations.rb +679 -0
  244. data/lib/active_record/relation/delegation.rb +154 -0
  245. data/lib/active_record/relation/finder_methods.rb +661 -0
  246. data/lib/active_record/relation/from_clause.rb +30 -0
  247. data/lib/active_record/relation/merger.rb +192 -0
  248. data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
  249. data/lib/active_record/relation/predicate_builder/association_query_value.rb +76 -0
  250. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  251. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +60 -0
  252. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  253. data/lib/active_record/relation/predicate_builder/relation_handler.rb +24 -0
  254. data/lib/active_record/relation/predicate_builder.rb +181 -0
  255. data/lib/active_record/relation/query_attribute.rb +68 -0
  256. data/lib/active_record/relation/query_methods.rb +2235 -0
  257. data/lib/active_record/relation/record_fetch_warning.rb +52 -0
  258. data/lib/active_record/relation/spawn_methods.rb +78 -0
  259. data/lib/active_record/relation/where_clause.rb +218 -0
  260. data/lib/active_record/relation.rb +1495 -0
  261. data/lib/active_record/result.rb +249 -0
  262. data/lib/active_record/runtime_registry.rb +82 -0
  263. data/lib/active_record/sanitization.rb +254 -0
  264. data/lib/active_record/schema.rb +77 -0
  265. data/lib/active_record/schema_dumper.rb +364 -0
  266. data/lib/active_record/schema_migration.rb +106 -0
  267. data/lib/active_record/scoping/default.rb +205 -0
  268. data/lib/active_record/scoping/named.rb +202 -0
  269. data/lib/active_record/scoping.rb +136 -0
  270. data/lib/active_record/secure_password.rb +60 -0
  271. data/lib/active_record/secure_token.rb +66 -0
  272. data/lib/active_record/serialization.rb +29 -0
  273. data/lib/active_record/signed_id.rb +137 -0
  274. data/lib/active_record/statement_cache.rb +164 -0
  275. data/lib/active_record/store.rb +299 -0
  276. data/lib/active_record/suppressor.rb +59 -0
  277. data/lib/active_record/table_metadata.rb +85 -0
  278. data/lib/active_record/tasks/database_tasks.rb +681 -0
  279. data/lib/active_record/tasks/mysql_database_tasks.rb +120 -0
  280. data/lib/active_record/tasks/postgresql_database_tasks.rb +147 -0
  281. data/lib/active_record/tasks/sqlite_database_tasks.rb +89 -0
  282. data/lib/active_record/test_databases.rb +24 -0
  283. data/lib/active_record/test_fixtures.rb +321 -0
  284. data/lib/active_record/testing/query_assertions.rb +121 -0
  285. data/lib/active_record/timestamp.rb +177 -0
  286. data/lib/active_record/token_for.rb +123 -0
  287. data/lib/active_record/touch_later.rb +70 -0
  288. data/lib/active_record/transaction.rb +132 -0
  289. data/lib/active_record/transactions.rb +523 -0
  290. data/lib/active_record/translation.rb +22 -0
  291. data/lib/active_record/type/adapter_specific_registry.rb +144 -0
  292. data/lib/active_record/type/date.rb +9 -0
  293. data/lib/active_record/type/date_time.rb +9 -0
  294. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  295. data/lib/active_record/type/hash_lookup_type_map.rb +57 -0
  296. data/lib/active_record/type/internal/timezone.rb +22 -0
  297. data/lib/active_record/type/json.rb +30 -0
  298. data/lib/active_record/type/serialized.rb +76 -0
  299. data/lib/active_record/type/text.rb +11 -0
  300. data/lib/active_record/type/time.rb +35 -0
  301. data/lib/active_record/type/type_map.rb +58 -0
  302. data/lib/active_record/type/unsigned_integer.rb +16 -0
  303. data/lib/active_record/type.rb +83 -0
  304. data/lib/active_record/type_caster/connection.rb +33 -0
  305. data/lib/active_record/type_caster/map.rb +23 -0
  306. data/lib/active_record/type_caster.rb +9 -0
  307. data/lib/active_record/validations/absence.rb +25 -0
  308. data/lib/active_record/validations/associated.rb +65 -0
  309. data/lib/active_record/validations/length.rb +26 -0
  310. data/lib/active_record/validations/numericality.rb +36 -0
  311. data/lib/active_record/validations/presence.rb +45 -0
  312. data/lib/active_record/validations/uniqueness.rb +295 -0
  313. data/lib/active_record/validations.rb +101 -0
  314. data/lib/active_record/version.rb +10 -0
  315. data/lib/active_record.rb +616 -0
  316. data/lib/arel/alias_predication.rb +9 -0
  317. data/lib/arel/attributes/attribute.rb +33 -0
  318. data/lib/arel/collectors/bind.rb +31 -0
  319. data/lib/arel/collectors/composite.rb +46 -0
  320. data/lib/arel/collectors/plain_string.rb +20 -0
  321. data/lib/arel/collectors/sql_string.rb +27 -0
  322. data/lib/arel/collectors/substitute_binds.rb +35 -0
  323. data/lib/arel/crud.rb +48 -0
  324. data/lib/arel/delete_manager.rb +32 -0
  325. data/lib/arel/errors.rb +19 -0
  326. data/lib/arel/expressions.rb +29 -0
  327. data/lib/arel/factory_methods.rb +53 -0
  328. data/lib/arel/filter_predications.rb +9 -0
  329. data/lib/arel/insert_manager.rb +48 -0
  330. data/lib/arel/math.rb +45 -0
  331. data/lib/arel/nodes/ascending.rb +23 -0
  332. data/lib/arel/nodes/binary.rb +125 -0
  333. data/lib/arel/nodes/bind_param.rb +44 -0
  334. data/lib/arel/nodes/bound_sql_literal.rb +65 -0
  335. data/lib/arel/nodes/case.rb +55 -0
  336. data/lib/arel/nodes/casted.rb +62 -0
  337. data/lib/arel/nodes/comment.rb +29 -0
  338. data/lib/arel/nodes/count.rb +12 -0
  339. data/lib/arel/nodes/cte.rb +36 -0
  340. data/lib/arel/nodes/delete_statement.rb +44 -0
  341. data/lib/arel/nodes/descending.rb +23 -0
  342. data/lib/arel/nodes/equality.rb +15 -0
  343. data/lib/arel/nodes/extract.rb +24 -0
  344. data/lib/arel/nodes/false.rb +16 -0
  345. data/lib/arel/nodes/filter.rb +10 -0
  346. data/lib/arel/nodes/fragments.rb +35 -0
  347. data/lib/arel/nodes/full_outer_join.rb +8 -0
  348. data/lib/arel/nodes/function.rb +45 -0
  349. data/lib/arel/nodes/grouping.rb +11 -0
  350. data/lib/arel/nodes/homogeneous_in.rb +68 -0
  351. data/lib/arel/nodes/in.rb +15 -0
  352. data/lib/arel/nodes/infix_operation.rb +92 -0
  353. data/lib/arel/nodes/inner_join.rb +8 -0
  354. data/lib/arel/nodes/insert_statement.rb +37 -0
  355. data/lib/arel/nodes/join_source.rb +20 -0
  356. data/lib/arel/nodes/leading_join.rb +8 -0
  357. data/lib/arel/nodes/matches.rb +18 -0
  358. data/lib/arel/nodes/named_function.rb +23 -0
  359. data/lib/arel/nodes/nary.rb +39 -0
  360. data/lib/arel/nodes/node.rb +161 -0
  361. data/lib/arel/nodes/node_expression.rb +13 -0
  362. data/lib/arel/nodes/ordering.rb +27 -0
  363. data/lib/arel/nodes/outer_join.rb +8 -0
  364. data/lib/arel/nodes/over.rb +15 -0
  365. data/lib/arel/nodes/regexp.rb +16 -0
  366. data/lib/arel/nodes/right_outer_join.rb +8 -0
  367. data/lib/arel/nodes/select_core.rb +67 -0
  368. data/lib/arel/nodes/select_statement.rb +41 -0
  369. data/lib/arel/nodes/sql_literal.rb +32 -0
  370. data/lib/arel/nodes/string_join.rb +11 -0
  371. data/lib/arel/nodes/table_alias.rb +35 -0
  372. data/lib/arel/nodes/terminal.rb +16 -0
  373. data/lib/arel/nodes/true.rb +16 -0
  374. data/lib/arel/nodes/unary.rb +44 -0
  375. data/lib/arel/nodes/unary_operation.rb +20 -0
  376. data/lib/arel/nodes/unqualified_column.rb +22 -0
  377. data/lib/arel/nodes/update_statement.rb +46 -0
  378. data/lib/arel/nodes/values_list.rb +9 -0
  379. data/lib/arel/nodes/window.rb +126 -0
  380. data/lib/arel/nodes/with.rb +11 -0
  381. data/lib/arel/nodes.rb +75 -0
  382. data/lib/arel/order_predications.rb +13 -0
  383. data/lib/arel/predications.rb +260 -0
  384. data/lib/arel/select_manager.rb +276 -0
  385. data/lib/arel/table.rb +121 -0
  386. data/lib/arel/tree_manager.rb +65 -0
  387. data/lib/arel/update_manager.rb +49 -0
  388. data/lib/arel/visitors/dot.rb +299 -0
  389. data/lib/arel/visitors/mysql.rb +111 -0
  390. data/lib/arel/visitors/postgresql.rb +99 -0
  391. data/lib/arel/visitors/sqlite.rb +38 -0
  392. data/lib/arel/visitors/to_sql.rb +1033 -0
  393. data/lib/arel/visitors/visitor.rb +45 -0
  394. data/lib/arel/visitors.rb +13 -0
  395. data/lib/arel/window_predications.rb +9 -0
  396. data/lib/arel.rb +73 -0
  397. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  398. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
  399. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  400. data/lib/rails/generators/active_record/migration/migration_generator.rb +76 -0
  401. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +29 -0
  402. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +48 -0
  403. data/lib/rails/generators/active_record/migration.rb +54 -0
  404. data/lib/rails/generators/active_record/model/USAGE +113 -0
  405. data/lib/rails/generators/active_record/model/model_generator.rb +94 -0
  406. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  407. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  408. data/lib/rails/generators/active_record/model/templates/module.rb.tt +7 -0
  409. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  410. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  411. data/lib/rails/generators/active_record.rb +19 -0
  412. metadata +505 -0
@@ -0,0 +1,290 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "concurrent/map"
4
+
5
+ module ActiveRecord
6
+ module ConnectionAdapters
7
+ # = Active Record Connection Handler
8
+ #
9
+ # ConnectionHandler is a collection of ConnectionPool objects. It is used
10
+ # for keeping separate connection pools that connect to different databases.
11
+ #
12
+ # For example, suppose that you have 5 models, with the following hierarchy:
13
+ #
14
+ # class Author < ActiveRecord::Base
15
+ # end
16
+ #
17
+ # class BankAccount < ActiveRecord::Base
18
+ # end
19
+ #
20
+ # class Book < ActiveRecord::Base
21
+ # establish_connection :library_db
22
+ # end
23
+ #
24
+ # class ScaryBook < Book
25
+ # end
26
+ #
27
+ # class GoodBook < Book
28
+ # end
29
+ #
30
+ # And a database.yml that looked like this:
31
+ #
32
+ # development:
33
+ # database: my_application
34
+ # host: localhost
35
+ #
36
+ # library_db:
37
+ # database: library
38
+ # host: some.library.org
39
+ #
40
+ # Your primary database in the development environment is "my_application"
41
+ # but the Book model connects to a separate database called "library_db"
42
+ # (this can even be a database on a different machine).
43
+ #
44
+ # Book, ScaryBook, and GoodBook will all use the same connection pool to
45
+ # "library_db" while Author, BankAccount, and any other models you create
46
+ # will use the default connection pool to "my_application".
47
+ #
48
+ # The various connection pools are managed by a single instance of
49
+ # ConnectionHandler accessible via ActiveRecord::Base.connection_handler.
50
+ # All Active Record models use this handler to determine the connection pool that they
51
+ # should use.
52
+ #
53
+ # The ConnectionHandler class is not coupled with the Active models, as it has no knowledge
54
+ # about the model. The model needs to pass a connection specification name to the handler,
55
+ # in order to look up the correct connection pool.
56
+ class ConnectionHandler
57
+ class StringConnectionName # :nodoc:
58
+ attr_reader :name
59
+
60
+ def initialize(name)
61
+ @name = name
62
+ end
63
+
64
+ def primary_class?
65
+ false
66
+ end
67
+
68
+ def current_preventing_writes
69
+ false
70
+ end
71
+ end
72
+
73
+ def initialize
74
+ # These caches are keyed by pool_config.connection_name (PoolConfig#connection_name).
75
+ @connection_name_to_pool_manager = Concurrent::Map.new(initial_capacity: 2)
76
+ end
77
+
78
+ def prevent_writes # :nodoc:
79
+ ActiveSupport::IsolatedExecutionState[:active_record_prevent_writes]
80
+ end
81
+
82
+ def prevent_writes=(prevent_writes) # :nodoc:
83
+ ActiveSupport::IsolatedExecutionState[:active_record_prevent_writes] = prevent_writes
84
+ end
85
+
86
+ def connection_pool_names # :nodoc:
87
+ connection_name_to_pool_manager.keys
88
+ end
89
+
90
+ # Returns the pools for a connection handler and given role. If +:all+ is passed,
91
+ # all pools belonging to the connection handler will be returned.
92
+ def connection_pool_list(role = nil)
93
+ if role.nil? || role == :all
94
+ connection_name_to_pool_manager.values.flat_map { |m| m.pool_configs.map(&:pool) }
95
+ else
96
+ connection_name_to_pool_manager.values.flat_map { |m| m.pool_configs(role).map(&:pool) }
97
+ end
98
+ end
99
+ alias :connection_pools :connection_pool_list
100
+
101
+ def each_connection_pool(role = nil, &block) # :nodoc:
102
+ role = nil if role == :all
103
+ return enum_for(__method__, role) unless block_given?
104
+
105
+ connection_name_to_pool_manager.each_value do |manager|
106
+ manager.each_pool_config(role) do |pool_config|
107
+ yield pool_config.pool
108
+ end
109
+ end
110
+ end
111
+
112
+ def establish_connection(config, owner_name: Base, role: Base.current_role, shard: Base.current_shard, clobber: false)
113
+ owner_name = determine_owner_name(owner_name, config)
114
+
115
+ pool_config = resolve_pool_config(config, owner_name, role, shard)
116
+ db_config = pool_config.db_config
117
+
118
+ pool_manager = set_pool_manager(pool_config.connection_name)
119
+
120
+ # If there is an existing pool with the same values as the pool_config
121
+ # don't remove the connection. Connections should only be removed if we are
122
+ # establishing a connection on a class that is already connected to a different
123
+ # configuration.
124
+ existing_pool_config = pool_manager.get_pool_config(role, shard)
125
+
126
+ if !clobber && existing_pool_config && existing_pool_config.db_config == db_config
127
+ # Update the pool_config's connection class if it differs. This is used
128
+ # for ensuring that ActiveRecord::Base and the primary_abstract_class use
129
+ # the same pool. Without this granular swapping will not work correctly.
130
+ if owner_name.primary_class? && (existing_pool_config.connection_class != owner_name)
131
+ existing_pool_config.connection_class = owner_name
132
+ end
133
+
134
+ existing_pool_config.pool
135
+ else
136
+ disconnect_pool_from_pool_manager(pool_manager, role, shard)
137
+ pool_manager.set_pool_config(role, shard, pool_config)
138
+
139
+ payload = {
140
+ connection_name: pool_config.connection_name,
141
+ role: role,
142
+ shard: shard,
143
+ config: db_config.configuration_hash
144
+ }
145
+
146
+ ActiveSupport::Notifications.instrumenter.instrument("!connection.active_record", payload) do
147
+ pool_config.pool
148
+ end
149
+ end
150
+ end
151
+
152
+ # Returns true if there are any active connections among the connection
153
+ # pools that the ConnectionHandler is managing.
154
+ def active_connections?(role = nil)
155
+ each_connection_pool(role).any?(&:active_connection?)
156
+ end
157
+
158
+ # Returns any connections in use by the current thread back to the pool,
159
+ # and also returns connections to the pool cached by threads that are no
160
+ # longer alive.
161
+ def clear_active_connections!(role = nil)
162
+ each_connection_pool(role).each do |pool|
163
+ pool.release_connection
164
+ pool.disable_query_cache!
165
+ end
166
+ end
167
+
168
+ # Clears the cache which maps classes.
169
+ #
170
+ # See ConnectionPool#clear_reloadable_connections! for details.
171
+ def clear_reloadable_connections!(role = nil)
172
+ each_connection_pool(role).each(&:clear_reloadable_connections!)
173
+ end
174
+
175
+ def clear_all_connections!(role = nil)
176
+ each_connection_pool(role).each(&:disconnect!)
177
+ end
178
+
179
+ # Disconnects all currently idle connections.
180
+ #
181
+ # See ConnectionPool#flush! for details.
182
+ def flush_idle_connections!(role = nil)
183
+ each_connection_pool(role).each(&:flush!)
184
+ end
185
+
186
+ # Locate the connection of the nearest super class. This can be an
187
+ # active or defined connection: if it is the latter, it will be
188
+ # opened and set as the active connection for the class it was defined
189
+ # for (not necessarily the current class).
190
+ def retrieve_connection(connection_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard) # :nodoc:
191
+ pool = retrieve_connection_pool(connection_name, role: role, shard: shard, strict: true)
192
+ pool.lease_connection
193
+ end
194
+
195
+ # Returns true if a connection that's accessible to this class has
196
+ # already been opened.
197
+ def connected?(connection_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard)
198
+ pool = retrieve_connection_pool(connection_name, role: role, shard: shard)
199
+ pool && pool.connected?
200
+ end
201
+
202
+ def remove_connection_pool(connection_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard)
203
+ if pool_manager = get_pool_manager(connection_name)
204
+ disconnect_pool_from_pool_manager(pool_manager, role, shard)
205
+ end
206
+ end
207
+
208
+ # Retrieving the connection pool happens a lot, so we cache it in @connection_name_to_pool_manager.
209
+ # This makes retrieving the connection pool O(1) once the process is warm.
210
+ # When a connection is established or removed, we invalidate the cache.
211
+ def retrieve_connection_pool(connection_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard, strict: false)
212
+ pool_manager = get_pool_manager(connection_name)
213
+ pool = pool_manager&.get_pool_config(role, shard)&.pool
214
+
215
+ if strict && !pool
216
+ selector = [
217
+ ("'#{shard}' shard" unless shard == ActiveRecord::Base.default_shard),
218
+ ("'#{role}' role" unless role == ActiveRecord::Base.default_role),
219
+ ].compact.join(" and ")
220
+
221
+ selector = [
222
+ (connection_name unless connection_name == "ActiveRecord::Base"),
223
+ selector.presence,
224
+ ].compact.join(" with ")
225
+
226
+ selector = " for #{selector}" if selector.present?
227
+
228
+ message = "No database connection defined#{selector}."
229
+
230
+ raise ConnectionNotDefined.new(message, connection_name: connection_name, shard: shard, role: role)
231
+ end
232
+
233
+ pool
234
+ end
235
+
236
+ private
237
+ attr_reader :connection_name_to_pool_manager
238
+
239
+ # Returns the pool manager for a connection name / identifier.
240
+ def get_pool_manager(connection_name)
241
+ connection_name_to_pool_manager[connection_name]
242
+ end
243
+
244
+ # Get the existing pool manager or initialize and assign a new one.
245
+ def set_pool_manager(connection_name)
246
+ connection_name_to_pool_manager[connection_name] ||= PoolManager.new
247
+ end
248
+
249
+ def pool_managers
250
+ connection_name_to_pool_manager.values
251
+ end
252
+
253
+ def disconnect_pool_from_pool_manager(pool_manager, role, shard)
254
+ pool_config = pool_manager.remove_pool_config(role, shard)
255
+
256
+ if pool_config
257
+ pool_config.disconnect!
258
+ pool_config.db_config
259
+ end
260
+ end
261
+
262
+ # Returns an instance of PoolConfig for a given adapter.
263
+ # Accepts a hash one layer deep that contains all connection information.
264
+ #
265
+ # == Example
266
+ #
267
+ # config = { "production" => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" } }
268
+ # pool_config = Base.configurations.resolve_pool_config(:production)
269
+ # pool_config.db_config.configuration_hash
270
+ # # => { host: "localhost", database: "foo", adapter: "sqlite3" }
271
+ #
272
+ def resolve_pool_config(config, connection_name, role, shard)
273
+ db_config = Base.configurations.resolve(config)
274
+ db_config.validate!
275
+ raise(AdapterNotSpecified, "database configuration does not specify adapter") unless db_config.adapter
276
+ ConnectionAdapters::PoolConfig.new(connection_name, db_config, role, shard)
277
+ end
278
+
279
+ def determine_owner_name(owner_name, config)
280
+ if owner_name.is_a?(String) || owner_name.is_a?(Symbol)
281
+ StringConnectionName.new(owner_name.to_s)
282
+ elsif config.is_a?(Symbol)
283
+ StringConnectionName.new(config.to_s)
284
+ else
285
+ owner_name
286
+ end
287
+ end
288
+ end
289
+ end
290
+ end
@@ -0,0 +1,210 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "monitor"
4
+
5
+ module ActiveRecord
6
+ module ConnectionAdapters
7
+ class ConnectionPool
8
+ # = Active Record Connection Pool \Queue
9
+ #
10
+ # Threadsafe, fair, LIFO queue. Meant to be used by ConnectionPool
11
+ # with which it shares a Monitor.
12
+ class Queue
13
+ def initialize(lock = Monitor.new)
14
+ @lock = lock
15
+ @cond = @lock.new_cond
16
+ @num_waiting = 0
17
+ @queue = []
18
+ end
19
+
20
+ # Test if any threads are currently waiting on the queue.
21
+ def any_waiting?
22
+ synchronize do
23
+ @num_waiting > 0
24
+ end
25
+ end
26
+
27
+ # Returns the number of threads currently waiting on this
28
+ # queue.
29
+ def num_waiting
30
+ synchronize do
31
+ @num_waiting
32
+ end
33
+ end
34
+
35
+ # Add +element+ to the queue. Never blocks.
36
+ def add(element)
37
+ synchronize do
38
+ @queue.push element
39
+ @cond.signal
40
+ end
41
+ end
42
+
43
+ # If +element+ is in the queue, remove and return it, or +nil+.
44
+ def delete(element)
45
+ synchronize do
46
+ @queue.delete(element)
47
+ end
48
+ end
49
+
50
+ # Remove all elements from the queue.
51
+ def clear
52
+ synchronize do
53
+ @queue.clear
54
+ end
55
+ end
56
+
57
+ # Remove the head of the queue.
58
+ #
59
+ # If +timeout+ is not given, remove and return the head of the
60
+ # queue if the number of available elements is strictly
61
+ # greater than the number of threads currently waiting (that
62
+ # is, don't jump ahead in line). Otherwise, return +nil+.
63
+ #
64
+ # If +timeout+ is given, block if there is no element
65
+ # available, waiting up to +timeout+ seconds for an element to
66
+ # become available.
67
+ #
68
+ # Raises:
69
+ # - ActiveRecord::ConnectionTimeoutError if +timeout+ is given and no element
70
+ # becomes available within +timeout+ seconds,
71
+ def poll(timeout = nil)
72
+ synchronize { internal_poll(timeout) }
73
+ end
74
+
75
+ private
76
+ def internal_poll(timeout)
77
+ no_wait_poll || (timeout && wait_poll(timeout))
78
+ end
79
+
80
+ def synchronize(&block)
81
+ @lock.synchronize(&block)
82
+ end
83
+
84
+ # Test if the queue currently contains any elements.
85
+ def any?
86
+ !@queue.empty?
87
+ end
88
+
89
+ # A thread can remove an element from the queue without
90
+ # waiting if and only if the number of currently available
91
+ # connections is strictly greater than the number of waiting
92
+ # threads.
93
+ def can_remove_no_wait?
94
+ @queue.size > @num_waiting
95
+ end
96
+
97
+ # Removes and returns the head of the queue if possible, or +nil+.
98
+ def remove
99
+ @queue.pop
100
+ end
101
+
102
+ # Remove and return the head of the queue if the number of
103
+ # available elements is strictly greater than the number of
104
+ # threads currently waiting. Otherwise, return +nil+.
105
+ def no_wait_poll
106
+ remove if can_remove_no_wait?
107
+ end
108
+
109
+ # Waits on the queue up to +timeout+ seconds, then removes and
110
+ # returns the head of the queue.
111
+ def wait_poll(timeout)
112
+ @num_waiting += 1
113
+
114
+ t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
115
+ elapsed = 0
116
+ loop do
117
+ ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
118
+ @cond.wait(timeout - elapsed)
119
+ end
120
+
121
+ return remove if any?
122
+
123
+ elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0
124
+ if elapsed >= timeout
125
+ msg = "could not obtain a connection from the pool within %0.3f seconds (waited %0.3f seconds); all pooled connections were in use" %
126
+ [timeout, elapsed]
127
+ raise ConnectionTimeoutError, msg
128
+ end
129
+ end
130
+ ensure
131
+ @num_waiting -= 1
132
+ end
133
+ end
134
+
135
+ # Adds the ability to turn a basic fair FIFO queue into one
136
+ # biased to some thread.
137
+ module BiasableQueue # :nodoc:
138
+ class BiasedConditionVariable # :nodoc:
139
+ # semantics of condition variables guarantee that +broadcast+, +broadcast_on_biased+,
140
+ # +signal+ and +wait+ methods are only called while holding a lock
141
+ def initialize(lock, other_cond, preferred_thread)
142
+ @real_cond = lock.new_cond
143
+ @other_cond = other_cond
144
+ @preferred_thread = preferred_thread
145
+ @num_waiting_on_real_cond = 0
146
+ end
147
+
148
+ def broadcast
149
+ broadcast_on_biased
150
+ @other_cond.broadcast
151
+ end
152
+
153
+ def broadcast_on_biased
154
+ @num_waiting_on_real_cond = 0
155
+ @real_cond.broadcast
156
+ end
157
+
158
+ def signal
159
+ if @num_waiting_on_real_cond > 0
160
+ @num_waiting_on_real_cond -= 1
161
+ @real_cond
162
+ else
163
+ @other_cond
164
+ end.signal
165
+ end
166
+
167
+ def wait(timeout)
168
+ if Thread.current == @preferred_thread
169
+ @num_waiting_on_real_cond += 1
170
+ @real_cond
171
+ else
172
+ @other_cond
173
+ end.wait(timeout)
174
+ end
175
+ end
176
+
177
+ def with_a_bias_for(thread)
178
+ previous_cond = nil
179
+ new_cond = nil
180
+ synchronize do
181
+ previous_cond = @cond
182
+ @cond = new_cond = BiasedConditionVariable.new(@lock, @cond, thread)
183
+ end
184
+ yield
185
+ ensure
186
+ synchronize do
187
+ @cond = previous_cond if previous_cond
188
+ new_cond.broadcast_on_biased if new_cond # wake up any remaining sleepers
189
+ end
190
+ end
191
+ end
192
+
193
+ # Connections must be leased while holding the main pool mutex. This is
194
+ # an internal subclass that also +.leases+ returned connections while
195
+ # still in queue's critical section (queue synchronizes with the same
196
+ # <tt>@lock</tt> as the main pool) so that a returned connection is already
197
+ # leased and there is no need to re-enter synchronized block.
198
+ class ConnectionLeasingQueue < Queue # :nodoc:
199
+ include BiasableQueue
200
+
201
+ private
202
+ def internal_poll(timeout)
203
+ conn = super
204
+ conn.lease if conn
205
+ conn
206
+ end
207
+ end
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "weakref"
4
+
5
+ module ActiveRecord
6
+ module ConnectionAdapters
7
+ class ConnectionPool
8
+ # = Active Record Connection Pool \Reaper
9
+ #
10
+ # Every +frequency+ seconds, the reaper will call +reap+ and +flush+ on
11
+ # +pool+. A reaper instantiated with a zero frequency will never reap
12
+ # the connection pool.
13
+ #
14
+ # Configure the frequency by setting +reaping_frequency+ in your database
15
+ # YAML file (default 60 seconds).
16
+ class Reaper
17
+ attr_reader :pool, :frequency
18
+
19
+ def initialize(pool, frequency)
20
+ @pool = pool
21
+ @frequency = frequency
22
+ end
23
+
24
+ @mutex = Mutex.new
25
+ @pools = {}
26
+ @threads = {}
27
+
28
+ class << self
29
+ def register_pool(pool, frequency) # :nodoc:
30
+ @mutex.synchronize do
31
+ unless @threads[frequency]&.alive?
32
+ @threads[frequency] = spawn_thread(frequency)
33
+ end
34
+ @pools[frequency] ||= []
35
+ @pools[frequency] << WeakRef.new(pool)
36
+ end
37
+ end
38
+
39
+ private
40
+ def spawn_thread(frequency)
41
+ Thread.new(frequency) do |t|
42
+ # Advise multi-threaded app servers to ignore this thread for
43
+ # the purposes of fork safety warnings
44
+ Thread.current.thread_variable_set(:fork_safe, true)
45
+ Thread.current.name = "AR Pool Reaper"
46
+ running = true
47
+ while running
48
+ sleep t
49
+ @mutex.synchronize do
50
+ @pools[frequency].select! do |pool|
51
+ pool.weakref_alive? && !pool.discarded?
52
+ end
53
+
54
+ @pools[frequency].each do |p|
55
+ p.reap
56
+ p.flush
57
+ rescue WeakRef::RefError
58
+ end
59
+
60
+ if @pools[frequency].empty?
61
+ @pools.delete(frequency)
62
+ @threads.delete(frequency)
63
+ running = false
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ def run
72
+ return unless frequency && frequency > 0
73
+ self.class.register_pool(pool, frequency)
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end