activesupport 7.1.5 → 7.2.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +113 -1173
- data/lib/active_support/array_inquirer.rb +1 -1
- data/lib/active_support/backtrace_cleaner.rb +10 -3
- data/lib/active_support/broadcast_logger.rb +18 -19
- data/lib/active_support/cache/file_store.rb +15 -10
- data/lib/active_support/cache/mem_cache_store.rb +16 -74
- data/lib/active_support/cache/memory_store.rb +2 -1
- data/lib/active_support/cache/redis_cache_store.rb +16 -13
- data/lib/active_support/cache/serializer_with_fallback.rb +0 -23
- data/lib/active_support/cache.rb +59 -67
- data/lib/active_support/callbacks.rb +74 -113
- data/lib/active_support/code_generator.rb +10 -15
- data/lib/active_support/core_ext/array/conversions.rb +0 -2
- data/lib/active_support/core_ext/class/subclasses.rb +15 -35
- data/lib/active_support/core_ext/date/blank.rb +4 -0
- data/lib/active_support/core_ext/date/conversions.rb +0 -2
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +12 -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 +0 -4
- data/lib/active_support/core_ext/erb/util.rb +5 -0
- data/lib/active_support/core_ext/hash/keys.rb +4 -4
- data/lib/active_support/core_ext/module/attr_internal.rb +17 -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/numeric/conversions.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 +4 -6
- data/lib/active_support/core_ext/object/with.rb +5 -3
- data/lib/active_support/core_ext/pathname/blank.rb +4 -0
- data/lib/active_support/core_ext/range/overlap.rb +1 -1
- data/lib/active_support/core_ext/string/conversions.rb +1 -1
- data/lib/active_support/core_ext/string/filters.rb +1 -1
- data/lib/active_support/core_ext/string/output_safety.rb +0 -7
- data/lib/active_support/core_ext/time/calculations.rb +12 -27
- data/lib/active_support/core_ext/time/compatibility.rb +2 -3
- data/lib/active_support/core_ext/time/conversions.rb +0 -2
- data/lib/active_support/core_ext.rb +0 -1
- data/lib/active_support/current_attributes.rb +33 -40
- data/lib/active_support/delegation.rb +188 -0
- data/lib/active_support/dependencies/autoload.rb +0 -12
- data/lib/active_support/deprecation/constant_accessor.rb +1 -3
- data/lib/active_support/deprecation/proxy_wrappers.rb +9 -12
- data/lib/active_support/deprecation/reporting.rb +9 -4
- 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 +11 -6
- data/lib/active_support/error_reporter.rb +41 -3
- data/lib/active_support/evented_file_update_checker.rb +0 -1
- data/lib/active_support/execution_wrapper.rb +0 -1
- data/lib/active_support/file_update_checker.rb +1 -1
- data/lib/active_support/fork_tracker.rb +2 -38
- data/lib/active_support/gem_version.rb +3 -3
- data/lib/active_support/hash_with_indifferent_access.rb +6 -8
- data/lib/active_support/html_safe_translation.rb +3 -0
- data/lib/active_support/log_subscriber.rb +0 -12
- data/lib/active_support/logger.rb +15 -2
- data/lib/active_support/message_pack/extensions.rb +15 -2
- data/lib/active_support/multibyte/chars.rb +2 -2
- data/lib/active_support/notifications/fanout.rb +4 -7
- data/lib/active_support/notifications/instrumenter.rb +21 -18
- data/lib/active_support/notifications.rb +28 -27
- data/lib/active_support/number_helper/number_converter.rb +2 -2
- data/lib/active_support/option_merger.rb +2 -2
- data/lib/active_support/ordered_options.rb +53 -15
- data/lib/active_support/proxy_object.rb +8 -5
- data/lib/active_support/railtie.rb +4 -11
- data/lib/active_support/string_inquirer.rb +1 -1
- data/lib/active_support/syntax_error_proxy.rb +11 -1
- data/lib/active_support/test_case.rb +3 -1
- data/lib/active_support/testing/assertions.rb +4 -4
- data/lib/active_support/testing/constant_stubbing.rb +30 -8
- data/lib/active_support/testing/deprecation.rb +5 -12
- data/lib/active_support/testing/isolation.rb +18 -8
- data/lib/active_support/testing/method_call_assertions.rb +2 -16
- data/lib/active_support/testing/strict_warnings.rb +5 -4
- data/lib/active_support/testing/tests_without_assertions.rb +19 -0
- data/lib/active_support/time_with_zone.rb +9 -10
- data/lib/active_support/values/time_zone.rb +1 -1
- data/lib/active_support/xml_mini.rb +11 -2
- data/lib/active_support.rb +7 -8
- metadata +20 -70
- data/lib/active_support/deprecation/instance_delegator.rb +0 -65
- data/lib/active_support/ruby_features.rb +0 -7
@@ -17,7 +17,8 @@ module ActiveSupport
|
|
17
17
|
# can focus on the rest.
|
18
18
|
#
|
19
19
|
# bc = ActiveSupport::BacktraceCleaner.new
|
20
|
-
#
|
20
|
+
# root = "#{Rails.root}/"
|
21
|
+
# bc.add_filter { |line| line.start_with?(root) ? line.from(root.size) : line } # strip the Rails.root prefix
|
21
22
|
# bc.add_silencer { |line| /puma|rubygems/.match?(line) } # skip any lines from puma or rubygems
|
22
23
|
# bc.clean(exception.backtrace) # perform the cleanup
|
23
24
|
#
|
@@ -76,8 +77,9 @@ module ActiveSupport
|
|
76
77
|
# Adds a filter from the block provided. Each line in the backtrace will be
|
77
78
|
# mapped against this filter.
|
78
79
|
#
|
79
|
-
# # Will turn "/my/rails/root/app/models/person.rb" into "
|
80
|
-
#
|
80
|
+
# # Will turn "/my/rails/root/app/models/person.rb" into "app/models/person.rb"
|
81
|
+
# root = "#{Rails.root}/"
|
82
|
+
# backtrace_cleaner.add_filter { |line| line.start_with?(root) ? line.from(root.size) : line }
|
81
83
|
def add_filter(&block)
|
82
84
|
@filters << block
|
83
85
|
end
|
@@ -108,6 +110,11 @@ module ActiveSupport
|
|
108
110
|
private
|
109
111
|
FORMATTED_GEMS_PATTERN = /\A[^\/]+ \([\w.]+\) /
|
110
112
|
|
113
|
+
def initialize_copy(_other)
|
114
|
+
@filters = @filters.dup
|
115
|
+
@silencers = @silencers.dup
|
116
|
+
end
|
117
|
+
|
111
118
|
def add_gem_filter
|
112
119
|
gems_paths = (Gem.path | [Gem.default_dir]).map { |p| Regexp.escape(p) }
|
113
120
|
return if gems_paths.empty?
|
@@ -113,33 +113,33 @@ module ActiveSupport
|
|
113
113
|
dispatch { |logger| logger.<<(message) }
|
114
114
|
end
|
115
115
|
|
116
|
-
def add(
|
117
|
-
dispatch { |logger| logger.add(
|
116
|
+
def add(*args, &block)
|
117
|
+
dispatch { |logger| logger.add(*args, &block) }
|
118
118
|
end
|
119
119
|
alias_method :log, :add
|
120
120
|
|
121
|
-
def debug(
|
122
|
-
dispatch { |logger| logger.debug(
|
121
|
+
def debug(*args, &block)
|
122
|
+
dispatch { |logger| logger.debug(*args, &block) }
|
123
123
|
end
|
124
124
|
|
125
|
-
def info(
|
126
|
-
dispatch { |logger| logger.info(
|
125
|
+
def info(*args, &block)
|
126
|
+
dispatch { |logger| logger.info(*args, &block) }
|
127
127
|
end
|
128
128
|
|
129
|
-
def warn(
|
130
|
-
dispatch { |logger| logger.warn(
|
129
|
+
def warn(*args, &block)
|
130
|
+
dispatch { |logger| logger.warn(*args, &block) }
|
131
131
|
end
|
132
132
|
|
133
|
-
def error(
|
134
|
-
dispatch { |logger| logger.error(
|
133
|
+
def error(*args, &block)
|
134
|
+
dispatch { |logger| logger.error(*args, &block) }
|
135
135
|
end
|
136
136
|
|
137
|
-
def fatal(
|
138
|
-
dispatch { |logger| logger.fatal(
|
137
|
+
def fatal(*args, &block)
|
138
|
+
dispatch { |logger| logger.fatal(*args, &block) }
|
139
139
|
end
|
140
140
|
|
141
|
-
def unknown(
|
142
|
-
dispatch { |logger| logger.unknown(
|
141
|
+
def unknown(*args, &block)
|
142
|
+
dispatch { |logger| logger.unknown(*args, &block) }
|
143
143
|
end
|
144
144
|
|
145
145
|
def formatter=(formatter)
|
@@ -229,18 +229,17 @@ module ActiveSupport
|
|
229
229
|
private
|
230
230
|
def dispatch(&block)
|
231
231
|
@broadcasts.each { |logger| block.call(logger) }
|
232
|
-
true
|
233
232
|
end
|
234
233
|
|
235
|
-
def method_missing(name,
|
234
|
+
def method_missing(name, ...)
|
236
235
|
loggers = @broadcasts.select { |logger| logger.respond_to?(name) }
|
237
236
|
|
238
237
|
if loggers.none?
|
239
|
-
super
|
238
|
+
super
|
240
239
|
elsif loggers.one?
|
241
|
-
loggers.first.send(name,
|
240
|
+
loggers.first.send(name, ...)
|
242
241
|
else
|
243
|
-
loggers.map { |logger| logger.send(name,
|
242
|
+
loggers.map { |logger| logger.send(name, ...) }
|
244
243
|
end
|
245
244
|
end
|
246
245
|
|
@@ -78,8 +78,9 @@ module ActiveSupport
|
|
78
78
|
|
79
79
|
def delete_matched(matcher, options = nil)
|
80
80
|
options = merged_options(options)
|
81
|
+
matcher = key_matcher(matcher, options)
|
82
|
+
|
81
83
|
instrument(:delete_matched, matcher.inspect) do
|
82
|
-
matcher = key_matcher(matcher, options)
|
83
84
|
search_dir(cache_path) do |path|
|
84
85
|
key = file_path_key(path)
|
85
86
|
delete_entry(path, **options) if key.match(matcher)
|
@@ -209,18 +210,22 @@ module ActiveSupport
|
|
209
210
|
# Modifies the amount of an integer value that is stored in the cache.
|
210
211
|
# If the key is not found it is created and set to +amount+.
|
211
212
|
def modify_value(name, amount, options)
|
212
|
-
|
213
|
+
options = merged_options(options)
|
214
|
+
key = normalize_key(name, options)
|
215
|
+
version = normalize_version(name, options)
|
216
|
+
amount = Integer(amount)
|
213
217
|
|
214
|
-
lock_file(
|
215
|
-
|
218
|
+
lock_file(key) do
|
219
|
+
entry = read_entry(key, **options)
|
216
220
|
|
217
|
-
if
|
218
|
-
|
219
|
-
write(name, num, options)
|
220
|
-
num
|
221
|
-
else
|
222
|
-
write(name, Integer(amount), options)
|
221
|
+
if !entry || entry.expired? || entry.mismatched?(version)
|
222
|
+
write(name, amount, options)
|
223
223
|
amount
|
224
|
+
else
|
225
|
+
num = entry.value.to_i + amount
|
226
|
+
entry = Entry.new(num, expires_at: entry.expires_at, version: entry.version)
|
227
|
+
write_entry(key, entry)
|
228
|
+
num
|
224
229
|
end
|
225
230
|
end
|
226
231
|
end
|
@@ -41,46 +41,6 @@ module ActiveSupport
|
|
41
41
|
|
42
42
|
prepend Strategy::LocalCache
|
43
43
|
|
44
|
-
module DupLocalCache
|
45
|
-
class DupLocalStore < DelegateClass(Strategy::LocalCache::LocalStore)
|
46
|
-
def write_entry(_key, entry)
|
47
|
-
if entry.is_a?(Entry)
|
48
|
-
entry.dup_value!
|
49
|
-
end
|
50
|
-
super
|
51
|
-
end
|
52
|
-
|
53
|
-
def fetch_entry(key)
|
54
|
-
entry = super do
|
55
|
-
new_entry = yield
|
56
|
-
if entry.is_a?(Entry)
|
57
|
-
new_entry.dup_value!
|
58
|
-
end
|
59
|
-
new_entry
|
60
|
-
end
|
61
|
-
entry = entry.dup
|
62
|
-
|
63
|
-
if entry.is_a?(Entry)
|
64
|
-
entry.dup_value!
|
65
|
-
end
|
66
|
-
|
67
|
-
entry
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
private
|
72
|
-
def local_cache
|
73
|
-
if ActiveSupport::Cache.format_version == 6.1
|
74
|
-
if local_cache = super
|
75
|
-
DupLocalStore.new(local_cache)
|
76
|
-
end
|
77
|
-
else
|
78
|
-
super
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
prepend DupLocalCache
|
83
|
-
|
84
44
|
KEY_MAX_SIZE = 250
|
85
45
|
ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
|
86
46
|
|
@@ -114,7 +74,6 @@ module ActiveSupport
|
|
114
74
|
#
|
115
75
|
# If no addresses are provided, but <tt>ENV['MEMCACHE_SERVERS']</tt> is defined, it will be used instead. Otherwise,
|
116
76
|
# +MemCacheStore+ will connect to localhost:11211 (the default memcached port).
|
117
|
-
# Passing a +Dalli::Client+ instance is deprecated and will be removed. Please pass an address instead.
|
118
77
|
def initialize(*addresses)
|
119
78
|
addresses = addresses.flatten
|
120
79
|
options = addresses.extract_options!
|
@@ -126,19 +85,12 @@ module ActiveSupport
|
|
126
85
|
unless [String, Dalli::Client, NilClass].include?(addresses.first.class)
|
127
86
|
raise ArgumentError, "First argument must be an empty array, address, or array of addresses."
|
128
87
|
end
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
else
|
136
|
-
@mem_cache_options = options.dup
|
137
|
-
# The value "compress: false" prevents duplicate compression within Dalli.
|
138
|
-
@mem_cache_options[:compress] = false
|
139
|
-
(OVERRIDDEN_OPTIONS - %i(compress)).each { |name| @mem_cache_options.delete(name) }
|
140
|
-
@data = self.class.build_mem_cache(*(addresses + [@mem_cache_options]))
|
141
|
-
end
|
88
|
+
|
89
|
+
@mem_cache_options = options.dup
|
90
|
+
# The value "compress: false" prevents duplicate compression within Dalli.
|
91
|
+
@mem_cache_options[:compress] = false
|
92
|
+
(OVERRIDDEN_OPTIONS - %i(compress)).each { |name| @mem_cache_options.delete(name) }
|
93
|
+
@data = self.class.build_mem_cache(*(addresses + [@mem_cache_options]))
|
142
94
|
end
|
143
95
|
|
144
96
|
def inspect
|
@@ -179,9 +131,11 @@ module ActiveSupport
|
|
179
131
|
# <tt>raw: true</tt>, will fail and return +nil+.
|
180
132
|
def increment(name, amount = 1, options = nil)
|
181
133
|
options = merged_options(options)
|
182
|
-
|
134
|
+
key = normalize_key(name, options)
|
135
|
+
|
136
|
+
instrument(:increment, key, amount: amount) do
|
183
137
|
rescue_error_with nil do
|
184
|
-
@data.with { |c| c.incr(
|
138
|
+
@data.with { |c| c.incr(key, amount, options[:expires_in], amount) }
|
185
139
|
end
|
186
140
|
end
|
187
141
|
end
|
@@ -203,9 +157,11 @@ module ActiveSupport
|
|
203
157
|
# <tt>raw: true</tt>, will fail and return +nil+.
|
204
158
|
def decrement(name, amount = 1, options = nil)
|
205
159
|
options = merged_options(options)
|
206
|
-
|
160
|
+
key = normalize_key(name, options)
|
161
|
+
|
162
|
+
instrument(:decrement, key, amount: amount) do
|
207
163
|
rescue_error_with nil do
|
208
|
-
@data.with { |c| c.decr(
|
164
|
+
@data.with { |c| c.decr(key, amount, options[:expires_in], 0) }
|
209
165
|
end
|
210
166
|
end
|
211
167
|
end
|
@@ -222,20 +178,6 @@ module ActiveSupport
|
|
222
178
|
end
|
223
179
|
|
224
180
|
private
|
225
|
-
def default_serializer
|
226
|
-
if Cache.format_version == 6.1
|
227
|
-
ActiveSupport.deprecator.warn <<~EOM
|
228
|
-
Support for `config.active_support.cache_format_version = 6.1` has been deprecated and will be removed in Rails 7.2.
|
229
|
-
|
230
|
-
Check the Rails upgrade guide at https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#new-activesupport-cache-serialization-format
|
231
|
-
for more information on how to upgrade.
|
232
|
-
EOM
|
233
|
-
Cache::SerializerWithFallback[:passthrough]
|
234
|
-
else
|
235
|
-
super
|
236
|
-
end
|
237
|
-
end
|
238
|
-
|
239
181
|
# Read an entry from the cache.
|
240
182
|
def read_entry(key, **options)
|
241
183
|
deserialize_entry(read_serialized_entry(key, **options), **options)
|
@@ -259,10 +201,10 @@ module ActiveSupport
|
|
259
201
|
# Set the memcache expire a few minutes in the future to support race condition ttls on read
|
260
202
|
expires_in += 5.minutes
|
261
203
|
end
|
262
|
-
rescue_error_with
|
204
|
+
rescue_error_with nil do
|
263
205
|
# Don't pass compress option to Dalli since we are already dealing with compression.
|
264
206
|
options.delete(:compress)
|
265
|
-
@data.with { |c| c.send(method, key, payload, expires_in, **options) }
|
207
|
+
@data.with { |c| !!c.send(method, key, payload, expires_in, **options) }
|
266
208
|
end
|
267
209
|
end
|
268
210
|
|
@@ -168,8 +168,9 @@ module ActiveSupport
|
|
168
168
|
# Deletes cache entries if the cache key matches a given pattern.
|
169
169
|
def delete_matched(matcher, options = nil)
|
170
170
|
options = merged_options(options)
|
171
|
+
matcher = key_matcher(matcher, options)
|
172
|
+
|
171
173
|
instrument(:delete_matched, matcher.inspect) do
|
172
|
-
matcher = key_matcher(matcher, options)
|
173
174
|
keys = synchronize { @data.keys }
|
174
175
|
keys.each do |key|
|
175
176
|
delete_entry(key, **options) if key.match(matcher)
|
@@ -196,12 +196,13 @@ module ActiveSupport
|
|
196
196
|
#
|
197
197
|
# Failsafe: Raises errors.
|
198
198
|
def delete_matched(matcher, options = nil)
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
199
|
+
unless String === matcher
|
200
|
+
raise ArgumentError, "Only Redis glob strings are supported: #{matcher.inspect}"
|
201
|
+
end
|
202
|
+
pattern = namespace_key(matcher, options)
|
203
|
+
|
204
|
+
instrument :delete_matched, pattern do
|
203
205
|
redis.then do |c|
|
204
|
-
pattern = namespace_key(matcher, options)
|
205
206
|
cursor = "0"
|
206
207
|
# Fetch keys in batches using SCAN to avoid blocking the Redis server.
|
207
208
|
nodes = c.respond_to?(:nodes) ? c.nodes : [c]
|
@@ -234,10 +235,11 @@ module ActiveSupport
|
|
234
235
|
#
|
235
236
|
# Failsafe: Raises errors.
|
236
237
|
def increment(name, amount = 1, options = nil)
|
237
|
-
|
238
|
+
options = merged_options(options)
|
239
|
+
key = normalize_key(name, options)
|
240
|
+
|
241
|
+
instrument :increment, key, amount: amount do
|
238
242
|
failsafe :increment do
|
239
|
-
options = merged_options(options)
|
240
|
-
key = normalize_key(name, options)
|
241
243
|
change_counter(key, amount, options)
|
242
244
|
end
|
243
245
|
end
|
@@ -260,10 +262,11 @@ module ActiveSupport
|
|
260
262
|
#
|
261
263
|
# Failsafe: Raises errors.
|
262
264
|
def decrement(name, amount = 1, options = nil)
|
263
|
-
|
265
|
+
options = merged_options(options)
|
266
|
+
key = normalize_key(name, options)
|
267
|
+
|
268
|
+
instrument :decrement, key, amount: amount do
|
264
269
|
failsafe :decrement do
|
265
|
-
options = merged_options(options)
|
266
|
-
key = normalize_key(name, options)
|
267
270
|
change_counter(key, -amount, options)
|
268
271
|
end
|
269
272
|
end
|
@@ -369,8 +372,8 @@ module ActiveSupport
|
|
369
372
|
if pipeline
|
370
373
|
pipeline.set(key, payload, **modifiers)
|
371
374
|
else
|
372
|
-
failsafe :write_entry, returning:
|
373
|
-
redis.then { |c| c.set
|
375
|
+
failsafe :write_entry, returning: nil do
|
376
|
+
redis.then { |c| !!c.set(key, payload, **modifiers) }
|
374
377
|
end
|
375
378
|
end
|
376
379
|
end
|
@@ -63,28 +63,6 @@ module ActiveSupport
|
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
-
module Marshal61WithFallback
|
67
|
-
include SerializerWithFallback
|
68
|
-
extend self
|
69
|
-
|
70
|
-
MARSHAL_SIGNATURE = "\x04\x08".b.freeze
|
71
|
-
|
72
|
-
def dump(entry)
|
73
|
-
Marshal.dump(entry)
|
74
|
-
end
|
75
|
-
|
76
|
-
def dump_compressed(entry, threshold)
|
77
|
-
Marshal.dump(entry.compressed(threshold))
|
78
|
-
end
|
79
|
-
|
80
|
-
alias_method :_load, :marshal_load
|
81
|
-
public :_load
|
82
|
-
|
83
|
-
def dumped?(dumped)
|
84
|
-
dumped.start_with?(MARSHAL_SIGNATURE)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
66
|
module Marshal70WithFallback
|
89
67
|
include SerializerWithFallback
|
90
68
|
extend self
|
@@ -165,7 +143,6 @@ module ActiveSupport
|
|
165
143
|
|
166
144
|
SERIALIZERS = {
|
167
145
|
passthrough: PassthroughWithFallback,
|
168
|
-
marshal_6_1: Marshal61WithFallback,
|
169
146
|
marshal_7_0: Marshal70WithFallback,
|
170
147
|
marshal_7_1: Marshal71WithFallback,
|
171
148
|
message_pack: MessagePackWithFallback,
|
data/lib/active_support/cache.rb
CHANGED
@@ -52,7 +52,7 @@ module ActiveSupport
|
|
52
52
|
autoload :LocalCache, "active_support/cache/strategy/local_cache"
|
53
53
|
end
|
54
54
|
|
55
|
-
@format_version =
|
55
|
+
@format_version = 7.0
|
56
56
|
|
57
57
|
class << self
|
58
58
|
attr_accessor :format_version
|
@@ -86,13 +86,7 @@ module ActiveSupport
|
|
86
86
|
case store
|
87
87
|
when Symbol
|
88
88
|
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
|
89
|
+
retrieve_store_class(store).new(*parameters, **options)
|
96
90
|
when Array
|
97
91
|
lookup_store(*store)
|
98
92
|
when nil
|
@@ -166,7 +160,7 @@ module ActiveSupport
|
|
166
160
|
# cache = ActiveSupport::Cache::MemoryStore.new
|
167
161
|
#
|
168
162
|
# cache.read('city') # => nil
|
169
|
-
# cache.write('city', "Duckburgh")
|
163
|
+
# cache.write('city', "Duckburgh") # => true
|
170
164
|
# cache.read('city') # => "Duckburgh"
|
171
165
|
#
|
172
166
|
# cache.write('not serializable', Proc.new {}) # => TypeError
|
@@ -206,24 +200,6 @@ module ActiveSupport
|
|
206
200
|
def retrieve_pool_options(options)
|
207
201
|
if options.key?(:pool)
|
208
202
|
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
203
|
else
|
228
204
|
pool_options = true
|
229
205
|
end
|
@@ -344,7 +320,7 @@ module ActiveSupport
|
|
344
320
|
|
345
321
|
# Silences the logger within a block.
|
346
322
|
def mute
|
347
|
-
previous_silence, @silence =
|
323
|
+
previous_silence, @silence = @silence, true
|
348
324
|
yield
|
349
325
|
ensure
|
350
326
|
@silence = previous_silence
|
@@ -411,31 +387,47 @@ module ActiveSupport
|
|
411
387
|
# has elapsed.
|
412
388
|
#
|
413
389
|
# # Set all values to expire after one minute.
|
414
|
-
# cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 1
|
390
|
+
# cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 1)
|
415
391
|
#
|
416
|
-
# cache.write(
|
392
|
+
# cache.write("foo", "original value")
|
417
393
|
# val_1 = nil
|
418
394
|
# val_2 = nil
|
419
|
-
#
|
395
|
+
# p cache.read("foo") # => "original value"
|
420
396
|
#
|
421
|
-
#
|
422
|
-
#
|
397
|
+
# sleep 1 # wait until the cache expires
|
398
|
+
#
|
399
|
+
# t1 = Thread.new do
|
400
|
+
# # fetch does the following:
|
401
|
+
# # 1. gets an recent expired entry
|
402
|
+
# # 2. extends the expiry by 2 seconds (race_condition_ttl)
|
403
|
+
# # 3. regenerates the new value
|
404
|
+
# val_1 = cache.fetch("foo", race_condition_ttl: 2) do
|
423
405
|
# sleep 1
|
424
|
-
#
|
406
|
+
# "new value 1"
|
425
407
|
# end
|
426
408
|
# end
|
427
409
|
#
|
428
|
-
#
|
429
|
-
#
|
430
|
-
#
|
431
|
-
#
|
410
|
+
# # Wait until t1 extends the expiry of the entry
|
411
|
+
# # but before generating the new value
|
412
|
+
# sleep 0.1
|
413
|
+
#
|
414
|
+
# val_2 = cache.fetch("foo", race_condition_ttl: 2) do
|
415
|
+
# # This block won't be executed because t1 extended the expiry
|
416
|
+
# "new value 2"
|
432
417
|
# end
|
433
418
|
#
|
434
|
-
#
|
435
|
-
#
|
436
|
-
#
|
437
|
-
#
|
438
|
-
#
|
419
|
+
# t1.join
|
420
|
+
#
|
421
|
+
# p val_1 # => "new value 1"
|
422
|
+
# p val_2 # => "oritinal value"
|
423
|
+
# p cache.fetch("foo") # => "new value 1"
|
424
|
+
#
|
425
|
+
# # The entry requires 3 seconds to expire (expires_in + race_condition_ttl)
|
426
|
+
# # We have waited 2 seconds already (sleep(1) + t1.join) thus we need to wait 1
|
427
|
+
# # more second to see the entry expire.
|
428
|
+
# sleep 1
|
429
|
+
#
|
430
|
+
# p cache.fetch("foo") # => nil
|
439
431
|
#
|
440
432
|
# ==== Dynamic Options
|
441
433
|
#
|
@@ -456,7 +448,7 @@ module ActiveSupport
|
|
456
448
|
|
457
449
|
entry = nil
|
458
450
|
unless options[:force]
|
459
|
-
instrument(:read,
|
451
|
+
instrument(:read, key, options) do |payload|
|
460
452
|
cached_entry = read_entry(key, **options, event: payload)
|
461
453
|
entry = handle_expired_entry(cached_entry, key, options)
|
462
454
|
if entry
|
@@ -478,7 +470,7 @@ module ActiveSupport
|
|
478
470
|
if entry
|
479
471
|
get_entry_value(entry, name, options)
|
480
472
|
else
|
481
|
-
save_block_result_to_cache(name, options, &block)
|
473
|
+
save_block_result_to_cache(name, key, options, &block)
|
482
474
|
end
|
483
475
|
elsif options && options[:force]
|
484
476
|
raise ArgumentError, "Missing block: Calling `Cache#fetch` with `force: true` requires a block."
|
@@ -508,7 +500,7 @@ module ActiveSupport
|
|
508
500
|
key = normalize_key(name, options)
|
509
501
|
version = normalize_version(name, options)
|
510
502
|
|
511
|
-
instrument(:read,
|
503
|
+
instrument(:read, key, options) do |payload|
|
512
504
|
entry = read_entry(key, **options, event: payload)
|
513
505
|
|
514
506
|
if entry
|
@@ -605,14 +597,14 @@ module ActiveSupport
|
|
605
597
|
options = names.extract_options!
|
606
598
|
options = merged_options(options)
|
607
599
|
|
608
|
-
|
600
|
+
writes = {}
|
601
|
+
ordered = instrument_multi :read_multi, names, options do |payload|
|
609
602
|
if options[:force]
|
610
603
|
reads = {}
|
611
604
|
else
|
612
605
|
reads = read_multi_entries(names, **options)
|
613
606
|
end
|
614
607
|
|
615
|
-
writes = {}
|
616
608
|
ordered = names.index_with do |name|
|
617
609
|
reads.fetch(name) { writes[name] = yield(name) }
|
618
610
|
end
|
@@ -621,15 +613,20 @@ module ActiveSupport
|
|
621
613
|
payload[:hits] = reads.keys
|
622
614
|
payload[:super_operation] = :fetch_multi
|
623
615
|
|
624
|
-
write_multi(writes, options)
|
625
|
-
|
626
616
|
ordered
|
627
617
|
end
|
618
|
+
|
619
|
+
write_multi(writes, options)
|
620
|
+
|
621
|
+
ordered
|
628
622
|
end
|
629
623
|
|
630
624
|
# Writes the value to the cache with the key. The value must be supported
|
631
625
|
# by the +coder+'s +dump+ and +load+ methods.
|
632
626
|
#
|
627
|
+
# Returns +true+ if the write succeeded, +nil+ if there was an error talking
|
628
|
+
# to the cache backend, or +false+ if the write failed for another reason.
|
629
|
+
#
|
633
630
|
# By default, cache entries larger than 1kB are compressed. Compression
|
634
631
|
# allows more data to be stored in the same memory footprint, leading to
|
635
632
|
# fewer cache evictions and higher hit rates.
|
@@ -662,10 +659,11 @@ module ActiveSupport
|
|
662
659
|
# Other options will be handled by the specific cache store implementation.
|
663
660
|
def write(name, value, options = nil)
|
664
661
|
options = merged_options(options)
|
662
|
+
key = normalize_key(name, options)
|
665
663
|
|
666
|
-
instrument(:write,
|
664
|
+
instrument(:write, key, options) do
|
667
665
|
entry = Entry.new(value, **options.merge(version: normalize_version(name, options)))
|
668
|
-
write_entry(
|
666
|
+
write_entry(key, entry, **options)
|
669
667
|
end
|
670
668
|
end
|
671
669
|
|
@@ -675,9 +673,10 @@ module ActiveSupport
|
|
675
673
|
# Options are passed to the underlying cache implementation.
|
676
674
|
def delete(name, options = nil)
|
677
675
|
options = merged_options(options)
|
676
|
+
key = normalize_key(name, options)
|
678
677
|
|
679
|
-
instrument(:delete,
|
680
|
-
delete_entry(
|
678
|
+
instrument(:delete, key) do
|
679
|
+
delete_entry(key, **options)
|
681
680
|
end
|
682
681
|
end
|
683
682
|
|
@@ -701,9 +700,10 @@ module ActiveSupport
|
|
701
700
|
# Options are passed to the underlying cache implementation.
|
702
701
|
def exist?(name, options = nil)
|
703
702
|
options = merged_options(options)
|
703
|
+
key = normalize_key(name, options)
|
704
704
|
|
705
|
-
instrument(:exist?,
|
706
|
-
entry = read_entry(
|
705
|
+
instrument(:exist?, key) do |payload|
|
706
|
+
entry = read_entry(key, **options, event: payload)
|
707
707
|
(entry && !entry.expired? && !entry.mismatched?(normalize_version(name, options))) || false
|
708
708
|
end
|
709
709
|
end
|
@@ -761,14 +761,6 @@ module ActiveSupport
|
|
761
761
|
private
|
762
762
|
def default_serializer
|
763
763
|
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
764
|
when 7.0
|
773
765
|
Cache::SerializerWithFallback[:marshal_7_0]
|
774
766
|
when 7.1
|
@@ -1016,7 +1008,7 @@ module ActiveSupport
|
|
1016
1008
|
if multi
|
1017
1009
|
": #{payload[:key].size} key(s) specified"
|
1018
1010
|
elsif payload[:key]
|
1019
|
-
": #{
|
1011
|
+
": #{payload[:key]}"
|
1020
1012
|
end
|
1021
1013
|
|
1022
1014
|
debug_options = " (#{options.inspect})" unless options.blank?
|
@@ -1053,10 +1045,10 @@ module ActiveSupport
|
|
1053
1045
|
entry.value
|
1054
1046
|
end
|
1055
1047
|
|
1056
|
-
def save_block_result_to_cache(name, options)
|
1048
|
+
def save_block_result_to_cache(name, key, options)
|
1057
1049
|
options = options.dup
|
1058
1050
|
|
1059
|
-
result = instrument(:generate,
|
1051
|
+
result = instrument(:generate, key, options) do
|
1060
1052
|
yield(name, WriteOptions.new(options))
|
1061
1053
|
end
|
1062
1054
|
|