activesupport 7.0.4 → 7.1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1076 -230
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -6
- data/lib/active_support/actionable_error.rb +3 -1
- data/lib/active_support/array_inquirer.rb +2 -0
- data/lib/active_support/backtrace_cleaner.rb +30 -5
- data/lib/active_support/benchmarkable.rb +1 -0
- data/lib/active_support/broadcast_logger.rb +251 -0
- data/lib/active_support/builder.rb +1 -1
- data/lib/active_support/cache/coder.rb +153 -0
- data/lib/active_support/cache/entry.rb +134 -0
- data/lib/active_support/cache/file_store.rb +37 -10
- data/lib/active_support/cache/mem_cache_store.rb +100 -76
- data/lib/active_support/cache/memory_store.rb +78 -24
- data/lib/active_support/cache/null_store.rb +6 -0
- data/lib/active_support/cache/redis_cache_store.rb +153 -141
- data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
- data/lib/active_support/cache/strategy/local_cache.rb +29 -14
- data/lib/active_support/cache.rb +333 -253
- data/lib/active_support/callbacks.rb +44 -21
- data/lib/active_support/code_generator.rb +15 -10
- data/lib/active_support/concern.rb +4 -2
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +42 -3
- data/lib/active_support/concurrency/null_lock.rb +13 -0
- data/lib/active_support/configurable.rb +10 -0
- data/lib/active_support/core_ext/array/conversions.rb +2 -1
- data/lib/active_support/core_ext/array.rb +0 -1
- data/lib/active_support/core_ext/class/subclasses.rb +13 -10
- data/lib/active_support/core_ext/date/calculations.rb +15 -0
- data/lib/active_support/core_ext/date/conversions.rb +2 -1
- data/lib/active_support/core_ext/date.rb +0 -1
- data/lib/active_support/core_ext/date_and_time/calculations.rb +10 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +6 -2
- data/lib/active_support/core_ext/date_time.rb +0 -1
- data/lib/active_support/core_ext/digest/uuid.rb +1 -10
- data/lib/active_support/core_ext/enumerable.rb +8 -75
- data/lib/active_support/core_ext/erb/util.rb +196 -0
- data/lib/active_support/core_ext/hash/conversions.rb +1 -1
- data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +3 -3
- data/lib/active_support/core_ext/integer/inflections.rb +12 -12
- data/lib/active_support/core_ext/module/attribute_accessors.rb +6 -0
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +34 -16
- data/lib/active_support/core_ext/module/concerning.rb +6 -6
- data/lib/active_support/core_ext/module/delegation.rb +81 -37
- data/lib/active_support/core_ext/module/deprecation.rb +15 -12
- data/lib/active_support/core_ext/module/introspection.rb +0 -1
- data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +2 -0
- data/lib/active_support/core_ext/numeric.rb +0 -1
- data/lib/active_support/core_ext/object/deep_dup.rb +16 -0
- data/lib/active_support/core_ext/object/duplicable.rb +25 -16
- data/lib/active_support/core_ext/object/inclusion.rb +13 -5
- data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
- data/lib/active_support/core_ext/object/json.rb +16 -6
- data/lib/active_support/core_ext/object/to_query.rb +0 -2
- data/lib/active_support/core_ext/object/with.rb +44 -0
- data/lib/active_support/core_ext/object/with_options.rb +9 -9
- data/lib/active_support/core_ext/object.rb +1 -0
- data/lib/active_support/core_ext/pathname/blank.rb +16 -0
- data/lib/active_support/core_ext/pathname/existence.rb +2 -0
- data/lib/active_support/core_ext/pathname.rb +1 -0
- data/lib/active_support/core_ext/range/conversions.rb +28 -7
- data/lib/active_support/core_ext/range/overlap.rb +40 -0
- data/lib/active_support/core_ext/range.rb +1 -2
- data/lib/active_support/core_ext/securerandom.rb +24 -12
- data/lib/active_support/core_ext/string/filters.rb +20 -14
- data/lib/active_support/core_ext/string/indent.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +16 -9
- data/lib/active_support/core_ext/string/output_safety.rb +42 -174
- data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
- data/lib/active_support/core_ext/time/calculations.rb +22 -2
- data/lib/active_support/core_ext/time/conversions.rb +2 -2
- data/lib/active_support/core_ext/time/zones.rb +7 -8
- data/lib/active_support/core_ext/time.rb +0 -1
- data/lib/active_support/current_attributes.rb +15 -6
- data/lib/active_support/deep_mergeable.rb +53 -0
- data/lib/active_support/dependencies/autoload.rb +17 -12
- data/lib/active_support/deprecation/behaviors.rb +65 -42
- data/lib/active_support/deprecation/constant_accessor.rb +5 -4
- data/lib/active_support/deprecation/deprecators.rb +104 -0
- data/lib/active_support/deprecation/disallowed.rb +6 -8
- data/lib/active_support/deprecation/instance_delegator.rb +31 -4
- data/lib/active_support/deprecation/method_wrappers.rb +6 -23
- data/lib/active_support/deprecation/proxy_wrappers.rb +37 -22
- data/lib/active_support/deprecation/reporting.rb +43 -26
- data/lib/active_support/deprecation.rb +32 -5
- data/lib/active_support/deprecator.rb +7 -0
- data/lib/active_support/descendants_tracker.rb +104 -132
- data/lib/active_support/duration/iso8601_serializer.rb +0 -2
- data/lib/active_support/duration.rb +2 -1
- data/lib/active_support/encrypted_configuration.rb +63 -11
- data/lib/active_support/encrypted_file.rb +16 -12
- data/lib/active_support/environment_inquirer.rb +22 -2
- data/lib/active_support/error_reporter/test_helper.rb +15 -0
- data/lib/active_support/error_reporter.rb +121 -35
- data/lib/active_support/evented_file_update_checker.rb +17 -2
- data/lib/active_support/execution_wrapper.rb +4 -4
- data/lib/active_support/file_update_checker.rb +4 -2
- data/lib/active_support/fork_tracker.rb +10 -2
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/gzip.rb +2 -0
- data/lib/active_support/hash_with_indifferent_access.rb +35 -17
- data/lib/active_support/html_safe_translation.rb +16 -6
- data/lib/active_support/i18n.rb +1 -1
- data/lib/active_support/i18n_railtie.rb +20 -13
- data/lib/active_support/inflector/inflections.rb +2 -0
- data/lib/active_support/inflector/methods.rb +28 -18
- data/lib/active_support/inflector/transliterate.rb +3 -1
- data/lib/active_support/isolated_execution_state.rb +26 -22
- data/lib/active_support/json/decoding.rb +2 -1
- data/lib/active_support/json/encoding.rb +25 -43
- data/lib/active_support/key_generator.rb +9 -1
- data/lib/active_support/lazy_load_hooks.rb +7 -5
- data/lib/active_support/locale/en.yml +2 -0
- data/lib/active_support/log_subscriber.rb +85 -33
- data/lib/active_support/logger.rb +9 -60
- data/lib/active_support/logger_thread_safe_level.rb +10 -24
- data/lib/active_support/message_encryptor.rb +197 -53
- data/lib/active_support/message_encryptors.rb +141 -0
- data/lib/active_support/message_pack/cache_serializer.rb +23 -0
- data/lib/active_support/message_pack/extensions.rb +292 -0
- data/lib/active_support/message_pack/serializer.rb +63 -0
- data/lib/active_support/message_pack.rb +50 -0
- data/lib/active_support/message_verifier.rb +212 -93
- data/lib/active_support/message_verifiers.rb +135 -0
- data/lib/active_support/messages/codec.rb +65 -0
- data/lib/active_support/messages/metadata.rb +111 -45
- data/lib/active_support/messages/rotation_coordinator.rb +93 -0
- data/lib/active_support/messages/rotator.rb +34 -32
- data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
- data/lib/active_support/multibyte/chars.rb +2 -0
- data/lib/active_support/multibyte/unicode.rb +9 -37
- data/lib/active_support/notifications/fanout.rb +245 -81
- data/lib/active_support/notifications/instrumenter.rb +87 -22
- data/lib/active_support/notifications.rb +3 -3
- data/lib/active_support/number_helper/number_converter.rb +14 -5
- data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -6
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -3
- data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -0
- data/lib/active_support/number_helper.rb +379 -317
- data/lib/active_support/ordered_hash.rb +3 -3
- data/lib/active_support/ordered_options.rb +14 -0
- data/lib/active_support/parameter_filter.rb +103 -84
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/railtie.rb +33 -21
- data/lib/active_support/reloader.rb +12 -4
- data/lib/active_support/rescuable.rb +2 -0
- data/lib/active_support/secure_compare_rotator.rb +16 -9
- data/lib/active_support/string_inquirer.rb +3 -1
- data/lib/active_support/subscriber.rb +9 -27
- data/lib/active_support/syntax_error_proxy.rb +60 -0
- data/lib/active_support/tagged_logging.rb +64 -24
- data/lib/active_support/test_case.rb +153 -6
- data/lib/active_support/testing/assertions.rb +26 -10
- data/lib/active_support/testing/autorun.rb +0 -2
- data/lib/active_support/testing/constant_stubbing.rb +32 -0
- data/lib/active_support/testing/deprecation.rb +25 -25
- data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
- data/lib/active_support/testing/isolation.rb +29 -28
- data/lib/active_support/testing/method_call_assertions.rb +21 -8
- data/lib/active_support/testing/parallelize_executor.rb +8 -3
- data/lib/active_support/testing/setup_and_teardown.rb +2 -0
- data/lib/active_support/testing/stream.rb +1 -1
- data/lib/active_support/testing/strict_warnings.rb +39 -0
- data/lib/active_support/testing/time_helpers.rb +37 -15
- data/lib/active_support/time_with_zone.rb +8 -37
- data/lib/active_support/values/time_zone.rb +18 -7
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/jdom.rb +3 -10
- data/lib/active_support/xml_mini/nokogiri.rb +1 -1
- 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 +2 -2
- data/lib/active_support.rb +14 -3
- metadata +148 -19
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +0 -25
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +0 -26
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +0 -22
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +0 -60
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +0 -26
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -7
- data/lib/active_support/core_ext/range/overlaps.rb +0 -10
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +0 -22
- data/lib/active_support/core_ext/uri.rb +0 -5
- data/lib/active_support/per_thread_registry.rb +0 -65
@@ -0,0 +1,134 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "zlib"
|
4
|
+
|
5
|
+
module ActiveSupport
|
6
|
+
module Cache
|
7
|
+
# This class is used to represent cache entries. Cache entries have a value, an optional
|
8
|
+
# expiration time, and an optional version. The expiration time is used to support the :race_condition_ttl option
|
9
|
+
# on the cache. The version is used to support the :version option on the cache for rejecting
|
10
|
+
# mismatches.
|
11
|
+
#
|
12
|
+
# Since cache entries in most instances will be serialized, the internals of this class are highly optimized
|
13
|
+
# using short instance variable names that are lazily defined.
|
14
|
+
class Entry # :nodoc:
|
15
|
+
class << self
|
16
|
+
def unpack(members)
|
17
|
+
new(members[0], expires_at: members[1], version: members[2])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :version
|
22
|
+
|
23
|
+
# Creates a new cache entry for the specified value. Options supported are
|
24
|
+
# +:compressed+, +:version+, +:expires_at+ and +:expires_in+.
|
25
|
+
def initialize(value, compressed: false, version: nil, expires_in: nil, expires_at: nil, **)
|
26
|
+
@value = value
|
27
|
+
@version = version
|
28
|
+
@created_at = 0.0
|
29
|
+
@expires_in = expires_at&.to_f || expires_in && (expires_in.to_f + Time.now.to_f)
|
30
|
+
@compressed = true if compressed
|
31
|
+
end
|
32
|
+
|
33
|
+
def value
|
34
|
+
compressed? ? uncompress(@value) : @value
|
35
|
+
end
|
36
|
+
|
37
|
+
def mismatched?(version)
|
38
|
+
@version && version && @version != version
|
39
|
+
end
|
40
|
+
|
41
|
+
# Checks if the entry is expired. The +expires_in+ parameter can override
|
42
|
+
# the value set when the entry was created.
|
43
|
+
def expired?
|
44
|
+
@expires_in && @created_at + @expires_in <= Time.now.to_f
|
45
|
+
end
|
46
|
+
|
47
|
+
def expires_at
|
48
|
+
@expires_in ? @created_at + @expires_in : nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def expires_at=(value)
|
52
|
+
if value
|
53
|
+
@expires_in = value.to_f - @created_at
|
54
|
+
else
|
55
|
+
@expires_in = nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns the size of the cached value. This could be less than
|
60
|
+
# <tt>value.bytesize</tt> if the data is compressed.
|
61
|
+
def bytesize
|
62
|
+
case value
|
63
|
+
when NilClass
|
64
|
+
0
|
65
|
+
when String
|
66
|
+
@value.bytesize
|
67
|
+
else
|
68
|
+
@s ||= Marshal.dump(@value).bytesize
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def compressed? # :nodoc:
|
73
|
+
defined?(@compressed)
|
74
|
+
end
|
75
|
+
|
76
|
+
def compressed(compress_threshold)
|
77
|
+
return self if compressed?
|
78
|
+
|
79
|
+
case @value
|
80
|
+
when nil, true, false, Numeric
|
81
|
+
uncompressed_size = 0
|
82
|
+
when String
|
83
|
+
uncompressed_size = @value.bytesize
|
84
|
+
else
|
85
|
+
serialized = Marshal.dump(@value)
|
86
|
+
uncompressed_size = serialized.bytesize
|
87
|
+
end
|
88
|
+
|
89
|
+
if uncompressed_size >= compress_threshold
|
90
|
+
serialized ||= Marshal.dump(@value)
|
91
|
+
compressed = Zlib::Deflate.deflate(serialized)
|
92
|
+
|
93
|
+
if compressed.bytesize < uncompressed_size
|
94
|
+
return Entry.new(compressed, compressed: true, expires_at: expires_at, version: version)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
self
|
98
|
+
end
|
99
|
+
|
100
|
+
def local?
|
101
|
+
false
|
102
|
+
end
|
103
|
+
|
104
|
+
# Duplicates the value in a class. This is used by cache implementations that don't natively
|
105
|
+
# serialize entries to protect against accidental cache modifications.
|
106
|
+
def dup_value!
|
107
|
+
if @value && !compressed? && !(@value.is_a?(Numeric) || @value == true || @value == false)
|
108
|
+
if @value.is_a?(String)
|
109
|
+
@value = @value.dup
|
110
|
+
else
|
111
|
+
@value = Marshal.load(Marshal.dump(@value))
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def pack
|
117
|
+
members = [value, expires_at, version]
|
118
|
+
members.pop while !members.empty? && members.last.nil?
|
119
|
+
members
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
def uncompress(value)
|
124
|
+
marshal_load(Zlib::Inflate.inflate(value))
|
125
|
+
end
|
126
|
+
|
127
|
+
def marshal_load(payload)
|
128
|
+
Marshal.load(payload)
|
129
|
+
rescue ArgumentError => error
|
130
|
+
raise Cache::DeserializationError, error.message
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -6,10 +6,9 @@ require "uri/common"
|
|
6
6
|
|
7
7
|
module ActiveSupport
|
8
8
|
module Cache
|
9
|
-
#
|
9
|
+
# = \File \Cache \Store
|
10
10
|
#
|
11
|
-
#
|
12
|
-
# an in-memory cache inside of a block.
|
11
|
+
# A cache store implementation which stores everything on the filesystem.
|
13
12
|
class FileStore < Store
|
14
13
|
attr_reader :cache_path
|
15
14
|
|
@@ -46,14 +45,33 @@ module ActiveSupport
|
|
46
45
|
end
|
47
46
|
end
|
48
47
|
|
49
|
-
#
|
50
|
-
#
|
48
|
+
# Increment a cached integer value. Returns the updated value.
|
49
|
+
#
|
50
|
+
# If the key is unset, it starts from +0+:
|
51
|
+
#
|
52
|
+
# cache.increment("foo") # => 1
|
53
|
+
# cache.increment("bar", 100) # => 100
|
54
|
+
#
|
55
|
+
# To set a specific value, call #write:
|
56
|
+
#
|
57
|
+
# cache.write("baz", 5)
|
58
|
+
# cache.increment("baz") # => 6
|
59
|
+
#
|
51
60
|
def increment(name, amount = 1, options = nil)
|
52
61
|
modify_value(name, amount, options)
|
53
62
|
end
|
54
63
|
|
55
|
-
#
|
56
|
-
#
|
64
|
+
# Decrement a cached integer value. Returns the updated value.
|
65
|
+
#
|
66
|
+
# If the key is unset, it will be set to +-amount+.
|
67
|
+
#
|
68
|
+
# cache.decrement("foo") # => -1
|
69
|
+
#
|
70
|
+
# To set a specific value, call #write:
|
71
|
+
#
|
72
|
+
# cache.write("baz", 5)
|
73
|
+
# cache.decrement("baz") # => 4
|
74
|
+
#
|
57
75
|
def decrement(name, amount = 1, options = nil)
|
58
76
|
modify_value(name, -amount, options)
|
59
77
|
end
|
@@ -69,6 +87,10 @@ module ActiveSupport
|
|
69
87
|
end
|
70
88
|
end
|
71
89
|
|
90
|
+
def inspect # :nodoc:
|
91
|
+
"#<#{self.class.name} cache_path=#{@cache_path}, options=#{@options.inspect}>"
|
92
|
+
end
|
93
|
+
|
72
94
|
private
|
73
95
|
def read_entry(key, **options)
|
74
96
|
if payload = read_serialized_entry(key, **options)
|
@@ -106,6 +128,8 @@ module ActiveSupport
|
|
106
128
|
raise if File.exist?(key)
|
107
129
|
false
|
108
130
|
end
|
131
|
+
else
|
132
|
+
false
|
109
133
|
end
|
110
134
|
end
|
111
135
|
|
@@ -152,7 +176,7 @@ module ActiveSupport
|
|
152
176
|
|
153
177
|
# Translate a file path into a key.
|
154
178
|
def file_path_key(path)
|
155
|
-
fname = path[cache_path.to_s.size..-1].split(File::SEPARATOR, 4).last
|
179
|
+
fname = path[cache_path.to_s.size..-1].split(File::SEPARATOR, 4).last.delete(File::SEPARATOR)
|
156
180
|
URI.decode_www_form_component(fname, Encoding::UTF_8)
|
157
181
|
end
|
158
182
|
|
@@ -182,8 +206,8 @@ module ActiveSupport
|
|
182
206
|
end
|
183
207
|
end
|
184
208
|
|
185
|
-
# Modifies the amount of an
|
186
|
-
# If the key is not found
|
209
|
+
# Modifies the amount of an integer value that is stored in the cache.
|
210
|
+
# If the key is not found it is created and set to +amount+.
|
187
211
|
def modify_value(name, amount, options)
|
188
212
|
file_name = normalize_key(name, options)
|
189
213
|
|
@@ -194,6 +218,9 @@ module ActiveSupport
|
|
194
218
|
num = num.to_i + amount
|
195
219
|
write(name, num, options)
|
196
220
|
num
|
221
|
+
else
|
222
|
+
write(name, Integer(amount), options)
|
223
|
+
amount
|
197
224
|
end
|
198
225
|
end
|
199
226
|
end
|
@@ -3,16 +3,20 @@
|
|
3
3
|
begin
|
4
4
|
require "dalli"
|
5
5
|
rescue LoadError => e
|
6
|
-
|
6
|
+
warn "You don't have dalli installed in your application. Please add it to your Gemfile and run bundle install"
|
7
7
|
raise e
|
8
8
|
end
|
9
9
|
|
10
|
+
require "connection_pool"
|
10
11
|
require "delegate"
|
11
12
|
require "active_support/core_ext/enumerable"
|
12
13
|
require "active_support/core_ext/array/extract_options"
|
14
|
+
require "active_support/core_ext/numeric/time"
|
13
15
|
|
14
16
|
module ActiveSupport
|
15
17
|
module Cache
|
18
|
+
# = Memcached \Cache \Store
|
19
|
+
#
|
16
20
|
# A cache store implementation which stores data in Memcached:
|
17
21
|
# https://memcached.org
|
18
22
|
#
|
@@ -20,12 +24,16 @@ module ActiveSupport
|
|
20
24
|
#
|
21
25
|
# Special features:
|
22
26
|
# - Clustering and load balancing. One can specify multiple memcached servers,
|
23
|
-
# and MemCacheStore will load balance between all available servers. If a
|
24
|
-
# server goes down, then MemCacheStore will ignore it until it comes back up.
|
27
|
+
# and +MemCacheStore+ will load balance between all available servers. If a
|
28
|
+
# server goes down, then +MemCacheStore+ will ignore it until it comes back up.
|
25
29
|
#
|
26
|
-
# MemCacheStore implements the Strategy::LocalCache strategy which
|
27
|
-
# an in-memory cache inside of a block.
|
30
|
+
# +MemCacheStore+ implements the Strategy::LocalCache strategy which
|
31
|
+
# implements an in-memory cache inside of a block.
|
28
32
|
class MemCacheStore < Store
|
33
|
+
# These options represent behavior overridden by this implementation and should
|
34
|
+
# not be allowed to get down to the Dalli client
|
35
|
+
OVERRIDDEN_OPTIONS = UNIVERSAL_OPTIONS
|
36
|
+
|
29
37
|
# Advertise cache versioning support.
|
30
38
|
def self.supports_cache_versioning?
|
31
39
|
true
|
@@ -73,6 +81,7 @@ module ActiveSupport
|
|
73
81
|
end
|
74
82
|
prepend DupLocalCache
|
75
83
|
|
84
|
+
KEY_MAX_SIZE = 250
|
76
85
|
ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
|
77
86
|
|
78
87
|
# Creates a new Dalli::Client instance with specified addresses and options.
|
@@ -90,22 +99,22 @@ module ActiveSupport
|
|
90
99
|
addresses = nil if addresses.compact.empty?
|
91
100
|
pool_options = retrieve_pool_options(options)
|
92
101
|
|
93
|
-
if pool_options
|
94
|
-
Dalli::Client.new(addresses, options)
|
95
|
-
else
|
96
|
-
ensure_connection_pool_added!
|
102
|
+
if pool_options
|
97
103
|
ConnectionPool.new(pool_options) { Dalli::Client.new(addresses, options.merge(threadsafe: false)) }
|
104
|
+
else
|
105
|
+
Dalli::Client.new(addresses, options)
|
98
106
|
end
|
99
107
|
end
|
100
108
|
|
101
|
-
# Creates a new MemCacheStore object, with the given memcached server
|
109
|
+
# Creates a new +MemCacheStore+ object, with the given memcached server
|
102
110
|
# addresses. Each address is either a host name, or a host-with-port string
|
103
111
|
# in the form of "host_name:port". For example:
|
104
112
|
#
|
105
113
|
# ActiveSupport::Cache::MemCacheStore.new("localhost", "server-downstairs.localnetwork:8229")
|
106
114
|
#
|
107
115
|
# If no addresses are provided, but <tt>ENV['MEMCACHE_SERVERS']</tt> is defined, it will be used instead. Otherwise,
|
108
|
-
# MemCacheStore will connect to localhost:11211 (the default memcached port).
|
116
|
+
# +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.
|
109
118
|
def initialize(*addresses)
|
110
119
|
addresses = addresses.flatten
|
111
120
|
options = addresses.extract_options!
|
@@ -115,19 +124,28 @@ module ActiveSupport
|
|
115
124
|
super(options)
|
116
125
|
|
117
126
|
unless [String, Dalli::Client, NilClass].include?(addresses.first.class)
|
118
|
-
raise ArgumentError, "First argument must be an empty array,
|
127
|
+
raise ArgumentError, "First argument must be an empty array, address, or array of addresses."
|
119
128
|
end
|
120
129
|
if addresses.first.is_a?(Dalli::Client)
|
130
|
+
ActiveSupport.deprecator.warn(<<~MSG)
|
131
|
+
Initializing MemCacheStore with a Dalli::Client is deprecated and will be removed in Rails 7.2.
|
132
|
+
Use memcached server addresses instead.
|
133
|
+
MSG
|
121
134
|
@data = addresses.first
|
122
135
|
else
|
123
|
-
mem_cache_options = options.dup
|
136
|
+
@mem_cache_options = options.dup
|
124
137
|
# The value "compress: false" prevents duplicate compression within Dalli.
|
125
|
-
mem_cache_options[:compress] = false
|
126
|
-
(
|
127
|
-
@data = self.class.build_mem_cache(*(addresses + [mem_cache_options]))
|
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]))
|
128
141
|
end
|
129
142
|
end
|
130
143
|
|
144
|
+
def inspect
|
145
|
+
instance = @data || @mem_cache_options
|
146
|
+
"#<#{self.class} options=#{options.inspect} mem_cache=#{instance.inspect}>"
|
147
|
+
end
|
148
|
+
|
131
149
|
##
|
132
150
|
# :method: write
|
133
151
|
# :call-seq: write(name, value, options = nil)
|
@@ -144,28 +162,50 @@ module ActiveSupport
|
|
144
162
|
# * <tt>unless_exist: true</tt> - Prevents overwriting an existing cache
|
145
163
|
# entry.
|
146
164
|
|
147
|
-
# Increment a cached value
|
148
|
-
#
|
149
|
-
#
|
150
|
-
# to
|
165
|
+
# Increment a cached integer value using the memcached incr atomic operator.
|
166
|
+
# Returns the updated value.
|
167
|
+
#
|
168
|
+
# If the key is unset or has expired, it will be set to +amount+:
|
169
|
+
#
|
170
|
+
# cache.increment("foo") # => 1
|
171
|
+
# cache.increment("bar", 100) # => 100
|
172
|
+
#
|
173
|
+
# To set a specific value, call #write passing <tt>raw: true</tt>:
|
174
|
+
#
|
175
|
+
# cache.write("baz", 5, raw: true)
|
176
|
+
# cache.increment("baz") # => 6
|
177
|
+
#
|
178
|
+
# Incrementing a non-numeric value, or a value written without
|
179
|
+
# <tt>raw: true</tt>, will fail and return +nil+.
|
151
180
|
def increment(name, amount = 1, options = nil)
|
152
181
|
options = merged_options(options)
|
153
182
|
instrument(:increment, name, amount: amount) do
|
154
183
|
rescue_error_with nil do
|
155
|
-
@data.with { |c| c.incr(normalize_key(name, options), amount, options[:expires_in]) }
|
184
|
+
@data.with { |c| c.incr(normalize_key(name, options), amount, options[:expires_in], amount) }
|
156
185
|
end
|
157
186
|
end
|
158
187
|
end
|
159
188
|
|
160
|
-
# Decrement a cached value
|
161
|
-
#
|
162
|
-
#
|
163
|
-
# to
|
189
|
+
# Decrement a cached integer value using the memcached decr atomic operator.
|
190
|
+
# Returns the updated value.
|
191
|
+
#
|
192
|
+
# If the key is unset or has expired, it will be set to 0. Memcached
|
193
|
+
# does not support negative counters.
|
194
|
+
#
|
195
|
+
# cache.decrement("foo") # => 0
|
196
|
+
#
|
197
|
+
# To set a specific value, call #write passing <tt>raw: true</tt>:
|
198
|
+
#
|
199
|
+
# cache.write("baz", 5, raw: true)
|
200
|
+
# cache.decrement("baz") # => 4
|
201
|
+
#
|
202
|
+
# Decrementing a non-numeric value, or a value written without
|
203
|
+
# <tt>raw: true</tt>, will fail and return +nil+.
|
164
204
|
def decrement(name, amount = 1, options = nil)
|
165
205
|
options = merged_options(options)
|
166
206
|
instrument(:decrement, name, amount: amount) do
|
167
207
|
rescue_error_with nil do
|
168
|
-
@data.with { |c| c.decr(normalize_key(name, options), amount, options[:expires_in]) }
|
208
|
+
@data.with { |c| c.decr(normalize_key(name, options), amount, options[:expires_in], 0) }
|
169
209
|
end
|
170
210
|
end
|
171
211
|
end
|
@@ -182,54 +222,20 @@ module ActiveSupport
|
|
182
222
|
end
|
183
223
|
|
184
224
|
private
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
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
|
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
|
226
236
|
end
|
227
237
|
end
|
228
238
|
|
229
|
-
def default_coder
|
230
|
-
Coders[Cache.format_version]
|
231
|
-
end
|
232
|
-
|
233
239
|
# Read an entry from the cache.
|
234
240
|
def read_entry(key, **options)
|
235
241
|
deserialize_entry(read_serialized_entry(key, **options), **options)
|
@@ -264,14 +270,22 @@ module ActiveSupport
|
|
264
270
|
def read_multi_entries(names, **options)
|
265
271
|
keys_to_names = names.index_by { |name| normalize_key(name, options) }
|
266
272
|
|
267
|
-
raw_values =
|
273
|
+
raw_values = begin
|
274
|
+
@data.with { |c| c.get_multi(keys_to_names.keys) }
|
275
|
+
rescue Dalli::UnmarshalError
|
276
|
+
{}
|
277
|
+
end
|
278
|
+
|
268
279
|
values = {}
|
269
280
|
|
270
281
|
raw_values.each do |key, value|
|
271
282
|
entry = deserialize_entry(value, raw: options[:raw])
|
272
283
|
|
273
|
-
unless entry.expired? || entry.mismatched?(normalize_version(keys_to_names[key], options))
|
274
|
-
|
284
|
+
unless entry.nil? || entry.expired? || entry.mismatched?(normalize_version(keys_to_names[key], options))
|
285
|
+
begin
|
286
|
+
values[keys_to_names[key]] = entry.value
|
287
|
+
rescue DeserializationError
|
288
|
+
end
|
275
289
|
end
|
276
290
|
end
|
277
291
|
|
@@ -299,7 +313,13 @@ module ActiveSupport
|
|
299
313
|
if key
|
300
314
|
key = key.dup.force_encoding(Encoding::ASCII_8BIT)
|
301
315
|
key = key.gsub(ESCAPE_KEY_CHARS) { |match| "%#{match.getbyte(0).to_s(16).upcase}" }
|
302
|
-
|
316
|
+
|
317
|
+
if key.size > KEY_MAX_SIZE
|
318
|
+
key_separator = ":hash:"
|
319
|
+
key_hash = ActiveSupport::Digest.hexdigest(key)
|
320
|
+
key_trim_size = KEY_MAX_SIZE - key_separator.size - key_hash.size
|
321
|
+
key = "#{key[0, key_trim_size]}#{key_separator}#{key_hash}"
|
322
|
+
end
|
303
323
|
end
|
304
324
|
key
|
305
325
|
end
|
@@ -315,8 +335,12 @@ module ActiveSupport
|
|
315
335
|
def rescue_error_with(fallback)
|
316
336
|
yield
|
317
337
|
rescue Dalli::DalliError => error
|
318
|
-
ActiveSupport.error_reporter&.report(error, handled: true, severity: :warning)
|
319
338
|
logger.error("DalliError (#{error}): #{error.message}") if logger
|
339
|
+
ActiveSupport.error_reporter&.report(
|
340
|
+
error,
|
341
|
+
severity: :warning,
|
342
|
+
source: "mem_cache_store.active_support",
|
343
|
+
)
|
320
344
|
fallback
|
321
345
|
end
|
322
346
|
end
|