activesupport 6.1.4.1 → 7.0.8.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +325 -395
- data/MIT-LICENSE +1 -1
- 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 +68 -85
- 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 +40 -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 +36 -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 +112 -38
- 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 +36 -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 +94 -38
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
- data/lib/active_support/core_ext/time/calculations.rb +13 -8
- data/lib/active_support/core_ext/time/conversions.rb +13 -12
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +73 -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 -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 +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 +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 +45 -3
- data/lib/active_support/encrypted_file.rb +21 -10
- 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 +20 -7
- 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 +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 +29 -55
- 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 -0
- data/lib/active_support/railtie.rb +69 -19
- data/lib/active_support/reloader.rb +1 -1
- 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 +2 -2
- data/lib/active_support/test_case.rb +13 -21
- data/lib/active_support/testing/assertions.rb +36 -6
- 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 +43 -22
- data/lib/active_support/values/time_zone.rb +35 -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 +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
data/MIT-LICENSE
CHANGED
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
|
|