activesupport 6.1.1 → 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 +231 -383
- data/MIT-LICENSE +1 -1
- data/README.rdoc +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 +16 -10
- data/lib/active_support/cache/mem_cache_store.rb +133 -34
- 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 +196 -46
- 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 +7 -2
- 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 -5
- 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 +32 -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 -10
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +9 -2
- 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 +2 -2
- 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 +16 -22
- 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/number_to_rounded_converter.rb +10 -6
- data/lib/active_support/number_helper/rounding_helper.rb +2 -6
- 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 +6 -1
- 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/security_utils.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 +55 -14
- data/lib/active_support/values/time_zone.rb +31 -10
- 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
|
@@ -58,7 +69,13 @@ module ActiveSupport
|
|
58
69
|
case store
|
59
70
|
when Symbol
|
60
71
|
options = parameters.extract_options!
|
61
|
-
|
72
|
+
# clean this up once Ruby 2.7 support is dropped
|
73
|
+
# see https://github.com/rails/rails/pull/41522#discussion_r581186602
|
74
|
+
if options.empty?
|
75
|
+
retrieve_store_class(store).new(*parameters)
|
76
|
+
else
|
77
|
+
retrieve_store_class(store).new(*parameters, **options)
|
78
|
+
end
|
62
79
|
when Array
|
63
80
|
lookup_store(*store)
|
64
81
|
when nil
|
@@ -158,8 +175,6 @@ module ActiveSupport
|
|
158
175
|
# threshold is configurable with the <tt>:compress_threshold</tt> option,
|
159
176
|
# specified in bytes.
|
160
177
|
class Store
|
161
|
-
DEFAULT_CODER = Marshal
|
162
|
-
|
163
178
|
cattr_accessor :logger, instance_writer: true
|
164
179
|
|
165
180
|
attr_reader :silence, :options
|
@@ -186,8 +201,12 @@ module ActiveSupport
|
|
186
201
|
# except for <tt>:namespace</tt> which can be used to set the global
|
187
202
|
# namespace for the cache.
|
188
203
|
def initialize(options = nil)
|
189
|
-
@options = options ? options
|
190
|
-
@
|
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)
|
191
210
|
end
|
192
211
|
|
193
212
|
# Silences the logger.
|
@@ -249,11 +268,21 @@ module ActiveSupport
|
|
249
268
|
# All caches support auto-expiring content after a specified number of
|
250
269
|
# seconds. This value can be specified as an option to the constructor
|
251
270
|
# (in which case all entries will be affected), or it can be supplied to
|
252
|
-
# 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>.
|
253
274
|
#
|
254
275
|
# cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 5.minutes)
|
255
276
|
# cache.write(key, value, expires_in: 1.minute) # Set a lower value for one entry
|
256
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
|
+
#
|
257
286
|
# Setting <tt>:version</tt> verifies the cache stored under <tt>name</tt>
|
258
287
|
# is of the same version. nil is returned on mismatches despite contents.
|
259
288
|
# This feature is used to support recyclable cache keys.
|
@@ -506,6 +535,10 @@ module ActiveSupport
|
|
506
535
|
end
|
507
536
|
end
|
508
537
|
|
538
|
+
def new_entry(value, options = nil) # :nodoc:
|
539
|
+
Entry.new(value, **merged_options(options))
|
540
|
+
end
|
541
|
+
|
509
542
|
# Deletes all entries with keys matching the pattern.
|
510
543
|
#
|
511
544
|
# Options are passed to the underlying cache implementation.
|
@@ -553,6 +586,10 @@ module ActiveSupport
|
|
553
586
|
end
|
554
587
|
|
555
588
|
private
|
589
|
+
def default_coder
|
590
|
+
Coders[Cache.format_version]
|
591
|
+
end
|
592
|
+
|
556
593
|
# Adds the namespace defined in the options to a pattern designed to
|
557
594
|
# match keys. Implementations that support delete_matched should call
|
558
595
|
# this method to translate a pattern that matches names into one that
|
@@ -584,8 +621,13 @@ module ActiveSupport
|
|
584
621
|
raise NotImplementedError.new
|
585
622
|
end
|
586
623
|
|
587
|
-
def serialize_entry(entry)
|
588
|
-
|
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
|
589
631
|
end
|
590
632
|
|
591
633
|
def deserialize_entry(payload)
|
@@ -634,6 +676,7 @@ module ActiveSupport
|
|
634
676
|
# Merges the default options with ones specific to a method call.
|
635
677
|
def merged_options(call_options)
|
636
678
|
if call_options
|
679
|
+
call_options = normalize_options(call_options)
|
637
680
|
if options.empty?
|
638
681
|
call_options
|
639
682
|
else
|
@@ -644,6 +687,18 @@ module ActiveSupport
|
|
644
687
|
end
|
645
688
|
end
|
646
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
|
+
|
647
702
|
# Expands and namespaces the cache key. May be overridden by
|
648
703
|
# cache stores to do additional normalization.
|
649
704
|
def normalize_key(key, options = nil)
|
@@ -726,7 +781,7 @@ module ActiveSupport
|
|
726
781
|
if (race_ttl > 0) && (Time.now.to_f - entry.expires_at <= race_ttl)
|
727
782
|
# When an entry has a positive :race_condition_ttl defined, put the stale entry back into the cache
|
728
783
|
# for a brief period while the entry is being recalculated.
|
729
|
-
entry.expires_at = Time.now + race_ttl
|
784
|
+
entry.expires_at = Time.now.to_f + race_ttl
|
730
785
|
write_entry(key, entry, expires_in: race_ttl * 2)
|
731
786
|
else
|
732
787
|
delete_entry(key, **options)
|
@@ -752,13 +807,93 @@ module ActiveSupport
|
|
752
807
|
end
|
753
808
|
|
754
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
|
+
|
755
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
|
+
|
756
846
|
def load(payload)
|
757
|
-
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)
|
758
863
|
end
|
864
|
+
end
|
865
|
+
|
866
|
+
module Rails61Coder
|
867
|
+
include Loader
|
868
|
+
extend self
|
759
869
|
|
760
870
|
def dump(entry)
|
761
|
-
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
|
762
897
|
end
|
763
898
|
end
|
764
899
|
end
|
@@ -771,19 +906,22 @@ module ActiveSupport
|
|
771
906
|
# Since cache entries in most instances will be serialized, the internals of this class are highly optimized
|
772
907
|
# using short instance variable names that are lazily defined.
|
773
908
|
class Entry # :nodoc:
|
774
|
-
|
909
|
+
class << self
|
910
|
+
def unpack(members)
|
911
|
+
new(members[0], expires_at: members[1], version: members[2])
|
912
|
+
end
|
913
|
+
end
|
775
914
|
|
776
|
-
|
915
|
+
attr_reader :version
|
777
916
|
|
778
917
|
# Creates a new cache entry for the specified value. Options supported are
|
779
|
-
# +:
|
780
|
-
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, **)
|
781
920
|
@value = value
|
782
921
|
@version = version
|
783
|
-
@created_at =
|
784
|
-
@expires_in = expires_in && expires_in.to_f
|
785
|
-
|
786
|
-
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
|
787
925
|
end
|
788
926
|
|
789
927
|
def value
|
@@ -825,6 +963,38 @@ module ActiveSupport
|
|
825
963
|
end
|
826
964
|
end
|
827
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
|
+
|
828
998
|
# Duplicates the value in a class. This is used by cache implementations that don't natively
|
829
999
|
# serialize entries to protect against accidental cache modifications.
|
830
1000
|
def dup_value!
|
@@ -837,33 +1007,13 @@ module ActiveSupport
|
|
837
1007
|
end
|
838
1008
|
end
|
839
1009
|
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
when String
|
846
|
-
uncompressed_size = @value.bytesize
|
847
|
-
else
|
848
|
-
serialized = Marshal.dump(@value)
|
849
|
-
uncompressed_size = serialized.bytesize
|
850
|
-
end
|
851
|
-
|
852
|
-
if uncompressed_size >= compress_threshold
|
853
|
-
serialized ||= Marshal.dump(@value)
|
854
|
-
compressed = Zlib::Deflate.deflate(serialized)
|
855
|
-
|
856
|
-
if compressed.bytesize < uncompressed_size
|
857
|
-
@value = compressed
|
858
|
-
@compressed = true
|
859
|
-
end
|
860
|
-
end
|
861
|
-
end
|
862
|
-
|
863
|
-
def compressed?
|
864
|
-
defined?(@compressed)
|
865
|
-
end
|
1010
|
+
def pack
|
1011
|
+
members = [value, expires_at, version]
|
1012
|
+
members.pop while !members.empty? && members.last.nil?
|
1013
|
+
members
|
1014
|
+
end
|
866
1015
|
|
1016
|
+
private
|
867
1017
|
def uncompress(value)
|
868
1018
|
Marshal.load(Zlib::Inflate.inflate(value))
|
869
1019
|
end
|