activesupport 6.1.4.1 → 7.0.8.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (185) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +325 -395
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -2
  5. data/lib/active_support/actionable_error.rb +1 -1
  6. data/lib/active_support/array_inquirer.rb +0 -2
  7. data/lib/active_support/backtrace_cleaner.rb +2 -2
  8. data/lib/active_support/benchmarkable.rb +2 -2
  9. data/lib/active_support/cache/file_store.rb +15 -9
  10. data/lib/active_support/cache/mem_cache_store.rb +148 -37
  11. data/lib/active_support/cache/memory_store.rb +24 -16
  12. data/lib/active_support/cache/null_store.rb +10 -2
  13. data/lib/active_support/cache/redis_cache_store.rb +68 -85
  14. data/lib/active_support/cache/strategy/local_cache.rb +38 -61
  15. data/lib/active_support/cache.rb +299 -147
  16. data/lib/active_support/callbacks.rb +184 -85
  17. data/lib/active_support/code_generator.rb +65 -0
  18. data/lib/active_support/concern.rb +5 -5
  19. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
  20. data/lib/active_support/concurrency/share_lock.rb +2 -2
  21. data/lib/active_support/configurable.rb +8 -5
  22. data/lib/active_support/configuration_file.rb +1 -1
  23. data/lib/active_support/core_ext/array/access.rb +1 -5
  24. data/lib/active_support/core_ext/array/conversions.rb +13 -12
  25. data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
  26. data/lib/active_support/core_ext/array/grouping.rb +6 -6
  27. data/lib/active_support/core_ext/array/inquiry.rb +2 -2
  28. data/lib/active_support/core_ext/array.rb +1 -0
  29. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  30. data/lib/active_support/core_ext/class/subclasses.rb +25 -17
  31. data/lib/active_support/core_ext/date/blank.rb +1 -1
  32. data/lib/active_support/core_ext/date/calculations.rb +24 -9
  33. data/lib/active_support/core_ext/date/conversions.rb +14 -14
  34. data/lib/active_support/core_ext/date/deprecated_conversions.rb +40 -0
  35. data/lib/active_support/core_ext/date.rb +1 -0
  36. data/lib/active_support/core_ext/date_and_time/calculations.rb +4 -4
  37. data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
  38. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  39. data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
  40. data/lib/active_support/core_ext/date_time/conversions.rb +13 -13
  41. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +36 -0
  42. data/lib/active_support/core_ext/date_time.rb +1 -0
  43. data/lib/active_support/core_ext/digest/uuid.rb +39 -13
  44. data/lib/active_support/core_ext/enumerable.rb +112 -38
  45. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  46. data/lib/active_support/core_ext/hash/conversions.rb +0 -1
  47. data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
  48. data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
  49. data/lib/active_support/core_ext/hash/keys.rb +4 -4
  50. data/lib/active_support/core_ext/integer/inflections.rb +12 -12
  51. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  52. data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
  53. data/lib/active_support/core_ext/module/attribute_accessors.rb +2 -0
  54. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +19 -10
  55. data/lib/active_support/core_ext/module/delegation.rb +2 -8
  56. data/lib/active_support/core_ext/name_error.rb +2 -8
  57. data/lib/active_support/core_ext/numeric/conversions.rb +80 -77
  58. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  59. data/lib/active_support/core_ext/numeric.rb +1 -0
  60. data/lib/active_support/core_ext/object/acts_like.rb +29 -5
  61. data/lib/active_support/core_ext/object/blank.rb +2 -2
  62. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  63. data/lib/active_support/core_ext/object/duplicable.rb +15 -4
  64. data/lib/active_support/core_ext/object/json.rb +30 -25
  65. data/lib/active_support/core_ext/object/to_query.rb +2 -4
  66. data/lib/active_support/core_ext/object/try.rb +20 -20
  67. data/lib/active_support/core_ext/object/with_options.rb +21 -2
  68. data/lib/active_support/core_ext/pathname/existence.rb +21 -0
  69. data/lib/active_support/core_ext/pathname.rb +3 -0
  70. data/lib/active_support/core_ext/range/compare_range.rb +0 -25
  71. data/lib/active_support/core_ext/range/conversions.rb +8 -8
  72. data/lib/active_support/core_ext/range/deprecated_conversions.rb +36 -0
  73. data/lib/active_support/core_ext/range/each.rb +1 -1
  74. data/lib/active_support/core_ext/range/include_time_with_zone.rb +3 -26
  75. data/lib/active_support/core_ext/range/overlaps.rb +1 -1
  76. data/lib/active_support/core_ext/range.rb +1 -1
  77. data/lib/active_support/core_ext/securerandom.rb +1 -1
  78. data/lib/active_support/core_ext/string/conversions.rb +2 -2
  79. data/lib/active_support/core_ext/string/filters.rb +1 -1
  80. data/lib/active_support/core_ext/string/inflections.rb +1 -5
  81. data/lib/active_support/core_ext/string/inquiry.rb +1 -1
  82. data/lib/active_support/core_ext/string/output_safety.rb +94 -38
  83. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
  84. data/lib/active_support/core_ext/time/calculations.rb +13 -8
  85. data/lib/active_support/core_ext/time/conversions.rb +13 -12
  86. data/lib/active_support/core_ext/time/deprecated_conversions.rb +73 -0
  87. data/lib/active_support/core_ext/time/zones.rb +10 -26
  88. data/lib/active_support/core_ext/time.rb +1 -0
  89. data/lib/active_support/core_ext/uri.rb +3 -27
  90. data/lib/active_support/core_ext.rb +1 -0
  91. data/lib/active_support/current_attributes.rb +31 -14
  92. data/lib/active_support/dependencies/interlock.rb +10 -18
  93. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  94. data/lib/active_support/dependencies.rb +58 -788
  95. data/lib/active_support/deprecation/behaviors.rb +8 -5
  96. data/lib/active_support/deprecation/disallowed.rb +3 -3
  97. data/lib/active_support/deprecation/method_wrappers.rb +3 -3
  98. data/lib/active_support/deprecation/proxy_wrappers.rb +2 -2
  99. data/lib/active_support/deprecation.rb +2 -2
  100. data/lib/active_support/descendants_tracker.rb +174 -68
  101. data/lib/active_support/digest.rb +5 -3
  102. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  103. data/lib/active_support/duration/iso8601_serializer.rb +9 -1
  104. data/lib/active_support/duration.rb +81 -51
  105. data/lib/active_support/encrypted_configuration.rb +45 -3
  106. data/lib/active_support/encrypted_file.rb +21 -10
  107. data/lib/active_support/environment_inquirer.rb +1 -1
  108. data/lib/active_support/error_reporter.rb +117 -0
  109. data/lib/active_support/evented_file_update_checker.rb +20 -7
  110. data/lib/active_support/execution_context/test_helper.rb +13 -0
  111. data/lib/active_support/execution_context.rb +53 -0
  112. data/lib/active_support/execution_wrapper.rb +43 -21
  113. data/lib/active_support/executor/test_helper.rb +7 -0
  114. data/lib/active_support/fork_tracker.rb +19 -12
  115. data/lib/active_support/gem_version.rb +5 -5
  116. data/lib/active_support/hash_with_indifferent_access.rb +3 -1
  117. data/lib/active_support/html_safe_translation.rb +43 -0
  118. data/lib/active_support/i18n.rb +1 -0
  119. data/lib/active_support/i18n_railtie.rb +1 -1
  120. data/lib/active_support/inflector/inflections.rb +23 -7
  121. data/lib/active_support/inflector/methods.rb +29 -55
  122. data/lib/active_support/inflector/transliterate.rb +1 -1
  123. data/lib/active_support/isolated_execution_state.rb +72 -0
  124. data/lib/active_support/json/encoding.rb +3 -3
  125. data/lib/active_support/key_generator.rb +22 -5
  126. data/lib/active_support/lazy_load_hooks.rb +28 -4
  127. data/lib/active_support/locale/en.yml +1 -1
  128. data/lib/active_support/log_subscriber/test_helper.rb +2 -2
  129. data/lib/active_support/log_subscriber.rb +15 -5
  130. data/lib/active_support/logger_thread_safe_level.rb +4 -13
  131. data/lib/active_support/message_encryptor.rb +12 -6
  132. data/lib/active_support/message_verifier.rb +46 -14
  133. data/lib/active_support/messages/metadata.rb +2 -2
  134. data/lib/active_support/multibyte/chars.rb +10 -11
  135. data/lib/active_support/multibyte/unicode.rb +0 -12
  136. data/lib/active_support/multibyte.rb +1 -1
  137. data/lib/active_support/notifications/fanout.rb +91 -65
  138. data/lib/active_support/notifications/instrumenter.rb +32 -15
  139. data/lib/active_support/notifications.rb +23 -23
  140. data/lib/active_support/number_helper/number_converter.rb +1 -3
  141. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  142. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  143. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  144. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
  145. data/lib/active_support/number_helper/rounding_helper.rb +1 -5
  146. data/lib/active_support/number_helper.rb +4 -5
  147. data/lib/active_support/option_merger.rb +10 -18
  148. data/lib/active_support/ordered_hash.rb +1 -1
  149. data/lib/active_support/ordered_options.rb +1 -1
  150. data/lib/active_support/parameter_filter.rb +20 -11
  151. data/lib/active_support/per_thread_registry.rb +5 -0
  152. data/lib/active_support/railtie.rb +69 -19
  153. data/lib/active_support/reloader.rb +1 -1
  154. data/lib/active_support/rescuable.rb +12 -12
  155. data/lib/active_support/ruby_features.rb +7 -0
  156. data/lib/active_support/secure_compare_rotator.rb +2 -2
  157. data/lib/active_support/string_inquirer.rb +0 -2
  158. data/lib/active_support/subscriber.rb +7 -18
  159. data/lib/active_support/tagged_logging.rb +2 -2
  160. data/lib/active_support/test_case.rb +13 -21
  161. data/lib/active_support/testing/assertions.rb +36 -6
  162. data/lib/active_support/testing/deprecation.rb +52 -1
  163. data/lib/active_support/testing/isolation.rb +30 -29
  164. data/lib/active_support/testing/method_call_assertions.rb +5 -5
  165. data/lib/active_support/testing/parallelization/server.rb +4 -0
  166. data/lib/active_support/testing/parallelization/worker.rb +3 -0
  167. data/lib/active_support/testing/parallelization.rb +4 -0
  168. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  169. data/lib/active_support/testing/stream.rb +3 -5
  170. data/lib/active_support/testing/tagged_logging.rb +1 -1
  171. data/lib/active_support/testing/time_helpers.rb +13 -2
  172. data/lib/active_support/time_with_zone.rb +43 -22
  173. data/lib/active_support/values/time_zone.rb +35 -14
  174. data/lib/active_support/version.rb +1 -1
  175. data/lib/active_support/xml_mini/jdom.rb +1 -1
  176. data/lib/active_support/xml_mini/libxml.rb +5 -5
  177. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  178. data/lib/active_support/xml_mini/nokogiri.rb +4 -4
  179. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  180. data/lib/active_support/xml_mini/rexml.rb +1 -1
  181. data/lib/active_support/xml_mini.rb +5 -4
  182. data/lib/active_support.rb +17 -1
  183. metadata +26 -23
  184. data/lib/active_support/core_ext/marshal.rb +0 -26
  185. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
@@ -5,18 +5,21 @@ begin
5
5
  require "redis"
6
6
  require "redis/distributed"
7
7
  rescue LoadError
8
- warn "The Redis cache store requires the redis gem, version 4.0.1 or later. Please add it to your Gemfile: `gem \"redis\", \"~> 4.0\"`"
8
+ warn "The Redis cache store requires the redis gem, version 4.0.1 or later. Please add it to your Gemfile: `gem \"redis\", \">= 4.0.1\"`"
9
9
  raise
10
10
  end
11
11
 
12
12
  # Prefer the hiredis driver but don't require it.
13
13
  begin
14
- require "redis/connection/hiredis"
14
+ if ::Redis::VERSION < "5"
15
+ require "redis/connection/hiredis"
16
+ else
17
+ require "hiredis-client"
18
+ end
15
19
  rescue LoadError
16
20
  end
17
21
 
18
- require "digest/sha2"
19
- require "active_support/core_ext/marshal"
22
+ require "active_support/digest"
20
23
 
21
24
  module ActiveSupport
22
25
  module Cache
@@ -46,7 +49,7 @@ module ActiveSupport
46
49
  # 4.0.1+ for distributed mget support.
47
50
  # * +delete_matched+ support for Redis KEYS globs.
48
51
  class RedisCacheStore < Store
49
- # Keys are truncated with their own SHA2 digest if they exceed 1kB
52
+ # Keys are truncated with the ActiveSupport digest if they exceed 1kB
50
53
  MAX_KEY_BYTESIZE = 1024
51
54
 
52
55
  DEFAULT_REDIS_OPTIONS = {
@@ -71,35 +74,7 @@ module ActiveSupport
71
74
  true
72
75
  end
73
76
 
74
- # Support raw values in the local cache strategy.
75
- module LocalCacheWithRaw # :nodoc:
76
- private
77
- def write_entry(key, entry, **options)
78
- if options[:raw] && local_cache
79
- raw_entry = Entry.new(serialize_entry(entry, raw: true))
80
- raw_entry.expires_at = entry.expires_at
81
- super(key, raw_entry, **options)
82
- else
83
- super
84
- end
85
- end
86
-
87
- def write_multi_entries(entries, **options)
88
- if options[:raw] && local_cache
89
- raw_entries = entries.map do |key, entry|
90
- raw_entry = Entry.new(serialize_entry(entry, raw: true))
91
- raw_entry.expires_at = entry.expires_at
92
- end.to_h
93
-
94
- super(raw_entries, **options)
95
- else
96
- super
97
- end
98
- end
99
- end
100
-
101
77
  prepend Strategy::LocalCache
102
- prepend LocalCacheWithRaw
103
78
 
104
79
  class << self
105
80
  # Factory method to create a new Redis instance.
@@ -113,7 +88,7 @@ module ActiveSupport
113
88
  # :url String -> Redis.new(url: …)
114
89
  # :url Array -> Redis::Distributed.new([{ url: … }, { url: … }, …])
115
90
  #
116
- def build_redis(redis: nil, url: nil, **redis_options) #:nodoc:
91
+ def build_redis(redis: nil, url: nil, **redis_options) # :nodoc:
117
92
  urls = Array(url)
118
93
 
119
94
  if redis.is_a?(Proc)
@@ -121,9 +96,11 @@ module ActiveSupport
121
96
  elsif redis
122
97
  redis
123
98
  elsif urls.size > 1
124
- build_redis_distributed_client urls: urls, **redis_options
99
+ build_redis_distributed_client(urls: urls, **redis_options)
100
+ elsif urls.empty?
101
+ build_redis_client(**redis_options)
125
102
  else
126
- build_redis_client url: urls.first, **redis_options
103
+ build_redis_client(url: urls.first, **redis_options)
127
104
  end
128
105
  end
129
106
 
@@ -134,8 +111,8 @@ module ActiveSupport
134
111
  end
135
112
  end
136
113
 
137
- def build_redis_client(url:, **redis_options)
138
- ::Redis.new DEFAULT_REDIS_OPTIONS.merge(redis_options.merge(url: url))
114
+ def build_redis_client(**redis_options)
115
+ ::Redis.new(DEFAULT_REDIS_OPTIONS.merge(redis_options))
139
116
  end
140
117
  end
141
118
 
@@ -168,8 +145,8 @@ module ActiveSupport
168
145
  #
169
146
  # Race condition TTL is not set by default. This can be used to avoid
170
147
  # "thundering herd" cache writes when hot cache entries are expired.
171
- # See <tt>ActiveSupport::Cache::Store#fetch</tt> for more.
172
- def initialize(namespace: nil, compress: true, compress_threshold: 1.kilobyte, coder: DEFAULT_CODER, expires_in: nil, race_condition_ttl: nil, error_handler: DEFAULT_ERROR_HANDLER, **redis_options)
148
+ # See ActiveSupport::Cache::Store#fetch for more.
149
+ def initialize(namespace: nil, compress: true, compress_threshold: 1.kilobyte, coder: default_coder, expires_in: nil, race_condition_ttl: nil, error_handler: DEFAULT_ERROR_HANDLER, **redis_options)
173
150
  @redis_options = redis_options
174
151
 
175
152
  @max_key_bytesize = MAX_KEY_BYTESIZE
@@ -254,8 +231,8 @@ module ActiveSupport
254
231
  # Cache Store API implementation.
255
232
  #
256
233
  # Increment a cached value. This method uses the Redis incr atomic
257
- # operator and can only be used on values written with the :raw option.
258
- # Calling it on a value not stored with :raw will initialize that value
234
+ # operator and can only be used on values written with the +:raw+ option.
235
+ # Calling it on a value not stored with +:raw+ will initialize that value
259
236
  # to zero.
260
237
  #
261
238
  # Failsafe: Raises errors.
@@ -277,8 +254,8 @@ module ActiveSupport
277
254
  # Cache Store API implementation.
278
255
  #
279
256
  # Decrement a cached value. This method uses the Redis decr atomic
280
- # operator and can only be used on values written with the :raw option.
281
- # Calling it on a value not stored with :raw will initialize that value
257
+ # operator and can only be used on values written with the +:raw+ option.
258
+ # Calling it on a value not stored with +:raw+ will initialize that value
282
259
  # to zero.
283
260
  #
284
261
  # Failsafe: Raises errors.
@@ -319,34 +296,44 @@ module ActiveSupport
319
296
  end
320
297
  end
321
298
 
322
- def mget_capable? #:nodoc:
299
+ # Get info from redis servers.
300
+ def stats
301
+ redis.with { |c| c.info }
302
+ end
303
+
304
+ def mget_capable? # :nodoc:
323
305
  set_redis_capabilities unless defined? @mget_capable
324
306
  @mget_capable
325
307
  end
326
308
 
327
- def mset_capable? #:nodoc:
309
+ def mset_capable? # :nodoc:
328
310
  set_redis_capabilities unless defined? @mset_capable
329
311
  @mset_capable
330
312
  end
331
313
 
332
314
  private
333
315
  def set_redis_capabilities
334
- case redis
335
- when Redis::Distributed
336
- @mget_capable = true
337
- @mset_capable = false
338
- else
339
- @mget_capable = true
340
- @mset_capable = true
316
+ redis.with do |c|
317
+ case c
318
+ when Redis::Distributed
319
+ @mget_capable = true
320
+ @mset_capable = false
321
+ else
322
+ @mget_capable = true
323
+ @mset_capable = true
324
+ end
341
325
  end
342
326
  end
343
327
 
344
328
  # Store provider interface:
345
329
  # Read an entry from the cache.
346
330
  def read_entry(key, **options)
331
+ deserialize_entry(read_serialized_entry(key, **options), **options)
332
+ end
333
+
334
+ def read_serialized_entry(key, raw: false, **options)
347
335
  failsafe :read_entry do
348
- raw = options&.fetch(:raw, false)
349
- deserialize_entry(redis.with { |c| c.get(key) }, raw: raw)
336
+ redis.with { |c| c.get(key) }
350
337
  end
351
338
  end
352
339
 
@@ -383,9 +370,11 @@ module ActiveSupport
383
370
  # Write an entry to the cache.
384
371
  #
385
372
  # Requires Redis 2.6.12+ for extended SET options.
386
- def write_entry(key, entry, unless_exist: false, raw: false, expires_in: nil, race_condition_ttl: nil, **options)
387
- serialized_entry = serialize_entry(entry, raw: raw)
373
+ def write_entry(key, entry, raw: false, **options)
374
+ write_serialized_entry(key, serialize_entry(entry, raw: raw, **options), raw: raw, **options)
375
+ end
388
376
 
377
+ def write_serialized_entry(key, payload, raw: false, unless_exist: false, expires_in: nil, race_condition_ttl: nil, **options)
389
378
  # If race condition TTL is in use, ensure that cache entries
390
379
  # stick around a bit longer after they would have expired
391
380
  # so we can purposefully serve stale entries.
@@ -393,16 +382,14 @@ module ActiveSupport
393
382
  expires_in += 5.minutes
394
383
  end
395
384
 
396
- failsafe :write_entry, returning: false do
397
- if unless_exist || expires_in
398
- modifiers = {}
399
- modifiers[:nx] = unless_exist
400
- modifiers[:px] = (1000 * expires_in.to_f).ceil if expires_in
385
+ modifiers = {}
386
+ if unless_exist || expires_in
387
+ modifiers[:nx] = unless_exist
388
+ modifiers[:px] = (1000 * expires_in.to_f).ceil if expires_in
389
+ end
401
390
 
402
- redis.with { |c| c.set key, serialized_entry, **modifiers }
403
- else
404
- redis.with { |c| c.set key, serialized_entry }
405
- end
391
+ failsafe :write_entry, returning: false do
392
+ redis.with { |c| c.set key, payload, **modifiers }
406
393
  end
407
394
  end
408
395
 
@@ -429,7 +416,10 @@ module ActiveSupport
429
416
  if entries.any?
430
417
  if mset_capable? && expires_in.nil?
431
418
  failsafe :write_multi_entries do
432
- redis.with { |c| c.mapped_mset(serialize_entries(entries, raw: options[:raw])) }
419
+ payload = serialize_entries(entries, **options)
420
+ redis.with do |c|
421
+ c.mapped_mset(payload)
422
+ end
433
423
  end
434
424
  else
435
425
  super
@@ -444,7 +434,7 @@ module ActiveSupport
444
434
 
445
435
  def truncate_key(key)
446
436
  if key && key.bytesize > max_key_bytesize
447
- suffix = ":sha2:#{::Digest::SHA2.hexdigest(key)}"
437
+ suffix = ":hash:#{ActiveSupport::Digest.hexdigest(key)}"
448
438
  truncate_at = max_key_bytesize - suffix.bytesize
449
439
  "#{key.byteslice(0, truncate_at)}#{suffix}"
450
440
  else
@@ -452,42 +442,35 @@ module ActiveSupport
452
442
  end
453
443
  end
454
444
 
455
- def deserialize_entry(payload, raw:)
456
- if payload && raw
457
- Entry.new(payload, compress: false)
445
+ def deserialize_entry(payload, raw: false, **)
446
+ if raw && !payload.nil?
447
+ Entry.new(payload)
458
448
  else
459
449
  super(payload)
460
450
  end
461
451
  end
462
452
 
463
- def serialize_entry(entry, raw: false)
453
+ def serialize_entry(entry, raw: false, **options)
464
454
  if raw
465
455
  entry.value.to_s
466
456
  else
467
- super(entry)
457
+ super(entry, raw: raw, **options)
468
458
  end
469
459
  end
470
460
 
471
- def serialize_entries(entries, raw: false)
461
+ def serialize_entries(entries, **options)
472
462
  entries.transform_values do |entry|
473
- serialize_entry entry, raw: raw
463
+ serialize_entry(entry, **options)
474
464
  end
475
465
  end
476
466
 
477
467
  def failsafe(method, returning: nil)
478
468
  yield
479
- rescue ::Redis::BaseError => e
480
- handle_exception exception: e, method: method, returning: returning
469
+ rescue ::Redis::BaseError => error
470
+ ActiveSupport.error_reporter&.report(error, handled: true, severity: :warning)
471
+ @error_handler&.call(method: method, exception: error, returning: returning)
481
472
  returning
482
473
  end
483
-
484
- def handle_exception(exception:, method:, returning:)
485
- if @error_handler
486
- @error_handler.(method: method, exception: exception, returning: returning)
487
- end
488
- rescue => failsafe
489
- warn "RedisCacheStore ignored exception in handle_exception: #{failsafe.class}: #{failsafe.message}\n #{failsafe.backtrace.join("\n ")}"
490
- end
491
474
  end
492
475
  end
493
476
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/string/inflections"
4
- require "active_support/per_thread_registry"
5
4
 
6
5
  module ActiveSupport
7
6
  module Cache
@@ -13,78 +12,56 @@ module ActiveSupport
13
12
  autoload :Middleware, "active_support/cache/strategy/local_cache_middleware"
14
13
 
15
14
  # Class for storing and registering the local caches.
16
- class LocalCacheRegistry # :nodoc:
17
- extend ActiveSupport::PerThreadRegistry
18
-
19
- def initialize
20
- @registry = {}
21
- end
15
+ module LocalCacheRegistry # :nodoc:
16
+ extend self
22
17
 
23
18
  def cache_for(local_cache_key)
24
- @registry[local_cache_key]
19
+ registry = ActiveSupport::IsolatedExecutionState[:active_support_local_cache_registry] ||= {}
20
+ registry[local_cache_key]
25
21
  end
26
22
 
27
23
  def set_cache_for(local_cache_key, value)
28
- @registry[local_cache_key] = value
24
+ registry = ActiveSupport::IsolatedExecutionState[:active_support_local_cache_registry] ||= {}
25
+ registry[local_cache_key] = value
29
26
  end
30
-
31
- def self.set_cache_for(l, v); instance.set_cache_for l, v; end
32
- def self.cache_for(l); instance.cache_for l; end
33
27
  end
34
28
 
35
29
  # Simple memory backed cache. This cache is not thread safe and is intended only
36
30
  # for serving as a temporary memory cache for a single thread.
37
- class LocalStore < Store
31
+ class LocalStore
38
32
  def initialize
39
- super
40
33
  @data = {}
41
34
  end
42
35
 
43
- # Don't allow synchronizing since it isn't thread safe.
44
- def synchronize # :nodoc:
45
- yield
46
- end
47
-
48
36
  def clear(options = nil)
49
37
  @data.clear
50
38
  end
51
39
 
52
- def read_entry(key, **options)
40
+ def read_entry(key)
53
41
  @data[key]
54
42
  end
55
43
 
56
- def read_multi_entries(keys, **options)
57
- values = {}
58
-
59
- keys.each do |name|
60
- entry = read_entry(name, **options)
61
- values[name] = entry.value if entry
62
- end
63
-
64
- values
44
+ def read_multi_entries(keys)
45
+ @data.slice(*keys)
65
46
  end
66
47
 
67
- def write_entry(key, entry, **options)
68
- entry.dup_value!
48
+ def write_entry(key, entry)
69
49
  @data[key] = entry
70
50
  true
71
51
  end
72
52
 
73
- def delete_entry(key, **options)
53
+ def delete_entry(key)
74
54
  !!@data.delete(key)
75
55
  end
76
56
 
77
- def fetch_entry(key, options = nil) # :nodoc:
78
- entry = @data.fetch(key) { @data[key] = yield }
79
- dup_entry = entry.dup
80
- dup_entry&.dup_value!
81
- dup_entry
57
+ def fetch_entry(key) # :nodoc:
58
+ @data.fetch(key) { @data[key] = yield }
82
59
  end
83
60
  end
84
61
 
85
62
  # Use a local cache for the duration of block.
86
- def with_local_cache
87
- use_temporary_local_cache(LocalStore.new) { yield }
63
+ def with_local_cache(&block)
64
+ use_temporary_local_cache(LocalStore.new, &block)
88
65
  end
89
66
 
90
67
  # Middleware class can be inserted as a Rack handler to be local cache for the
@@ -116,27 +93,27 @@ module ActiveSupport
116
93
  def increment(name, amount = 1, **options) # :nodoc:
117
94
  return super unless local_cache
118
95
  value = bypass_local_cache { super }
119
- write_cache_value(name, value, **options)
96
+ write_cache_value(name, value, raw: true, **options)
120
97
  value
121
98
  end
122
99
 
123
100
  def decrement(name, amount = 1, **options) # :nodoc:
124
101
  return super unless local_cache
125
102
  value = bypass_local_cache { super }
126
- write_cache_value(name, value, **options)
103
+ write_cache_value(name, value, raw: true, **options)
127
104
  value
128
105
  end
129
106
 
130
107
  private
131
- def read_entry(key, **options)
108
+ def read_serialized_entry(key, raw: false, **options)
132
109
  if cache = local_cache
133
110
  hit = true
134
- value = cache.fetch_entry(key) do
111
+ entry = cache.fetch_entry(key) do
135
112
  hit = false
136
113
  super
137
114
  end
138
115
  options[:event][:store] = cache.class.name if hit && options[:event]
139
- value
116
+ entry
140
117
  else
141
118
  super
142
119
  end
@@ -145,7 +122,10 @@ module ActiveSupport
145
122
  def read_multi_entries(keys, **options)
146
123
  return super unless local_cache
147
124
 
148
- local_entries = local_cache.read_multi_entries(keys, **options)
125
+ local_entries = local_cache.read_multi_entries(keys)
126
+ local_entries.transform_values! do |payload|
127
+ deserialize_entry(payload)&.value
128
+ end
149
129
  missed_keys = keys - local_entries.keys
150
130
 
151
131
  if missed_keys.any?
@@ -155,30 +135,27 @@ module ActiveSupport
155
135
  end
156
136
  end
157
137
 
158
- def write_entry(key, entry, **options)
159
- if options[:unless_exist]
160
- local_cache.delete_entry(key, **options) if local_cache
138
+ def write_serialized_entry(key, payload, **)
139
+ if return_value = super
140
+ local_cache.write_entry(key, payload) if local_cache
161
141
  else
162
- local_cache.write_entry(key, entry, **options) if local_cache
142
+ local_cache.delete_entry(key) if local_cache
163
143
  end
164
-
165
- super
144
+ return_value
166
145
  end
167
146
 
168
- def delete_entry(key, **options)
169
- local_cache.delete_entry(key, **options) if local_cache
147
+ def delete_entry(key, **)
148
+ local_cache.delete_entry(key) if local_cache
170
149
  super
171
150
  end
172
151
 
173
152
  def write_cache_value(name, value, **options)
174
153
  name = normalize_key(name, options)
175
154
  cache = local_cache
176
- cache.mute do
177
- if value
178
- cache.write(name, value, options)
179
- else
180
- cache.delete(name, **options)
181
- end
155
+ if value
156
+ cache.write_entry(name, serialize_entry(new_entry(value, **options), **options))
157
+ else
158
+ cache.delete_entry(name)
182
159
  end
183
160
  end
184
161
 
@@ -190,8 +167,8 @@ module ActiveSupport
190
167
  LocalCacheRegistry.cache_for(local_cache_key)
191
168
  end
192
169
 
193
- def bypass_local_cache
194
- use_temporary_local_cache(nil) { yield }
170
+ def bypass_local_cache(&block)
171
+ use_temporary_local_cache(nil, &block)
195
172
  end
196
173
 
197
174
  def use_temporary_local_cache(temporary_cache)