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