activesupport 5.0.0 → 6.1.0
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 +5 -5
- data/CHANGELOG.md +343 -590
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -4
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/all.rb +5 -3
- data/lib/active_support/array_inquirer.rb +11 -5
- data/lib/active_support/backtrace_cleaner.rb +33 -5
- data/lib/active_support/benchmarkable.rb +5 -3
- data/lib/active_support/builder.rb +3 -1
- data/lib/active_support/cache/file_store.rb +45 -53
- data/lib/active_support/cache/mem_cache_store.rb +81 -79
- data/lib/active_support/cache/memory_store.rb +69 -41
- data/lib/active_support/cache/null_store.rb +11 -4
- data/lib/active_support/cache/redis_cache_store.rb +493 -0
- data/lib/active_support/cache/strategy/local_cache.rb +74 -37
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
- data/lib/active_support/cache.rb +332 -161
- data/lib/active_support/callbacks.rb +657 -586
- data/lib/active_support/concern.rb +79 -6
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -0
- data/lib/active_support/concurrency/share_lock.rb +59 -19
- data/lib/active_support/configurable.rb +15 -17
- data/lib/active_support/configuration_file.rb +46 -0
- data/lib/active_support/core_ext/array/access.rb +21 -7
- data/lib/active_support/core_ext/array/conversions.rb +20 -18
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/array/extract_options.rb +2 -0
- data/lib/active_support/core_ext/array/grouping.rb +3 -1
- data/lib/active_support/core_ext/array/inquiry.rb +3 -1
- data/lib/active_support/core_ext/array/wrap.rb +2 -0
- data/lib/active_support/core_ext/array.rb +9 -7
- data/lib/active_support/core_ext/benchmark.rb +5 -3
- data/lib/active_support/core_ext/big_decimal/conversions.rb +6 -6
- data/lib/active_support/core_ext/big_decimal.rb +3 -1
- data/lib/active_support/core_ext/class/attribute.rb +52 -49
- data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
- data/lib/active_support/core_ext/class/subclasses.rb +18 -26
- data/lib/active_support/core_ext/class.rb +4 -2
- data/lib/active_support/core_ext/date/acts_like.rb +3 -1
- data/lib/active_support/core_ext/date/blank.rb +3 -1
- data/lib/active_support/core_ext/date/calculations.rb +16 -13
- data/lib/active_support/core_ext/date/conversions.rb +23 -21
- data/lib/active_support/core_ext/date/zones.rb +4 -2
- data/lib/active_support/core_ext/date.rb +7 -5
- data/lib/active_support/core_ext/date_and_time/calculations.rb +82 -53
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -5
- data/lib/active_support/core_ext/date_and_time/zones.rb +9 -9
- data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
- data/lib/active_support/core_ext/date_time/blank.rb +3 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +23 -11
- data/lib/active_support/core_ext/date_time/compatibility.rb +15 -2
- data/lib/active_support/core_ext/date_time/conversions.rb +14 -13
- data/lib/active_support/core_ext/date_time.rb +7 -5
- data/lib/active_support/core_ext/digest/uuid.rb +7 -5
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +165 -29
- data/lib/active_support/core_ext/file/atomic.rb +7 -5
- data/lib/active_support/core_ext/file.rb +3 -1
- data/lib/active_support/core_ext/hash/conversions.rb +40 -39
- data/lib/active_support/core_ext/hash/deep_merge.rb +8 -12
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +4 -2
- data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -2
- data/lib/active_support/core_ext/hash/keys.rb +9 -36
- data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
- data/lib/active_support/core_ext/hash/slice.rb +8 -29
- data/lib/active_support/core_ext/hash.rb +10 -9
- data/lib/active_support/core_ext/integer/inflections.rb +3 -1
- data/lib/active_support/core_ext/integer/multiple.rb +3 -1
- data/lib/active_support/core_ext/integer/time.rb +11 -18
- data/lib/active_support/core_ext/integer.rb +5 -3
- data/lib/active_support/core_ext/kernel/concern.rb +3 -1
- data/lib/active_support/core_ext/kernel/reporting.rb +3 -1
- data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
- data/lib/active_support/core_ext/kernel.rb +5 -4
- data/lib/active_support/core_ext/load_error.rb +2 -23
- data/lib/active_support/core_ext/marshal.rb +6 -2
- data/lib/active_support/core_ext/module/aliasing.rb +5 -48
- data/lib/active_support/core_ext/module/anonymous.rb +2 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +7 -5
- data/lib/active_support/core_ext/module/attribute_accessors.rb +53 -59
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +31 -24
- data/lib/active_support/core_ext/module/concerning.rb +16 -11
- data/lib/active_support/core_ext/module/delegation.rb +159 -44
- data/lib/active_support/core_ext/module/deprecation.rb +2 -0
- data/lib/active_support/core_ext/module/introspection.rb +23 -26
- data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
- data/lib/active_support/core_ext/module/remove_method.rb +5 -23
- data/lib/active_support/core_ext/module.rb +13 -12
- data/lib/active_support/core_ext/name_error.rb +36 -2
- data/lib/active_support/core_ext/numeric/bytes.rb +2 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +129 -134
- data/lib/active_support/core_ext/numeric/time.rb +18 -26
- data/lib/active_support/core_ext/numeric.rb +5 -4
- data/lib/active_support/core_ext/object/acts_like.rb +12 -1
- data/lib/active_support/core_ext/object/blank.rb +14 -2
- data/lib/active_support/core_ext/object/conversions.rb +6 -4
- data/lib/active_support/core_ext/object/deep_dup.rb +4 -2
- data/lib/active_support/core_ext/object/duplicable.rb +13 -62
- data/lib/active_support/core_ext/object/inclusion.rb +3 -1
- data/lib/active_support/core_ext/object/instance_variables.rb +2 -0
- data/lib/active_support/core_ext/object/json.rb +42 -15
- data/lib/active_support/core_ext/object/to_param.rb +3 -1
- data/lib/active_support/core_ext/object/to_query.rb +10 -5
- data/lib/active_support/core_ext/object/try.rb +20 -8
- data/lib/active_support/core_ext/object/with_options.rb +15 -2
- data/lib/active_support/core_ext/object.rb +14 -12
- data/lib/active_support/core_ext/range/compare_range.rb +82 -0
- data/lib/active_support/core_ext/range/conversions.rb +35 -25
- data/lib/active_support/core_ext/range/each.rb +5 -2
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +28 -0
- data/lib/active_support/core_ext/range/overlaps.rb +2 -0
- data/lib/active_support/core_ext/range.rb +7 -4
- data/lib/active_support/core_ext/regexp.rb +10 -1
- data/lib/active_support/core_ext/securerandom.rb +28 -6
- data/lib/active_support/core_ext/string/access.rb +9 -18
- data/lib/active_support/core_ext/string/behavior.rb +2 -0
- data/lib/active_support/core_ext/string/conversions.rb +5 -2
- data/lib/active_support/core_ext/string/exclude.rb +2 -0
- data/lib/active_support/core_ext/string/filters.rb +47 -4
- data/lib/active_support/core_ext/string/indent.rb +6 -4
- data/lib/active_support/core_ext/string/inflections.rb +78 -29
- data/lib/active_support/core_ext/string/inquiry.rb +4 -1
- data/lib/active_support/core_ext/string/multibyte.rb +10 -5
- data/lib/active_support/core_ext/string/output_safety.rb +86 -31
- data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
- data/lib/active_support/core_ext/string/strip.rb +5 -1
- data/lib/active_support/core_ext/string/zones.rb +4 -2
- data/lib/active_support/core_ext/string.rb +15 -13
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/time/acts_like.rb +3 -1
- data/lib/active_support/core_ext/time/calculations.rb +117 -45
- data/lib/active_support/core_ext/time/compatibility.rb +13 -2
- data/lib/active_support/core_ext/time/conversions.rb +18 -12
- data/lib/active_support/core_ext/time/zones.rb +9 -7
- data/lib/active_support/core_ext/time.rb +7 -5
- data/lib/active_support/core_ext/uri.rb +12 -7
- data/lib/active_support/core_ext.rb +3 -2
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +208 -0
- data/lib/active_support/dependencies/autoload.rb +2 -0
- data/lib/active_support/dependencies/interlock.rb +7 -1
- data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
- data/lib/active_support/dependencies.rb +172 -98
- data/lib/active_support/deprecation/behaviors.rb +45 -13
- data/lib/active_support/deprecation/constant_accessor.rb +52 -0
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +16 -2
- data/lib/active_support/deprecation/method_wrappers.rb +32 -17
- data/lib/active_support/deprecation/proxy_wrappers.rb +35 -7
- data/lib/active_support/deprecation/reporting.rb +61 -16
- data/lib/active_support/deprecation.rb +17 -9
- data/lib/active_support/descendants_tracker.rb +61 -9
- data/lib/active_support/digest.rb +20 -0
- data/lib/active_support/duration/iso8601_parser.rb +67 -66
- data/lib/active_support/duration/iso8601_serializer.rb +25 -17
- data/lib/active_support/duration.rb +349 -46
- data/lib/active_support/encrypted_configuration.rb +45 -0
- data/lib/active_support/encrypted_file.rb +117 -0
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/evented_file_update_checker.rb +88 -112
- data/lib/active_support/execution_wrapper.rb +25 -13
- data/lib/active_support/executor.rb +3 -1
- data/lib/active_support/file_update_checker.rb +56 -51
- data/lib/active_support/fork_tracker.rb +62 -0
- data/lib/active_support/gem_version.rb +4 -2
- data/lib/active_support/gzip.rb +7 -5
- data/lib/active_support/hash_with_indifferent_access.rb +153 -49
- data/lib/active_support/i18n.rb +9 -6
- data/lib/active_support/i18n_railtie.rb +30 -20
- data/lib/active_support/inflections.rb +13 -11
- data/lib/active_support/inflector/inflections.rb +28 -15
- data/lib/active_support/inflector/methods.rb +120 -109
- data/lib/active_support/inflector/transliterate.rb +60 -25
- data/lib/active_support/inflector.rb +7 -5
- data/lib/active_support/json/decoding.rb +30 -29
- data/lib/active_support/json/encoding.rb +22 -11
- data/lib/active_support/json.rb +4 -2
- data/lib/active_support/key_generator.rb +6 -36
- data/lib/active_support/lazy_load_hooks.rb +53 -20
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/locale/en.yml +7 -3
- data/lib/active_support/log_subscriber/test_helper.rb +11 -9
- data/lib/active_support/log_subscriber.rb +51 -18
- data/lib/active_support/logger.rb +9 -22
- data/lib/active_support/logger_silence.rb +14 -21
- data/lib/active_support/logger_thread_safe_level.rb +55 -8
- data/lib/active_support/message_encryptor.rb +170 -53
- data/lib/active_support/message_verifier.rb +91 -20
- data/lib/active_support/messages/metadata.rb +80 -0
- data/lib/active_support/messages/rotation_configuration.rb +23 -0
- data/lib/active_support/messages/rotator.rb +57 -0
- data/lib/active_support/multibyte/chars.rb +24 -78
- data/lib/active_support/multibyte/unicode.rb +21 -352
- data/lib/active_support/multibyte.rb +4 -2
- data/lib/active_support/notifications/fanout.rb +121 -19
- data/lib/active_support/notifications/instrumenter.rb +78 -14
- data/lib/active_support/notifications.rb +80 -12
- data/lib/active_support/number_helper/number_converter.rb +17 -16
- data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -9
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +5 -3
- data/lib/active_support/number_helper/number_to_human_converter.rb +13 -12
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +11 -13
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +5 -4
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +18 -55
- data/lib/active_support/number_helper/rounding_helper.rb +50 -0
- data/lib/active_support/number_helper.rb +45 -16
- data/lib/active_support/option_merger.rb +25 -4
- data/lib/active_support/ordered_hash.rb +6 -4
- data/lib/active_support/ordered_options.rb +23 -9
- data/lib/active_support/parameter_filter.rb +133 -0
- data/lib/active_support/per_thread_registry.rb +7 -5
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/rails.rb +8 -9
- data/lib/active_support/railtie.rb +62 -11
- data/lib/active_support/reloader.rb +12 -11
- data/lib/active_support/rescuable.rb +20 -11
- data/lib/active_support/secure_compare_rotator.rb +51 -0
- data/lib/active_support/security_utils.rb +26 -15
- data/lib/active_support/string_inquirer.rb +12 -3
- data/lib/active_support/subscriber.rb +77 -23
- data/lib/active_support/tagged_logging.rb +52 -17
- data/lib/active_support/test_case.rb +106 -29
- data/lib/active_support/testing/assertions.rb +144 -8
- data/lib/active_support/testing/autorun.rb +5 -10
- data/lib/active_support/testing/constant_lookup.rb +2 -1
- data/lib/active_support/testing/declarative.rb +3 -1
- data/lib/active_support/testing/deprecation.rb +4 -2
- data/lib/active_support/testing/file_fixtures.rb +4 -0
- data/lib/active_support/testing/isolation.rb +19 -24
- data/lib/active_support/testing/method_call_assertions.rb +31 -2
- data/lib/active_support/testing/parallelization/server.rb +78 -0
- data/lib/active_support/testing/parallelization/worker.rb +100 -0
- data/lib/active_support/testing/parallelization.rb +51 -0
- data/lib/active_support/testing/setup_and_teardown.rb +13 -8
- data/lib/active_support/testing/stream.rb +30 -29
- data/lib/active_support/testing/tagged_logging.rb +3 -1
- data/lib/active_support/testing/time_helpers.rb +125 -24
- data/lib/active_support/time.rb +14 -12
- data/lib/active_support/time_with_zone.rb +142 -55
- data/lib/active_support/values/time_zone.rb +160 -53
- data/lib/active_support/version.rb +3 -1
- data/lib/active_support/xml_mini/jdom.rb +115 -114
- data/lib/active_support/xml_mini/libxml.rb +15 -14
- data/lib/active_support/xml_mini/libxmlsax.rb +16 -18
- data/lib/active_support/xml_mini/nokogiri.rb +13 -13
- data/lib/active_support/xml_mini/nokogirisax.rb +15 -16
- data/lib/active_support/xml_mini/rexml.rb +18 -9
- data/lib/active_support/xml_mini.rb +44 -42
- data/lib/active_support.rb +19 -10
- metadata +79 -37
- data/lib/active_support/concurrency/latch.rb +0 -19
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
- data/lib/active_support/core_ext/hash/compact.rb +0 -20
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -29
- data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
- data/lib/active_support/core_ext/kernel/debugger.rb +0 -3
- data/lib/active_support/core_ext/module/method_transplanting.rb +0 -3
- data/lib/active_support/core_ext/module/qualified_const.rb +0 -70
- data/lib/active_support/core_ext/module/reachable.rb +0 -8
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -26
- data/lib/active_support/core_ext/range/include_range.rb +0 -23
- data/lib/active_support/core_ext/struct.rb +0 -3
- data/lib/active_support/core_ext/time/marshal.rb +0 -3
- data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,18 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
begin
|
2
|
-
require
|
4
|
+
require "dalli"
|
3
5
|
rescue LoadError => e
|
4
6
|
$stderr.puts "You don't have dalli installed in your application. Please add it to your Gemfile and run bundle install"
|
5
7
|
raise e
|
6
8
|
end
|
7
9
|
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
10
|
+
require "active_support/core_ext/enumerable"
|
11
|
+
require "active_support/core_ext/marshal"
|
12
|
+
require "active_support/core_ext/array/extract_options"
|
11
13
|
|
12
14
|
module ActiveSupport
|
13
15
|
module Cache
|
14
16
|
# A cache store implementation which stores data in Memcached:
|
15
|
-
#
|
17
|
+
# https://memcached.org
|
16
18
|
#
|
17
19
|
# This is currently the most popular cache store for production websites.
|
18
20
|
#
|
@@ -24,26 +26,25 @@ module ActiveSupport
|
|
24
26
|
# MemCacheStore implements the Strategy::LocalCache strategy which implements
|
25
27
|
# an in-memory cache inside of a block.
|
26
28
|
class MemCacheStore < Store
|
29
|
+
DEFAULT_CODER = NullCoder # Dalli automatically Marshal values
|
30
|
+
|
27
31
|
# Provide support for raw values in the local cache strategy.
|
28
32
|
module LocalCacheWithRaw # :nodoc:
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
33
|
+
private
|
34
|
+
def write_entry(key, entry, **options)
|
35
|
+
if options[:raw] && local_cache
|
36
|
+
raw_entry = Entry.new(entry.value.to_s)
|
37
|
+
raw_entry.expires_at = entry.expires_at
|
38
|
+
super(key, raw_entry, **options)
|
39
|
+
else
|
40
|
+
super
|
41
|
+
end
|
34
42
|
end
|
35
|
-
|
36
|
-
end
|
43
|
+
end
|
37
44
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
raw_entry.expires_at = entry.expires_at
|
42
|
-
super(key, raw_entry, options)
|
43
|
-
else
|
44
|
-
super
|
45
|
-
end
|
46
|
-
end
|
45
|
+
# Advertise cache versioning support.
|
46
|
+
def self.supports_cache_versioning?
|
47
|
+
true
|
47
48
|
end
|
48
49
|
|
49
50
|
prepend Strategy::LocalCache
|
@@ -52,17 +53,26 @@ module ActiveSupport
|
|
52
53
|
ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
|
53
54
|
|
54
55
|
# Creates a new Dalli::Client instance with specified addresses and options.
|
55
|
-
#
|
56
|
+
# If no addresses are provided, we give nil to Dalli::Client, so it uses its fallbacks:
|
57
|
+
# - ENV["MEMCACHE_SERVERS"] (if defined)
|
58
|
+
# - "127.0.0.1:11211" (otherwise)
|
56
59
|
#
|
57
60
|
# ActiveSupport::Cache::MemCacheStore.build_mem_cache
|
58
|
-
# # => #<Dalli::Client:0x007f98a47d2028 @servers=["
|
61
|
+
# # => #<Dalli::Client:0x007f98a47d2028 @servers=["127.0.0.1:11211"], @options={}, @ring=nil>
|
59
62
|
# ActiveSupport::Cache::MemCacheStore.build_mem_cache('localhost:10290')
|
60
63
|
# # => #<Dalli::Client:0x007f98a47b3a60 @servers=["localhost:10290"], @options={}, @ring=nil>
|
61
64
|
def self.build_mem_cache(*addresses) # :nodoc:
|
62
65
|
addresses = addresses.flatten
|
63
66
|
options = addresses.extract_options!
|
64
|
-
addresses =
|
65
|
-
|
67
|
+
addresses = nil if addresses.empty?
|
68
|
+
pool_options = retrieve_pool_options(options)
|
69
|
+
|
70
|
+
if pool_options.empty?
|
71
|
+
Dalli::Client.new(addresses, options)
|
72
|
+
else
|
73
|
+
ensure_connection_pool_added!
|
74
|
+
ConnectionPool.new(pool_options) { Dalli::Client.new(addresses, options.merge(threadsafe: false)) }
|
75
|
+
end
|
66
76
|
end
|
67
77
|
|
68
78
|
# Creates a new MemCacheStore object, with the given memcached server
|
@@ -71,8 +81,8 @@ module ActiveSupport
|
|
71
81
|
#
|
72
82
|
# ActiveSupport::Cache::MemCacheStore.new("localhost", "server-downstairs.localnetwork:8229")
|
73
83
|
#
|
74
|
-
# If no addresses are
|
75
|
-
#
|
84
|
+
# If no addresses are provided, but ENV['MEMCACHE_SERVERS'] is defined, it will be used instead. Otherwise,
|
85
|
+
# MemCacheStore will connect to localhost:11211 (the default memcached port).
|
76
86
|
def initialize(*addresses)
|
77
87
|
addresses = addresses.flatten
|
78
88
|
options = addresses.extract_options!
|
@@ -85,36 +95,20 @@ module ActiveSupport
|
|
85
95
|
@data = addresses.first
|
86
96
|
else
|
87
97
|
mem_cache_options = options.dup
|
88
|
-
UNIVERSAL_OPTIONS.each{|name| mem_cache_options.delete(name)}
|
98
|
+
UNIVERSAL_OPTIONS.each { |name| mem_cache_options.delete(name) }
|
89
99
|
@data = self.class.build_mem_cache(*(addresses + [mem_cache_options]))
|
90
100
|
end
|
91
101
|
end
|
92
102
|
|
93
|
-
# Reads multiple values from the cache using a single call to the
|
94
|
-
# servers for all keys. Options can be passed in the last argument.
|
95
|
-
def read_multi(*names)
|
96
|
-
options = names.extract_options!
|
97
|
-
options = merged_options(options)
|
98
|
-
|
99
|
-
keys_to_names = Hash[names.map{|name| [normalize_key(name, options), name]}]
|
100
|
-
raw_values = @data.get_multi(keys_to_names.keys, :raw => true)
|
101
|
-
values = {}
|
102
|
-
raw_values.each do |key, value|
|
103
|
-
entry = deserialize_entry(value)
|
104
|
-
values[keys_to_names[key]] = entry.value unless entry.expired?
|
105
|
-
end
|
106
|
-
values
|
107
|
-
end
|
108
|
-
|
109
103
|
# Increment a cached value. This method uses the memcached incr atomic
|
110
104
|
# operator and can only be used on values written with the :raw option.
|
111
105
|
# Calling it on a value not stored with :raw will initialize that value
|
112
106
|
# to zero.
|
113
|
-
def increment(name, amount = 1, options = nil)
|
107
|
+
def increment(name, amount = 1, options = nil)
|
114
108
|
options = merged_options(options)
|
115
|
-
instrument(:increment, name, :
|
109
|
+
instrument(:increment, name, amount: amount) do
|
116
110
|
rescue_error_with nil do
|
117
|
-
@data.incr(normalize_key(name, options), amount)
|
111
|
+
@data.with { |c| c.incr(normalize_key(name, options), amount, options[:expires_in]) }
|
118
112
|
end
|
119
113
|
end
|
120
114
|
end
|
@@ -123,11 +117,11 @@ module ActiveSupport
|
|
123
117
|
# operator and can only be used on values written with the :raw option.
|
124
118
|
# Calling it on a value not stored with :raw will initialize that value
|
125
119
|
# to zero.
|
126
|
-
def decrement(name, amount = 1, options = nil)
|
120
|
+
def decrement(name, amount = 1, options = nil)
|
127
121
|
options = merged_options(options)
|
128
|
-
instrument(:decrement, name, :
|
122
|
+
instrument(:decrement, name, amount: amount) do
|
129
123
|
rescue_error_with nil do
|
130
|
-
@data.decr(normalize_key(name, options), amount)
|
124
|
+
@data.with { |c| c.decr(normalize_key(name, options), amount, options[:expires_in]) }
|
131
125
|
end
|
132
126
|
end
|
133
127
|
end
|
@@ -135,40 +129,57 @@ module ActiveSupport
|
|
135
129
|
# Clear the entire cache on all memcached servers. This method should
|
136
130
|
# be used with care when shared cache is being used.
|
137
131
|
def clear(options = nil)
|
138
|
-
rescue_error_with(nil) { @data.flush_all }
|
132
|
+
rescue_error_with(nil) { @data.with { |c| c.flush_all } }
|
139
133
|
end
|
140
134
|
|
141
135
|
# Get the statistics from the memcached servers.
|
142
136
|
def stats
|
143
|
-
@data.stats
|
137
|
+
@data.with { |c| c.stats }
|
144
138
|
end
|
145
139
|
|
146
|
-
|
140
|
+
private
|
147
141
|
# Read an entry from the cache.
|
148
|
-
def read_entry(key, options)
|
149
|
-
rescue_error_with(nil) { deserialize_entry(@data.get(key, options)) }
|
142
|
+
def read_entry(key, **options)
|
143
|
+
rescue_error_with(nil) { deserialize_entry(@data.with { |c| c.get(key, options) }) }
|
150
144
|
end
|
151
145
|
|
152
146
|
# Write an entry to the cache.
|
153
|
-
def write_entry(key, entry, options)
|
154
|
-
method = options
|
155
|
-
value = options[:raw] ? entry.value.to_s : entry
|
147
|
+
def write_entry(key, entry, **options)
|
148
|
+
method = options[:unless_exist] ? :add : :set
|
149
|
+
value = options[:raw] ? entry.value.to_s : serialize_entry(entry)
|
156
150
|
expires_in = options[:expires_in].to_i
|
157
|
-
if expires_in > 0 && !options[:raw]
|
151
|
+
if options[:race_condition_ttl] && expires_in > 0 && !options[:raw]
|
158
152
|
# Set the memcache expire a few minutes in the future to support race condition ttls on read
|
159
153
|
expires_in += 5.minutes
|
160
154
|
end
|
161
155
|
rescue_error_with false do
|
162
|
-
|
156
|
+
# The value "compress: false" prevents duplicate compression within Dalli.
|
157
|
+
@data.with { |c| c.send(method, key, value, expires_in, **options, compress: false) }
|
163
158
|
end
|
164
159
|
end
|
165
160
|
|
166
|
-
#
|
167
|
-
def
|
168
|
-
|
161
|
+
# Reads multiple entries from the cache implementation.
|
162
|
+
def read_multi_entries(names, **options)
|
163
|
+
keys_to_names = names.index_by { |name| normalize_key(name, options) }
|
164
|
+
|
165
|
+
raw_values = @data.with { |c| c.get_multi(keys_to_names.keys) }
|
166
|
+
values = {}
|
167
|
+
|
168
|
+
raw_values.each do |key, value|
|
169
|
+
entry = deserialize_entry(value)
|
170
|
+
|
171
|
+
unless entry.expired? || entry.mismatched?(normalize_version(keys_to_names[key], options))
|
172
|
+
values[keys_to_names[key]] = entry.value
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
values
|
169
177
|
end
|
170
178
|
|
171
|
-
|
179
|
+
# Delete an entry from the cache.
|
180
|
+
def delete_entry(key, **options)
|
181
|
+
rescue_error_with(false) { @data.with { |c| c.delete(key) } }
|
182
|
+
end
|
172
183
|
|
173
184
|
# Memcache keys are binaries. So we need to force their encoding to binary
|
174
185
|
# before applying the regular expression to ensure we are escaping all
|
@@ -176,24 +187,15 @@ module ActiveSupport
|
|
176
187
|
def normalize_key(key, options)
|
177
188
|
key = super.dup
|
178
189
|
key = key.force_encoding(Encoding::ASCII_8BIT)
|
179
|
-
key = key.gsub(ESCAPE_KEY_CHARS){ |match| "%#{match.getbyte(0).to_s(16).upcase}" }
|
180
|
-
key = "#{key[0, 213]}:md5:#{Digest
|
181
|
-
key
|
182
|
-
end
|
183
|
-
|
184
|
-
def escape_key(key)
|
185
|
-
ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
|
186
|
-
`escape_key` is deprecated and will be removed from Rails 5.1.
|
187
|
-
Please use `normalize_key` which will return a fully resolved key or nothing.
|
188
|
-
MESSAGE
|
190
|
+
key = key.gsub(ESCAPE_KEY_CHARS) { |match| "%#{match.getbyte(0).to_s(16).upcase}" }
|
191
|
+
key = "#{key[0, 213]}:md5:#{ActiveSupport::Digest.hexdigest(key)}" if key.size > 250
|
189
192
|
key
|
190
193
|
end
|
191
194
|
|
192
|
-
def deserialize_entry(
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
end
|
195
|
+
def deserialize_entry(payload)
|
196
|
+
entry = super
|
197
|
+
entry = Entry.new(entry, compress: false) if entry && !entry.is_a?(Entry)
|
198
|
+
entry
|
197
199
|
end
|
198
200
|
|
199
201
|
def rescue_error_with(fallback)
|
@@ -1,10 +1,12 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "monitor"
|
2
4
|
|
3
5
|
module ActiveSupport
|
4
6
|
module Cache
|
5
7
|
# A cache store implementation which stores everything into memory in the
|
6
8
|
# same process. If you're running multiple Ruby on Rails server processes
|
7
|
-
# (which is the case if you're using
|
9
|
+
# (which is the case if you're using Phusion Passenger or puma clustered mode),
|
8
10
|
# then this means that Rails server process instances won't be able
|
9
11
|
# to share cache data with each other and this may not be the most
|
10
12
|
# appropriate cache in that scenario.
|
@@ -14,13 +16,37 @@ module ActiveSupport
|
|
14
16
|
# a cleanup will occur which tries to prune the cache down to three quarters
|
15
17
|
# of the maximum size by removing the least recently used entries.
|
16
18
|
#
|
19
|
+
# Unlike other Cache store implementations, MemoryStore does not compress
|
20
|
+
# values by default. MemoryStore does not benefit from compression as much
|
21
|
+
# as other Store implementations, as it does not send data over a network.
|
22
|
+
# However, when compression is enabled, it still pays the full cost of
|
23
|
+
# compression in terms of cpu use.
|
24
|
+
#
|
17
25
|
# MemoryStore is thread-safe.
|
18
26
|
class MemoryStore < Store
|
27
|
+
module DupCoder # :nodoc:
|
28
|
+
class << self
|
29
|
+
def load(entry)
|
30
|
+
entry = entry.dup
|
31
|
+
entry.dup_value!
|
32
|
+
entry
|
33
|
+
end
|
34
|
+
|
35
|
+
def dump(entry)
|
36
|
+
entry.dup_value!
|
37
|
+
entry
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
DEFAULT_CODER = DupCoder
|
43
|
+
|
19
44
|
def initialize(options = nil)
|
20
45
|
options ||= {}
|
46
|
+
# Disable compression by default.
|
47
|
+
options[:compress] ||= false
|
21
48
|
super(options)
|
22
49
|
@data = {}
|
23
|
-
@key_access = {}
|
24
50
|
@max_size = options[:size] || 32.megabytes
|
25
51
|
@max_prune_time = options[:max_prune_time] || 2
|
26
52
|
@cache_size = 0
|
@@ -28,10 +54,15 @@ module ActiveSupport
|
|
28
54
|
@pruning = false
|
29
55
|
end
|
30
56
|
|
57
|
+
# Advertise cache versioning support.
|
58
|
+
def self.supports_cache_versioning?
|
59
|
+
true
|
60
|
+
end
|
61
|
+
|
62
|
+
# Delete all data stored in a given cache store.
|
31
63
|
def clear(options = nil)
|
32
64
|
synchronize do
|
33
65
|
@data.clear
|
34
|
-
@key_access.clear
|
35
66
|
@cache_size = 0
|
36
67
|
end
|
37
68
|
end
|
@@ -39,11 +70,11 @@ module ActiveSupport
|
|
39
70
|
# Preemptively iterates through all stored keys and removes the ones which have expired.
|
40
71
|
def cleanup(options = nil)
|
41
72
|
options = merged_options(options)
|
42
|
-
instrument(:cleanup, :
|
43
|
-
keys = synchronize{ @data.keys }
|
73
|
+
instrument(:cleanup, size: @data.size) do
|
74
|
+
keys = synchronize { @data.keys }
|
44
75
|
keys.each do |key|
|
45
76
|
entry = @data[key]
|
46
|
-
delete_entry(key, options) if entry && entry.expired?
|
77
|
+
delete_entry(key, **options) if entry && entry.expired?
|
47
78
|
end
|
48
79
|
end
|
49
80
|
end
|
@@ -54,13 +85,13 @@ module ActiveSupport
|
|
54
85
|
return if pruning?
|
55
86
|
@pruning = true
|
56
87
|
begin
|
57
|
-
start_time =
|
88
|
+
start_time = Concurrent.monotonic_time
|
58
89
|
cleanup
|
59
|
-
instrument(:prune, target_size, :
|
60
|
-
keys = synchronize{ @
|
90
|
+
instrument(:prune, target_size, from: @cache_size) do
|
91
|
+
keys = synchronize { @data.keys }
|
61
92
|
keys.each do |key|
|
62
|
-
delete_entry(key, options)
|
63
|
-
return if @cache_size <= target_size || (max_time &&
|
93
|
+
delete_entry(key, **options)
|
94
|
+
return if @cache_size <= target_size || (max_time && Concurrent.monotonic_time - start_time > max_time)
|
64
95
|
end
|
65
96
|
end
|
66
97
|
ensure
|
@@ -83,19 +114,20 @@ module ActiveSupport
|
|
83
114
|
modify_value(name, -amount, options)
|
84
115
|
end
|
85
116
|
|
117
|
+
# Deletes cache entries if the cache key matches a given pattern.
|
86
118
|
def delete_matched(matcher, options = nil)
|
87
119
|
options = merged_options(options)
|
88
120
|
instrument(:delete_matched, matcher.inspect) do
|
89
121
|
matcher = key_matcher(matcher, options)
|
90
122
|
keys = synchronize { @data.keys }
|
91
123
|
keys.each do |key|
|
92
|
-
delete_entry(key, options) if key.match(matcher)
|
124
|
+
delete_entry(key, **options) if key.match(matcher)
|
93
125
|
end
|
94
126
|
end
|
95
127
|
end
|
96
128
|
|
97
129
|
def inspect # :nodoc:
|
98
|
-
"
|
130
|
+
"#<#{self.class.name} entries=#{@data.size}, size=#{@cache_size}, options=#{@options.inspect}>"
|
99
131
|
end
|
100
132
|
|
101
133
|
# Synchronize calls to the cache. This should be called wherever the underlying cache implementation
|
@@ -104,57 +136,53 @@ module ActiveSupport
|
|
104
136
|
@monitor.synchronize(&block)
|
105
137
|
end
|
106
138
|
|
107
|
-
|
108
|
-
|
139
|
+
private
|
109
140
|
PER_ENTRY_OVERHEAD = 240
|
110
141
|
|
111
|
-
def cached_size(key,
|
112
|
-
key.to_s.bytesize +
|
142
|
+
def cached_size(key, payload)
|
143
|
+
key.to_s.bytesize + payload.bytesize + PER_ENTRY_OVERHEAD
|
113
144
|
end
|
114
145
|
|
115
|
-
def read_entry(key, options)
|
116
|
-
entry =
|
146
|
+
def read_entry(key, **options)
|
147
|
+
entry = nil
|
117
148
|
synchronize do
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
149
|
+
payload = @data.delete(key)
|
150
|
+
if payload
|
151
|
+
@data[key] = payload
|
152
|
+
entry = deserialize_entry(payload)
|
122
153
|
end
|
123
154
|
end
|
124
155
|
entry
|
125
156
|
end
|
126
157
|
|
127
|
-
def write_entry(key, entry, options)
|
128
|
-
entry
|
158
|
+
def write_entry(key, entry, **options)
|
159
|
+
payload = serialize_entry(entry)
|
129
160
|
synchronize do
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
161
|
+
return false if options[:unless_exist] && @data.key?(key)
|
162
|
+
|
163
|
+
old_payload = @data[key]
|
164
|
+
if old_payload
|
165
|
+
@cache_size -= (old_payload.bytesize - payload.bytesize)
|
134
166
|
else
|
135
|
-
@cache_size += cached_size(key,
|
167
|
+
@cache_size += cached_size(key, payload)
|
136
168
|
end
|
137
|
-
@
|
138
|
-
@data[key] = entry
|
169
|
+
@data[key] = payload
|
139
170
|
prune(@max_size * 0.75, @max_prune_time) if @cache_size > @max_size
|
140
171
|
true
|
141
172
|
end
|
142
173
|
end
|
143
174
|
|
144
|
-
def delete_entry(key, options)
|
175
|
+
def delete_entry(key, **options)
|
145
176
|
synchronize do
|
146
|
-
@
|
147
|
-
|
148
|
-
|
149
|
-
!!entry
|
177
|
+
payload = @data.delete(key)
|
178
|
+
@cache_size -= cached_size(key, payload) if payload
|
179
|
+
!!payload
|
150
180
|
end
|
151
181
|
end
|
152
182
|
|
153
|
-
private
|
154
|
-
|
155
183
|
def modify_value(name, amount, options)
|
184
|
+
options = merged_options(options)
|
156
185
|
synchronize do
|
157
|
-
options = merged_options(options)
|
158
186
|
if num = read(name, options)
|
159
187
|
num = num.to_i + amount
|
160
188
|
write(name, num, options)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveSupport
|
2
4
|
module Cache
|
3
5
|
# A cache store implementation which doesn't actually store anything. Useful in
|
@@ -10,6 +12,11 @@ module ActiveSupport
|
|
10
12
|
class NullStore < Store
|
11
13
|
prepend Strategy::LocalCache
|
12
14
|
|
15
|
+
# Advertise cache versioning support.
|
16
|
+
def self.supports_cache_versioning?
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
13
20
|
def clear(options = nil)
|
14
21
|
end
|
15
22
|
|
@@ -25,15 +32,15 @@ module ActiveSupport
|
|
25
32
|
def delete_matched(matcher, options = nil)
|
26
33
|
end
|
27
34
|
|
28
|
-
|
29
|
-
def read_entry(key, options)
|
35
|
+
private
|
36
|
+
def read_entry(key, **options)
|
30
37
|
end
|
31
38
|
|
32
|
-
def write_entry(key, entry, options)
|
39
|
+
def write_entry(key, entry, **options)
|
33
40
|
true
|
34
41
|
end
|
35
42
|
|
36
|
-
def delete_entry(key, options)
|
43
|
+
def delete_entry(key, **options)
|
37
44
|
false
|
38
45
|
end
|
39
46
|
end
|