activesupport 6.1.7.2 → 7.0.6
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 +272 -501
- data/README.rdoc +2 -2
- data/lib/active_support/actionable_error.rb +1 -1
- data/lib/active_support/array_inquirer.rb +0 -2
- data/lib/active_support/backtrace_cleaner.rb +2 -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 +148 -37
- data/lib/active_support/cache/memory_store.rb +24 -16
- data/lib/active_support/cache/null_store.rb +10 -2
- data/lib/active_support/cache/redis_cache_store.rb +59 -78
- data/lib/active_support/cache/strategy/local_cache.rb +38 -61
- data/lib/active_support/cache.rb +299 -147
- data/lib/active_support/callbacks.rb +184 -85
- 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 +8 -5
- 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 -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/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 +24 -9
- data/lib/active_support/core_ext/date/conversions.rb +14 -14
- 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 +4 -4
- 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/calculations.rb +4 -0
- 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 -14
- data/lib/active_support/core_ext/enumerable.rb +106 -37
- data/lib/active_support/core_ext/file/atomic.rb +3 -1
- data/lib/active_support/core_ext/hash/conversions.rb +0 -1
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
- data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +4 -4
- data/lib/active_support/core_ext/integer/inflections.rb +12 -12
- 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/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 +80 -77
- 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 +15 -4
- data/lib/active_support/core_ext/object/json.rb +30 -25
- data/lib/active_support/core_ext/object/to_query.rb +2 -4
- data/lib/active_support/core_ext/object/try.rb +20 -20
- data/lib/active_support/core_ext/object/with_options.rb +21 -2
- 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 +3 -26
- 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/securerandom.rb +1 -1
- data/lib/active_support/core_ext/string/conversions.rb +2 -2
- data/lib/active_support/core_ext/string/filters.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +1 -5
- data/lib/active_support/core_ext/string/inquiry.rb +1 -1
- data/lib/active_support/core_ext/string/output_safety.rb +66 -38
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
- data/lib/active_support/core_ext/time/calculations.rb +11 -8
- 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 +10 -26
- 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 -15
- 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 +8 -5
- data/lib/active_support/deprecation/disallowed.rb +3 -3
- data/lib/active_support/deprecation/method_wrappers.rb +3 -3
- data/lib/active_support/deprecation/proxy_wrappers.rb +2 -2
- data/lib/active_support/deprecation.rb +2 -2
- data/lib/active_support/descendants_tracker.rb +174 -68
- data/lib/active_support/digest.rb +4 -4
- 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 +77 -48
- data/lib/active_support/encrypted_configuration.rb +45 -3
- data/lib/active_support/encrypted_file.rb +13 -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 +17 -6
- 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 +30 -11
- 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 +5 -5
- 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 +28 -53
- data/lib/active_support/inflector/transliterate.rb +1 -1
- data/lib/active_support/isolated_execution_state.rb +72 -0
- data/lib/active_support/json/encoding.rb +3 -3
- data/lib/active_support/key_generator.rb +22 -5
- data/lib/active_support/lazy_load_hooks.rb +28 -4
- data/lib/active_support/locale/en.yml +1 -1
- data/lib/active_support/log_subscriber/test_helper.rb +2 -2
- data/lib/active_support/log_subscriber.rb +15 -5
- data/lib/active_support/logger_thread_safe_level.rb +4 -13
- data/lib/active_support/message_encryptor.rb +12 -6
- 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 +23 -23
- 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 +4 -5
- data/lib/active_support/option_merger.rb +10 -18
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/ordered_options.rb +1 -1
- data/lib/active_support/parameter_filter.rb +20 -11
- data/lib/active_support/per_thread_registry.rb +5 -1
- data/lib/active_support/railtie.rb +69 -19
- data/lib/active_support/rescuable.rb +12 -12
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/secure_compare_rotator.rb +2 -2
- data/lib/active_support/string_inquirer.rb +0 -2
- data/lib/active_support/subscriber.rb +7 -18
- data/lib/active_support/tagged_logging.rb +1 -1
- data/lib/active_support/test_case.rb +13 -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 +30 -29
- 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 +62 -22
- data/lib/active_support/values/time_zone.rb +33 -14
- 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 +1 -1
- data/lib/active_support/xml_mini.rb +5 -4
- data/lib/active_support.rb +16 -0
- metadata +28 -26
- data/lib/active_support/core_ext/marshal.rb +0 -26
- data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -120
data/README.rdoc
CHANGED
@@ -13,7 +13,7 @@ The latest version of Active Support can be installed with RubyGems:
|
|
13
13
|
|
14
14
|
$ gem install activesupport
|
15
15
|
|
16
|
-
Source code can be downloaded as part of the Rails project on GitHub:
|
16
|
+
Source code can be downloaded as part of the \Rails project on GitHub:
|
17
17
|
|
18
18
|
* https://github.com/rails/rails/tree/main/activesupport
|
19
19
|
|
@@ -31,7 +31,7 @@ API documentation is at:
|
|
31
31
|
|
32
32
|
* https://api.rubyonrails.org
|
33
33
|
|
34
|
-
Bug reports for the Ruby on Rails project can be filed here:
|
34
|
+
Bug reports for the Ruby on \Rails project can be filed here:
|
35
35
|
|
36
36
|
* https://github.com/rails/rails/issues
|
37
37
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveSupport
|
4
|
-
# Actionable errors
|
4
|
+
# Actionable errors lets you define actions to resolve an error.
|
5
5
|
#
|
6
6
|
# To make an error actionable, include the <tt>ActiveSupport::ActionableError</tt>
|
7
7
|
# module and invoke the +action+ class macro to define the action. An action
|
@@ -21,10 +21,10 @@ module ActiveSupport
|
|
21
21
|
#
|
22
22
|
# To reconfigure an existing BacktraceCleaner (like the default one in Rails)
|
23
23
|
# and show as much data as possible, you can always call
|
24
|
-
#
|
24
|
+
# BacktraceCleaner#remove_silencers!, which will restore the
|
25
25
|
# backtrace to a pristine state. If you need to reconfigure an existing
|
26
26
|
# BacktraceCleaner so that it does not filter or modify the paths of any lines
|
27
|
-
# of the backtrace, you can call
|
27
|
+
# of the backtrace, you can call BacktraceCleaner#remove_filters!
|
28
28
|
# These two methods will give you a completely untouched backtrace.
|
29
29
|
#
|
30
30
|
# Inspired by the Quiet Backtrace gem by thoughtbot.
|
@@ -34,13 +34,13 @@ module ActiveSupport
|
|
34
34
|
# <% benchmark 'Process data files', level: :info, silence: true do %>
|
35
35
|
# <%= expensive_and_chatty_files_operation %>
|
36
36
|
# <% end %>
|
37
|
-
def benchmark(message = "Benchmarking", options = {})
|
37
|
+
def benchmark(message = "Benchmarking", options = {}, &block)
|
38
38
|
if logger
|
39
39
|
options.assert_valid_keys(:level, :silence)
|
40
40
|
options[:level] ||= :info
|
41
41
|
|
42
42
|
result = nil
|
43
|
-
ms = Benchmark.ms { result = options[:silence] ? logger.silence
|
43
|
+
ms = Benchmark.ms { result = options[:silence] ? logger.silence(&block) : yield }
|
44
44
|
logger.public_send(options[:level], "%s (%.1fms)" % [ message, ms ])
|
45
45
|
result
|
46
46
|
else
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/core_ext/marshal"
|
4
3
|
require "active_support/core_ext/file/atomic"
|
5
4
|
require "active_support/core_ext/string/conversions"
|
6
5
|
require "uri/common"
|
@@ -12,7 +11,6 @@ module ActiveSupport
|
|
12
11
|
# FileStore implements the Strategy::LocalCache strategy which implements
|
13
12
|
# an in-memory cache inside of a block.
|
14
13
|
class FileStore < Store
|
15
|
-
prepend Strategy::LocalCache
|
16
14
|
attr_reader :cache_path
|
17
15
|
|
18
16
|
DIR_FORMATTER = "%03X"
|
@@ -73,19 +71,27 @@ module ActiveSupport
|
|
73
71
|
|
74
72
|
private
|
75
73
|
def read_entry(key, **options)
|
76
|
-
if
|
77
|
-
entry =
|
74
|
+
if payload = read_serialized_entry(key, **options)
|
75
|
+
entry = deserialize_entry(payload)
|
78
76
|
entry if entry.is_a?(Cache::Entry)
|
79
77
|
end
|
80
|
-
|
81
|
-
|
78
|
+
end
|
79
|
+
|
80
|
+
def read_serialized_entry(key, **)
|
81
|
+
File.binread(key) if File.exist?(key)
|
82
|
+
rescue => error
|
83
|
+
logger.error("FileStoreError (#{error}): #{error.message}") if logger
|
82
84
|
nil
|
83
85
|
end
|
84
86
|
|
85
87
|
def write_entry(key, entry, **options)
|
88
|
+
write_serialized_entry(key, serialize_entry(entry, **options), **options)
|
89
|
+
end
|
90
|
+
|
91
|
+
def write_serialized_entry(key, payload, **options)
|
86
92
|
return false if options[:unless_exist] && File.exist?(key)
|
87
93
|
ensure_cache_path(File.dirname(key))
|
88
|
-
File.atomic_write(key, cache_path) { |f| f.write(
|
94
|
+
File.atomic_write(key, cache_path) { |f| f.write(payload) }
|
89
95
|
true
|
90
96
|
end
|
91
97
|
|
@@ -95,9 +101,9 @@ module ActiveSupport
|
|
95
101
|
File.delete(key)
|
96
102
|
delete_empty_directories(File.dirname(key))
|
97
103
|
true
|
98
|
-
rescue
|
104
|
+
rescue
|
99
105
|
# Just in case the error was caused by another process deleting the file first.
|
100
|
-
raise
|
106
|
+
raise if File.exist?(key)
|
101
107
|
false
|
102
108
|
end
|
103
109
|
end
|
@@ -7,8 +7,8 @@ rescue LoadError => e
|
|
7
7
|
raise e
|
8
8
|
end
|
9
9
|
|
10
|
+
require "delegate"
|
10
11
|
require "active_support/core_ext/enumerable"
|
11
|
-
require "active_support/core_ext/marshal"
|
12
12
|
require "active_support/core_ext/array/extract_options"
|
13
13
|
|
14
14
|
module ActiveSupport
|
@@ -26,29 +26,52 @@ module ActiveSupport
|
|
26
26
|
# MemCacheStore implements the Strategy::LocalCache strategy which implements
|
27
27
|
# an in-memory cache inside of a block.
|
28
28
|
class MemCacheStore < Store
|
29
|
-
|
29
|
+
# Advertise cache versioning support.
|
30
|
+
def self.supports_cache_versioning?
|
31
|
+
true
|
32
|
+
end
|
33
|
+
|
34
|
+
prepend Strategy::LocalCache
|
35
|
+
|
36
|
+
module DupLocalCache
|
37
|
+
class DupLocalStore < DelegateClass(Strategy::LocalCache::LocalStore)
|
38
|
+
def write_entry(_key, entry)
|
39
|
+
if entry.is_a?(Entry)
|
40
|
+
entry.dup_value!
|
41
|
+
end
|
42
|
+
super
|
43
|
+
end
|
44
|
+
|
45
|
+
def fetch_entry(key)
|
46
|
+
entry = super do
|
47
|
+
new_entry = yield
|
48
|
+
if entry.is_a?(Entry)
|
49
|
+
new_entry.dup_value!
|
50
|
+
end
|
51
|
+
new_entry
|
52
|
+
end
|
53
|
+
entry = entry.dup
|
54
|
+
|
55
|
+
if entry.is_a?(Entry)
|
56
|
+
entry.dup_value!
|
57
|
+
end
|
58
|
+
|
59
|
+
entry
|
60
|
+
end
|
61
|
+
end
|
30
62
|
|
31
|
-
# Provide support for raw values in the local cache strategy.
|
32
|
-
module LocalCacheWithRaw # :nodoc:
|
33
63
|
private
|
34
|
-
def
|
35
|
-
if
|
36
|
-
|
37
|
-
|
38
|
-
|
64
|
+
def local_cache
|
65
|
+
if ActiveSupport::Cache.format_version == 6.1
|
66
|
+
if local_cache = super
|
67
|
+
DupLocalStore.new(local_cache)
|
68
|
+
end
|
39
69
|
else
|
40
70
|
super
|
41
71
|
end
|
42
72
|
end
|
43
73
|
end
|
44
|
-
|
45
|
-
# Advertise cache versioning support.
|
46
|
-
def self.supports_cache_versioning?
|
47
|
-
true
|
48
|
-
end
|
49
|
-
|
50
|
-
prepend Strategy::LocalCache
|
51
|
-
prepend LocalCacheWithRaw
|
74
|
+
prepend DupLocalCache
|
52
75
|
|
53
76
|
ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
|
54
77
|
|
@@ -81,11 +104,14 @@ module ActiveSupport
|
|
81
104
|
#
|
82
105
|
# ActiveSupport::Cache::MemCacheStore.new("localhost", "server-downstairs.localnetwork:8229")
|
83
106
|
#
|
84
|
-
# If no addresses are provided, but ENV['MEMCACHE_SERVERS'] is defined, it will be used instead. Otherwise,
|
107
|
+
# If no addresses are provided, but <tt>ENV['MEMCACHE_SERVERS']</tt> is defined, it will be used instead. Otherwise,
|
85
108
|
# MemCacheStore will connect to localhost:11211 (the default memcached port).
|
86
109
|
def initialize(*addresses)
|
87
110
|
addresses = addresses.flatten
|
88
111
|
options = addresses.extract_options!
|
112
|
+
if options.key?(:cache_nils)
|
113
|
+
options[:skip_nil] = !options.delete(:cache_nils)
|
114
|
+
end
|
89
115
|
super(options)
|
90
116
|
|
91
117
|
unless [String, Dalli::Client, NilClass].include?(addresses.first.class)
|
@@ -95,14 +121,32 @@ module ActiveSupport
|
|
95
121
|
@data = addresses.first
|
96
122
|
else
|
97
123
|
mem_cache_options = options.dup
|
98
|
-
|
124
|
+
# The value "compress: false" prevents duplicate compression within Dalli.
|
125
|
+
mem_cache_options[:compress] = false
|
126
|
+
(UNIVERSAL_OPTIONS - %i(compress)).each { |name| mem_cache_options.delete(name) }
|
99
127
|
@data = self.class.build_mem_cache(*(addresses + [mem_cache_options]))
|
100
128
|
end
|
101
129
|
end
|
102
130
|
|
131
|
+
##
|
132
|
+
# :method: write
|
133
|
+
# :call-seq: write(name, value, options = nil)
|
134
|
+
#
|
135
|
+
# Behaves the same as ActiveSupport::Cache::Store#write, but supports
|
136
|
+
# additional options specific to memcached.
|
137
|
+
#
|
138
|
+
# ==== Additional Options
|
139
|
+
#
|
140
|
+
# * <tt>raw: true</tt> - Sends the value directly to the server as raw
|
141
|
+
# bytes. The value must be a string or number. You can use memcached
|
142
|
+
# direct operations like +increment+ and +decrement+ only on raw values.
|
143
|
+
#
|
144
|
+
# * <tt>unless_exist: true</tt> - Prevents overwriting an existing cache
|
145
|
+
# entry.
|
146
|
+
|
103
147
|
# Increment a cached value. This method uses the memcached incr atomic
|
104
|
-
# operator and can only be used on values written with the
|
105
|
-
# Calling it on a value not stored with
|
148
|
+
# operator and can only be used on values written with the +:raw+ option.
|
149
|
+
# Calling it on a value not stored with +:raw+ will initialize that value
|
106
150
|
# to zero.
|
107
151
|
def increment(name, amount = 1, options = nil)
|
108
152
|
options = merged_options(options)
|
@@ -114,8 +158,8 @@ module ActiveSupport
|
|
114
158
|
end
|
115
159
|
|
116
160
|
# Decrement a cached value. This method uses the memcached decr atomic
|
117
|
-
# operator and can only be used on values written with the
|
118
|
-
# Calling it on a value not stored with
|
161
|
+
# operator and can only be used on values written with the +:raw+ option.
|
162
|
+
# Calling it on a value not stored with +:raw+ will initialize that value
|
119
163
|
# to zero.
|
120
164
|
def decrement(name, amount = 1, options = nil)
|
121
165
|
options = merged_options(options)
|
@@ -138,23 +182,81 @@ module ActiveSupport
|
|
138
182
|
end
|
139
183
|
|
140
184
|
private
|
185
|
+
module Coders # :nodoc:
|
186
|
+
class << self
|
187
|
+
def [](version)
|
188
|
+
case version
|
189
|
+
when 6.1
|
190
|
+
Rails61Coder
|
191
|
+
when 7.0
|
192
|
+
Rails70Coder
|
193
|
+
else
|
194
|
+
raise ArgumentError, "Unknown ActiveSupport::Cache.format_version #{Cache.format_version.inspect}"
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
module Loader
|
200
|
+
def load(payload)
|
201
|
+
if payload.is_a?(Entry)
|
202
|
+
payload
|
203
|
+
else
|
204
|
+
Cache::Coders::Loader.load(payload)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
module Rails61Coder
|
210
|
+
include Loader
|
211
|
+
extend self
|
212
|
+
|
213
|
+
def dump(entry)
|
214
|
+
entry
|
215
|
+
end
|
216
|
+
|
217
|
+
def dump_compressed(entry, threshold)
|
218
|
+
entry.compressed(threshold)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
module Rails70Coder
|
223
|
+
include Cache::Coders::Rails70Coder
|
224
|
+
include Loader
|
225
|
+
extend self
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def default_coder
|
230
|
+
Coders[Cache.format_version]
|
231
|
+
end
|
232
|
+
|
141
233
|
# Read an entry from the cache.
|
142
234
|
def read_entry(key, **options)
|
143
|
-
|
235
|
+
deserialize_entry(read_serialized_entry(key, **options), **options)
|
236
|
+
end
|
237
|
+
|
238
|
+
def read_serialized_entry(key, **options)
|
239
|
+
rescue_error_with(nil) do
|
240
|
+
@data.with { |c| c.get(key, options) }
|
241
|
+
end
|
144
242
|
end
|
145
243
|
|
146
244
|
# Write an entry to the cache.
|
147
245
|
def write_entry(key, entry, **options)
|
246
|
+
write_serialized_entry(key, serialize_entry(entry, **options), **options)
|
247
|
+
end
|
248
|
+
|
249
|
+
def write_serialized_entry(key, payload, **options)
|
148
250
|
method = options[:unless_exist] ? :add : :set
|
149
|
-
value = options[:raw] ? entry.value.to_s : serialize_entry(entry)
|
150
251
|
expires_in = options[:expires_in].to_i
|
151
252
|
if options[:race_condition_ttl] && expires_in > 0 && !options[:raw]
|
152
253
|
# Set the memcache expire a few minutes in the future to support race condition ttls on read
|
153
254
|
expires_in += 5.minutes
|
154
255
|
end
|
155
256
|
rescue_error_with false do
|
156
|
-
#
|
157
|
-
|
257
|
+
# Don't pass compress option to Dalli since we are already dealing with compression.
|
258
|
+
options.delete(:compress)
|
259
|
+
@data.with { |c| c.send(method, key, payload, expires_in, **options) }
|
158
260
|
end
|
159
261
|
end
|
160
262
|
|
@@ -166,7 +268,7 @@ module ActiveSupport
|
|
166
268
|
values = {}
|
167
269
|
|
168
270
|
raw_values.each do |key, value|
|
169
|
-
entry = deserialize_entry(value)
|
271
|
+
entry = deserialize_entry(value, raw: options[:raw])
|
170
272
|
|
171
273
|
unless entry.expired? || entry.mismatched?(normalize_version(keys_to_names[key], options))
|
172
274
|
values[keys_to_names[key]] = entry.value
|
@@ -181,31 +283,40 @@ module ActiveSupport
|
|
181
283
|
rescue_error_with(false) { @data.with { |c| c.delete(key) } }
|
182
284
|
end
|
183
285
|
|
286
|
+
def serialize_entry(entry, raw: false, **options)
|
287
|
+
if raw
|
288
|
+
entry.value.to_s
|
289
|
+
else
|
290
|
+
super(entry, raw: raw, **options)
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
184
294
|
# Memcache keys are binaries. So we need to force their encoding to binary
|
185
295
|
# before applying the regular expression to ensure we are escaping all
|
186
296
|
# characters properly.
|
187
297
|
def normalize_key(key, options)
|
188
298
|
key = super
|
189
|
-
|
190
299
|
if key
|
191
300
|
key = key.dup.force_encoding(Encoding::ASCII_8BIT)
|
192
301
|
key = key.gsub(ESCAPE_KEY_CHARS) { |match| "%#{match.getbyte(0).to_s(16).upcase}" }
|
193
|
-
key = "#{key[0,
|
302
|
+
key = "#{key[0, 212]}:hash:#{ActiveSupport::Digest.hexdigest(key)}" if key.size > 250
|
194
303
|
end
|
195
|
-
|
196
304
|
key
|
197
305
|
end
|
198
306
|
|
199
|
-
def deserialize_entry(payload)
|
200
|
-
|
201
|
-
|
202
|
-
|
307
|
+
def deserialize_entry(payload, raw: false, **)
|
308
|
+
if payload && raw
|
309
|
+
Entry.new(payload)
|
310
|
+
else
|
311
|
+
super(payload)
|
312
|
+
end
|
203
313
|
end
|
204
314
|
|
205
315
|
def rescue_error_with(fallback)
|
206
316
|
yield
|
207
|
-
rescue Dalli::DalliError =>
|
208
|
-
|
317
|
+
rescue Dalli::DalliError => error
|
318
|
+
ActiveSupport.error_reporter&.report(error, handled: true, severity: :warning)
|
319
|
+
logger.error("DalliError (#{error}): #{error.message}") if logger
|
209
320
|
fallback
|
210
321
|
end
|
211
322
|
end
|
@@ -11,7 +11,7 @@ module ActiveSupport
|
|
11
11
|
# to share cache data with each other and this may not be the most
|
12
12
|
# appropriate cache in that scenario.
|
13
13
|
#
|
14
|
-
# This cache has a bounded size specified by the
|
14
|
+
# This cache has a bounded size specified by the +:size+ options to the
|
15
15
|
# initializer (default is 32Mb). When the cache exceeds the allotted size,
|
16
16
|
# a cleanup will occur which tries to prune the cache down to three quarters
|
17
17
|
# of the maximum size by removing the least recently used entries.
|
@@ -25,21 +25,25 @@ module ActiveSupport
|
|
25
25
|
# MemoryStore is thread-safe.
|
26
26
|
class MemoryStore < Store
|
27
27
|
module DupCoder # :nodoc:
|
28
|
-
|
29
|
-
def load(entry)
|
30
|
-
entry = entry.dup
|
31
|
-
entry.dup_value!
|
32
|
-
entry
|
33
|
-
end
|
28
|
+
extend self
|
34
29
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
30
|
+
def dump(entry)
|
31
|
+
entry.dup_value! unless entry.compressed?
|
32
|
+
entry
|
33
|
+
end
|
34
|
+
|
35
|
+
def dump_compressed(entry, threshold)
|
36
|
+
entry = entry.compressed(threshold)
|
37
|
+
entry.dup_value! unless entry.compressed?
|
38
|
+
entry
|
39
39
|
end
|
40
|
-
end
|
41
40
|
|
42
|
-
|
41
|
+
def load(entry)
|
42
|
+
entry = entry.dup
|
43
|
+
entry.dup_value!
|
44
|
+
entry
|
45
|
+
end
|
46
|
+
end
|
43
47
|
|
44
48
|
def initialize(options = nil)
|
45
49
|
options ||= {}
|
@@ -85,13 +89,13 @@ module ActiveSupport
|
|
85
89
|
return if pruning?
|
86
90
|
@pruning = true
|
87
91
|
begin
|
88
|
-
start_time =
|
92
|
+
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
89
93
|
cleanup
|
90
94
|
instrument(:prune, target_size, from: @cache_size) do
|
91
95
|
keys = synchronize { @data.keys }
|
92
96
|
keys.each do |key|
|
93
97
|
delete_entry(key, **options)
|
94
|
-
return if @cache_size <= target_size || (max_time &&
|
98
|
+
return if @cache_size <= target_size || (max_time && Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time > max_time)
|
95
99
|
end
|
96
100
|
end
|
97
101
|
ensure
|
@@ -139,6 +143,10 @@ module ActiveSupport
|
|
139
143
|
private
|
140
144
|
PER_ENTRY_OVERHEAD = 240
|
141
145
|
|
146
|
+
def default_coder
|
147
|
+
DupCoder
|
148
|
+
end
|
149
|
+
|
142
150
|
def cached_size(key, payload)
|
143
151
|
key.to_s.bytesize + payload.bytesize + PER_ENTRY_OVERHEAD
|
144
152
|
end
|
@@ -156,7 +164,7 @@ module ActiveSupport
|
|
156
164
|
end
|
157
165
|
|
158
166
|
def write_entry(key, entry, **options)
|
159
|
-
payload = serialize_entry(entry)
|
167
|
+
payload = serialize_entry(entry, **options)
|
160
168
|
synchronize do
|
161
169
|
return false if options[:unless_exist] && @data.key?(key)
|
162
170
|
|
@@ -33,10 +33,18 @@ module ActiveSupport
|
|
33
33
|
end
|
34
34
|
|
35
35
|
private
|
36
|
-
def read_entry(key, **
|
36
|
+
def read_entry(key, **s)
|
37
|
+
deserialize_entry(read_serialized_entry(key))
|
37
38
|
end
|
38
39
|
|
39
|
-
def
|
40
|
+
def read_serialized_entry(_key, **)
|
41
|
+
end
|
42
|
+
|
43
|
+
def write_entry(key, entry, **)
|
44
|
+
write_serialized_entry(key, serialize_entry(entry))
|
45
|
+
end
|
46
|
+
|
47
|
+
def write_serialized_entry(_key, _payload, **)
|
40
48
|
true
|
41
49
|
end
|
42
50
|
|