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
data/lib/active_support/cache.rb
CHANGED
@@ -1,29 +1,31 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "zlib"
|
4
|
+
require "active_support/core_ext/array/extract_options"
|
5
|
+
require "active_support/core_ext/array/wrap"
|
6
|
+
require "active_support/core_ext/enumerable"
|
7
|
+
require "active_support/core_ext/module/attribute_accessors"
|
8
|
+
require "active_support/core_ext/numeric/bytes"
|
9
|
+
require "active_support/core_ext/numeric/time"
|
10
|
+
require "active_support/core_ext/object/to_param"
|
11
|
+
require "active_support/core_ext/object/try"
|
12
|
+
require "active_support/core_ext/string/inflections"
|
12
13
|
|
13
14
|
module ActiveSupport
|
14
15
|
# See ActiveSupport::Cache::Store for documentation.
|
15
16
|
module Cache
|
16
|
-
autoload :FileStore,
|
17
|
-
autoload :MemoryStore,
|
18
|
-
autoload :MemCacheStore,
|
19
|
-
autoload :NullStore,
|
17
|
+
autoload :FileStore, "active_support/cache/file_store"
|
18
|
+
autoload :MemoryStore, "active_support/cache/memory_store"
|
19
|
+
autoload :MemCacheStore, "active_support/cache/mem_cache_store"
|
20
|
+
autoload :NullStore, "active_support/cache/null_store"
|
21
|
+
autoload :RedisCacheStore, "active_support/cache/redis_cache_store"
|
20
22
|
|
21
23
|
# These options mean something to all cache implementations. Individual cache
|
22
24
|
# implementations may support additional options.
|
23
|
-
UNIVERSAL_OPTIONS = [:namespace, :compress, :compress_threshold, :expires_in, :race_condition_ttl]
|
25
|
+
UNIVERSAL_OPTIONS = [:namespace, :compress, :compress_threshold, :expires_in, :race_condition_ttl, :coder]
|
24
26
|
|
25
27
|
module Strategy
|
26
|
-
autoload :LocalCache,
|
28
|
+
autoload :LocalCache, "active_support/cache/strategy/local_cache"
|
27
29
|
end
|
28
30
|
|
29
31
|
class << self
|
@@ -52,12 +54,13 @@ module ActiveSupport
|
|
52
54
|
#
|
53
55
|
# ActiveSupport::Cache.lookup_store(MyOwnCacheStore.new)
|
54
56
|
# # => returns MyOwnCacheStore.new
|
55
|
-
def lookup_store(*
|
56
|
-
store, *parameters = *Array.wrap(store_option).flatten
|
57
|
-
|
57
|
+
def lookup_store(store = nil, *parameters)
|
58
58
|
case store
|
59
59
|
when Symbol
|
60
|
-
|
60
|
+
options = parameters.extract_options!
|
61
|
+
retrieve_store_class(store).new(*parameters, **options)
|
62
|
+
when Array
|
63
|
+
lookup_store(*store)
|
61
64
|
when nil
|
62
65
|
ActiveSupport::Cache::MemoryStore.new
|
63
66
|
else
|
@@ -73,12 +76,12 @@ module ActiveSupport
|
|
73
76
|
# each of elements in the array will be turned into parameters/keys and
|
74
77
|
# concatenated into a single key. For example:
|
75
78
|
#
|
76
|
-
# expand_cache_key([:foo, :bar]) # => "foo/bar"
|
77
|
-
# expand_cache_key([:foo, :bar], "namespace") # => "namespace/foo/bar"
|
79
|
+
# ActiveSupport::Cache.expand_cache_key([:foo, :bar]) # => "foo/bar"
|
80
|
+
# ActiveSupport::Cache.expand_cache_key([:foo, :bar], "namespace") # => "namespace/foo/bar"
|
78
81
|
#
|
79
82
|
# The +key+ argument can also respond to +cache_key+ or +to_param+.
|
80
83
|
def expand_cache_key(key, namespace = nil)
|
81
|
-
expanded_cache_key = namespace ? "#{namespace}/" : ""
|
84
|
+
expanded_cache_key = namespace ? +"#{namespace}/" : +""
|
82
85
|
|
83
86
|
if prefix = ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]
|
84
87
|
expanded_cache_key << "#{prefix}/"
|
@@ -91,16 +94,19 @@ module ActiveSupport
|
|
91
94
|
private
|
92
95
|
def retrieve_cache_key(key)
|
93
96
|
case
|
94
|
-
when key.respond_to?(:
|
95
|
-
when key.
|
96
|
-
when key.
|
97
|
-
|
97
|
+
when key.respond_to?(:cache_key_with_version) then key.cache_key_with_version
|
98
|
+
when key.respond_to?(:cache_key) then key.cache_key
|
99
|
+
when key.is_a?(Array) then key.map { |element| retrieve_cache_key(element) }.to_param
|
100
|
+
when key.respond_to?(:to_a) then retrieve_cache_key(key.to_a)
|
101
|
+
else key.to_param
|
98
102
|
end.to_s
|
99
103
|
end
|
100
104
|
|
101
105
|
# Obtains the specified cache store class, given the name of the +store+.
|
102
106
|
# Raises an error when the store class cannot be found.
|
103
107
|
def retrieve_store_class(store)
|
108
|
+
# require_relative cannot be used here because the class might be
|
109
|
+
# provided by another gem, like redis-activesupport for example.
|
104
110
|
require "active_support/cache/#{store}"
|
105
111
|
rescue LoadError => e
|
106
112
|
raise "Could not find cache store adapter for #{store} (#{e})"
|
@@ -146,23 +152,42 @@ module ActiveSupport
|
|
146
152
|
# cache.namespace = -> { @last_mod_time } # Set the namespace to a variable
|
147
153
|
# @last_mod_time = Time.now # Invalidate the entire cache by changing namespace
|
148
154
|
#
|
149
|
-
#
|
150
|
-
#
|
151
|
-
#
|
152
|
-
# <tt
|
153
|
-
#
|
154
|
-
# <tt>:compress_threshold</tt> option. The default threshold is 16K.
|
155
|
+
# Cached data larger than 1kB are compressed by default. To turn off
|
156
|
+
# compression, pass <tt>compress: false</tt> to the initializer or to
|
157
|
+
# individual +fetch+ or +write+ method calls. The 1kB compression
|
158
|
+
# threshold is configurable with the <tt>:compress_threshold</tt> option,
|
159
|
+
# specified in bytes.
|
155
160
|
class Store
|
156
|
-
|
161
|
+
DEFAULT_CODER = Marshal
|
162
|
+
|
163
|
+
cattr_accessor :logger, instance_writer: true
|
157
164
|
|
158
165
|
attr_reader :silence, :options
|
159
166
|
alias :silence? :silence
|
160
167
|
|
168
|
+
class << self
|
169
|
+
private
|
170
|
+
def retrieve_pool_options(options)
|
171
|
+
{}.tap do |pool_options|
|
172
|
+
pool_options[:size] = options.delete(:pool_size) if options[:pool_size]
|
173
|
+
pool_options[:timeout] = options.delete(:pool_timeout) if options[:pool_timeout]
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def ensure_connection_pool_added!
|
178
|
+
require "connection_pool"
|
179
|
+
rescue LoadError => e
|
180
|
+
$stderr.puts "You don't have connection_pool installed in your application. Please add it to your Gemfile and run bundle install"
|
181
|
+
raise e
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
161
185
|
# Creates a new cache. The options will be passed to any write method calls
|
162
186
|
# except for <tt>:namespace</tt> which can be used to set the global
|
163
187
|
# namespace for the cache.
|
164
188
|
def initialize(options = nil)
|
165
189
|
@options = options ? options.dup : {}
|
190
|
+
@coder = @options.delete(:coder) { self.class::DEFAULT_CODER } || NullCoder
|
166
191
|
end
|
167
192
|
|
168
193
|
# Silences the logger.
|
@@ -200,18 +225,25 @@ module ActiveSupport
|
|
200
225
|
# You may also specify additional options via the +options+ argument.
|
201
226
|
# Setting <tt>force: true</tt> forces a cache "miss," meaning we treat
|
202
227
|
# the cache value as missing even if it's present. Passing a block is
|
203
|
-
# required when
|
228
|
+
# required when +force+ is true so this always results in a cache write.
|
204
229
|
#
|
205
230
|
# cache.write('today', 'Monday')
|
206
231
|
# cache.fetch('today', force: true) { 'Tuesday' } # => 'Tuesday'
|
207
232
|
# cache.fetch('today', force: true) # => ArgumentError
|
208
233
|
#
|
209
|
-
# The
|
234
|
+
# The +:force+ option is useful when you're calling some other method to
|
210
235
|
# ask whether you should force a cache write. Otherwise, it's clearer to
|
211
|
-
# just call
|
236
|
+
# just call <tt>Cache#write</tt>.
|
212
237
|
#
|
213
|
-
# Setting <tt
|
214
|
-
#
|
238
|
+
# Setting <tt>skip_nil: true</tt> will not cache nil result:
|
239
|
+
#
|
240
|
+
# cache.fetch('foo') { nil }
|
241
|
+
# cache.fetch('bar', skip_nil: true) { nil }
|
242
|
+
# cache.exist?('foo') # => true
|
243
|
+
# cache.exist?('bar') # => false
|
244
|
+
#
|
245
|
+
#
|
246
|
+
# Setting <tt>compress: false</tt> disables compression of the cache entry.
|
215
247
|
#
|
216
248
|
# Setting <tt>:expires_in</tt> will set an expiration time on the cache.
|
217
249
|
# All caches support auto-expiring content after a specified number of
|
@@ -222,6 +254,10 @@ module ActiveSupport
|
|
222
254
|
# cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 5.minutes)
|
223
255
|
# cache.write(key, value, expires_in: 1.minute) # Set a lower value for one entry
|
224
256
|
#
|
257
|
+
# Setting <tt>:version</tt> verifies the cache stored under <tt>name</tt>
|
258
|
+
# is of the same version. nil is returned on mismatches despite contents.
|
259
|
+
# This feature is used to support recyclable cache keys.
|
260
|
+
#
|
225
261
|
# Setting <tt>:race_condition_ttl</tt> is very useful in situations where
|
226
262
|
# a cache entry is used very frequently and is under heavy load. If a
|
227
263
|
# cache expires and due to heavy load several different processes will try
|
@@ -250,14 +286,14 @@ module ActiveSupport
|
|
250
286
|
# sleep 60
|
251
287
|
#
|
252
288
|
# Thread.new do
|
253
|
-
# val_1 = cache.fetch('foo', race_condition_ttl: 10) do
|
289
|
+
# val_1 = cache.fetch('foo', race_condition_ttl: 10.seconds) do
|
254
290
|
# sleep 1
|
255
291
|
# 'new value 1'
|
256
292
|
# end
|
257
293
|
# end
|
258
294
|
#
|
259
295
|
# Thread.new do
|
260
|
-
# val_2 = cache.fetch('foo', race_condition_ttl: 10) do
|
296
|
+
# val_2 = cache.fetch('foo', race_condition_ttl: 10.seconds) do
|
261
297
|
# 'new value 2'
|
262
298
|
# end
|
263
299
|
# end
|
@@ -281,15 +317,16 @@ module ActiveSupport
|
|
281
317
|
# :bar
|
282
318
|
# end
|
283
319
|
# cache.fetch('foo') # => "bar"
|
284
|
-
def fetch(name, options = nil)
|
320
|
+
def fetch(name, options = nil, &block)
|
285
321
|
if block_given?
|
286
322
|
options = merged_options(options)
|
287
323
|
key = normalize_key(name, options)
|
288
324
|
|
289
325
|
entry = nil
|
290
326
|
instrument(:read, name, options) do |payload|
|
291
|
-
cached_entry = read_entry(key, options) unless options[:force]
|
327
|
+
cached_entry = read_entry(key, **options, event: payload) unless options[:force]
|
292
328
|
entry = handle_expired_entry(cached_entry, key, options)
|
329
|
+
entry = nil if entry && entry.mismatched?(normalize_version(name, options))
|
293
330
|
payload[:super_operation] = :fetch if payload
|
294
331
|
payload[:hit] = !!entry if payload
|
295
332
|
end
|
@@ -297,28 +334,38 @@ module ActiveSupport
|
|
297
334
|
if entry
|
298
335
|
get_entry_value(entry, name, options)
|
299
336
|
else
|
300
|
-
save_block_result_to_cache(name, options)
|
337
|
+
save_block_result_to_cache(name, options, &block)
|
301
338
|
end
|
302
339
|
elsif options && options[:force]
|
303
|
-
raise ArgumentError,
|
340
|
+
raise ArgumentError, "Missing block: Calling `Cache#fetch` with `force: true` requires a block."
|
304
341
|
else
|
305
342
|
read(name, options)
|
306
343
|
end
|
307
344
|
end
|
308
345
|
|
309
|
-
#
|
346
|
+
# Reads data from the cache, using the given key. If there is data in
|
310
347
|
# the cache with the given key, then that data is returned. Otherwise,
|
311
348
|
# +nil+ is returned.
|
312
349
|
#
|
350
|
+
# Note, if data was written with the <tt>:expires_in</tt> or
|
351
|
+
# <tt>:version</tt> options, both of these conditions are applied before
|
352
|
+
# the data is returned.
|
353
|
+
#
|
313
354
|
# Options are passed to the underlying cache implementation.
|
314
355
|
def read(name, options = nil)
|
315
356
|
options = merged_options(options)
|
316
|
-
key
|
357
|
+
key = normalize_key(name, options)
|
358
|
+
version = normalize_version(name, options)
|
359
|
+
|
317
360
|
instrument(:read, name, options) do |payload|
|
318
|
-
entry = read_entry(key, options)
|
361
|
+
entry = read_entry(key, **options, event: payload)
|
362
|
+
|
319
363
|
if entry
|
320
364
|
if entry.expired?
|
321
|
-
delete_entry(key, options)
|
365
|
+
delete_entry(key, **options)
|
366
|
+
payload[:hit] = false if payload
|
367
|
+
nil
|
368
|
+
elsif entry.mismatched?(version)
|
322
369
|
payload[:hit] = false if payload
|
323
370
|
nil
|
324
371
|
else
|
@@ -342,27 +389,33 @@ module ActiveSupport
|
|
342
389
|
options = names.extract_options!
|
343
390
|
options = merged_options(options)
|
344
391
|
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
392
|
+
instrument :read_multi, names, options do |payload|
|
393
|
+
read_multi_entries(names, **options, event: payload).tap do |results|
|
394
|
+
payload[:hits] = results.keys
|
395
|
+
end
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
# Cache Storage API to write multiple values at once.
|
400
|
+
def write_multi(hash, options = nil)
|
401
|
+
options = merged_options(options)
|
402
|
+
|
403
|
+
instrument :write_multi, hash, options do |payload|
|
404
|
+
entries = hash.each_with_object({}) do |(name, value), memo|
|
405
|
+
memo[normalize_key(name, options)] = Entry.new(value, **options.merge(version: normalize_version(name, options)))
|
355
406
|
end
|
407
|
+
|
408
|
+
write_multi_entries entries, **options
|
356
409
|
end
|
357
|
-
results
|
358
410
|
end
|
359
411
|
|
360
412
|
# Fetches data from the cache, using the given keys. If there is data in
|
361
413
|
# the cache with the given keys, then that data is returned. Otherwise,
|
362
414
|
# the supplied block is called for each key for which there was no data,
|
363
415
|
# and the result will be written to the cache and returned.
|
364
|
-
#
|
365
|
-
#
|
416
|
+
# Therefore, you need to pass a block that returns the data to be written
|
417
|
+
# to the cache. If you do not want to write the cache when the cache is
|
418
|
+
# not found, use #read_multi.
|
366
419
|
#
|
367
420
|
# Returns a hash with the data for each of the names. For example:
|
368
421
|
#
|
@@ -373,17 +426,36 @@ module ActiveSupport
|
|
373
426
|
# # => { "bim" => "bam",
|
374
427
|
# # "unknown_key" => "Fallback value for key: unknown_key" }
|
375
428
|
#
|
429
|
+
# Options are passed to the underlying cache implementation. For example:
|
430
|
+
#
|
431
|
+
# cache.fetch_multi("fizz", expires_in: 5.seconds) do |key|
|
432
|
+
# "buzz"
|
433
|
+
# end
|
434
|
+
# # => {"fizz"=>"buzz"}
|
435
|
+
# cache.read("fizz")
|
436
|
+
# # => "buzz"
|
437
|
+
# sleep(6)
|
438
|
+
# cache.read("fizz")
|
439
|
+
# # => nil
|
376
440
|
def fetch_multi(*names)
|
441
|
+
raise ArgumentError, "Missing block: `Cache#fetch_multi` requires a block." unless block_given?
|
442
|
+
|
377
443
|
options = names.extract_options!
|
378
444
|
options = merged_options(options)
|
379
|
-
results = read_multi(*names, options)
|
380
445
|
|
381
|
-
names
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
446
|
+
instrument :read_multi, names, options do |payload|
|
447
|
+
reads = read_multi_entries(names, **options)
|
448
|
+
writes = {}
|
449
|
+
ordered = names.index_with do |name|
|
450
|
+
reads.fetch(name) { writes[name] = yield(name) }
|
386
451
|
end
|
452
|
+
|
453
|
+
payload[:hits] = reads.keys
|
454
|
+
payload[:super_operation] = :fetch_multi
|
455
|
+
|
456
|
+
write_multi(writes, options)
|
457
|
+
|
458
|
+
ordered
|
387
459
|
end
|
388
460
|
end
|
389
461
|
|
@@ -394,8 +466,8 @@ module ActiveSupport
|
|
394
466
|
options = merged_options(options)
|
395
467
|
|
396
468
|
instrument(:write, name, options) do
|
397
|
-
entry = Entry.new(value, options)
|
398
|
-
write_entry(normalize_key(name, options), entry, options)
|
469
|
+
entry = Entry.new(value, **options.merge(version: normalize_version(name, options)))
|
470
|
+
write_entry(normalize_key(name, options), entry, **options)
|
399
471
|
end
|
400
472
|
end
|
401
473
|
|
@@ -406,7 +478,19 @@ module ActiveSupport
|
|
406
478
|
options = merged_options(options)
|
407
479
|
|
408
480
|
instrument(:delete, name) do
|
409
|
-
delete_entry(normalize_key(name, options), options)
|
481
|
+
delete_entry(normalize_key(name, options), **options)
|
482
|
+
end
|
483
|
+
end
|
484
|
+
|
485
|
+
# Deletes multiple entries in the cache.
|
486
|
+
#
|
487
|
+
# Options are passed to the underlying cache implementation.
|
488
|
+
def delete_multi(names, options = nil)
|
489
|
+
options = merged_options(options)
|
490
|
+
names.map! { |key| normalize_key(key, options) }
|
491
|
+
|
492
|
+
instrument :delete_multi, names do
|
493
|
+
delete_multi_entries(names, **options)
|
410
494
|
end
|
411
495
|
end
|
412
496
|
|
@@ -416,9 +500,9 @@ module ActiveSupport
|
|
416
500
|
def exist?(name, options = nil)
|
417
501
|
options = merged_options(options)
|
418
502
|
|
419
|
-
instrument(:exist?, name) do
|
420
|
-
entry = read_entry(normalize_key(name, options), options)
|
421
|
-
(entry && !entry.expired?) || false
|
503
|
+
instrument(:exist?, name) do |payload|
|
504
|
+
entry = read_entry(normalize_key(name, options), **options, event: payload)
|
505
|
+
(entry && !entry.expired? && !entry.mismatched?(normalize_version(name, options))) || false
|
422
506
|
end
|
423
507
|
end
|
424
508
|
|
@@ -426,7 +510,7 @@ module ActiveSupport
|
|
426
510
|
#
|
427
511
|
# Options are passed to the underlying cache implementation.
|
428
512
|
#
|
429
|
-
#
|
513
|
+
# Some implementations may not support this method.
|
430
514
|
def delete_matched(matcher, options = nil)
|
431
515
|
raise NotImplementedError.new("#{self.class.name} does not support delete_matched")
|
432
516
|
end
|
@@ -435,7 +519,7 @@ module ActiveSupport
|
|
435
519
|
#
|
436
520
|
# Options are passed to the underlying cache implementation.
|
437
521
|
#
|
438
|
-
#
|
522
|
+
# Some implementations may not support this method.
|
439
523
|
def increment(name, amount = 1, options = nil)
|
440
524
|
raise NotImplementedError.new("#{self.class.name} does not support increment")
|
441
525
|
end
|
@@ -444,7 +528,7 @@ module ActiveSupport
|
|
444
528
|
#
|
445
529
|
# Options are passed to the underlying cache implementation.
|
446
530
|
#
|
447
|
-
#
|
531
|
+
# Some implementations may not support this method.
|
448
532
|
def decrement(name, amount = 1, options = nil)
|
449
533
|
raise NotImplementedError.new("#{self.class.name} does not support decrement")
|
450
534
|
end
|
@@ -453,7 +537,7 @@ module ActiveSupport
|
|
453
537
|
#
|
454
538
|
# Options are passed to the underlying cache implementation.
|
455
539
|
#
|
456
|
-
#
|
540
|
+
# Some implementations may not support this method.
|
457
541
|
def cleanup(options = nil)
|
458
542
|
raise NotImplementedError.new("#{self.class.name} does not support cleanup")
|
459
543
|
end
|
@@ -463,21 +547,21 @@ module ActiveSupport
|
|
463
547
|
#
|
464
548
|
# The options hash is passed to the underlying cache implementation.
|
465
549
|
#
|
466
|
-
#
|
550
|
+
# Some implementations may not support this method.
|
467
551
|
def clear(options = nil)
|
468
552
|
raise NotImplementedError.new("#{self.class.name} does not support clear")
|
469
553
|
end
|
470
554
|
|
471
|
-
|
555
|
+
private
|
472
556
|
# Adds the namespace defined in the options to a pattern designed to
|
473
557
|
# match keys. Implementations that support delete_matched should call
|
474
558
|
# this method to translate a pattern that matches names into one that
|
475
559
|
# matches namespaced keys.
|
476
|
-
def key_matcher(pattern, options)
|
560
|
+
def key_matcher(pattern, options) # :doc:
|
477
561
|
prefix = options[:namespace].is_a?(Proc) ? options[:namespace].call : options[:namespace]
|
478
562
|
if prefix
|
479
563
|
source = pattern.source
|
480
|
-
if source.start_with?(
|
564
|
+
if source.start_with?("^")
|
481
565
|
source = source[1, source.length]
|
482
566
|
else
|
483
567
|
source = ".*#{source[0, source.length]}"
|
@@ -490,81 +574,150 @@ module ActiveSupport
|
|
490
574
|
|
491
575
|
# Reads an entry from the cache implementation. Subclasses must implement
|
492
576
|
# this method.
|
493
|
-
def read_entry(key, options)
|
577
|
+
def read_entry(key, **options)
|
494
578
|
raise NotImplementedError.new
|
495
579
|
end
|
496
580
|
|
497
581
|
# Writes an entry to the cache implementation. Subclasses must implement
|
498
582
|
# this method.
|
499
|
-
def write_entry(key, entry, options)
|
583
|
+
def write_entry(key, entry, **options)
|
500
584
|
raise NotImplementedError.new
|
501
585
|
end
|
502
586
|
|
587
|
+
def serialize_entry(entry)
|
588
|
+
@coder.dump(entry)
|
589
|
+
end
|
590
|
+
|
591
|
+
def deserialize_entry(payload)
|
592
|
+
payload.nil? ? nil : @coder.load(payload)
|
593
|
+
end
|
594
|
+
|
595
|
+
# Reads multiple entries from the cache implementation. Subclasses MAY
|
596
|
+
# implement this method.
|
597
|
+
def read_multi_entries(names, **options)
|
598
|
+
names.each_with_object({}) do |name, results|
|
599
|
+
key = normalize_key(name, options)
|
600
|
+
entry = read_entry(key, **options)
|
601
|
+
|
602
|
+
next unless entry
|
603
|
+
|
604
|
+
version = normalize_version(name, options)
|
605
|
+
|
606
|
+
if entry.expired?
|
607
|
+
delete_entry(key, **options)
|
608
|
+
elsif !entry.mismatched?(version)
|
609
|
+
results[name] = entry.value
|
610
|
+
end
|
611
|
+
end
|
612
|
+
end
|
613
|
+
|
614
|
+
# Writes multiple entries to the cache implementation. Subclasses MAY
|
615
|
+
# implement this method.
|
616
|
+
def write_multi_entries(hash, **options)
|
617
|
+
hash.each do |key, entry|
|
618
|
+
write_entry key, entry, **options
|
619
|
+
end
|
620
|
+
end
|
621
|
+
|
503
622
|
# Deletes an entry from the cache implementation. Subclasses must
|
504
623
|
# implement this method.
|
505
|
-
def delete_entry(key, options)
|
624
|
+
def delete_entry(key, **options)
|
506
625
|
raise NotImplementedError.new
|
507
626
|
end
|
508
627
|
|
509
|
-
|
628
|
+
# Deletes multiples entries in the cache implementation. Subclasses MAY
|
629
|
+
# implement this method.
|
630
|
+
def delete_multi_entries(entries, **options)
|
631
|
+
entries.count { |key| delete_entry(key, **options) }
|
632
|
+
end
|
633
|
+
|
510
634
|
# Merges the default options with ones specific to a method call.
|
511
|
-
def merged_options(call_options)
|
635
|
+
def merged_options(call_options)
|
512
636
|
if call_options
|
513
|
-
options.
|
637
|
+
if options.empty?
|
638
|
+
call_options
|
639
|
+
else
|
640
|
+
options.merge(call_options)
|
641
|
+
end
|
514
642
|
else
|
515
|
-
options
|
643
|
+
options
|
644
|
+
end
|
645
|
+
end
|
646
|
+
|
647
|
+
# Expands and namespaces the cache key. May be overridden by
|
648
|
+
# cache stores to do additional normalization.
|
649
|
+
def normalize_key(key, options = nil)
|
650
|
+
namespace_key expanded_key(key), options
|
651
|
+
end
|
652
|
+
|
653
|
+
# Prefix the key with a namespace string:
|
654
|
+
#
|
655
|
+
# namespace_key 'foo', namespace: 'cache'
|
656
|
+
# # => 'cache:foo'
|
657
|
+
#
|
658
|
+
# With a namespace block:
|
659
|
+
#
|
660
|
+
# namespace_key 'foo', namespace: -> { 'cache' }
|
661
|
+
# # => 'cache:foo'
|
662
|
+
def namespace_key(key, options = nil)
|
663
|
+
options = merged_options(options)
|
664
|
+
namespace = options[:namespace]
|
665
|
+
|
666
|
+
if namespace.respond_to?(:call)
|
667
|
+
namespace = namespace.call
|
668
|
+
end
|
669
|
+
|
670
|
+
if key && key.encoding != Encoding::UTF_8
|
671
|
+
key = key.dup.force_encoding(Encoding::UTF_8)
|
672
|
+
end
|
673
|
+
|
674
|
+
if namespace
|
675
|
+
"#{namespace}:#{key}"
|
676
|
+
else
|
677
|
+
key
|
516
678
|
end
|
517
679
|
end
|
518
680
|
|
519
681
|
# Expands key to be a consistent string value. Invokes +cache_key+ if
|
520
682
|
# object responds to +cache_key+. Otherwise, +to_param+ method will be
|
521
683
|
# called. If the key is a Hash, then keys will be sorted alphabetically.
|
522
|
-
def expanded_key(key)
|
684
|
+
def expanded_key(key)
|
523
685
|
return key.cache_key.to_s if key.respond_to?(:cache_key)
|
524
686
|
|
525
687
|
case key
|
526
688
|
when Array
|
527
689
|
if key.size > 1
|
528
|
-
key
|
690
|
+
key.collect { |element| expanded_key(element) }
|
529
691
|
else
|
530
|
-
key
|
692
|
+
expanded_key(key.first)
|
531
693
|
end
|
532
694
|
when Hash
|
533
|
-
key
|
534
|
-
|
535
|
-
|
536
|
-
|
695
|
+
key.collect { |k, v| "#{k}=#{v}" }.sort!
|
696
|
+
else
|
697
|
+
key
|
698
|
+
end.to_param
|
537
699
|
end
|
538
700
|
|
539
|
-
|
540
|
-
|
541
|
-
def normalize_key(key, options)
|
542
|
-
key = expanded_key(key)
|
543
|
-
namespace = options[:namespace] if options
|
544
|
-
prefix = namespace.is_a?(Proc) ? namespace.call : namespace
|
545
|
-
key = "#{prefix}:#{key}" if prefix
|
546
|
-
key
|
701
|
+
def normalize_version(key, options = nil)
|
702
|
+
(options && options[:version].try(:to_param)) || expanded_version(key)
|
547
703
|
end
|
548
704
|
|
549
|
-
def
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
705
|
+
def expanded_version(key)
|
706
|
+
case
|
707
|
+
when key.respond_to?(:cache_version) then key.cache_version.to_param
|
708
|
+
when key.is_a?(Array) then key.map { |element| expanded_version(element) }.tap(&:compact!).to_param
|
709
|
+
when key.respond_to?(:to_a) then expanded_version(key.to_a)
|
710
|
+
end
|
555
711
|
end
|
556
712
|
|
557
713
|
def instrument(operation, key, options = nil)
|
558
|
-
|
714
|
+
if logger && logger.debug? && !silence?
|
715
|
+
logger.debug "Cache #{operation}: #{normalize_key(key, options)}#{options.blank? ? "" : " (#{options.inspect})"}"
|
716
|
+
end
|
559
717
|
|
560
|
-
payload = { :key
|
718
|
+
payload = { key: key, store: self.class.name }
|
561
719
|
payload.merge!(options) if options.is_a?(Hash)
|
562
|
-
ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload){ yield(payload) }
|
563
|
-
end
|
564
|
-
|
565
|
-
def log
|
566
|
-
return unless logger && logger.debug? && !silence?
|
567
|
-
logger.debug(yield)
|
720
|
+
ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload) { yield(payload) }
|
568
721
|
end
|
569
722
|
|
570
723
|
def handle_expired_entry(entry, key, options)
|
@@ -574,9 +727,9 @@ module ActiveSupport
|
|
574
727
|
# When an entry has a positive :race_condition_ttl defined, put the stale entry back into the cache
|
575
728
|
# for a brief period while the entry is being recalculated.
|
576
729
|
entry.expires_at = Time.now + race_ttl
|
577
|
-
write_entry(key, entry, :
|
730
|
+
write_entry(key, entry, expires_in: race_ttl * 2)
|
578
731
|
else
|
579
|
-
delete_entry(key, options)
|
732
|
+
delete_entry(key, **options)
|
580
733
|
end
|
581
734
|
entry = nil
|
582
735
|
end
|
@@ -593,39 +746,54 @@ module ActiveSupport
|
|
593
746
|
yield(name)
|
594
747
|
end
|
595
748
|
|
596
|
-
write(name, result, options)
|
749
|
+
write(name, result, options) unless result.nil? && options[:skip_nil]
|
597
750
|
result
|
598
751
|
end
|
599
752
|
end
|
600
753
|
|
601
|
-
|
602
|
-
|
603
|
-
|
754
|
+
module NullCoder # :nodoc:
|
755
|
+
class << self
|
756
|
+
def load(payload)
|
757
|
+
payload
|
758
|
+
end
|
759
|
+
|
760
|
+
def dump(entry)
|
761
|
+
entry
|
762
|
+
end
|
763
|
+
end
|
764
|
+
end
|
765
|
+
|
766
|
+
# This class is used to represent cache entries. Cache entries have a value, an optional
|
767
|
+
# expiration time, and an optional version. The expiration time is used to support the :race_condition_ttl option
|
768
|
+
# on the cache. The version is used to support the :version option on the cache for rejecting
|
769
|
+
# mismatches.
|
604
770
|
#
|
605
771
|
# Since cache entries in most instances will be serialized, the internals of this class are highly optimized
|
606
772
|
# using short instance variable names that are lazily defined.
|
607
773
|
class Entry # :nodoc:
|
608
|
-
|
774
|
+
attr_reader :version
|
609
775
|
|
610
|
-
|
611
|
-
# +:compress+, +:compress_threshold+, and +:expires_in+.
|
612
|
-
def initialize(value, options = {})
|
613
|
-
if should_compress?(value, options)
|
614
|
-
@value = compress(value)
|
615
|
-
@compressed = true
|
616
|
-
else
|
617
|
-
@value = value
|
618
|
-
end
|
776
|
+
DEFAULT_COMPRESS_LIMIT = 1.kilobyte
|
619
777
|
|
778
|
+
# Creates a new cache entry for the specified value. Options supported are
|
779
|
+
# +:compress+, +:compress_threshold+, +:version+ and +:expires_in+.
|
780
|
+
def initialize(value, compress: true, compress_threshold: DEFAULT_COMPRESS_LIMIT, version: nil, expires_in: nil, **)
|
781
|
+
@value = value
|
782
|
+
@version = version
|
620
783
|
@created_at = Time.now.to_f
|
621
|
-
@expires_in =
|
622
|
-
|
784
|
+
@expires_in = expires_in && expires_in.to_f
|
785
|
+
|
786
|
+
compress!(compress_threshold) if compress
|
623
787
|
end
|
624
788
|
|
625
789
|
def value
|
626
790
|
compressed? ? uncompress(@value) : @value
|
627
791
|
end
|
628
792
|
|
793
|
+
def mismatched?(version)
|
794
|
+
@version && version && @version != version
|
795
|
+
end
|
796
|
+
|
629
797
|
# Checks if the entry is expired. The +expires_in+ parameter can override
|
630
798
|
# the value set when the entry was created.
|
631
799
|
def expired?
|
@@ -645,19 +813,15 @@ module ActiveSupport
|
|
645
813
|
end
|
646
814
|
|
647
815
|
# Returns the size of the cached value. This could be less than
|
648
|
-
# <tt>value.
|
649
|
-
def
|
650
|
-
|
651
|
-
|
816
|
+
# <tt>value.bytesize</tt> if the data is compressed.
|
817
|
+
def bytesize
|
818
|
+
case value
|
819
|
+
when NilClass
|
820
|
+
0
|
821
|
+
when String
|
822
|
+
@value.bytesize
|
652
823
|
else
|
653
|
-
|
654
|
-
when NilClass
|
655
|
-
0
|
656
|
-
when String
|
657
|
-
@value.bytesize
|
658
|
-
else
|
659
|
-
@s = Marshal.dump(@value).bytesize
|
660
|
-
end
|
824
|
+
@s ||= Marshal.dump(@value).bytesize
|
661
825
|
end
|
662
826
|
end
|
663
827
|
|
@@ -674,23 +838,30 @@ module ActiveSupport
|
|
674
838
|
end
|
675
839
|
|
676
840
|
private
|
677
|
-
def
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
841
|
+
def compress!(compress_threshold)
|
842
|
+
case @value
|
843
|
+
when nil, true, false, Numeric
|
844
|
+
uncompressed_size = 0
|
845
|
+
when String
|
846
|
+
uncompressed_size = @value.bytesize
|
847
|
+
else
|
848
|
+
serialized = Marshal.dump(@value)
|
849
|
+
uncompressed_size = serialized.bytesize
|
683
850
|
end
|
684
851
|
|
685
|
-
|
686
|
-
|
852
|
+
if uncompressed_size >= compress_threshold
|
853
|
+
serialized ||= Marshal.dump(@value)
|
854
|
+
compressed = Zlib::Deflate.deflate(serialized)
|
687
855
|
|
688
|
-
|
689
|
-
|
856
|
+
if compressed.bytesize < uncompressed_size
|
857
|
+
@value = compressed
|
858
|
+
@compressed = true
|
859
|
+
end
|
860
|
+
end
|
690
861
|
end
|
691
862
|
|
692
|
-
def
|
693
|
-
|
863
|
+
def compressed?
|
864
|
+
defined?(@compressed)
|
694
865
|
end
|
695
866
|
|
696
867
|
def uncompress(value)
|