activesupport 6.0.4.4 → 7.0.4.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +257 -532
- data/MIT-LICENSE +1 -1
- data/lib/active_support/actionable_error.rb +1 -1
- data/lib/active_support/array_inquirer.rb +2 -2
- data/lib/active_support/backtrace_cleaner.rb +5 -5
- data/lib/active_support/benchmarkable.rb +3 -3
- data/lib/active_support/cache/file_store.rb +16 -10
- data/lib/active_support/cache/mem_cache_store.rb +163 -42
- data/lib/active_support/cache/memory_store.rb +57 -29
- data/lib/active_support/cache/null_store.rb +10 -2
- data/lib/active_support/cache/redis_cache_store.rb +79 -98
- data/lib/active_support/cache/strategy/local_cache.rb +49 -57
- data/lib/active_support/cache.rb +378 -179
- data/lib/active_support/callbacks.rb +230 -122
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +49 -5
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
- data/lib/active_support/concurrency/share_lock.rb +2 -2
- data/lib/active_support/configurable.rb +9 -6
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/array/access.rb +1 -5
- data/lib/active_support/core_ext/array/conversions.rb +13 -12
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
- data/lib/active_support/core_ext/array/grouping.rb +6 -6
- data/lib/active_support/core_ext/array/inquiry.rb +2 -2
- data/lib/active_support/core_ext/array.rb +1 -0
- data/lib/active_support/core_ext/benchmark.rb +2 -2
- data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
- data/lib/active_support/core_ext/class/attribute.rb +34 -44
- data/lib/active_support/core_ext/class/subclasses.rb +9 -22
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +9 -9
- data/lib/active_support/core_ext/date/conversions.rb +16 -15
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/date.rb +1 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +17 -4
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/date_time/conversions.rb +13 -13
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/date_time.rb +1 -0
- data/lib/active_support/core_ext/digest/uuid.rb +39 -13
- data/lib/active_support/core_ext/enumerable.rb +164 -23
- data/lib/active_support/core_ext/file/atomic.rb +3 -1
- data/lib/active_support/core_ext/hash/conversions.rb +2 -3
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
- data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +2 -2
- data/lib/active_support/core_ext/hash/slice.rb +3 -2
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
- data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
- data/lib/active_support/core_ext/load_error.rb +1 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +25 -29
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +26 -13
- data/lib/active_support/core_ext/module/concerning.rb +8 -2
- data/lib/active_support/core_ext/module/delegation.rb +40 -36
- data/lib/active_support/core_ext/module/introspection.rb +1 -25
- data/lib/active_support/core_ext/name_error.rb +23 -2
- data/lib/active_support/core_ext/numeric/conversions.rb +80 -73
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
- data/lib/active_support/core_ext/numeric.rb +1 -0
- data/lib/active_support/core_ext/object/acts_like.rb +29 -5
- data/lib/active_support/core_ext/object/blank.rb +2 -2
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/duplicable.rb +11 -0
- data/lib/active_support/core_ext/object/json.rb +42 -26
- data/lib/active_support/core_ext/object/to_query.rb +2 -2
- data/lib/active_support/core_ext/object/try.rb +20 -20
- data/lib/active_support/core_ext/object/with_options.rb +20 -1
- data/lib/active_support/core_ext/pathname/existence.rb +21 -0
- data/lib/active_support/core_ext/pathname.rb +3 -0
- data/lib/active_support/core_ext/range/compare_range.rb +6 -25
- data/lib/active_support/core_ext/range/conversions.rb +8 -8
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/range/each.rb +1 -1
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -20
- data/lib/active_support/core_ext/range/overlaps.rb +1 -1
- data/lib/active_support/core_ext/range.rb +1 -1
- data/lib/active_support/core_ext/regexp.rb +8 -1
- data/lib/active_support/core_ext/securerandom.rb +1 -1
- data/lib/active_support/core_ext/string/access.rb +5 -24
- data/lib/active_support/core_ext/string/conversions.rb +3 -2
- data/lib/active_support/core_ext/string/filters.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +39 -5
- data/lib/active_support/core_ext/string/inquiry.rb +2 -1
- data/lib/active_support/core_ext/string/multibyte.rb +2 -2
- data/lib/active_support/core_ext/string/output_safety.rb +92 -41
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/time/calculations.rb +25 -7
- data/lib/active_support/core_ext/time/conversions.rb +15 -12
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/time/zones.rb +7 -22
- data/lib/active_support/core_ext/time.rb +1 -0
- data/lib/active_support/core_ext/uri.rb +3 -23
- data/lib/active_support/core_ext.rb +2 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +39 -16
- data/lib/active_support/dependencies/interlock.rb +10 -18
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +58 -769
- data/lib/active_support/deprecation/behaviors.rb +23 -7
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +0 -1
- data/lib/active_support/deprecation/method_wrappers.rb +6 -5
- data/lib/active_support/deprecation/proxy_wrappers.rb +4 -4
- data/lib/active_support/deprecation/reporting.rb +50 -7
- data/lib/active_support/deprecation.rb +7 -2
- data/lib/active_support/descendants_tracker.rb +174 -64
- data/lib/active_support/digest.rb +5 -3
- data/lib/active_support/duration/iso8601_parser.rb +3 -3
- data/lib/active_support/duration/iso8601_serializer.rb +24 -10
- data/lib/active_support/duration.rb +134 -55
- data/lib/active_support/encrypted_configuration.rb +13 -2
- data/lib/active_support/encrypted_file.rb +32 -3
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/error_reporter.rb +117 -0
- data/lib/active_support/evented_file_update_checker.rb +72 -138
- data/lib/active_support/execution_context/test_helper.rb +13 -0
- data/lib/active_support/execution_context.rb +53 -0
- data/lib/active_support/execution_wrapper.rb +43 -21
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/fork_tracker.rb +71 -0
- data/lib/active_support/gem_version.rb +3 -3
- data/lib/active_support/hash_with_indifferent_access.rb +51 -25
- data/lib/active_support/html_safe_translation.rb +43 -0
- data/lib/active_support/i18n.rb +1 -0
- data/lib/active_support/i18n_railtie.rb +14 -19
- data/lib/active_support/inflector/inflections.rb +24 -9
- data/lib/active_support/inflector/methods.rb +29 -49
- data/lib/active_support/inflector/transliterate.rb +5 -5
- data/lib/active_support/isolated_execution_state.rb +72 -0
- data/lib/active_support/json/decoding.rb +4 -4
- data/lib/active_support/json/encoding.rb +8 -4
- data/lib/active_support/key_generator.rb +23 -6
- data/lib/active_support/lazy_load_hooks.rb +28 -4
- data/lib/active_support/locale/en.yml +8 -4
- data/lib/active_support/log_subscriber/test_helper.rb +2 -2
- data/lib/active_support/log_subscriber.rb +23 -5
- data/lib/active_support/logger.rb +1 -1
- data/lib/active_support/logger_silence.rb +2 -26
- data/lib/active_support/logger_thread_safe_level.rb +34 -21
- data/lib/active_support/message_encryptor.rb +16 -13
- data/lib/active_support/message_verifier.rb +50 -18
- data/lib/active_support/messages/metadata.rb +2 -2
- data/lib/active_support/messages/rotation_configuration.rb +2 -1
- data/lib/active_support/messages/rotator.rb +6 -5
- data/lib/active_support/multibyte/chars.rb +13 -52
- data/lib/active_support/multibyte/unicode.rb +1 -87
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +110 -69
- data/lib/active_support/notifications/instrumenter.rb +37 -29
- data/lib/active_support/notifications.rb +55 -28
- data/lib/active_support/number_helper/number_converter.rb +2 -4
- data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +2 -2
- data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
- data/lib/active_support/number_helper/rounding_helper.rb +12 -32
- data/lib/active_support/number_helper.rb +29 -16
- data/lib/active_support/option_merger.rb +11 -18
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/ordered_options.rb +9 -3
- data/lib/active_support/parameter_filter.rb +21 -11
- data/lib/active_support/per_thread_registry.rb +6 -1
- data/lib/active_support/rails.rb +1 -4
- data/lib/active_support/railtie.rb +77 -5
- data/lib/active_support/reloader.rb +1 -1
- data/lib/active_support/rescuable.rb +16 -16
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/secure_compare_rotator.rb +51 -0
- data/lib/active_support/security_utils.rb +19 -12
- data/lib/active_support/string_inquirer.rb +2 -2
- data/lib/active_support/subscriber.rb +19 -25
- data/lib/active_support/tagged_logging.rb +31 -6
- data/lib/active_support/test_case.rb +13 -21
- data/lib/active_support/testing/assertions.rb +50 -13
- data/lib/active_support/testing/deprecation.rb +52 -1
- data/lib/active_support/testing/isolation.rb +2 -2
- data/lib/active_support/testing/method_call_assertions.rb +5 -5
- data/lib/active_support/testing/parallelization/server.rb +82 -0
- data/lib/active_support/testing/parallelization/worker.rb +103 -0
- data/lib/active_support/testing/parallelization.rb +16 -95
- data/lib/active_support/testing/parallelize_executor.rb +76 -0
- data/lib/active_support/testing/stream.rb +3 -5
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +53 -5
- data/lib/active_support/time_with_zone.rb +126 -62
- data/lib/active_support/values/time_zone.rb +54 -23
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/jdom.rb +1 -1
- data/lib/active_support/xml_mini/libxml.rb +5 -5
- data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
- data/lib/active_support/xml_mini/nokogiri.rb +4 -4
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
- data/lib/active_support/xml_mini/rexml.rb +9 -2
- data/lib/active_support/xml_mini.rb +5 -4
- data/lib/active_support.rb +29 -1
- metadata +46 -45
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
- data/lib/active_support/core_ext/hash/compact.rb +0 -5
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
- data/lib/active_support/core_ext/marshal.rb +0 -24
- data/lib/active_support/core_ext/module/reachable.rb +0 -6
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
- data/lib/active_support/core_ext/range/include_range.rb +0 -9
- 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\", \"
|
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
|
-
|
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
|
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
|
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)
|
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
|
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
|
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(
|
138
|
-
::Redis.new
|
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
|
172
|
-
def initialize(namespace: nil, compress: true, compress_threshold: 1.kilobyte, 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
|
@@ -177,7 +154,8 @@ module ActiveSupport
|
|
177
154
|
|
178
155
|
super namespace: namespace,
|
179
156
|
compress: compress, compress_threshold: compress_threshold,
|
180
|
-
expires_in: expires_in, race_condition_ttl: race_condition_ttl
|
157
|
+
expires_in: expires_in, race_condition_ttl: race_condition_ttl,
|
158
|
+
coder: coder
|
181
159
|
end
|
182
160
|
|
183
161
|
def redis
|
@@ -195,7 +173,7 @@ module ActiveSupport
|
|
195
173
|
|
196
174
|
def inspect
|
197
175
|
instance = @redis || @redis_options
|
198
|
-
"
|
176
|
+
"#<#{self.class} options=#{options.inspect} redis=#{instance.inspect}>"
|
199
177
|
end
|
200
178
|
|
201
179
|
# Cache Store API implementation.
|
@@ -238,10 +216,14 @@ module ActiveSupport
|
|
238
216
|
pattern = namespace_key(matcher, options)
|
239
217
|
cursor = "0"
|
240
218
|
# Fetch keys in batches using SCAN to avoid blocking the Redis server.
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
219
|
+
nodes = c.respond_to?(:nodes) ? c.nodes : [c]
|
220
|
+
|
221
|
+
nodes.each do |node|
|
222
|
+
begin
|
223
|
+
cursor, keys = node.scan(cursor, match: pattern, count: SCAN_BATCH_SIZE)
|
224
|
+
node.del(*keys) unless keys.empty?
|
225
|
+
end until cursor == "0"
|
226
|
+
end
|
245
227
|
end
|
246
228
|
end
|
247
229
|
end
|
@@ -249,8 +231,8 @@ module ActiveSupport
|
|
249
231
|
# Cache Store API implementation.
|
250
232
|
#
|
251
233
|
# Increment a cached value. This method uses the Redis incr atomic
|
252
|
-
# operator and can only be used on values written with the
|
253
|
-
# Calling it on a value not stored with
|
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
|
254
236
|
# to zero.
|
255
237
|
#
|
256
238
|
# Failsafe: Raises errors.
|
@@ -272,8 +254,8 @@ module ActiveSupport
|
|
272
254
|
# Cache Store API implementation.
|
273
255
|
#
|
274
256
|
# Decrement a cached value. This method uses the Redis decr atomic
|
275
|
-
# operator and can only be used on values written with the
|
276
|
-
# Calling it on a value not stored with
|
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
|
277
259
|
# to zero.
|
278
260
|
#
|
279
261
|
# Failsafe: Raises errors.
|
@@ -314,12 +296,17 @@ module ActiveSupport
|
|
314
296
|
end
|
315
297
|
end
|
316
298
|
|
317
|
-
|
299
|
+
# Get info from redis servers.
|
300
|
+
def stats
|
301
|
+
redis.with { |c| c.info }
|
302
|
+
end
|
303
|
+
|
304
|
+
def mget_capable? # :nodoc:
|
318
305
|
set_redis_capabilities unless defined? @mget_capable
|
319
306
|
@mget_capable
|
320
307
|
end
|
321
308
|
|
322
|
-
def mset_capable?
|
309
|
+
def mset_capable? # :nodoc:
|
323
310
|
set_redis_capabilities unless defined? @mset_capable
|
324
311
|
@mset_capable
|
325
312
|
end
|
@@ -339,9 +326,12 @@ module ActiveSupport
|
|
339
326
|
# Store provider interface:
|
340
327
|
# Read an entry from the cache.
|
341
328
|
def read_entry(key, **options)
|
329
|
+
deserialize_entry(read_serialized_entry(key, **options), **options)
|
330
|
+
end
|
331
|
+
|
332
|
+
def read_serialized_entry(key, raw: false, **options)
|
342
333
|
failsafe :read_entry do
|
343
|
-
|
344
|
-
deserialize_entry(redis.with { |c| c.get(key) }, raw: raw)
|
334
|
+
redis.with { |c| c.get(key) }
|
345
335
|
end
|
346
336
|
end
|
347
337
|
|
@@ -378,9 +368,11 @@ module ActiveSupport
|
|
378
368
|
# Write an entry to the cache.
|
379
369
|
#
|
380
370
|
# Requires Redis 2.6.12+ for extended SET options.
|
381
|
-
def write_entry(key, entry,
|
382
|
-
|
371
|
+
def write_entry(key, entry, raw: false, **options)
|
372
|
+
write_serialized_entry(key, serialize_entry(entry, raw: raw, **options), raw: raw, **options)
|
373
|
+
end
|
383
374
|
|
375
|
+
def write_serialized_entry(key, payload, raw: false, unless_exist: false, expires_in: nil, race_condition_ttl: nil, **options)
|
384
376
|
# If race condition TTL is in use, ensure that cache entries
|
385
377
|
# stick around a bit longer after they would have expired
|
386
378
|
# so we can purposefully serve stale entries.
|
@@ -388,16 +380,14 @@ module ActiveSupport
|
|
388
380
|
expires_in += 5.minutes
|
389
381
|
end
|
390
382
|
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
383
|
+
modifiers = {}
|
384
|
+
if unless_exist || expires_in
|
385
|
+
modifiers[:nx] = unless_exist
|
386
|
+
modifiers[:px] = (1000 * expires_in.to_f).ceil if expires_in
|
387
|
+
end
|
396
388
|
|
397
|
-
|
398
|
-
|
399
|
-
redis.with { |c| c.set key, serialized_entry }
|
400
|
-
end
|
389
|
+
failsafe :write_entry, returning: false do
|
390
|
+
redis.with { |c| c.set key, payload, **modifiers }
|
401
391
|
end
|
402
392
|
end
|
403
393
|
|
@@ -414,12 +404,20 @@ module ActiveSupport
|
|
414
404
|
end
|
415
405
|
end
|
416
406
|
|
407
|
+
# Deletes multiple entries in the cache. Returns the number of entries deleted.
|
408
|
+
def delete_multi_entries(entries, **_options)
|
409
|
+
redis.with { |c| c.del(entries) }
|
410
|
+
end
|
411
|
+
|
417
412
|
# Nonstandard store provider API to write multiple values at once.
|
418
413
|
def write_multi_entries(entries, expires_in: nil, **options)
|
419
414
|
if entries.any?
|
420
415
|
if mset_capable? && expires_in.nil?
|
421
416
|
failsafe :write_multi_entries do
|
422
|
-
|
417
|
+
payload = serialize_entries(entries, **options)
|
418
|
+
redis.with do |c|
|
419
|
+
c.mapped_mset(payload)
|
420
|
+
end
|
423
421
|
end
|
424
422
|
else
|
425
423
|
super
|
@@ -429,12 +427,12 @@ module ActiveSupport
|
|
429
427
|
|
430
428
|
# Truncate keys that exceed 1kB.
|
431
429
|
def normalize_key(key, options)
|
432
|
-
truncate_key super
|
430
|
+
truncate_key super&.b
|
433
431
|
end
|
434
432
|
|
435
433
|
def truncate_key(key)
|
436
|
-
if key.bytesize > max_key_bytesize
|
437
|
-
suffix = ":
|
434
|
+
if key && key.bytesize > max_key_bytesize
|
435
|
+
suffix = ":hash:#{ActiveSupport::Digest.hexdigest(key)}"
|
438
436
|
truncate_at = max_key_bytesize - suffix.bytesize
|
439
437
|
"#{key.byteslice(0, truncate_at)}#{suffix}"
|
440
438
|
else
|
@@ -442,52 +440,35 @@ module ActiveSupport
|
|
442
440
|
end
|
443
441
|
end
|
444
442
|
|
445
|
-
def deserialize_entry(
|
446
|
-
if
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
if raw != written_raw
|
451
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
452
|
-
Using a different value for the raw option when reading and writing
|
453
|
-
to a cache key is deprecated for :redis_cache_store and Rails 6.0
|
454
|
-
will stop automatically detecting the format when reading to avoid
|
455
|
-
marshal loading untrusted raw strings.
|
456
|
-
MSG
|
457
|
-
end
|
458
|
-
|
459
|
-
entry.is_a?(Entry) ? entry : Entry.new(entry)
|
443
|
+
def deserialize_entry(payload, raw: false, **)
|
444
|
+
if raw && !payload.nil?
|
445
|
+
Entry.new(payload)
|
446
|
+
else
|
447
|
+
super(payload)
|
460
448
|
end
|
461
449
|
end
|
462
450
|
|
463
|
-
def serialize_entry(entry, raw: false)
|
451
|
+
def serialize_entry(entry, raw: false, **options)
|
464
452
|
if raw
|
465
453
|
entry.value.to_s
|
466
454
|
else
|
467
|
-
|
455
|
+
super(entry, raw: raw, **options)
|
468
456
|
end
|
469
457
|
end
|
470
458
|
|
471
|
-
def serialize_entries(entries,
|
459
|
+
def serialize_entries(entries, **options)
|
472
460
|
entries.transform_values do |entry|
|
473
|
-
serialize_entry
|
461
|
+
serialize_entry(entry, **options)
|
474
462
|
end
|
475
463
|
end
|
476
464
|
|
477
465
|
def failsafe(method, returning: nil)
|
478
466
|
yield
|
479
|
-
rescue ::Redis::BaseError =>
|
480
|
-
|
467
|
+
rescue ::Redis::BaseError => error
|
468
|
+
ActiveSupport.error_reporter&.report(error, handled: true, severity: :warning)
|
469
|
+
@error_handler&.call(method: method, exception: error, returning: returning)
|
481
470
|
returning
|
482
471
|
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
472
|
end
|
492
473
|
end
|
493
474
|
end
|
@@ -1,8 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/core_ext/object/duplicable"
|
4
3
|
require "active_support/core_ext/string/inflections"
|
5
|
-
require "active_support/per_thread_registry"
|
6
4
|
|
7
5
|
module ActiveSupport
|
8
6
|
module Cache
|
@@ -14,74 +12,56 @@ module ActiveSupport
|
|
14
12
|
autoload :Middleware, "active_support/cache/strategy/local_cache_middleware"
|
15
13
|
|
16
14
|
# Class for storing and registering the local caches.
|
17
|
-
|
18
|
-
extend
|
19
|
-
|
20
|
-
def initialize
|
21
|
-
@registry = {}
|
22
|
-
end
|
15
|
+
module LocalCacheRegistry # :nodoc:
|
16
|
+
extend self
|
23
17
|
|
24
18
|
def cache_for(local_cache_key)
|
25
|
-
|
19
|
+
registry = ActiveSupport::IsolatedExecutionState[:active_support_local_cache_registry] ||= {}
|
20
|
+
registry[local_cache_key]
|
26
21
|
end
|
27
22
|
|
28
23
|
def set_cache_for(local_cache_key, value)
|
29
|
-
|
24
|
+
registry = ActiveSupport::IsolatedExecutionState[:active_support_local_cache_registry] ||= {}
|
25
|
+
registry[local_cache_key] = value
|
30
26
|
end
|
31
|
-
|
32
|
-
def self.set_cache_for(l, v); instance.set_cache_for l, v; end
|
33
|
-
def self.cache_for(l); instance.cache_for l; end
|
34
27
|
end
|
35
28
|
|
36
29
|
# Simple memory backed cache. This cache is not thread safe and is intended only
|
37
30
|
# for serving as a temporary memory cache for a single thread.
|
38
|
-
class LocalStore
|
31
|
+
class LocalStore
|
39
32
|
def initialize
|
40
|
-
super
|
41
33
|
@data = {}
|
42
34
|
end
|
43
35
|
|
44
|
-
# Don't allow synchronizing since it isn't thread safe.
|
45
|
-
def synchronize # :nodoc:
|
46
|
-
yield
|
47
|
-
end
|
48
|
-
|
49
36
|
def clear(options = nil)
|
50
37
|
@data.clear
|
51
38
|
end
|
52
39
|
|
53
|
-
def read_entry(key
|
40
|
+
def read_entry(key)
|
54
41
|
@data[key]
|
55
42
|
end
|
56
43
|
|
57
|
-
def read_multi_entries(keys
|
58
|
-
|
59
|
-
|
60
|
-
keys.each do |name|
|
61
|
-
entry = read_entry(name, **options)
|
62
|
-
values[name] = entry.value if entry
|
63
|
-
end
|
64
|
-
|
65
|
-
values
|
44
|
+
def read_multi_entries(keys)
|
45
|
+
@data.slice(*keys)
|
66
46
|
end
|
67
47
|
|
68
|
-
def write_entry(key,
|
69
|
-
@data[key] =
|
48
|
+
def write_entry(key, entry)
|
49
|
+
@data[key] = entry
|
70
50
|
true
|
71
51
|
end
|
72
52
|
|
73
|
-
def delete_entry(key
|
53
|
+
def delete_entry(key)
|
74
54
|
!!@data.delete(key)
|
75
55
|
end
|
76
56
|
|
77
|
-
def fetch_entry(key
|
57
|
+
def fetch_entry(key) # :nodoc:
|
78
58
|
@data.fetch(key) { @data[key] = yield }
|
79
59
|
end
|
80
60
|
end
|
81
61
|
|
82
62
|
# Use a local cache for the duration of block.
|
83
|
-
def with_local_cache
|
84
|
-
use_temporary_local_cache(LocalStore.new)
|
63
|
+
def with_local_cache(&block)
|
64
|
+
use_temporary_local_cache(LocalStore.new, &block)
|
85
65
|
end
|
86
66
|
|
87
67
|
# Middleware class can be inserted as a Rack handler to be local cache for the
|
@@ -104,24 +84,36 @@ module ActiveSupport
|
|
104
84
|
super
|
105
85
|
end
|
106
86
|
|
87
|
+
def delete_matched(matcher, options = nil) # :nodoc:
|
88
|
+
return super unless cache = local_cache
|
89
|
+
cache.clear
|
90
|
+
super
|
91
|
+
end
|
92
|
+
|
107
93
|
def increment(name, amount = 1, **options) # :nodoc:
|
108
94
|
return super unless local_cache
|
109
95
|
value = bypass_local_cache { super }
|
110
|
-
write_cache_value(name, value, **options)
|
96
|
+
write_cache_value(name, value, raw: true, **options)
|
111
97
|
value
|
112
98
|
end
|
113
99
|
|
114
100
|
def decrement(name, amount = 1, **options) # :nodoc:
|
115
101
|
return super unless local_cache
|
116
102
|
value = bypass_local_cache { super }
|
117
|
-
write_cache_value(name, value, **options)
|
103
|
+
write_cache_value(name, value, raw: true, **options)
|
118
104
|
value
|
119
105
|
end
|
120
106
|
|
121
107
|
private
|
122
|
-
def
|
108
|
+
def read_serialized_entry(key, raw: false, **options)
|
123
109
|
if cache = local_cache
|
124
|
-
|
110
|
+
hit = true
|
111
|
+
entry = cache.fetch_entry(key) do
|
112
|
+
hit = false
|
113
|
+
super
|
114
|
+
end
|
115
|
+
options[:event][:store] = cache.class.name if hit && options[:event]
|
116
|
+
entry
|
125
117
|
else
|
126
118
|
super
|
127
119
|
end
|
@@ -130,7 +122,10 @@ module ActiveSupport
|
|
130
122
|
def read_multi_entries(keys, **options)
|
131
123
|
return super unless local_cache
|
132
124
|
|
133
|
-
local_entries = local_cache.read_multi_entries(keys
|
125
|
+
local_entries = local_cache.read_multi_entries(keys)
|
126
|
+
local_entries.transform_values! do |payload|
|
127
|
+
deserialize_entry(payload).value
|
128
|
+
end
|
134
129
|
missed_keys = keys - local_entries.keys
|
135
130
|
|
136
131
|
if missed_keys.any?
|
@@ -140,30 +135,27 @@ module ActiveSupport
|
|
140
135
|
end
|
141
136
|
end
|
142
137
|
|
143
|
-
def
|
144
|
-
if
|
145
|
-
local_cache.
|
138
|
+
def write_serialized_entry(key, payload, **)
|
139
|
+
if return_value = super
|
140
|
+
local_cache.write_entry(key, payload) if local_cache
|
146
141
|
else
|
147
|
-
local_cache.
|
142
|
+
local_cache.delete_entry(key) if local_cache
|
148
143
|
end
|
149
|
-
|
150
|
-
super
|
144
|
+
return_value
|
151
145
|
end
|
152
146
|
|
153
|
-
def delete_entry(key, **
|
154
|
-
local_cache.delete_entry(key
|
147
|
+
def delete_entry(key, **)
|
148
|
+
local_cache.delete_entry(key) if local_cache
|
155
149
|
super
|
156
150
|
end
|
157
151
|
|
158
152
|
def write_cache_value(name, value, **options)
|
159
153
|
name = normalize_key(name, options)
|
160
154
|
cache = local_cache
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
cache.delete(name, **options)
|
166
|
-
end
|
155
|
+
if value
|
156
|
+
cache.write_entry(name, serialize_entry(new_entry(value, **options), **options))
|
157
|
+
else
|
158
|
+
cache.delete_entry(name)
|
167
159
|
end
|
168
160
|
end
|
169
161
|
|
@@ -175,8 +167,8 @@ module ActiveSupport
|
|
175
167
|
LocalCacheRegistry.cache_for(local_cache_key)
|
176
168
|
end
|
177
169
|
|
178
|
-
def bypass_local_cache
|
179
|
-
use_temporary_local_cache(nil)
|
170
|
+
def bypass_local_cache(&block)
|
171
|
+
use_temporary_local_cache(nil, &block)
|
180
172
|
end
|
181
173
|
|
182
174
|
def use_temporary_local_cache(temporary_cache)
|