activesupport 4.2.11.1 → 6.0.3.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.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +399 -411
- data/MIT-LICENSE +2 -2
- data/README.rdoc +7 -7
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/all.rb +5 -3
- data/lib/active_support/array_inquirer.rb +48 -0
- data/lib/active_support/backtrace_cleaner.rb +34 -6
- data/lib/active_support/benchmarkable.rb +6 -4
- data/lib/active_support/builder.rb +3 -1
- data/lib/active_support/cache/file_store.rb +58 -53
- data/lib/active_support/cache/mem_cache_store.rb +95 -91
- data/lib/active_support/cache/memory_store.rb +39 -36
- data/lib/active_support/cache/null_store.rb +11 -7
- data/lib/active_support/cache/redis_cache_store.rb +493 -0
- data/lib/active_support/cache/strategy/local_cache.rb +75 -42
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
- data/lib/active_support/cache.rb +331 -217
- data/lib/active_support/callbacks.rb +650 -592
- data/lib/active_support/concern.rb +35 -6
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -0
- data/lib/active_support/concurrency/share_lock.rb +226 -0
- data/lib/active_support/configurable.rb +13 -14
- data/lib/active_support/core_ext/array/access.rb +41 -1
- data/lib/active_support/core_ext/array/conversions.rb +24 -20
- 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 +11 -18
- data/lib/active_support/core_ext/array/inquiry.rb +19 -0
- data/lib/active_support/core_ext/array/prepend_and_append.rb +4 -6
- data/lib/active_support/core_ext/array/wrap.rb +7 -4
- data/lib/active_support/core_ext/array.rb +9 -6
- data/lib/active_support/core_ext/benchmark.rb +3 -1
- data/lib/active_support/core_ext/big_decimal/conversions.rb +10 -12
- data/lib/active_support/core_ext/big_decimal.rb +3 -1
- data/lib/active_support/core_ext/class/attribute.rb +45 -31
- data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
- data/lib/active_support/core_ext/class/subclasses.rb +20 -6
- data/lib/active_support/core_ext/class.rb +4 -3
- data/lib/active_support/core_ext/date/acts_like.rb +3 -1
- data/lib/active_support/core_ext/date/blank.rb +14 -0
- data/lib/active_support/core_ext/date/calculations.rb +17 -14
- data/lib/active_support/core_ext/date/conversions.rb +25 -23
- data/lib/active_support/core_ext/date/zones.rb +4 -2
- data/lib/active_support/core_ext/date.rb +6 -4
- data/lib/active_support/core_ext/date_and_time/calculations.rb +154 -65
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +4 -3
- data/lib/active_support/core_ext/date_and_time/zones.rb +12 -13
- data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
- data/lib/active_support/core_ext/date_time/blank.rb +14 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +37 -19
- data/lib/active_support/core_ext/date_time/compatibility.rb +8 -6
- data/lib/active_support/core_ext/date_time/conversions.rb +16 -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 +114 -22
- data/lib/active_support/core_ext/file/atomic.rb +38 -31
- data/lib/active_support/core_ext/file.rb +3 -1
- data/lib/active_support/core_ext/hash/compact.rb +4 -23
- data/lib/active_support/core_ext/hash/conversions.rb +62 -41
- data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +12 -9
- data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -3
- data/lib/active_support/core_ext/hash/keys.rb +19 -42
- data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
- data/lib/active_support/core_ext/hash/slice.rb +5 -27
- data/lib/active_support/core_ext/hash/transform_values.rb +4 -22
- 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 +5 -1
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -84
- data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
- data/lib/active_support/core_ext/kernel.rb +5 -5
- data/lib/active_support/core_ext/load_error.rb +3 -22
- data/lib/active_support/core_ext/marshal.rb +8 -8
- data/lib/active_support/core_ext/module/aliasing.rb +6 -44
- data/lib/active_support/core_ext/module/anonymous.rb +12 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +8 -9
- data/lib/active_support/core_ext/module/attribute_accessors.rb +46 -46
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +144 -0
- data/lib/active_support/core_ext/module/concerning.rb +11 -12
- data/lib/active_support/core_ext/module/delegation.rb +133 -30
- data/lib/active_support/core_ext/module/deprecation.rb +4 -2
- data/lib/active_support/core_ext/module/introspection.rb +44 -19
- data/lib/active_support/core_ext/module/reachable.rb +5 -7
- data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
- data/lib/active_support/core_ext/module/remove_method.rb +8 -3
- data/lib/active_support/core_ext/module.rb +13 -11
- data/lib/active_support/core_ext/name_error.rb +22 -2
- data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +129 -136
- data/lib/active_support/core_ext/numeric/inquiry.rb +5 -0
- data/lib/active_support/core_ext/numeric/time.rb +35 -23
- data/lib/active_support/core_ext/numeric.rb +5 -3
- data/lib/active_support/core_ext/object/acts_like.rb +12 -1
- data/lib/active_support/core_ext/object/blank.rb +27 -3
- data/lib/active_support/core_ext/object/conversions.rb +6 -4
- data/lib/active_support/core_ext/object/deep_dup.rb +13 -4
- data/lib/active_support/core_ext/object/duplicable.rb +13 -93
- data/lib/active_support/core_ext/object/inclusion.rb +5 -3
- data/lib/active_support/core_ext/object/instance_variables.rb +3 -1
- data/lib/active_support/core_ext/object/json.rb +51 -20
- 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 +81 -23
- data/lib/active_support/core_ext/object/with_options.rb +16 -3
- data/lib/active_support/core_ext/object.rb +14 -13
- data/lib/active_support/core_ext/range/compare_range.rb +76 -0
- data/lib/active_support/core_ext/range/conversions.rb +37 -15
- data/lib/active_support/core_ext/range/each.rb +18 -17
- data/lib/active_support/core_ext/range/include_range.rb +7 -21
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -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 +2 -0
- data/lib/active_support/core_ext/securerandom.rb +45 -0
- data/lib/active_support/core_ext/string/access.rb +16 -6
- data/lib/active_support/core_ext/string/behavior.rb +3 -1
- data/lib/active_support/core_ext/string/conversions.rb +7 -4
- data/lib/active_support/core_ext/string/exclude.rb +2 -0
- data/lib/active_support/core_ext/string/filters.rb +48 -6
- data/lib/active_support/core_ext/string/indent.rb +6 -4
- data/lib/active_support/core_ext/string/inflections.rb +66 -24
- data/lib/active_support/core_ext/string/inquiry.rb +3 -1
- data/lib/active_support/core_ext/string/multibyte.rb +16 -7
- data/lib/active_support/core_ext/string/output_safety.rb +93 -40
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -0
- data/lib/active_support/core_ext/string/strip.rb +6 -5
- 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/time/acts_like.rb +3 -1
- data/lib/active_support/core_ext/time/calculations.rb +115 -52
- data/lib/active_support/core_ext/time/compatibility.rb +4 -2
- data/lib/active_support/core_ext/time/conversions.rb +20 -13
- data/lib/active_support/core_ext/time/zones.rb +41 -7
- data/lib/active_support/core_ext/time.rb +7 -6
- data/lib/active_support/core_ext/uri.rb +6 -7
- data/lib/active_support/core_ext.rb +3 -1
- data/lib/active_support/current_attributes.rb +203 -0
- data/lib/active_support/dependencies/autoload.rb +2 -0
- data/lib/active_support/dependencies/interlock.rb +57 -0
- data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
- data/lib/active_support/dependencies.rb +208 -166
- data/lib/active_support/deprecation/behaviors.rb +44 -11
- data/lib/active_support/deprecation/constant_accessor.rb +52 -0
- data/lib/active_support/deprecation/instance_delegator.rb +17 -2
- data/lib/active_support/deprecation/method_wrappers.rb +61 -21
- data/lib/active_support/deprecation/proxy_wrappers.rb +81 -30
- data/lib/active_support/deprecation/reporting.rb +32 -12
- data/lib/active_support/deprecation.rb +12 -9
- data/lib/active_support/descendants_tracker.rb +57 -9
- data/lib/active_support/digest.rb +20 -0
- data/lib/active_support/duration/iso8601_parser.rb +123 -0
- data/lib/active_support/duration/iso8601_serializer.rb +53 -0
- data/lib/active_support/duration.rb +315 -40
- data/lib/active_support/encrypted_configuration.rb +45 -0
- data/lib/active_support/encrypted_file.rb +100 -0
- data/lib/active_support/evented_file_update_checker.rb +234 -0
- data/lib/active_support/execution_wrapper.rb +129 -0
- data/lib/active_support/executor.rb +8 -0
- data/lib/active_support/file_update_checker.rb +62 -37
- data/lib/active_support/gem_version.rb +6 -4
- data/lib/active_support/gzip.rb +7 -5
- data/lib/active_support/hash_with_indifferent_access.rb +129 -30
- data/lib/active_support/i18n.rb +9 -6
- data/lib/active_support/i18n_railtie.rb +50 -14
- data/lib/active_support/inflections.rb +13 -11
- data/lib/active_support/inflector/inflections.rb +58 -13
- data/lib/active_support/inflector/methods.rb +159 -145
- data/lib/active_support/inflector/transliterate.rb +84 -34
- data/lib/active_support/inflector.rb +7 -5
- data/lib/active_support/json/decoding.rb +32 -30
- data/lib/active_support/json/encoding.rb +17 -60
- data/lib/active_support/json.rb +4 -2
- data/lib/active_support/key_generator.rb +11 -43
- 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 +2 -0
- data/lib/active_support/log_subscriber/test_helper.rb +14 -12
- data/lib/active_support/log_subscriber.rb +44 -19
- data/lib/active_support/logger.rb +9 -23
- data/lib/active_support/logger_silence.rb +32 -14
- data/lib/active_support/logger_thread_safe_level.rb +32 -8
- data/lib/active_support/message_encryptor.rb +166 -53
- data/lib/active_support/message_verifier.rb +149 -16
- data/lib/active_support/messages/metadata.rb +72 -0
- data/lib/active_support/messages/rotation_configuration.rb +22 -0
- data/lib/active_support/messages/rotator.rb +56 -0
- data/lib/active_support/multibyte/chars.rb +56 -63
- data/lib/active_support/multibyte/unicode.rb +56 -290
- data/lib/active_support/multibyte.rb +4 -2
- data/lib/active_support/notifications/fanout.rb +109 -22
- data/lib/active_support/notifications/instrumenter.rb +107 -16
- data/lib/active_support/notifications.rb +51 -10
- data/lib/active_support/number_helper/number_converter.rb +16 -15
- data/lib/active_support/number_helper/number_to_currency_converter.rb +14 -15
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +11 -4
- data/lib/active_support/number_helper/number_to_human_converter.rb +13 -10
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +11 -9
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +15 -5
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +25 -57
- data/lib/active_support/number_helper/rounding_helper.rb +66 -0
- data/lib/active_support/number_helper.rb +105 -68
- data/lib/active_support/option_merger.rb +24 -4
- data/lib/active_support/ordered_hash.rb +7 -5
- data/lib/active_support/ordered_options.rb +27 -5
- data/lib/active_support/parameter_filter.rb +128 -0
- data/lib/active_support/per_thread_registry.rb +9 -4
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/rails.rb +10 -8
- data/lib/active_support/railtie.rb +43 -9
- data/lib/active_support/reloader.rb +130 -0
- data/lib/active_support/rescuable.rb +108 -53
- data/lib/active_support/security_utils.rb +15 -11
- data/lib/active_support/string_inquirer.rb +11 -4
- data/lib/active_support/subscriber.rb +74 -30
- data/lib/active_support/tagged_logging.rb +25 -13
- data/lib/active_support/test_case.rb +107 -44
- data/lib/active_support/testing/assertions.rb +151 -20
- data/lib/active_support/testing/autorun.rb +4 -2
- 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 +13 -10
- data/lib/active_support/testing/file_fixtures.rb +38 -0
- data/lib/active_support/testing/isolation.rb +35 -26
- data/lib/active_support/testing/method_call_assertions.rb +70 -0
- data/lib/active_support/testing/parallelization.rb +134 -0
- data/lib/active_support/testing/setup_and_teardown.rb +13 -8
- data/lib/active_support/testing/stream.rb +43 -0
- data/lib/active_support/testing/tagged_logging.rb +3 -1
- data/lib/active_support/testing/time_helpers.rb +84 -20
- data/lib/active_support/time.rb +14 -12
- data/lib/active_support/time_with_zone.rb +179 -39
- data/lib/active_support/values/time_zone.rb +203 -63
- data/lib/active_support/version.rb +3 -1
- data/lib/active_support/xml_mini/jdom.rb +116 -115
- data/lib/active_support/xml_mini/libxml.rb +16 -13
- data/lib/active_support/xml_mini/libxmlsax.rb +15 -14
- data/lib/active_support/xml_mini/nokogiri.rb +14 -12
- data/lib/active_support/xml_mini/nokogirisax.rb +14 -13
- data/lib/active_support/xml_mini/rexml.rb +11 -9
- data/lib/active_support/xml_mini.rb +38 -46
- data/lib/active_support.rb +13 -11
- metadata +84 -26
- data/lib/active_support/concurrency/latch.rb +0 -27
- data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -16
- data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
- data/lib/active_support/core_ext/date_time/zones.rb +0 -6
- data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
- data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
- data/lib/active_support/core_ext/module/method_transplanting.rb +0 -13
- data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
- data/lib/active_support/core_ext/object/itself.rb +0 -15
- data/lib/active_support/core_ext/struct.rb +0 -6
- data/lib/active_support/core_ext/thread.rb +0 -86
- data/lib/active_support/core_ext/time/marshal.rb +0 -30
- data/lib/active_support/values/unicode_tables.dat +0 -0
data/lib/active_support/cache.rb
CHANGED
@@ -1,29 +1,29 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require 'active_support/deprecation'
|
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/module/attribute_accessors"
|
7
|
+
require "active_support/core_ext/numeric/bytes"
|
8
|
+
require "active_support/core_ext/numeric/time"
|
9
|
+
require "active_support/core_ext/object/to_param"
|
10
|
+
require "active_support/core_ext/string/inflections"
|
12
11
|
|
13
12
|
module ActiveSupport
|
14
13
|
# See ActiveSupport::Cache::Store for documentation.
|
15
14
|
module Cache
|
16
|
-
autoload :FileStore,
|
17
|
-
autoload :MemoryStore,
|
18
|
-
autoload :MemCacheStore,
|
19
|
-
autoload :NullStore,
|
15
|
+
autoload :FileStore, "active_support/cache/file_store"
|
16
|
+
autoload :MemoryStore, "active_support/cache/memory_store"
|
17
|
+
autoload :MemCacheStore, "active_support/cache/mem_cache_store"
|
18
|
+
autoload :NullStore, "active_support/cache/null_store"
|
19
|
+
autoload :RedisCacheStore, "active_support/cache/redis_cache_store"
|
20
20
|
|
21
21
|
# These options mean something to all cache implementations. Individual cache
|
22
22
|
# implementations may support additional options.
|
23
23
|
UNIVERSAL_OPTIONS = [:namespace, :compress, :compress_threshold, :expires_in, :race_condition_ttl]
|
24
24
|
|
25
25
|
module Strategy
|
26
|
-
autoload :LocalCache,
|
26
|
+
autoload :LocalCache, "active_support/cache/strategy/local_cache"
|
27
27
|
end
|
28
28
|
|
29
29
|
class << self
|
@@ -52,12 +52,13 @@ module ActiveSupport
|
|
52
52
|
#
|
53
53
|
# ActiveSupport::Cache.lookup_store(MyOwnCacheStore.new)
|
54
54
|
# # => returns MyOwnCacheStore.new
|
55
|
-
def lookup_store(*
|
56
|
-
store, *parameters = *Array.wrap(store_option).flatten
|
57
|
-
|
55
|
+
def lookup_store(store = nil, *parameters)
|
58
56
|
case store
|
59
57
|
when Symbol
|
60
|
-
|
58
|
+
options = parameters.extract_options!
|
59
|
+
retrieve_store_class(store).new(*parameters, **options)
|
60
|
+
when Array
|
61
|
+
lookup_store(*store)
|
61
62
|
when nil
|
62
63
|
ActiveSupport::Cache::MemoryStore.new
|
63
64
|
else
|
@@ -73,12 +74,12 @@ module ActiveSupport
|
|
73
74
|
# each of elements in the array will be turned into parameters/keys and
|
74
75
|
# concatenated into a single key. For example:
|
75
76
|
#
|
76
|
-
# expand_cache_key([:foo, :bar]) # => "foo/bar"
|
77
|
-
# expand_cache_key([:foo, :bar], "namespace") # => "namespace/foo/bar"
|
77
|
+
# ActiveSupport::Cache.expand_cache_key([:foo, :bar]) # => "foo/bar"
|
78
|
+
# ActiveSupport::Cache.expand_cache_key([:foo, :bar], "namespace") # => "namespace/foo/bar"
|
78
79
|
#
|
79
80
|
# The +key+ argument can also respond to +cache_key+ or +to_param+.
|
80
81
|
def expand_cache_key(key, namespace = nil)
|
81
|
-
expanded_cache_key = namespace ? "#{namespace}/" : ""
|
82
|
+
expanded_cache_key = (namespace ? "#{namespace}/" : "").dup
|
82
83
|
|
83
84
|
if prefix = ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]
|
84
85
|
expanded_cache_key << "#{prefix}/"
|
@@ -91,16 +92,19 @@ module ActiveSupport
|
|
91
92
|
private
|
92
93
|
def retrieve_cache_key(key)
|
93
94
|
case
|
94
|
-
when key.respond_to?(:
|
95
|
-
when key.
|
96
|
-
when key.
|
97
|
-
|
95
|
+
when key.respond_to?(:cache_key_with_version) then key.cache_key_with_version
|
96
|
+
when key.respond_to?(:cache_key) then key.cache_key
|
97
|
+
when key.is_a?(Array) then key.map { |element| retrieve_cache_key(element) }.to_param
|
98
|
+
when key.respond_to?(:to_a) then retrieve_cache_key(key.to_a)
|
99
|
+
else key.to_param
|
98
100
|
end.to_s
|
99
101
|
end
|
100
102
|
|
101
103
|
# Obtains the specified cache store class, given the name of the +store+.
|
102
104
|
# Raises an error when the store class cannot be found.
|
103
105
|
def retrieve_store_class(store)
|
106
|
+
# require_relative cannot be used here because the class might be
|
107
|
+
# provided by another gem, like redis-activesupport for example.
|
104
108
|
require "active_support/cache/#{store}"
|
105
109
|
rescue LoadError => e
|
106
110
|
raise "Could not find cache store adapter for #{store} (#{e})"
|
@@ -146,32 +150,48 @@ module ActiveSupport
|
|
146
150
|
# cache.namespace = -> { @last_mod_time } # Set the namespace to a variable
|
147
151
|
# @last_mod_time = Time.now # Invalidate the entire cache by changing namespace
|
148
152
|
#
|
149
|
-
#
|
150
|
-
#
|
151
|
-
#
|
152
|
-
# <tt
|
153
|
-
#
|
154
|
-
# <tt>:compress_threshold</tt> option. The default threshold is 16K.
|
153
|
+
# Cached data larger than 1kB are compressed by default. To turn off
|
154
|
+
# compression, pass <tt>compress: false</tt> to the initializer or to
|
155
|
+
# individual +fetch+ or +write+ method calls. The 1kB compression
|
156
|
+
# threshold is configurable with the <tt>:compress_threshold</tt> option,
|
157
|
+
# specified in bytes.
|
155
158
|
class Store
|
156
|
-
cattr_accessor :logger, :
|
159
|
+
cattr_accessor :logger, instance_writer: true
|
157
160
|
|
158
161
|
attr_reader :silence, :options
|
159
162
|
alias :silence? :silence
|
160
163
|
|
161
|
-
|
164
|
+
class << self
|
165
|
+
private
|
166
|
+
def retrieve_pool_options(options)
|
167
|
+
{}.tap do |pool_options|
|
168
|
+
pool_options[:size] = options.delete(:pool_size) if options[:pool_size]
|
169
|
+
pool_options[:timeout] = options.delete(:pool_timeout) if options[:pool_timeout]
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def ensure_connection_pool_added!
|
174
|
+
require "connection_pool"
|
175
|
+
rescue LoadError => e
|
176
|
+
$stderr.puts "You don't have connection_pool installed in your application. Please add it to your Gemfile and run bundle install"
|
177
|
+
raise e
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# Creates a new cache. The options will be passed to any write method calls
|
162
182
|
# except for <tt>:namespace</tt> which can be used to set the global
|
163
183
|
# namespace for the cache.
|
164
184
|
def initialize(options = nil)
|
165
185
|
@options = options ? options.dup : {}
|
166
186
|
end
|
167
187
|
|
168
|
-
#
|
188
|
+
# Silences the logger.
|
169
189
|
def silence!
|
170
190
|
@silence = true
|
171
191
|
self
|
172
192
|
end
|
173
193
|
|
174
|
-
#
|
194
|
+
# Silences the logger within a block.
|
175
195
|
def mute
|
176
196
|
previous_silence, @silence = defined?(@silence) && @silence, true
|
177
197
|
yield
|
@@ -179,18 +199,6 @@ module ActiveSupport
|
|
179
199
|
@silence = previous_silence
|
180
200
|
end
|
181
201
|
|
182
|
-
# :deprecated:
|
183
|
-
def self.instrument=(boolean)
|
184
|
-
ActiveSupport::Deprecation.warn "ActiveSupport::Cache.instrument= is deprecated and will be removed in Rails 5. Instrumentation is now always on so you can safely stop using it."
|
185
|
-
true
|
186
|
-
end
|
187
|
-
|
188
|
-
# :deprecated:
|
189
|
-
def self.instrument
|
190
|
-
ActiveSupport::Deprecation.warn "ActiveSupport::Cache.instrument is deprecated and will be removed in Rails 5. Instrumentation is now always on so you can safely stop using it."
|
191
|
-
true
|
192
|
-
end
|
193
|
-
|
194
202
|
# Fetches data from the cache, using the given key. If there is data in
|
195
203
|
# the cache with the given key, then that data is returned.
|
196
204
|
#
|
@@ -210,13 +218,27 @@ module ActiveSupport
|
|
210
218
|
# cache.fetch('city') # => "Duckburgh"
|
211
219
|
#
|
212
220
|
# You may also specify additional options via the +options+ argument.
|
213
|
-
# Setting <tt>force: true</tt>
|
221
|
+
# Setting <tt>force: true</tt> forces a cache "miss," meaning we treat
|
222
|
+
# the cache value as missing even if it's present. Passing a block is
|
223
|
+
# required when +force+ is true so this always results in a cache write.
|
214
224
|
#
|
215
225
|
# cache.write('today', 'Monday')
|
216
|
-
# cache.fetch('today', force: true)
|
226
|
+
# cache.fetch('today', force: true) { 'Tuesday' } # => 'Tuesday'
|
227
|
+
# cache.fetch('today', force: true) # => ArgumentError
|
228
|
+
#
|
229
|
+
# The +:force+ option is useful when you're calling some other method to
|
230
|
+
# ask whether you should force a cache write. Otherwise, it's clearer to
|
231
|
+
# just call <tt>Cache#write</tt>.
|
217
232
|
#
|
218
|
-
# Setting <tt
|
219
|
-
#
|
233
|
+
# Setting <tt>skip_nil: true</tt> will not cache nil result:
|
234
|
+
#
|
235
|
+
# cache.fetch('foo') { nil }
|
236
|
+
# cache.fetch('bar', skip_nil: true) { nil }
|
237
|
+
# cache.exist?('foo') # => true
|
238
|
+
# cache.exist?('bar') # => false
|
239
|
+
#
|
240
|
+
#
|
241
|
+
# Setting <tt>compress: false</tt> disables compression of the cache entry.
|
220
242
|
#
|
221
243
|
# Setting <tt>:expires_in</tt> will set an expiration time on the cache.
|
222
244
|
# All caches support auto-expiring content after a specified number of
|
@@ -227,6 +249,10 @@ module ActiveSupport
|
|
227
249
|
# cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 5.minutes)
|
228
250
|
# cache.write(key, value, expires_in: 1.minute) # Set a lower value for one entry
|
229
251
|
#
|
252
|
+
# Setting <tt>:version</tt> verifies the cache stored under <tt>name</tt>
|
253
|
+
# is of the same version. nil is returned on mismatches despite contents.
|
254
|
+
# This feature is used to support recyclable cache keys.
|
255
|
+
#
|
230
256
|
# Setting <tt>:race_condition_ttl</tt> is very useful in situations where
|
231
257
|
# a cache entry is used very frequently and is under heavy load. If a
|
232
258
|
# cache expires and due to heavy load several different processes will try
|
@@ -255,22 +281,23 @@ module ActiveSupport
|
|
255
281
|
# sleep 60
|
256
282
|
#
|
257
283
|
# Thread.new do
|
258
|
-
# val_1 = cache.fetch('foo', race_condition_ttl: 10) do
|
284
|
+
# val_1 = cache.fetch('foo', race_condition_ttl: 10.seconds) do
|
259
285
|
# sleep 1
|
260
286
|
# 'new value 1'
|
261
287
|
# end
|
262
288
|
# end
|
263
289
|
#
|
264
290
|
# Thread.new do
|
265
|
-
# val_2 = cache.fetch('foo', race_condition_ttl: 10) do
|
291
|
+
# val_2 = cache.fetch('foo', race_condition_ttl: 10.seconds) do
|
266
292
|
# 'new value 2'
|
267
293
|
# end
|
268
294
|
# end
|
269
295
|
#
|
270
|
-
# #
|
271
|
-
# #
|
272
|
-
#
|
273
|
-
# #
|
296
|
+
# cache.fetch('foo') # => "original value"
|
297
|
+
# sleep 10 # First thread extended the life of cache by another 10 seconds
|
298
|
+
# cache.fetch('foo') # => "new value 1"
|
299
|
+
# val_1 # => "new value 1"
|
300
|
+
# val_2 # => "original value"
|
274
301
|
#
|
275
302
|
# Other options will be handled by the specific cache store implementation.
|
276
303
|
# Internally, #fetch calls #read_entry, and calls #write_entry on a cache
|
@@ -288,34 +315,52 @@ module ActiveSupport
|
|
288
315
|
def fetch(name, options = nil)
|
289
316
|
if block_given?
|
290
317
|
options = merged_options(options)
|
291
|
-
key =
|
318
|
+
key = normalize_key(name, options)
|
292
319
|
|
293
|
-
|
294
|
-
|
320
|
+
entry = nil
|
321
|
+
instrument(:read, name, options) do |payload|
|
322
|
+
cached_entry = read_entry(key, **options) unless options[:force]
|
323
|
+
entry = handle_expired_entry(cached_entry, key, options)
|
324
|
+
entry = nil if entry && entry.mismatched?(normalize_version(name, options))
|
325
|
+
payload[:super_operation] = :fetch if payload
|
326
|
+
payload[:hit] = !!entry if payload
|
327
|
+
end
|
295
328
|
|
296
329
|
if entry
|
297
|
-
get_entry_value(entry, name, options)
|
330
|
+
get_entry_value(entry, name, **options)
|
298
331
|
else
|
299
|
-
save_block_result_to_cache(name, options) { |_name| yield _name }
|
332
|
+
save_block_result_to_cache(name, **options) { |_name| yield _name }
|
300
333
|
end
|
334
|
+
elsif options && options[:force]
|
335
|
+
raise ArgumentError, "Missing block: Calling `Cache#fetch` with `force: true` requires a block."
|
301
336
|
else
|
302
337
|
read(name, options)
|
303
338
|
end
|
304
339
|
end
|
305
340
|
|
306
|
-
#
|
341
|
+
# Reads data from the cache, using the given key. If there is data in
|
307
342
|
# the cache with the given key, then that data is returned. Otherwise,
|
308
343
|
# +nil+ is returned.
|
309
344
|
#
|
345
|
+
# Note, if data was written with the <tt>:expires_in</tt> or
|
346
|
+
# <tt>:version</tt> options, both of these conditions are applied before
|
347
|
+
# the data is returned.
|
348
|
+
#
|
310
349
|
# Options are passed to the underlying cache implementation.
|
311
350
|
def read(name, options = nil)
|
312
351
|
options = merged_options(options)
|
313
|
-
key
|
352
|
+
key = normalize_key(name, options)
|
353
|
+
version = normalize_version(name, options)
|
354
|
+
|
314
355
|
instrument(:read, name, options) do |payload|
|
315
|
-
entry = read_entry(key, options)
|
356
|
+
entry = read_entry(key, **options)
|
357
|
+
|
316
358
|
if entry
|
317
359
|
if entry.expired?
|
318
|
-
delete_entry(key, options)
|
360
|
+
delete_entry(key, **options)
|
361
|
+
payload[:hit] = false if payload
|
362
|
+
nil
|
363
|
+
elsif entry.mismatched?(version)
|
319
364
|
payload[:hit] = false if payload
|
320
365
|
nil
|
321
366
|
else
|
@@ -329,7 +374,7 @@ module ActiveSupport
|
|
329
374
|
end
|
330
375
|
end
|
331
376
|
|
332
|
-
#
|
377
|
+
# Reads multiple values at once from the cache. Options can be passed
|
333
378
|
# in the last argument.
|
334
379
|
#
|
335
380
|
# Some cache implementation may optimize this method.
|
@@ -338,45 +383,74 @@ module ActiveSupport
|
|
338
383
|
def read_multi(*names)
|
339
384
|
options = names.extract_options!
|
340
385
|
options = merged_options(options)
|
341
|
-
|
342
|
-
names
|
343
|
-
|
344
|
-
|
345
|
-
if entry
|
346
|
-
if entry.expired?
|
347
|
-
delete_entry(key, options)
|
348
|
-
else
|
349
|
-
results[name] = entry.value
|
350
|
-
end
|
386
|
+
|
387
|
+
instrument :read_multi, names, options do |payload|
|
388
|
+
read_multi_entries(names, **options).tap do |results|
|
389
|
+
payload[:hits] = results.keys
|
351
390
|
end
|
352
391
|
end
|
353
|
-
|
392
|
+
end
|
393
|
+
|
394
|
+
# Cache Storage API to write multiple values at once.
|
395
|
+
def write_multi(hash, options = nil)
|
396
|
+
options = merged_options(options)
|
397
|
+
|
398
|
+
instrument :write_multi, hash, options do |payload|
|
399
|
+
entries = hash.each_with_object({}) do |(name, value), memo|
|
400
|
+
memo[normalize_key(name, options)] = Entry.new(value, **options.merge(version: normalize_version(name, options)))
|
401
|
+
end
|
402
|
+
|
403
|
+
write_multi_entries entries, **options
|
404
|
+
end
|
354
405
|
end
|
355
406
|
|
356
407
|
# Fetches data from the cache, using the given keys. If there is data in
|
357
408
|
# the cache with the given keys, then that data is returned. Otherwise,
|
358
409
|
# the supplied block is called for each key for which there was no data,
|
359
410
|
# and the result will be written to the cache and returned.
|
360
|
-
#
|
361
|
-
#
|
411
|
+
# Therefore, you need to pass a block that returns the data to be written
|
412
|
+
# to the cache. If you do not want to write the cache when the cache is
|
413
|
+
# not found, use #read_multi.
|
362
414
|
#
|
363
415
|
# Returns a hash with the data for each of the names. For example:
|
364
416
|
#
|
365
417
|
# cache.write("bim", "bam")
|
366
|
-
# cache.fetch_multi("bim", "
|
367
|
-
#
|
418
|
+
# cache.fetch_multi("bim", "unknown_key") do |key|
|
419
|
+
# "Fallback value for key: #{key}"
|
420
|
+
# end
|
421
|
+
# # => { "bim" => "bam",
|
422
|
+
# # "unknown_key" => "Fallback value for key: unknown_key" }
|
368
423
|
#
|
424
|
+
# Options are passed to the underlying cache implementation. For example:
|
425
|
+
#
|
426
|
+
# cache.fetch_multi("fizz", expires_in: 5.seconds) do |key|
|
427
|
+
# "buzz"
|
428
|
+
# end
|
429
|
+
# # => {"fizz"=>"buzz"}
|
430
|
+
# cache.read("fizz")
|
431
|
+
# # => "buzz"
|
432
|
+
# sleep(6)
|
433
|
+
# cache.read("fizz")
|
434
|
+
# # => nil
|
369
435
|
def fetch_multi(*names)
|
436
|
+
raise ArgumentError, "Missing block: `Cache#fetch_multi` requires a block." unless block_given?
|
437
|
+
|
370
438
|
options = names.extract_options!
|
371
439
|
options = merged_options(options)
|
372
|
-
results = read_multi(*names, options)
|
373
440
|
|
374
|
-
names
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
441
|
+
instrument :read_multi, names, options do |payload|
|
442
|
+
reads = read_multi_entries(names, **options)
|
443
|
+
writes = {}
|
444
|
+
ordered = names.each_with_object({}) do |name, hash|
|
445
|
+
hash[name] = reads.fetch(name) { writes[name] = yield(name) }
|
379
446
|
end
|
447
|
+
|
448
|
+
payload[:hits] = reads.keys
|
449
|
+
payload[:super_operation] = :fetch_multi
|
450
|
+
|
451
|
+
write_multi(writes, **options)
|
452
|
+
|
453
|
+
ordered
|
380
454
|
end
|
381
455
|
end
|
382
456
|
|
@@ -387,8 +461,8 @@ module ActiveSupport
|
|
387
461
|
options = merged_options(options)
|
388
462
|
|
389
463
|
instrument(:write, name, options) do
|
390
|
-
entry = Entry.new(value, options)
|
391
|
-
write_entry(
|
464
|
+
entry = Entry.new(value, **options.merge(version: normalize_version(name, options)))
|
465
|
+
write_entry(normalize_key(name, options), entry, **options)
|
392
466
|
end
|
393
467
|
end
|
394
468
|
|
@@ -399,7 +473,7 @@ module ActiveSupport
|
|
399
473
|
options = merged_options(options)
|
400
474
|
|
401
475
|
instrument(:delete, name) do
|
402
|
-
delete_entry(
|
476
|
+
delete_entry(normalize_key(name, options), **options)
|
403
477
|
end
|
404
478
|
end
|
405
479
|
|
@@ -410,67 +484,67 @@ module ActiveSupport
|
|
410
484
|
options = merged_options(options)
|
411
485
|
|
412
486
|
instrument(:exist?, name) do
|
413
|
-
entry = read_entry(
|
414
|
-
(entry && !entry.expired?) || false
|
487
|
+
entry = read_entry(normalize_key(name, options), **options)
|
488
|
+
(entry && !entry.expired? && !entry.mismatched?(normalize_version(name, options))) || false
|
415
489
|
end
|
416
490
|
end
|
417
491
|
|
418
|
-
#
|
492
|
+
# Deletes all entries with keys matching the pattern.
|
419
493
|
#
|
420
494
|
# Options are passed to the underlying cache implementation.
|
421
495
|
#
|
422
|
-
#
|
496
|
+
# Some implementations may not support this method.
|
423
497
|
def delete_matched(matcher, options = nil)
|
424
498
|
raise NotImplementedError.new("#{self.class.name} does not support delete_matched")
|
425
499
|
end
|
426
500
|
|
427
|
-
#
|
501
|
+
# Increments an integer value in the cache.
|
428
502
|
#
|
429
503
|
# Options are passed to the underlying cache implementation.
|
430
504
|
#
|
431
|
-
#
|
505
|
+
# Some implementations may not support this method.
|
432
506
|
def increment(name, amount = 1, options = nil)
|
433
507
|
raise NotImplementedError.new("#{self.class.name} does not support increment")
|
434
508
|
end
|
435
509
|
|
436
|
-
#
|
510
|
+
# Decrements an integer value in the cache.
|
437
511
|
#
|
438
512
|
# Options are passed to the underlying cache implementation.
|
439
513
|
#
|
440
|
-
#
|
514
|
+
# Some implementations may not support this method.
|
441
515
|
def decrement(name, amount = 1, options = nil)
|
442
516
|
raise NotImplementedError.new("#{self.class.name} does not support decrement")
|
443
517
|
end
|
444
518
|
|
445
|
-
#
|
519
|
+
# Cleanups the cache by removing expired entries.
|
446
520
|
#
|
447
521
|
# Options are passed to the underlying cache implementation.
|
448
522
|
#
|
449
|
-
#
|
523
|
+
# Some implementations may not support this method.
|
450
524
|
def cleanup(options = nil)
|
451
525
|
raise NotImplementedError.new("#{self.class.name} does not support cleanup")
|
452
526
|
end
|
453
527
|
|
454
|
-
#
|
528
|
+
# Clears the entire cache. Be careful with this method since it could
|
455
529
|
# affect other processes if shared cache is being used.
|
456
530
|
#
|
457
531
|
# The options hash is passed to the underlying cache implementation.
|
458
532
|
#
|
459
|
-
#
|
533
|
+
# Some implementations may not support this method.
|
460
534
|
def clear(options = nil)
|
461
535
|
raise NotImplementedError.new("#{self.class.name} does not support clear")
|
462
536
|
end
|
463
537
|
|
464
|
-
|
465
|
-
#
|
538
|
+
private
|
539
|
+
# Adds the namespace defined in the options to a pattern designed to
|
466
540
|
# match keys. Implementations that support delete_matched should call
|
467
541
|
# this method to translate a pattern that matches names into one that
|
468
542
|
# matches namespaced keys.
|
469
|
-
def key_matcher(pattern, options)
|
543
|
+
def key_matcher(pattern, options) # :doc:
|
470
544
|
prefix = options[:namespace].is_a?(Proc) ? options[:namespace].call : options[:namespace]
|
471
545
|
if prefix
|
472
546
|
source = pattern.source
|
473
|
-
if source.start_with?(
|
547
|
+
if source.start_with?("^")
|
474
548
|
source = source[1, source.length]
|
475
549
|
else
|
476
550
|
source = ".*#{source[0, source.length]}"
|
@@ -481,94 +555,152 @@ module ActiveSupport
|
|
481
555
|
end
|
482
556
|
end
|
483
557
|
|
484
|
-
#
|
558
|
+
# Reads an entry from the cache implementation. Subclasses must implement
|
485
559
|
# this method.
|
486
|
-
def read_entry(key, options)
|
560
|
+
def read_entry(key, **options)
|
487
561
|
raise NotImplementedError.new
|
488
562
|
end
|
489
563
|
|
490
|
-
#
|
564
|
+
# Writes an entry to the cache implementation. Subclasses must implement
|
491
565
|
# this method.
|
492
|
-
def write_entry(key, entry, options)
|
566
|
+
def write_entry(key, entry, **options)
|
493
567
|
raise NotImplementedError.new
|
494
568
|
end
|
495
569
|
|
496
|
-
#
|
570
|
+
# Reads multiple entries from the cache implementation. Subclasses MAY
|
571
|
+
# implement this method.
|
572
|
+
def read_multi_entries(names, **options)
|
573
|
+
results = {}
|
574
|
+
names.each do |name|
|
575
|
+
key = normalize_key(name, options)
|
576
|
+
version = normalize_version(name, options)
|
577
|
+
entry = read_entry(key, **options)
|
578
|
+
|
579
|
+
if entry
|
580
|
+
if entry.expired?
|
581
|
+
delete_entry(key, **options)
|
582
|
+
elsif entry.mismatched?(version)
|
583
|
+
# Skip mismatched versions
|
584
|
+
else
|
585
|
+
results[name] = entry.value
|
586
|
+
end
|
587
|
+
end
|
588
|
+
end
|
589
|
+
results
|
590
|
+
end
|
591
|
+
|
592
|
+
# Writes multiple entries to the cache implementation. Subclasses MAY
|
497
593
|
# implement this method.
|
498
|
-
def
|
594
|
+
def write_multi_entries(hash, **options)
|
595
|
+
hash.each do |key, entry|
|
596
|
+
write_entry key, entry, **options
|
597
|
+
end
|
598
|
+
end
|
599
|
+
|
600
|
+
# Deletes an entry from the cache implementation. Subclasses must
|
601
|
+
# implement this method.
|
602
|
+
def delete_entry(key, **options)
|
499
603
|
raise NotImplementedError.new
|
500
604
|
end
|
501
605
|
|
502
|
-
|
503
|
-
|
504
|
-
def merged_options(call_options) # :nodoc:
|
606
|
+
# Merges the default options with ones specific to a method call.
|
607
|
+
def merged_options(call_options)
|
505
608
|
if call_options
|
506
|
-
options.
|
609
|
+
if options.empty?
|
610
|
+
call_options
|
611
|
+
else
|
612
|
+
options.merge(call_options)
|
613
|
+
end
|
614
|
+
else
|
615
|
+
options
|
616
|
+
end
|
617
|
+
end
|
618
|
+
|
619
|
+
# Expands and namespaces the cache key. May be overridden by
|
620
|
+
# cache stores to do additional normalization.
|
621
|
+
def normalize_key(key, options = nil)
|
622
|
+
namespace_key expanded_key(key), options
|
623
|
+
end
|
624
|
+
|
625
|
+
# Prefix the key with a namespace string:
|
626
|
+
#
|
627
|
+
# namespace_key 'foo', namespace: 'cache'
|
628
|
+
# # => 'cache:foo'
|
629
|
+
#
|
630
|
+
# With a namespace block:
|
631
|
+
#
|
632
|
+
# namespace_key 'foo', namespace: -> { 'cache' }
|
633
|
+
# # => 'cache:foo'
|
634
|
+
def namespace_key(key, options = nil)
|
635
|
+
options = merged_options(options)
|
636
|
+
namespace = options[:namespace]
|
637
|
+
|
638
|
+
if namespace.respond_to?(:call)
|
639
|
+
namespace = namespace.call
|
640
|
+
end
|
641
|
+
|
642
|
+
if namespace
|
643
|
+
"#{namespace}:#{key}"
|
507
644
|
else
|
508
|
-
|
645
|
+
key
|
509
646
|
end
|
510
647
|
end
|
511
648
|
|
512
|
-
#
|
649
|
+
# Expands key to be a consistent string value. Invokes +cache_key+ if
|
513
650
|
# object responds to +cache_key+. Otherwise, +to_param+ method will be
|
514
651
|
# called. If the key is a Hash, then keys will be sorted alphabetically.
|
515
|
-
def expanded_key(key)
|
652
|
+
def expanded_key(key)
|
516
653
|
return key.cache_key.to_s if key.respond_to?(:cache_key)
|
517
654
|
|
518
655
|
case key
|
519
656
|
when Array
|
520
657
|
if key.size > 1
|
521
|
-
key = key.collect{|element| expanded_key(element)}
|
658
|
+
key = key.collect { |element| expanded_key(element) }
|
522
659
|
else
|
523
|
-
key = key.first
|
660
|
+
key = expanded_key(key.first)
|
524
661
|
end
|
525
662
|
when Hash
|
526
|
-
key = key.sort_by { |k,_| k.to_s }.collect{|k,v| "#{k}=#{v}"}
|
663
|
+
key = key.sort_by { |k, _| k.to_s }.collect { |k, v| "#{k}=#{v}" }
|
527
664
|
end
|
528
665
|
|
529
666
|
key.to_param
|
530
667
|
end
|
531
668
|
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
key
|
539
|
-
key
|
669
|
+
def normalize_version(key, options = nil)
|
670
|
+
(options && options[:version].try(:to_param)) || expanded_version(key)
|
671
|
+
end
|
672
|
+
|
673
|
+
def expanded_version(key)
|
674
|
+
case
|
675
|
+
when key.respond_to?(:cache_version) then key.cache_version.to_param
|
676
|
+
when key.is_a?(Array) then key.map { |element| expanded_version(element) }.compact.to_param
|
677
|
+
when key.respond_to?(:to_a) then expanded_version(key.to_a)
|
678
|
+
end
|
540
679
|
end
|
541
680
|
|
542
681
|
def instrument(operation, key, options = nil)
|
543
|
-
log
|
682
|
+
log { "Cache #{operation}: #{normalize_key(key, options)}#{options.blank? ? "" : " (#{options.inspect})"}" }
|
544
683
|
|
545
|
-
payload = { :
|
684
|
+
payload = { key: key }
|
546
685
|
payload.merge!(options) if options.is_a?(Hash)
|
547
|
-
ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload){ yield(payload) }
|
686
|
+
ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload) { yield(payload) }
|
548
687
|
end
|
549
688
|
|
550
|
-
def log
|
689
|
+
def log
|
551
690
|
return unless logger && logger.debug? && !silence?
|
552
|
-
logger.debug(
|
553
|
-
end
|
554
|
-
|
555
|
-
def find_cached_entry(key, name, options)
|
556
|
-
instrument(:read, name, options) do |payload|
|
557
|
-
payload[:super_operation] = :fetch if payload
|
558
|
-
read_entry(key, options)
|
559
|
-
end
|
691
|
+
logger.debug(yield)
|
560
692
|
end
|
561
693
|
|
562
694
|
def handle_expired_entry(entry, key, options)
|
563
695
|
if entry && entry.expired?
|
564
696
|
race_ttl = options[:race_condition_ttl].to_i
|
565
697
|
if (race_ttl > 0) && (Time.now.to_f - entry.expires_at <= race_ttl)
|
566
|
-
# When an entry has :race_condition_ttl defined, put the stale entry back into the cache
|
567
|
-
# for a brief period while the entry is
|
698
|
+
# When an entry has a positive :race_condition_ttl defined, put the stale entry back into the cache
|
699
|
+
# for a brief period while the entry is being recalculated.
|
568
700
|
entry.expires_at = Time.now + race_ttl
|
569
|
-
write_entry(key, entry, :
|
701
|
+
write_entry(key, entry, expires_in: race_ttl * 2)
|
570
702
|
else
|
571
|
-
delete_entry(key, options)
|
703
|
+
delete_entry(key, **options)
|
572
704
|
end
|
573
705
|
entry = nil
|
574
706
|
end
|
@@ -576,53 +708,54 @@ module ActiveSupport
|
|
576
708
|
end
|
577
709
|
|
578
710
|
def get_entry_value(entry, name, options)
|
579
|
-
instrument(:fetch_hit, name, options) {
|
711
|
+
instrument(:fetch_hit, name, options) { }
|
580
712
|
entry.value
|
581
713
|
end
|
582
714
|
|
583
|
-
def save_block_result_to_cache(name, options)
|
584
|
-
result = instrument(:generate, name, options) do
|
715
|
+
def save_block_result_to_cache(name, **options)
|
716
|
+
result = instrument(:generate, name, options) do
|
585
717
|
yield(name)
|
586
718
|
end
|
587
719
|
|
588
|
-
write(name, result, options)
|
720
|
+
write(name, result, options) unless result.nil? && options[:skip_nil]
|
589
721
|
result
|
590
722
|
end
|
591
723
|
end
|
592
724
|
|
593
|
-
# This class is used to represent cache entries. Cache entries have a value
|
594
|
-
# expiration time. The expiration time is used to support the :race_condition_ttl option
|
595
|
-
# on the cache.
|
725
|
+
# This class is used to represent cache entries. Cache entries have a value, an optional
|
726
|
+
# expiration time, and an optional version. The expiration time is used to support the :race_condition_ttl option
|
727
|
+
# on the cache. The version is used to support the :version option on the cache for rejecting
|
728
|
+
# mismatches.
|
596
729
|
#
|
597
730
|
# Since cache entries in most instances will be serialized, the internals of this class are highly optimized
|
598
731
|
# using short instance variable names that are lazily defined.
|
599
732
|
class Entry # :nodoc:
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
# +:compress+, +:compress_threshold+, and +:expires_in+.
|
604
|
-
def initialize(value, options = {})
|
605
|
-
if should_compress?(value, options)
|
606
|
-
@value = compress(value)
|
607
|
-
@compressed = true
|
608
|
-
else
|
609
|
-
@value = value
|
610
|
-
end
|
733
|
+
attr_reader :version
|
734
|
+
|
735
|
+
DEFAULT_COMPRESS_LIMIT = 1.kilobyte
|
611
736
|
|
737
|
+
# Creates a new cache entry for the specified value. Options supported are
|
738
|
+
# +:compress+, +:compress_threshold+, +:version+ and +:expires_in+.
|
739
|
+
def initialize(value, compress: true, compress_threshold: DEFAULT_COMPRESS_LIMIT, version: nil, expires_in: nil, **)
|
740
|
+
@value = value
|
741
|
+
@version = version
|
612
742
|
@created_at = Time.now.to_f
|
613
|
-
@expires_in =
|
614
|
-
|
743
|
+
@expires_in = expires_in && expires_in.to_f
|
744
|
+
|
745
|
+
compress!(compress_threshold) if compress
|
615
746
|
end
|
616
747
|
|
617
748
|
def value
|
618
|
-
convert_version_4beta1_entry! if defined?(@v)
|
619
749
|
compressed? ? uncompress(@value) : @value
|
620
750
|
end
|
621
751
|
|
622
|
-
|
752
|
+
def mismatched?(version)
|
753
|
+
@version && version && @version != version
|
754
|
+
end
|
755
|
+
|
756
|
+
# Checks if the entry is expired. The +expires_in+ parameter can override
|
623
757
|
# the value set when the entry was created.
|
624
758
|
def expired?
|
625
|
-
convert_version_4beta1_entry! if defined?(@v)
|
626
759
|
@expires_in && @created_at + @expires_in <= Time.now.to_f
|
627
760
|
end
|
628
761
|
|
@@ -641,25 +774,19 @@ module ActiveSupport
|
|
641
774
|
# Returns the size of the cached value. This could be less than
|
642
775
|
# <tt>value.size</tt> if the data is compressed.
|
643
776
|
def size
|
644
|
-
|
645
|
-
|
777
|
+
case value
|
778
|
+
when NilClass
|
779
|
+
0
|
780
|
+
when String
|
781
|
+
@value.bytesize
|
646
782
|
else
|
647
|
-
|
648
|
-
when NilClass
|
649
|
-
0
|
650
|
-
when String
|
651
|
-
@value.bytesize
|
652
|
-
else
|
653
|
-
@s = Marshal.dump(@value).bytesize
|
654
|
-
end
|
783
|
+
@s ||= Marshal.dump(@value).bytesize
|
655
784
|
end
|
656
785
|
end
|
657
786
|
|
658
|
-
#
|
787
|
+
# Duplicates the value in a class. This is used by cache implementations that don't natively
|
659
788
|
# serialize entries to protect against accidental cache modifications.
|
660
789
|
def dup_value!
|
661
|
-
convert_version_4beta1_entry! if defined?(@v)
|
662
|
-
|
663
790
|
if @value && !compressed? && !(@value.is_a?(Numeric) || @value == true || @value == false)
|
664
791
|
if @value.is_a?(String)
|
665
792
|
@value = @value.dup
|
@@ -670,48 +797,35 @@ module ActiveSupport
|
|
670
797
|
end
|
671
798
|
|
672
799
|
private
|
673
|
-
def
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
800
|
+
def compress!(compress_threshold)
|
801
|
+
case @value
|
802
|
+
when nil, true, false, Numeric
|
803
|
+
uncompressed_size = 0
|
804
|
+
when String
|
805
|
+
uncompressed_size = @value.bytesize
|
806
|
+
else
|
807
|
+
serialized = Marshal.dump(@value)
|
808
|
+
uncompressed_size = serialized.bytesize
|
679
809
|
end
|
680
810
|
|
681
|
-
|
682
|
-
|
811
|
+
if uncompressed_size >= compress_threshold
|
812
|
+
serialized ||= Marshal.dump(@value)
|
813
|
+
compressed = Zlib::Deflate.deflate(serialized)
|
683
814
|
|
684
|
-
|
685
|
-
|
815
|
+
if compressed.bytesize < uncompressed_size
|
816
|
+
@value = compressed
|
817
|
+
@compressed = true
|
818
|
+
end
|
819
|
+
end
|
686
820
|
end
|
687
821
|
|
688
|
-
def
|
689
|
-
|
822
|
+
def compressed?
|
823
|
+
defined?(@compressed)
|
690
824
|
end
|
691
825
|
|
692
826
|
def uncompress(value)
|
693
827
|
Marshal.load(Zlib::Inflate.inflate(value))
|
694
828
|
end
|
695
|
-
|
696
|
-
# The internals of this method changed between Rails 3.x and 4.0. This method provides the glue
|
697
|
-
# to ensure that cache entries created under the old version still work with the new class definition.
|
698
|
-
def convert_version_4beta1_entry!
|
699
|
-
if defined?(@v)
|
700
|
-
@value = @v
|
701
|
-
remove_instance_variable(:@v)
|
702
|
-
end
|
703
|
-
|
704
|
-
if defined?(@c)
|
705
|
-
@compressed = @c
|
706
|
-
remove_instance_variable(:@c)
|
707
|
-
end
|
708
|
-
|
709
|
-
if defined?(@x) && @x
|
710
|
-
@created_at ||= Time.now.to_f
|
711
|
-
@expires_in = @x - @created_at
|
712
|
-
remove_instance_variable(:@x)
|
713
|
-
end
|
714
|
-
end
|
715
829
|
end
|
716
830
|
end
|
717
831
|
end
|