activesupport 6.1.4.2 → 7.0.2.3
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 +226 -462
- data/MIT-LICENSE +1 -1
- data/lib/active_support/actionable_error.rb +1 -1
- data/lib/active_support/array_inquirer.rb +0 -2
- data/lib/active_support/benchmarkable.rb +2 -2
- data/lib/active_support/cache/file_store.rb +15 -9
- data/lib/active_support/cache/mem_cache_store.rb +127 -32
- data/lib/active_support/cache/memory_store.rb +23 -15
- data/lib/active_support/cache/null_store.rb +10 -2
- data/lib/active_support/cache/redis_cache_store.rb +42 -67
- data/lib/active_support/cache/strategy/local_cache.rb +35 -61
- data/lib/active_support/cache.rb +189 -45
- data/lib/active_support/callbacks.rb +180 -81
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +5 -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 +6 -3
- data/lib/active_support/configuration_file.rb +1 -1
- data/lib/active_support/core_ext/array/access.rb +1 -5
- data/lib/active_support/core_ext/array/conversions.rb +13 -11
- 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.rb +1 -0
- data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
- data/lib/active_support/core_ext/class/subclasses.rb +25 -17
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +4 -4
- data/lib/active_support/core_ext/date/conversions.rb +11 -11
- 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/compatibility.rb +1 -1
- 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 +78 -26
- data/lib/active_support/core_ext/file/atomic.rb +3 -1
- data/lib/active_support/core_ext/hash/keys.rb +1 -1
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
- data/lib/active_support/core_ext/module/attribute_accessors.rb +2 -0
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +19 -10
- data/lib/active_support/core_ext/module/delegation.rb +2 -8
- data/lib/active_support/core_ext/name_error.rb +2 -8
- data/lib/active_support/core_ext/numeric/conversions.rb +79 -76
- 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 +29 -24
- 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 +0 -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 -25
- data/lib/active_support/core_ext/range.rb +1 -1
- data/lib/active_support/core_ext/string/filters.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +1 -1
- data/lib/active_support/core_ext/string/output_safety.rb +60 -36
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
- data/lib/active_support/core_ext/time/calculations.rb +7 -6
- data/lib/active_support/core_ext/time/conversions.rb +13 -12
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/time/zones.rb +4 -19
- data/lib/active_support/core_ext/time.rb +1 -0
- data/lib/active_support/core_ext/uri.rb +3 -27
- data/lib/active_support/core_ext.rb +1 -0
- data/lib/active_support/current_attributes.rb +31 -14
- 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 -788
- data/lib/active_support/deprecation/behaviors.rb +4 -1
- data/lib/active_support/deprecation/method_wrappers.rb +3 -3
- data/lib/active_support/deprecation/proxy_wrappers.rb +1 -1
- data/lib/active_support/deprecation.rb +1 -1
- data/lib/active_support/descendants_tracker.rb +174 -68
- 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 +9 -1
- data/lib/active_support/duration.rb +81 -51
- data/lib/active_support/encrypted_configuration.rb +13 -2
- data/lib/active_support/encrypted_file.rb +1 -1
- data/lib/active_support/environment_inquirer.rb +1 -1
- data/lib/active_support/error_reporter.rb +117 -0
- data/lib/active_support/evented_file_update_checker.rb +1 -1
- 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 +19 -12
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +3 -1
- 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 +1 -1
- data/lib/active_support/inflector/inflections.rb +23 -7
- data/lib/active_support/inflector/methods.rb +24 -48
- data/lib/active_support/isolated_execution_state.rb +64 -0
- data/lib/active_support/json/encoding.rb +3 -3
- data/lib/active_support/key_generator.rb +18 -1
- data/lib/active_support/locale/en.yml +1 -1
- data/lib/active_support/log_subscriber.rb +13 -3
- data/lib/active_support/logger_thread_safe_level.rb +4 -13
- data/lib/active_support/message_encryptor.rb +8 -3
- data/lib/active_support/message_verifier.rb +46 -14
- data/lib/active_support/messages/metadata.rb +2 -2
- data/lib/active_support/multibyte/chars.rb +10 -11
- data/lib/active_support/multibyte/unicode.rb +0 -12
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +91 -65
- data/lib/active_support/notifications/instrumenter.rb +32 -15
- data/lib/active_support/notifications.rb +15 -21
- data/lib/active_support/number_helper/number_converter.rb +1 -3
- 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_size_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
- data/lib/active_support/number_helper/rounding_helper.rb +1 -5
- data/lib/active_support/number_helper.rb +0 -2
- data/lib/active_support/option_merger.rb +8 -16
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/parameter_filter.rb +5 -0
- data/lib/active_support/per_thread_registry.rb +5 -0
- data/lib/active_support/railtie.rb +69 -19
- data/lib/active_support/reloader.rb +1 -1
- data/lib/active_support/rescuable.rb +2 -2
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/secure_compare_rotator.rb +1 -1
- data/lib/active_support/string_inquirer.rb +0 -2
- data/lib/active_support/subscriber.rb +7 -18
- data/lib/active_support/tagged_logging.rb +2 -2
- data/lib/active_support/test_case.rb +9 -21
- data/lib/active_support/testing/assertions.rb +35 -5
- 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 +4 -0
- data/lib/active_support/testing/parallelization/worker.rb +3 -0
- data/lib/active_support/testing/parallelization.rb +4 -0
- 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 +13 -2
- data/lib/active_support/time_with_zone.rb +54 -13
- data/lib/active_support/values/time_zone.rb +30 -9
- 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 +1 -1
- data/lib/active_support/xml_mini.rb +5 -4
- data/lib/active_support.rb +17 -1
- metadata +26 -23
- data/lib/active_support/core_ext/marshal.rb +0 -26
- data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
@@ -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
|
-
|
17
|
-
extend
|
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
|
-
|
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
|
-
|
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
|
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
|
40
|
+
def read_entry(key)
|
53
41
|
@data[key]
|
54
42
|
end
|
55
43
|
|
56
|
-
def read_multi_entries(keys
|
57
|
-
|
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
|
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
|
53
|
+
def delete_entry(key)
|
74
54
|
!!@data.delete(key)
|
75
55
|
end
|
76
56
|
|
77
|
-
def fetch_entry(key
|
78
|
-
|
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)
|
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
|
108
|
+
def read_serialized_entry(key, raw: false, **options)
|
132
109
|
if cache = local_cache
|
133
110
|
hit = true
|
134
|
-
|
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
|
-
|
116
|
+
entry
|
140
117
|
else
|
141
118
|
super
|
142
119
|
end
|
@@ -145,7 +122,7 @@ 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
|
125
|
+
local_entries = local_cache.read_multi_entries(keys)
|
149
126
|
missed_keys = keys - local_entries.keys
|
150
127
|
|
151
128
|
if missed_keys.any?
|
@@ -155,30 +132,27 @@ module ActiveSupport
|
|
155
132
|
end
|
156
133
|
end
|
157
134
|
|
158
|
-
def
|
159
|
-
if
|
160
|
-
local_cache.
|
135
|
+
def write_serialized_entry(key, payload, **)
|
136
|
+
if return_value = super
|
137
|
+
local_cache.write_entry(key, payload) if local_cache
|
161
138
|
else
|
162
|
-
local_cache.
|
139
|
+
local_cache.delete_entry(key) if local_cache
|
163
140
|
end
|
164
|
-
|
165
|
-
super
|
141
|
+
return_value
|
166
142
|
end
|
167
143
|
|
168
|
-
def delete_entry(key, **
|
169
|
-
local_cache.delete_entry(key
|
144
|
+
def delete_entry(key, **)
|
145
|
+
local_cache.delete_entry(key) if local_cache
|
170
146
|
super
|
171
147
|
end
|
172
148
|
|
173
149
|
def write_cache_value(name, value, **options)
|
174
150
|
name = normalize_key(name, options)
|
175
151
|
cache = local_cache
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
cache.delete(name, **options)
|
181
|
-
end
|
152
|
+
if value
|
153
|
+
cache.write_entry(name, serialize_entry(new_entry(value, **options), **options))
|
154
|
+
else
|
155
|
+
cache.delete_entry(name)
|
182
156
|
end
|
183
157
|
end
|
184
158
|
|
@@ -190,8 +164,8 @@ module ActiveSupport
|
|
190
164
|
LocalCacheRegistry.cache_for(local_cache_key)
|
191
165
|
end
|
192
166
|
|
193
|
-
def bypass_local_cache
|
194
|
-
use_temporary_local_cache(nil)
|
167
|
+
def bypass_local_cache(&block)
|
168
|
+
use_temporary_local_cache(nil, &block)
|
195
169
|
end
|
196
170
|
|
197
171
|
def use_temporary_local_cache(temporary_cache)
|
data/lib/active_support/cache.rb
CHANGED
@@ -22,13 +22,24 @@ module ActiveSupport
|
|
22
22
|
|
23
23
|
# These options mean something to all cache implementations. Individual cache
|
24
24
|
# implementations may support additional options.
|
25
|
-
UNIVERSAL_OPTIONS = [:namespace, :compress, :compress_threshold, :expires_in, :race_condition_ttl, :coder]
|
25
|
+
UNIVERSAL_OPTIONS = [:namespace, :compress, :compress_threshold, :expires_in, :expire_in, :expired_in, :race_condition_ttl, :coder, :skip_nil]
|
26
|
+
|
27
|
+
DEFAULT_COMPRESS_LIMIT = 1.kilobyte
|
28
|
+
|
29
|
+
# Mapping of canonical option names to aliases that a store will recognize.
|
30
|
+
OPTION_ALIASES = {
|
31
|
+
expires_in: [:expire_in, :expired_in]
|
32
|
+
}.freeze
|
26
33
|
|
27
34
|
module Strategy
|
28
35
|
autoload :LocalCache, "active_support/cache/strategy/local_cache"
|
29
36
|
end
|
30
37
|
|
38
|
+
@format_version = 6.1
|
39
|
+
|
31
40
|
class << self
|
41
|
+
attr_accessor :format_version
|
42
|
+
|
32
43
|
# Creates a new Store object according to the given options.
|
33
44
|
#
|
34
45
|
# If no arguments are passed to this method, then a new
|
@@ -164,8 +175,6 @@ module ActiveSupport
|
|
164
175
|
# threshold is configurable with the <tt>:compress_threshold</tt> option,
|
165
176
|
# specified in bytes.
|
166
177
|
class Store
|
167
|
-
DEFAULT_CODER = Marshal
|
168
|
-
|
169
178
|
cattr_accessor :logger, instance_writer: true
|
170
179
|
|
171
180
|
attr_reader :silence, :options
|
@@ -192,8 +201,12 @@ module ActiveSupport
|
|
192
201
|
# except for <tt>:namespace</tt> which can be used to set the global
|
193
202
|
# namespace for the cache.
|
194
203
|
def initialize(options = nil)
|
195
|
-
@options = options ? options
|
196
|
-
@
|
204
|
+
@options = options ? normalize_options(options) : {}
|
205
|
+
@options[:compress] = true unless @options.key?(:compress)
|
206
|
+
@options[:compress_threshold] = DEFAULT_COMPRESS_LIMIT unless @options.key?(:compress_threshold)
|
207
|
+
|
208
|
+
@coder = @options.delete(:coder) { default_coder } || NullCoder
|
209
|
+
@coder_supports_compression = @coder.respond_to?(:dump_compressed)
|
197
210
|
end
|
198
211
|
|
199
212
|
# Silences the logger.
|
@@ -255,11 +268,21 @@ module ActiveSupport
|
|
255
268
|
# All caches support auto-expiring content after a specified number of
|
256
269
|
# seconds. This value can be specified as an option to the constructor
|
257
270
|
# (in which case all entries will be affected), or it can be supplied to
|
258
|
-
# the +fetch+ or +write+ method to
|
271
|
+
# the +fetch+ or +write+ method to affect just one entry.
|
272
|
+
# <tt>:expire_in</tt> and <tt>:expired_in</tt> are aliases for
|
273
|
+
# <tt>:expires_in</tt>.
|
259
274
|
#
|
260
275
|
# cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 5.minutes)
|
261
276
|
# cache.write(key, value, expires_in: 1.minute) # Set a lower value for one entry
|
262
277
|
#
|
278
|
+
# Setting <tt>:expires_at</tt> will set an absolute expiration time on the cache.
|
279
|
+
# All caches support auto-expiring content after a specified number of
|
280
|
+
# seconds. This value can only be supplied to the +fetch+ or +write+ method to
|
281
|
+
# affect just one entry.
|
282
|
+
#
|
283
|
+
# cache = ActiveSupport::Cache::MemoryStore.new
|
284
|
+
# cache.write(key, value, expires_at: Time.now.at_end_of_hour)
|
285
|
+
#
|
263
286
|
# Setting <tt>:version</tt> verifies the cache stored under <tt>name</tt>
|
264
287
|
# is of the same version. nil is returned on mismatches despite contents.
|
265
288
|
# This feature is used to support recyclable cache keys.
|
@@ -512,6 +535,10 @@ module ActiveSupport
|
|
512
535
|
end
|
513
536
|
end
|
514
537
|
|
538
|
+
def new_entry(value, options = nil) # :nodoc:
|
539
|
+
Entry.new(value, **merged_options(options))
|
540
|
+
end
|
541
|
+
|
515
542
|
# Deletes all entries with keys matching the pattern.
|
516
543
|
#
|
517
544
|
# Options are passed to the underlying cache implementation.
|
@@ -559,6 +586,10 @@ module ActiveSupport
|
|
559
586
|
end
|
560
587
|
|
561
588
|
private
|
589
|
+
def default_coder
|
590
|
+
Coders[Cache.format_version]
|
591
|
+
end
|
592
|
+
|
562
593
|
# Adds the namespace defined in the options to a pattern designed to
|
563
594
|
# match keys. Implementations that support delete_matched should call
|
564
595
|
# this method to translate a pattern that matches names into one that
|
@@ -590,8 +621,13 @@ module ActiveSupport
|
|
590
621
|
raise NotImplementedError.new
|
591
622
|
end
|
592
623
|
|
593
|
-
def serialize_entry(entry)
|
594
|
-
|
624
|
+
def serialize_entry(entry, **options)
|
625
|
+
options = merged_options(options)
|
626
|
+
if @coder_supports_compression && options[:compress]
|
627
|
+
@coder.dump_compressed(entry, options[:compress_threshold] || DEFAULT_COMPRESS_LIMIT)
|
628
|
+
else
|
629
|
+
@coder.dump(entry)
|
630
|
+
end
|
595
631
|
end
|
596
632
|
|
597
633
|
def deserialize_entry(payload)
|
@@ -640,6 +676,7 @@ module ActiveSupport
|
|
640
676
|
# Merges the default options with ones specific to a method call.
|
641
677
|
def merged_options(call_options)
|
642
678
|
if call_options
|
679
|
+
call_options = normalize_options(call_options)
|
643
680
|
if options.empty?
|
644
681
|
call_options
|
645
682
|
else
|
@@ -650,6 +687,18 @@ module ActiveSupport
|
|
650
687
|
end
|
651
688
|
end
|
652
689
|
|
690
|
+
# Normalize aliased options to their canonical form
|
691
|
+
def normalize_options(options)
|
692
|
+
options = options.dup
|
693
|
+
OPTION_ALIASES.each do |canonical_name, aliases|
|
694
|
+
alias_key = aliases.detect { |key| options.key?(key) }
|
695
|
+
options[canonical_name] ||= options[alias_key] if alias_key
|
696
|
+
options.except!(*aliases)
|
697
|
+
end
|
698
|
+
|
699
|
+
options
|
700
|
+
end
|
701
|
+
|
653
702
|
# Expands and namespaces the cache key. May be overridden by
|
654
703
|
# cache stores to do additional normalization.
|
655
704
|
def normalize_key(key, options = nil)
|
@@ -732,7 +781,7 @@ module ActiveSupport
|
|
732
781
|
if (race_ttl > 0) && (Time.now.to_f - entry.expires_at <= race_ttl)
|
733
782
|
# When an entry has a positive :race_condition_ttl defined, put the stale entry back into the cache
|
734
783
|
# for a brief period while the entry is being recalculated.
|
735
|
-
entry.expires_at = Time.now + race_ttl
|
784
|
+
entry.expires_at = Time.now.to_f + race_ttl
|
736
785
|
write_entry(key, entry, expires_in: race_ttl * 2)
|
737
786
|
else
|
738
787
|
delete_entry(key, **options)
|
@@ -758,13 +807,93 @@ module ActiveSupport
|
|
758
807
|
end
|
759
808
|
|
760
809
|
module NullCoder # :nodoc:
|
810
|
+
extend self
|
811
|
+
|
812
|
+
def dump(entry)
|
813
|
+
entry
|
814
|
+
end
|
815
|
+
|
816
|
+
def dump_compressed(entry, threshold)
|
817
|
+
entry.compressed(threshold)
|
818
|
+
end
|
819
|
+
|
820
|
+
def load(payload)
|
821
|
+
payload
|
822
|
+
end
|
823
|
+
end
|
824
|
+
|
825
|
+
module Coders # :nodoc:
|
826
|
+
MARK_61 = "\x04\b".b.freeze # The one set by Marshal.
|
827
|
+
MARK_70_UNCOMPRESSED = "\x00".b.freeze
|
828
|
+
MARK_70_COMPRESSED = "\x01".b.freeze
|
829
|
+
|
761
830
|
class << self
|
831
|
+
def [](version)
|
832
|
+
case version
|
833
|
+
when 6.1
|
834
|
+
Rails61Coder
|
835
|
+
when 7.0
|
836
|
+
Rails70Coder
|
837
|
+
else
|
838
|
+
raise ArgumentError, "Unknown ActiveSupport::Cache.format_version #{Cache.format_version.inspect}"
|
839
|
+
end
|
840
|
+
end
|
841
|
+
end
|
842
|
+
|
843
|
+
module Loader
|
844
|
+
extend self
|
845
|
+
|
762
846
|
def load(payload)
|
763
|
-
payload
|
847
|
+
if !payload.is_a?(String)
|
848
|
+
ActiveSupport::Cache::Store.logger&.warn %{Payload wasn't a string, was #{payload.class.name} - couldn't unmarshal, so returning nil."}
|
849
|
+
|
850
|
+
return nil
|
851
|
+
elsif payload.start_with?(MARK_70_UNCOMPRESSED)
|
852
|
+
members = Marshal.load(payload.byteslice(1..-1))
|
853
|
+
elsif payload.start_with?(MARK_70_COMPRESSED)
|
854
|
+
members = Marshal.load(Zlib::Inflate.inflate(payload.byteslice(1..-1)))
|
855
|
+
elsif payload.start_with?(MARK_61)
|
856
|
+
return Marshal.load(payload)
|
857
|
+
else
|
858
|
+
ActiveSupport::Cache::Store.logger&.warn %{Invalid cache prefix: #{payload.byteslice(0).inspect}, expected "\\x00" or "\\x01"}
|
859
|
+
|
860
|
+
return nil
|
861
|
+
end
|
862
|
+
Entry.unpack(members)
|
764
863
|
end
|
864
|
+
end
|
865
|
+
|
866
|
+
module Rails61Coder
|
867
|
+
include Loader
|
868
|
+
extend self
|
765
869
|
|
766
870
|
def dump(entry)
|
767
|
-
entry
|
871
|
+
Marshal.dump(entry)
|
872
|
+
end
|
873
|
+
|
874
|
+
def dump_compressed(entry, threshold)
|
875
|
+
Marshal.dump(entry.compressed(threshold))
|
876
|
+
end
|
877
|
+
end
|
878
|
+
|
879
|
+
module Rails70Coder
|
880
|
+
include Loader
|
881
|
+
extend self
|
882
|
+
|
883
|
+
def dump(entry)
|
884
|
+
MARK_70_UNCOMPRESSED + Marshal.dump(entry.pack)
|
885
|
+
end
|
886
|
+
|
887
|
+
def dump_compressed(entry, threshold)
|
888
|
+
payload = Marshal.dump(entry.pack)
|
889
|
+
if payload.bytesize >= threshold
|
890
|
+
compressed_payload = Zlib::Deflate.deflate(payload)
|
891
|
+
if compressed_payload.bytesize < payload.bytesize
|
892
|
+
return MARK_70_COMPRESSED + compressed_payload
|
893
|
+
end
|
894
|
+
end
|
895
|
+
|
896
|
+
MARK_70_UNCOMPRESSED + payload
|
768
897
|
end
|
769
898
|
end
|
770
899
|
end
|
@@ -777,19 +906,22 @@ module ActiveSupport
|
|
777
906
|
# Since cache entries in most instances will be serialized, the internals of this class are highly optimized
|
778
907
|
# using short instance variable names that are lazily defined.
|
779
908
|
class Entry # :nodoc:
|
780
|
-
|
909
|
+
class << self
|
910
|
+
def unpack(members)
|
911
|
+
new(members[0], expires_at: members[1], version: members[2])
|
912
|
+
end
|
913
|
+
end
|
781
914
|
|
782
|
-
|
915
|
+
attr_reader :version
|
783
916
|
|
784
917
|
# Creates a new cache entry for the specified value. Options supported are
|
785
|
-
# +:
|
786
|
-
def initialize(value,
|
918
|
+
# +:compressed+, +:version+, +:expires_at+ and +:expires_in+.
|
919
|
+
def initialize(value, compressed: false, version: nil, expires_in: nil, expires_at: nil, **)
|
787
920
|
@value = value
|
788
921
|
@version = version
|
789
|
-
@created_at =
|
790
|
-
@expires_in = expires_in && expires_in.to_f
|
791
|
-
|
792
|
-
compress!(compress_threshold) if compress
|
922
|
+
@created_at = 0.0
|
923
|
+
@expires_in = expires_at&.to_f || expires_in && (expires_in.to_f + Time.now.to_f)
|
924
|
+
@compressed = true if compressed
|
793
925
|
end
|
794
926
|
|
795
927
|
def value
|
@@ -831,6 +963,38 @@ module ActiveSupport
|
|
831
963
|
end
|
832
964
|
end
|
833
965
|
|
966
|
+
def compressed? # :nodoc:
|
967
|
+
defined?(@compressed)
|
968
|
+
end
|
969
|
+
|
970
|
+
def compressed(compress_threshold)
|
971
|
+
return self if compressed?
|
972
|
+
|
973
|
+
case @value
|
974
|
+
when nil, true, false, Numeric
|
975
|
+
uncompressed_size = 0
|
976
|
+
when String
|
977
|
+
uncompressed_size = @value.bytesize
|
978
|
+
else
|
979
|
+
serialized = Marshal.dump(@value)
|
980
|
+
uncompressed_size = serialized.bytesize
|
981
|
+
end
|
982
|
+
|
983
|
+
if uncompressed_size >= compress_threshold
|
984
|
+
serialized ||= Marshal.dump(@value)
|
985
|
+
compressed = Zlib::Deflate.deflate(serialized)
|
986
|
+
|
987
|
+
if compressed.bytesize < uncompressed_size
|
988
|
+
return Entry.new(compressed, compressed: true, expires_at: expires_at, version: version)
|
989
|
+
end
|
990
|
+
end
|
991
|
+
self
|
992
|
+
end
|
993
|
+
|
994
|
+
def local?
|
995
|
+
false
|
996
|
+
end
|
997
|
+
|
834
998
|
# Duplicates the value in a class. This is used by cache implementations that don't natively
|
835
999
|
# serialize entries to protect against accidental cache modifications.
|
836
1000
|
def dup_value!
|
@@ -843,33 +1007,13 @@ module ActiveSupport
|
|
843
1007
|
end
|
844
1008
|
end
|
845
1009
|
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
when String
|
852
|
-
uncompressed_size = @value.bytesize
|
853
|
-
else
|
854
|
-
serialized = Marshal.dump(@value)
|
855
|
-
uncompressed_size = serialized.bytesize
|
856
|
-
end
|
857
|
-
|
858
|
-
if uncompressed_size >= compress_threshold
|
859
|
-
serialized ||= Marshal.dump(@value)
|
860
|
-
compressed = Zlib::Deflate.deflate(serialized)
|
861
|
-
|
862
|
-
if compressed.bytesize < uncompressed_size
|
863
|
-
@value = compressed
|
864
|
-
@compressed = true
|
865
|
-
end
|
866
|
-
end
|
867
|
-
end
|
868
|
-
|
869
|
-
def compressed?
|
870
|
-
defined?(@compressed)
|
871
|
-
end
|
1010
|
+
def pack
|
1011
|
+
members = [value, expires_at, version]
|
1012
|
+
members.pop while !members.empty? && members.last.nil?
|
1013
|
+
members
|
1014
|
+
end
|
872
1015
|
|
1016
|
+
private
|
873
1017
|
def uncompress(value)
|
874
1018
|
Marshal.load(Zlib::Inflate.inflate(value))
|
875
1019
|
end
|