activesupport 7.1.6 → 8.1.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +256 -1133
- data/README.rdoc +1 -1
- data/lib/active_support/array_inquirer.rb +1 -1
- data/lib/active_support/backtrace_cleaner.rb +81 -3
- data/lib/active_support/benchmark.rb +21 -0
- data/lib/active_support/benchmarkable.rb +3 -2
- data/lib/active_support/broadcast_logger.rb +65 -78
- data/lib/active_support/cache/file_store.rb +29 -14
- data/lib/active_support/cache/mem_cache_store.rb +42 -102
- data/lib/active_support/cache/memory_store.rb +11 -6
- data/lib/active_support/cache/null_store.rb +2 -2
- data/lib/active_support/cache/redis_cache_store.rb +58 -46
- data/lib/active_support/cache/serializer_with_fallback.rb +0 -23
- data/lib/active_support/cache/strategy/local_cache.rb +72 -27
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +7 -7
- data/lib/active_support/cache.rb +146 -86
- data/lib/active_support/callbacks.rb +102 -126
- data/lib/active_support/class_attribute.rb +33 -0
- data/lib/active_support/code_generator.rb +9 -0
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +8 -62
- data/lib/active_support/concurrency/share_lock.rb +0 -1
- data/lib/active_support/concurrency/thread_monitor.rb +55 -0
- data/lib/active_support/configurable.rb +34 -0
- data/lib/active_support/configuration_file.rb +15 -6
- data/lib/active_support/continuous_integration.rb +145 -0
- data/lib/active_support/core_ext/array/conversions.rb +3 -5
- data/lib/active_support/core_ext/array.rb +7 -7
- data/lib/active_support/core_ext/benchmark.rb +4 -14
- data/lib/active_support/core_ext/big_decimal.rb +1 -1
- data/lib/active_support/core_ext/class/attribute.rb +26 -19
- data/lib/active_support/core_ext/class/subclasses.rb +15 -35
- data/lib/active_support/core_ext/class.rb +2 -2
- data/lib/active_support/core_ext/date/blank.rb +4 -0
- data/lib/active_support/core_ext/date/conversions.rb +2 -2
- data/lib/active_support/core_ext/date.rb +5 -5
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -9
- data/lib/active_support/core_ext/date_time/blank.rb +4 -0
- data/lib/active_support/core_ext/date_time/compatibility.rb +3 -5
- data/lib/active_support/core_ext/date_time/conversions.rb +4 -6
- data/lib/active_support/core_ext/date_time.rb +5 -5
- data/lib/active_support/core_ext/digest/uuid.rb +6 -0
- data/lib/active_support/core_ext/digest.rb +1 -1
- data/lib/active_support/core_ext/enumerable.rb +25 -8
- data/lib/active_support/core_ext/erb/util.rb +10 -5
- data/lib/active_support/core_ext/file.rb +1 -1
- data/lib/active_support/core_ext/hash/deep_merge.rb +1 -0
- data/lib/active_support/core_ext/hash/except.rb +0 -12
- data/lib/active_support/core_ext/hash/keys.rb +4 -4
- data/lib/active_support/core_ext/hash.rb +8 -8
- data/lib/active_support/core_ext/integer.rb +3 -3
- data/lib/active_support/core_ext/kernel.rb +3 -3
- data/lib/active_support/core_ext/module/attr_internal.rb +16 -6
- data/lib/active_support/core_ext/module/delegation.rb +20 -163
- data/lib/active_support/core_ext/module/deprecation.rb +1 -4
- data/lib/active_support/core_ext/module/introspection.rb +3 -0
- data/lib/active_support/core_ext/module.rb +11 -11
- data/lib/active_support/core_ext/numeric/conversions.rb +3 -3
- data/lib/active_support/core_ext/numeric.rb +3 -3
- data/lib/active_support/core_ext/object/blank.rb +45 -1
- data/lib/active_support/core_ext/object/instance_variables.rb +11 -19
- data/lib/active_support/core_ext/object/json.rb +24 -11
- data/lib/active_support/core_ext/object/to_query.rb +7 -1
- data/lib/active_support/core_ext/object/try.rb +2 -2
- data/lib/active_support/core_ext/object/with.rb +5 -3
- data/lib/active_support/core_ext/object.rb +13 -13
- data/lib/active_support/core_ext/pathname/blank.rb +4 -0
- data/lib/active_support/core_ext/pathname.rb +2 -2
- data/lib/active_support/core_ext/range/overlap.rb +4 -4
- data/lib/active_support/core_ext/range/sole.rb +17 -0
- data/lib/active_support/core_ext/range.rb +4 -4
- data/lib/active_support/core_ext/securerandom.rb +4 -4
- data/lib/active_support/core_ext/string/conversions.rb +1 -1
- data/lib/active_support/core_ext/string/filters.rb +4 -4
- data/lib/active_support/core_ext/string/multibyte.rb +13 -4
- data/lib/active_support/core_ext/string/output_safety.rb +19 -19
- data/lib/active_support/core_ext/string.rb +13 -13
- data/lib/active_support/core_ext/symbol.rb +1 -1
- data/lib/active_support/core_ext/thread/backtrace/location.rb +2 -7
- data/lib/active_support/core_ext/time/calculations.rb +25 -30
- data/lib/active_support/core_ext/time/compatibility.rb +2 -3
- data/lib/active_support/core_ext/time/conversions.rb +2 -2
- data/lib/active_support/core_ext/time/zones.rb +1 -1
- data/lib/active_support/core_ext/time.rb +5 -5
- data/lib/active_support/core_ext.rb +1 -2
- data/lib/active_support/current_attributes/test_helper.rb +2 -2
- data/lib/active_support/current_attributes.rb +58 -50
- data/lib/active_support/delegation.rb +200 -0
- data/lib/active_support/dependencies/autoload.rb +0 -12
- data/lib/active_support/dependencies/interlock.rb +11 -5
- data/lib/active_support/dependencies.rb +6 -2
- data/lib/active_support/deprecation/constant_accessor.rb +47 -26
- data/lib/active_support/deprecation/proxy_wrappers.rb +9 -12
- data/lib/active_support/deprecation/reporting.rb +5 -17
- data/lib/active_support/deprecation.rb +8 -5
- data/lib/active_support/descendants_tracker.rb +9 -87
- data/lib/active_support/duration/iso8601_parser.rb +2 -2
- data/lib/active_support/duration/iso8601_serializer.rb +1 -2
- data/lib/active_support/duration.rb +25 -16
- data/lib/active_support/editor.rb +70 -0
- data/lib/active_support/encrypted_configuration.rb +20 -2
- data/lib/active_support/encrypted_file.rb +1 -1
- data/lib/active_support/error_reporter.rb +121 -6
- data/lib/active_support/event_reporter/test_helper.rb +32 -0
- data/lib/active_support/event_reporter.rb +592 -0
- data/lib/active_support/evented_file_update_checker.rb +5 -3
- data/lib/active_support/execution_context.rb +64 -7
- data/lib/active_support/execution_wrapper.rb +1 -2
- data/lib/active_support/file_update_checker.rb +9 -7
- data/lib/active_support/fork_tracker.rb +2 -38
- data/lib/active_support/gem_version.rb +2 -2
- data/lib/active_support/gzip.rb +1 -0
- data/lib/active_support/hash_with_indifferent_access.rb +66 -45
- data/lib/active_support/html_safe_translation.rb +3 -0
- data/lib/active_support/i18n_railtie.rb +19 -11
- data/lib/active_support/inflector/inflections.rb +31 -15
- data/lib/active_support/inflector/transliterate.rb +6 -8
- data/lib/active_support/isolated_execution_state.rb +12 -17
- data/lib/active_support/json/decoding.rb +6 -4
- data/lib/active_support/json/encoding.rb +157 -21
- data/lib/active_support/lazy_load_hooks.rb +1 -1
- data/lib/active_support/log_subscriber.rb +2 -18
- data/lib/active_support/logger.rb +15 -2
- data/lib/active_support/logger_thread_safe_level.rb +4 -9
- data/lib/active_support/message_encryptors.rb +54 -2
- data/lib/active_support/message_pack/extensions.rb +20 -2
- data/lib/active_support/message_verifier.rb +21 -0
- data/lib/active_support/message_verifiers.rb +57 -3
- data/lib/active_support/messages/rotation_coordinator.rb +9 -0
- data/lib/active_support/messages/rotator.rb +10 -0
- data/lib/active_support/multibyte/chars.rb +14 -4
- data/lib/active_support/multibyte.rb +4 -0
- data/lib/active_support/notifications/fanout.rb +68 -50
- data/lib/active_support/notifications/instrumenter.rb +22 -19
- data/lib/active_support/notifications.rb +28 -27
- data/lib/active_support/number_helper/number_converter.rb +2 -2
- data/lib/active_support/number_helper.rb +22 -0
- data/lib/active_support/option_merger.rb +2 -2
- data/lib/active_support/ordered_options.rb +53 -15
- data/lib/active_support/railtie.rb +36 -20
- data/lib/active_support/string_inquirer.rb +1 -1
- data/lib/active_support/structured_event_subscriber.rb +99 -0
- data/lib/active_support/subscriber.rb +1 -5
- data/lib/active_support/syntax_error_proxy.rb +3 -0
- data/lib/active_support/tagged_logging.rb +5 -1
- data/lib/active_support/test_case.rb +63 -6
- data/lib/active_support/testing/assertions.rb +113 -27
- data/lib/active_support/testing/constant_stubbing.rb +30 -8
- data/lib/active_support/testing/deprecation.rb +5 -12
- data/lib/active_support/testing/error_reporter_assertions.rb +18 -1
- data/lib/active_support/testing/event_reporter_assertions.rb +227 -0
- data/lib/active_support/testing/isolation.rb +19 -9
- data/lib/active_support/testing/method_call_assertions.rb +2 -16
- data/lib/active_support/testing/notification_assertions.rb +92 -0
- data/lib/active_support/testing/parallelization/server.rb +18 -2
- data/lib/active_support/testing/parallelization/worker.rb +4 -2
- data/lib/active_support/testing/parallelization.rb +25 -1
- data/lib/active_support/testing/tests_without_assertions.rb +19 -0
- data/lib/active_support/testing/time_helpers.rb +11 -6
- data/lib/active_support/time_with_zone.rb +39 -26
- data/lib/active_support/values/time_zone.rb +26 -17
- data/lib/active_support/xml_mini.rb +14 -4
- data/lib/active_support.rb +22 -9
- metadata +31 -17
- data/lib/active_support/core_ext/range/each.rb +0 -24
- data/lib/active_support/deprecation/instance_delegator.rb +0 -65
- data/lib/active_support/proxy_object.rb +0 -17
- data/lib/active_support/ruby_features.rb +0 -7
- data/lib/active_support/testing/strict_warnings.rb +0 -39
|
@@ -11,11 +11,12 @@ module ActiveSupport
|
|
|
11
11
|
# This class wraps up local storage for middlewares. Only the middleware method should
|
|
12
12
|
# construct them.
|
|
13
13
|
class Middleware # :nodoc:
|
|
14
|
-
attr_reader :name
|
|
14
|
+
attr_reader :name
|
|
15
|
+
attr_accessor :cache
|
|
15
16
|
|
|
16
|
-
def initialize(name,
|
|
17
|
+
def initialize(name, cache)
|
|
17
18
|
@name = name
|
|
18
|
-
@
|
|
19
|
+
@cache = cache
|
|
19
20
|
@app = nil
|
|
20
21
|
end
|
|
21
22
|
|
|
@@ -25,18 +26,17 @@ module ActiveSupport
|
|
|
25
26
|
end
|
|
26
27
|
|
|
27
28
|
def call(env)
|
|
28
|
-
|
|
29
|
+
cache.new_local_cache
|
|
29
30
|
response = @app.call(env)
|
|
30
31
|
response[2] = ::Rack::BodyProxy.new(response[2]) do
|
|
31
|
-
|
|
32
|
+
cache.unset_local_cache
|
|
32
33
|
end
|
|
33
34
|
cleanup_on_body_close = true
|
|
34
35
|
response
|
|
35
36
|
rescue Rack::Utils::InvalidParameterError
|
|
36
37
|
[400, {}, []]
|
|
37
38
|
ensure
|
|
38
|
-
|
|
39
|
-
cleanup_on_body_close
|
|
39
|
+
cache.unset_local_cache unless cleanup_on_body_close
|
|
40
40
|
end
|
|
41
41
|
end
|
|
42
42
|
end
|
data/lib/active_support/cache.rb
CHANGED
|
@@ -35,6 +35,8 @@ module ActiveSupport
|
|
|
35
35
|
:race_condition_ttl,
|
|
36
36
|
:serializer,
|
|
37
37
|
:skip_nil,
|
|
38
|
+
:raw,
|
|
39
|
+
:max_key_size,
|
|
38
40
|
]
|
|
39
41
|
|
|
40
42
|
# Mapping of canonical option names to aliases that a store will recognize.
|
|
@@ -52,7 +54,7 @@ module ActiveSupport
|
|
|
52
54
|
autoload :LocalCache, "active_support/cache/strategy/local_cache"
|
|
53
55
|
end
|
|
54
56
|
|
|
55
|
-
@format_version =
|
|
57
|
+
@format_version = 7.0
|
|
56
58
|
|
|
57
59
|
class << self
|
|
58
60
|
attr_accessor :format_version
|
|
@@ -86,13 +88,7 @@ module ActiveSupport
|
|
|
86
88
|
case store
|
|
87
89
|
when Symbol
|
|
88
90
|
options = parameters.extract_options!
|
|
89
|
-
|
|
90
|
-
# see https://github.com/rails/rails/pull/41522#discussion_r581186602
|
|
91
|
-
if options.empty?
|
|
92
|
-
retrieve_store_class(store).new(*parameters)
|
|
93
|
-
else
|
|
94
|
-
retrieve_store_class(store).new(*parameters, **options)
|
|
95
|
-
end
|
|
91
|
+
retrieve_store_class(store).new(*parameters, **options)
|
|
96
92
|
when Array
|
|
97
93
|
lookup_store(*store)
|
|
98
94
|
when nil
|
|
@@ -166,7 +162,7 @@ module ActiveSupport
|
|
|
166
162
|
# cache = ActiveSupport::Cache::MemoryStore.new
|
|
167
163
|
#
|
|
168
164
|
# cache.read('city') # => nil
|
|
169
|
-
# cache.write('city', "Duckburgh")
|
|
165
|
+
# cache.write('city', "Duckburgh") # => true
|
|
170
166
|
# cache.read('city') # => "Duckburgh"
|
|
171
167
|
#
|
|
172
168
|
# cache.write('not serializable', Proc.new {}) # => TypeError
|
|
@@ -192,6 +188,12 @@ module ActiveSupport
|
|
|
192
188
|
# @last_mod_time = Time.now # Invalidate the entire cache by changing namespace
|
|
193
189
|
#
|
|
194
190
|
class Store
|
|
191
|
+
# Default +ConnectionPool+ options
|
|
192
|
+
DEFAULT_POOL_OPTIONS = { size: 5, timeout: 5 }.freeze
|
|
193
|
+
|
|
194
|
+
# Keys are truncated with the Active Support digest if they exceed the limit.
|
|
195
|
+
MAX_KEY_SIZE = 250
|
|
196
|
+
|
|
195
197
|
cattr_accessor :logger, instance_writer: true
|
|
196
198
|
cattr_accessor :raise_on_invalid_cache_expiration_time, default: false
|
|
197
199
|
|
|
@@ -200,30 +202,9 @@ module ActiveSupport
|
|
|
200
202
|
|
|
201
203
|
class << self
|
|
202
204
|
private
|
|
203
|
-
DEFAULT_POOL_OPTIONS = { size: 5, timeout: 5 }.freeze
|
|
204
|
-
private_constant :DEFAULT_POOL_OPTIONS
|
|
205
|
-
|
|
206
205
|
def retrieve_pool_options(options)
|
|
207
206
|
if options.key?(:pool)
|
|
208
207
|
pool_options = options.delete(:pool)
|
|
209
|
-
elsif options.key?(:pool_size) || options.key?(:pool_timeout)
|
|
210
|
-
pool_options = {}
|
|
211
|
-
|
|
212
|
-
if options.key?(:pool_size)
|
|
213
|
-
ActiveSupport.deprecator.warn(<<~MSG)
|
|
214
|
-
Using :pool_size is deprecated and will be removed in Rails 7.2.
|
|
215
|
-
Use `pool: { size: #{options[:pool_size].inspect} }` instead.
|
|
216
|
-
MSG
|
|
217
|
-
pool_options[:size] = options.delete(:pool_size)
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
if options.key?(:pool_timeout)
|
|
221
|
-
ActiveSupport.deprecator.warn(<<~MSG)
|
|
222
|
-
Using :pool_timeout is deprecated and will be removed in Rails 7.2.
|
|
223
|
-
Use `pool: { timeout: #{options[:pool_timeout].inspect} }` instead.
|
|
224
|
-
MSG
|
|
225
|
-
pool_options[:timeout] = options.delete(:pool_timeout)
|
|
226
|
-
end
|
|
227
208
|
else
|
|
228
209
|
pool_options = true
|
|
229
210
|
end
|
|
@@ -310,7 +291,7 @@ module ActiveSupport
|
|
|
310
291
|
# <tt>coder: nil</tt> to avoid the overhead of safeguarding against
|
|
311
292
|
# mutation.
|
|
312
293
|
#
|
|
313
|
-
# The +:coder+ option is
|
|
294
|
+
# The +:coder+ option is mutually exclusive with the +:serializer+ and
|
|
314
295
|
# +:compressor+ options. Specifying them together will raise an
|
|
315
296
|
# +ArgumentError+.
|
|
316
297
|
#
|
|
@@ -322,6 +303,9 @@ module ActiveSupport
|
|
|
322
303
|
@options[:compress] = true unless @options.key?(:compress)
|
|
323
304
|
@options[:compress_threshold] ||= DEFAULT_COMPRESS_LIMIT
|
|
324
305
|
|
|
306
|
+
@max_key_size = @options.delete(:max_key_size)
|
|
307
|
+
@max_key_size = MAX_KEY_SIZE if @max_key_size.nil? # allow 'false' as a value
|
|
308
|
+
|
|
325
309
|
@coder = @options.delete(:coder) do
|
|
326
310
|
legacy_serializer = Cache.format_version < 7.1 && !@options[:serializer]
|
|
327
311
|
serializer = @options.delete(:serializer) || default_serializer
|
|
@@ -344,7 +328,7 @@ module ActiveSupport
|
|
|
344
328
|
|
|
345
329
|
# Silences the logger within a block.
|
|
346
330
|
def mute
|
|
347
|
-
previous_silence, @silence =
|
|
331
|
+
previous_silence, @silence = @silence, true
|
|
348
332
|
yield
|
|
349
333
|
ensure
|
|
350
334
|
@silence = previous_silence
|
|
@@ -410,32 +394,48 @@ module ActiveSupport
|
|
|
410
394
|
# process can try to generate a new value after the extended time window
|
|
411
395
|
# has elapsed.
|
|
412
396
|
#
|
|
413
|
-
# # Set all values to expire after one
|
|
414
|
-
# cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 1
|
|
397
|
+
# # Set all values to expire after one second.
|
|
398
|
+
# cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 1)
|
|
415
399
|
#
|
|
416
|
-
# cache.write(
|
|
400
|
+
# cache.write("foo", "original value")
|
|
417
401
|
# val_1 = nil
|
|
418
402
|
# val_2 = nil
|
|
419
|
-
#
|
|
403
|
+
# p cache.read("foo") # => "original value"
|
|
420
404
|
#
|
|
421
|
-
#
|
|
422
|
-
#
|
|
405
|
+
# sleep 1 # wait until the cache expires
|
|
406
|
+
#
|
|
407
|
+
# t1 = Thread.new do
|
|
408
|
+
# # fetch does the following:
|
|
409
|
+
# # 1. gets an recent expired entry
|
|
410
|
+
# # 2. extends the expiry by 2 seconds (race_condition_ttl)
|
|
411
|
+
# # 3. regenerates the new value
|
|
412
|
+
# val_1 = cache.fetch("foo", race_condition_ttl: 2) do
|
|
423
413
|
# sleep 1
|
|
424
|
-
#
|
|
414
|
+
# "new value 1"
|
|
425
415
|
# end
|
|
426
416
|
# end
|
|
427
417
|
#
|
|
428
|
-
#
|
|
429
|
-
#
|
|
430
|
-
#
|
|
431
|
-
#
|
|
418
|
+
# # Wait until t1 extends the expiry of the entry
|
|
419
|
+
# # but before generating the new value
|
|
420
|
+
# sleep 0.1
|
|
421
|
+
#
|
|
422
|
+
# val_2 = cache.fetch("foo", race_condition_ttl: 2) do
|
|
423
|
+
# # This block won't be executed because t1 extended the expiry
|
|
424
|
+
# "new value 2"
|
|
432
425
|
# end
|
|
433
426
|
#
|
|
434
|
-
#
|
|
435
|
-
#
|
|
436
|
-
#
|
|
437
|
-
#
|
|
438
|
-
#
|
|
427
|
+
# t1.join
|
|
428
|
+
#
|
|
429
|
+
# p val_1 # => "new value 1"
|
|
430
|
+
# p val_2 # => "original value"
|
|
431
|
+
# p cache.fetch("foo") # => "new value 1"
|
|
432
|
+
#
|
|
433
|
+
# # The entry requires 3 seconds to expire (expires_in + race_condition_ttl)
|
|
434
|
+
# # We have waited 2 seconds already (sleep(1) + t1.join) thus we need to wait 1
|
|
435
|
+
# # more second to see the entry expire.
|
|
436
|
+
# sleep 1
|
|
437
|
+
#
|
|
438
|
+
# p cache.fetch("foo") # => nil
|
|
439
439
|
#
|
|
440
440
|
# ==== Dynamic Options
|
|
441
441
|
#
|
|
@@ -456,7 +456,7 @@ module ActiveSupport
|
|
|
456
456
|
|
|
457
457
|
entry = nil
|
|
458
458
|
unless options[:force]
|
|
459
|
-
instrument(:read,
|
|
459
|
+
instrument(:read, key, options) do |payload|
|
|
460
460
|
cached_entry = read_entry(key, **options, event: payload)
|
|
461
461
|
entry = handle_expired_entry(cached_entry, key, options)
|
|
462
462
|
if entry
|
|
@@ -478,7 +478,7 @@ module ActiveSupport
|
|
|
478
478
|
if entry
|
|
479
479
|
get_entry_value(entry, name, options)
|
|
480
480
|
else
|
|
481
|
-
save_block_result_to_cache(name, options, &block)
|
|
481
|
+
save_block_result_to_cache(name, key, options, &block)
|
|
482
482
|
end
|
|
483
483
|
elsif options && options[:force]
|
|
484
484
|
raise ArgumentError, "Missing block: Calling `Cache#fetch` with `force: true` requires a block."
|
|
@@ -508,7 +508,7 @@ module ActiveSupport
|
|
|
508
508
|
key = normalize_key(name, options)
|
|
509
509
|
version = normalize_version(name, options)
|
|
510
510
|
|
|
511
|
-
instrument(:read,
|
|
511
|
+
instrument(:read, key, options) do |payload|
|
|
512
512
|
entry = read_entry(key, **options, event: payload)
|
|
513
513
|
|
|
514
514
|
if entry
|
|
@@ -546,10 +546,11 @@ module ActiveSupport
|
|
|
546
546
|
|
|
547
547
|
options = names.extract_options!
|
|
548
548
|
options = merged_options(options)
|
|
549
|
+
keys = names.map { |name| normalize_key(name, options) }
|
|
549
550
|
|
|
550
|
-
instrument_multi :read_multi,
|
|
551
|
+
instrument_multi :read_multi, keys, options do |payload|
|
|
551
552
|
read_multi_entries(names, **options, event: payload).tap do |results|
|
|
552
|
-
payload[:hits] = results.keys
|
|
553
|
+
payload[:hits] = results.keys.map { |name| normalize_key(name, options) }
|
|
553
554
|
end
|
|
554
555
|
end
|
|
555
556
|
end
|
|
@@ -559,10 +560,11 @@ module ActiveSupport
|
|
|
559
560
|
return hash if hash.empty?
|
|
560
561
|
|
|
561
562
|
options = merged_options(options)
|
|
563
|
+
normalized_hash = hash.transform_keys { |key| normalize_key(key, options) }
|
|
562
564
|
|
|
563
|
-
instrument_multi :write_multi,
|
|
565
|
+
instrument_multi :write_multi, normalized_hash, options do |payload|
|
|
564
566
|
entries = hash.each_with_object({}) do |(name, value), memo|
|
|
565
|
-
memo[normalize_key(name, options)] = Entry.new(value, **options
|
|
567
|
+
memo[normalize_key(name, options)] = Entry.new(value, **options, version: normalize_version(name, options))
|
|
566
568
|
end
|
|
567
569
|
|
|
568
570
|
write_multi_entries entries, **options
|
|
@@ -604,32 +606,37 @@ module ActiveSupport
|
|
|
604
606
|
|
|
605
607
|
options = names.extract_options!
|
|
606
608
|
options = merged_options(options)
|
|
607
|
-
|
|
608
|
-
|
|
609
|
+
keys = names.map { |name| normalize_key(name, options) }
|
|
610
|
+
writes = {}
|
|
611
|
+
ordered = instrument_multi :read_multi, keys, options do |payload|
|
|
609
612
|
if options[:force]
|
|
610
613
|
reads = {}
|
|
611
614
|
else
|
|
612
615
|
reads = read_multi_entries(names, **options)
|
|
613
616
|
end
|
|
614
617
|
|
|
615
|
-
writes = {}
|
|
616
618
|
ordered = names.index_with do |name|
|
|
617
619
|
reads.fetch(name) { writes[name] = yield(name) }
|
|
618
620
|
end
|
|
619
621
|
writes.compact! if options[:skip_nil]
|
|
620
622
|
|
|
621
|
-
payload[:hits] = reads.keys
|
|
623
|
+
payload[:hits] = reads.keys.map { |name| normalize_key(name, options) }
|
|
622
624
|
payload[:super_operation] = :fetch_multi
|
|
623
625
|
|
|
624
|
-
write_multi(writes, options)
|
|
625
|
-
|
|
626
626
|
ordered
|
|
627
627
|
end
|
|
628
|
+
|
|
629
|
+
write_multi(writes, options)
|
|
630
|
+
|
|
631
|
+
ordered
|
|
628
632
|
end
|
|
629
633
|
|
|
630
634
|
# Writes the value to the cache with the key. The value must be supported
|
|
631
635
|
# by the +coder+'s +dump+ and +load+ methods.
|
|
632
636
|
#
|
|
637
|
+
# Returns +true+ if the write succeeded, +nil+ if there was an error talking
|
|
638
|
+
# to the cache backend, or +false+ if the write failed for another reason.
|
|
639
|
+
#
|
|
633
640
|
# By default, cache entries larger than 1kB are compressed. Compression
|
|
634
641
|
# allows more data to be stored in the same memory footprint, leading to
|
|
635
642
|
# fewer cache evictions and higher hit rates.
|
|
@@ -659,13 +666,16 @@ module ActiveSupport
|
|
|
659
666
|
# version, the read will be treated as a cache miss. This feature is
|
|
660
667
|
# used to support recyclable cache keys.
|
|
661
668
|
#
|
|
669
|
+
# * +:unless_exist+ - Prevents overwriting an existing cache entry.
|
|
670
|
+
#
|
|
662
671
|
# Other options will be handled by the specific cache store implementation.
|
|
663
672
|
def write(name, value, options = nil)
|
|
664
673
|
options = merged_options(options)
|
|
674
|
+
key = normalize_key(name, options)
|
|
665
675
|
|
|
666
|
-
instrument(:write,
|
|
667
|
-
entry = Entry.new(value, **options
|
|
668
|
-
write_entry(
|
|
676
|
+
instrument(:write, key, options) do
|
|
677
|
+
entry = Entry.new(value, **options, version: normalize_version(name, options))
|
|
678
|
+
write_entry(key, entry, **options)
|
|
669
679
|
end
|
|
670
680
|
end
|
|
671
681
|
|
|
@@ -675,9 +685,10 @@ module ActiveSupport
|
|
|
675
685
|
# Options are passed to the underlying cache implementation.
|
|
676
686
|
def delete(name, options = nil)
|
|
677
687
|
options = merged_options(options)
|
|
688
|
+
key = normalize_key(name, options)
|
|
678
689
|
|
|
679
|
-
instrument(:delete,
|
|
680
|
-
delete_entry(
|
|
690
|
+
instrument(:delete, key, options) do
|
|
691
|
+
delete_entry(key, **options)
|
|
681
692
|
end
|
|
682
693
|
end
|
|
683
694
|
|
|
@@ -691,7 +702,7 @@ module ActiveSupport
|
|
|
691
702
|
options = merged_options(options)
|
|
692
703
|
names.map! { |key| normalize_key(key, options) }
|
|
693
704
|
|
|
694
|
-
instrument_multi
|
|
705
|
+
instrument_multi(:delete_multi, names, options) do
|
|
695
706
|
delete_multi_entries(names, **options)
|
|
696
707
|
end
|
|
697
708
|
end
|
|
@@ -701,9 +712,10 @@ module ActiveSupport
|
|
|
701
712
|
# Options are passed to the underlying cache implementation.
|
|
702
713
|
def exist?(name, options = nil)
|
|
703
714
|
options = merged_options(options)
|
|
715
|
+
key = normalize_key(name, options)
|
|
704
716
|
|
|
705
|
-
instrument(:exist?,
|
|
706
|
-
entry = read_entry(
|
|
717
|
+
instrument(:exist?, key) do |payload|
|
|
718
|
+
entry = read_entry(key, **options, event: payload)
|
|
707
719
|
(entry && !entry.expired? && !entry.mismatched?(normalize_version(name, options))) || false
|
|
708
720
|
end
|
|
709
721
|
end
|
|
@@ -739,6 +751,32 @@ module ActiveSupport
|
|
|
739
751
|
raise NotImplementedError.new("#{self.class.name} does not support decrement")
|
|
740
752
|
end
|
|
741
753
|
|
|
754
|
+
# Reads a counter that was set by #increment / #decrement.
|
|
755
|
+
#
|
|
756
|
+
# cache.write_counter("foo", 1)
|
|
757
|
+
# cache.read_counter("foo") # => 1
|
|
758
|
+
# cache.increment("foo")
|
|
759
|
+
# cache.read_counter("foo") # => 2
|
|
760
|
+
#
|
|
761
|
+
# Options are passed to the underlying cache implementation.
|
|
762
|
+
def read_counter(name, **options)
|
|
763
|
+
options = merged_options(options).merge(raw: true)
|
|
764
|
+
read(name, **options)&.to_i
|
|
765
|
+
end
|
|
766
|
+
|
|
767
|
+
# Writes a counter that can then be modified by #increment / #decrement.
|
|
768
|
+
#
|
|
769
|
+
# cache.write_counter("foo", 1)
|
|
770
|
+
# cache.read_counter("foo") # => 1
|
|
771
|
+
# cache.increment("foo")
|
|
772
|
+
# cache.read_counter("foo") # => 2
|
|
773
|
+
#
|
|
774
|
+
# Options are passed to the underlying cache implementation.
|
|
775
|
+
def write_counter(name, value, **options)
|
|
776
|
+
options = merged_options(options).merge(raw: true)
|
|
777
|
+
write(name, value.to_i, **options)
|
|
778
|
+
end
|
|
779
|
+
|
|
742
780
|
# Cleans up the cache by removing expired entries.
|
|
743
781
|
#
|
|
744
782
|
# Options are passed to the underlying cache implementation.
|
|
@@ -758,17 +796,20 @@ module ActiveSupport
|
|
|
758
796
|
raise NotImplementedError.new("#{self.class.name} does not support clear")
|
|
759
797
|
end
|
|
760
798
|
|
|
799
|
+
# Get the current namespace
|
|
800
|
+
def namespace
|
|
801
|
+
@options[:namespace]
|
|
802
|
+
end
|
|
803
|
+
|
|
804
|
+
# Set the current namespace. Note, this will be ignored if custom
|
|
805
|
+
# options are passed to cache wills with a namespace key.
|
|
806
|
+
def namespace=(namespace)
|
|
807
|
+
@options[:namespace] = namespace
|
|
808
|
+
end
|
|
809
|
+
|
|
761
810
|
private
|
|
762
811
|
def default_serializer
|
|
763
812
|
case Cache.format_version
|
|
764
|
-
when 6.1
|
|
765
|
-
ActiveSupport.deprecator.warn <<~EOM
|
|
766
|
-
Support for `config.active_support.cache_format_version = 6.1` has been deprecated and will be removed in Rails 7.2.
|
|
767
|
-
|
|
768
|
-
Check the Rails upgrade guide at https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#new-activesupport-cache-serialization-format
|
|
769
|
-
for more information on how to upgrade.
|
|
770
|
-
EOM
|
|
771
|
-
Cache::SerializerWithFallback[:marshal_6_1]
|
|
772
813
|
when 7.0
|
|
773
814
|
Cache::SerializerWithFallback[:marshal_7_0]
|
|
774
815
|
when 7.1
|
|
@@ -932,16 +973,33 @@ module ActiveSupport
|
|
|
932
973
|
options
|
|
933
974
|
end
|
|
934
975
|
|
|
935
|
-
# Expands and
|
|
976
|
+
# Expands, namespaces and truncates the cache key.
|
|
936
977
|
# Raises an exception when the key is +nil+ or an empty string.
|
|
937
978
|
# May be overridden by cache stores to do additional normalization.
|
|
938
979
|
def normalize_key(key, options = nil)
|
|
980
|
+
key = expand_and_namespace_key(key, options)
|
|
981
|
+
truncate_key(key)
|
|
982
|
+
end
|
|
983
|
+
|
|
984
|
+
def expand_and_namespace_key(key, options = nil)
|
|
939
985
|
str_key = expanded_key(key)
|
|
940
986
|
raise(ArgumentError, "key cannot be blank") if !str_key || str_key.empty?
|
|
941
987
|
|
|
942
988
|
namespace_key str_key, options
|
|
943
989
|
end
|
|
944
990
|
|
|
991
|
+
def truncate_key(key)
|
|
992
|
+
if key && @max_key_size && key.bytesize > @max_key_size
|
|
993
|
+
suffix = ":hash:#{ActiveSupport::Digest.hexdigest(key)}"
|
|
994
|
+
truncate_at = @max_key_size - suffix.bytesize
|
|
995
|
+
key = key.byteslice(0, truncate_at)
|
|
996
|
+
key.scrub!("")
|
|
997
|
+
"#{key}#{suffix}"
|
|
998
|
+
else
|
|
999
|
+
key
|
|
1000
|
+
end
|
|
1001
|
+
end
|
|
1002
|
+
|
|
945
1003
|
# Prefix the key with a namespace string:
|
|
946
1004
|
#
|
|
947
1005
|
# namespace_key 'foo', namespace: 'cache'
|
|
@@ -951,9 +1009,12 @@ module ActiveSupport
|
|
|
951
1009
|
#
|
|
952
1010
|
# namespace_key 'foo', namespace: -> { 'cache' }
|
|
953
1011
|
# # => 'cache:foo'
|
|
954
|
-
def namespace_key(key,
|
|
955
|
-
|
|
956
|
-
|
|
1012
|
+
def namespace_key(key, call_options = nil)
|
|
1013
|
+
namespace = if call_options&.key?(:namespace)
|
|
1014
|
+
call_options[:namespace]
|
|
1015
|
+
else
|
|
1016
|
+
options[:namespace]
|
|
1017
|
+
end
|
|
957
1018
|
|
|
958
1019
|
if namespace.respond_to?(:call)
|
|
959
1020
|
namespace = namespace.call
|
|
@@ -1016,7 +1077,7 @@ module ActiveSupport
|
|
|
1016
1077
|
if multi
|
|
1017
1078
|
": #{payload[:key].size} key(s) specified"
|
|
1018
1079
|
elsif payload[:key]
|
|
1019
|
-
": #{
|
|
1080
|
+
": #{payload[:key]}"
|
|
1020
1081
|
end
|
|
1021
1082
|
|
|
1022
1083
|
debug_options = " (#{options.inspect})" unless options.blank?
|
|
@@ -1038,8 +1099,7 @@ module ActiveSupport
|
|
|
1038
1099
|
# When an entry has a positive :race_condition_ttl defined, put the stale entry back into the cache
|
|
1039
1100
|
# for a brief period while the entry is being recalculated.
|
|
1040
1101
|
entry.expires_at = Time.now.to_f + race_ttl
|
|
1041
|
-
options
|
|
1042
|
-
write_entry(key, entry, **options)
|
|
1102
|
+
write_entry(key, entry, **options, expires_in: race_ttl * 2)
|
|
1043
1103
|
else
|
|
1044
1104
|
delete_entry(key, **options)
|
|
1045
1105
|
end
|
|
@@ -1053,10 +1113,10 @@ module ActiveSupport
|
|
|
1053
1113
|
entry.value
|
|
1054
1114
|
end
|
|
1055
1115
|
|
|
1056
|
-
def save_block_result_to_cache(name, options)
|
|
1116
|
+
def save_block_result_to_cache(name, key, options)
|
|
1057
1117
|
options = options.dup
|
|
1058
1118
|
|
|
1059
|
-
result = instrument(:generate,
|
|
1119
|
+
result = instrument(:generate, key, options) do
|
|
1060
1120
|
yield(name, WriteOptions.new(options))
|
|
1061
1121
|
end
|
|
1062
1122
|
|