activesupport 4.0.12 → 7.0.2.4
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 +249 -501
- data/MIT-LICENSE +2 -2
- data/README.rdoc +10 -5
- 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 +41 -13
- data/lib/active_support/benchmarkable.rb +7 -15
- data/lib/active_support/builder.rb +3 -1
- data/lib/active_support/cache/file_store.rb +96 -74
- data/lib/active_support/cache/mem_cache_store.rb +211 -103
- data/lib/active_support/cache/memory_store.rb +90 -58
- data/lib/active_support/cache/null_store.rb +19 -7
- data/lib/active_support/cache/redis_cache_store.rb +468 -0
- data/lib/active_support/cache/strategy/local_cache.rb +86 -83
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
- data/lib/active_support/cache.rb +580 -241
- data/lib/active_support/callbacks.rb +812 -425
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +103 -14
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +33 -0
- data/lib/active_support/concurrency/share_lock.rb +226 -0
- data/lib/active_support/configurable.rb +21 -19
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/array/access.rb +47 -1
- data/lib/active_support/core_ext/array/conversions.rb +35 -44
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
- 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 +26 -16
- data/lib/active_support/core_ext/array/inquiry.rb +19 -0
- data/lib/active_support/core_ext/array/wrap.rb +7 -4
- data/lib/active_support/core_ext/array.rb +10 -7
- data/lib/active_support/core_ext/benchmark.rb +5 -3
- 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 +52 -49
- data/lib/active_support/core_ext/class/attribute_accessors.rb +5 -169
- data/lib/active_support/core_ext/class/subclasses.rb +25 -26
- 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 +31 -18
- data/lib/active_support/core_ext/date/conversions.rb +43 -32
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/date/zones.rb +5 -34
- data/lib/active_support/core_ext/date.rb +7 -4
- data/lib/active_support/core_ext/date_and_time/calculations.rb +198 -66
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +31 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +40 -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 +79 -38
- data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +31 -26
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/date_time.rb +8 -4
- data/lib/active_support/core_ext/digest/uuid.rb +79 -0
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +249 -17
- data/lib/active_support/core_ext/file/atomic.rb +41 -32
- data/lib/active_support/core_ext/file.rb +3 -1
- 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/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +14 -5
- data/lib/active_support/core_ext/hash/indifferent_access.rb +5 -3
- data/lib/active_support/core_ext/hash/keys.rb +39 -56
- data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
- data/lib/active_support/core_ext/hash/slice.rb +8 -23
- data/lib/active_support/core_ext/hash.rb +10 -8
- 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 -33
- data/lib/active_support/core_ext/integer.rb +5 -3
- data/lib/active_support/core_ext/kernel/concern.rb +14 -0
- data/lib/active_support/core_ext/kernel/reporting.rb +9 -78
- data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
- data/lib/active_support/core_ext/kernel.rb +5 -4
- data/lib/active_support/core_ext/load_error.rb +5 -21
- 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 +186 -44
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +157 -0
- data/lib/active_support/core_ext/module/concerning.rb +140 -0
- data/lib/active_support/core_ext/module/delegation.rb +172 -45
- data/lib/active_support/core_ext/module/deprecation.rb +3 -3
- data/lib/active_support/core_ext/module/introspection.rb +23 -38
- 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 -10
- data/lib/active_support/core_ext/name_error.rb +45 -4
- data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +135 -127
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -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 +41 -6
- data/lib/active_support/core_ext/object/blank.rb +70 -20
- 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 +17 -47
- 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 +244 -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 +106 -26
- data/lib/active_support/core_ext/object/with_options.rb +64 -5
- data/lib/active_support/core_ext/object.rb +14 -12
- data/lib/active_support/core_ext/pathname/existence.rb +21 -0
- data/lib/active_support/core_ext/pathname.rb +3 -0
- data/lib/active_support/core_ext/range/compare_range.rb +57 -0
- data/lib/active_support/core_ext/range/conversions.rb +37 -15
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/range/each.rb +18 -17
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +7 -0
- data/lib/active_support/core_ext/range/overlaps.rb +2 -0
- data/lib/active_support/core_ext/range.rb +7 -4
- data/lib/active_support/core_ext/regexp.rb +10 -1
- data/lib/active_support/core_ext/securerandom.rb +45 -0
- data/lib/active_support/core_ext/string/access.rb +42 -51
- data/lib/active_support/core_ext/string/behavior.rb +3 -1
- data/lib/active_support/core_ext/string/conversions.rb +18 -13
- data/lib/active_support/core_ext/string/exclude.rb +5 -3
- data/lib/active_support/core_ext/string/filters.rb +97 -7
- data/lib/active_support/core_ext/string/indent.rb +6 -4
- data/lib/active_support/core_ext/string/inflections.rb +106 -25
- data/lib/active_support/core_ext/string/inquiry.rb +4 -1
- data/lib/active_support/core_ext/string/multibyte.rb +18 -9
- data/lib/active_support/core_ext/string/output_safety.rb +227 -54
- data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
- data/lib/active_support/core_ext/string/strip.rb +6 -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/symbol/starts_ends_with.rb +6 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/time/acts_like.rb +3 -1
- data/lib/active_support/core_ext/time/calculations.rb +178 -116
- data/lib/active_support/core_ext/time/compatibility.rb +16 -0
- data/lib/active_support/core_ext/time/conversions.rb +37 -25
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/time/zones.rb +44 -42
- data/lib/active_support/core_ext/time.rb +8 -5
- data/lib/active_support/core_ext/uri.rb +4 -25
- data/lib/active_support/core_ext.rb +4 -2
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +226 -0
- data/lib/active_support/dependencies/autoload.rb +3 -1
- data/lib/active_support/dependencies/interlock.rb +49 -0
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +71 -696
- data/lib/active_support/deprecation/behaviors.rb +65 -16
- data/lib/active_support/deprecation/constant_accessor.rb +52 -0
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +16 -2
- data/lib/active_support/deprecation/method_wrappers.rb +62 -21
- data/lib/active_support/deprecation/proxy_wrappers.rb +82 -31
- data/lib/active_support/deprecation/reporting.rb +81 -18
- data/lib/active_support/deprecation.rb +19 -11
- data/lib/active_support/descendants_tracker.rb +192 -34
- data/lib/active_support/digest.rb +22 -0
- data/lib/active_support/duration/iso8601_parser.rb +123 -0
- data/lib/active_support/duration/iso8601_serializer.rb +67 -0
- data/lib/active_support/duration.rb +437 -39
- data/lib/active_support/encrypted_configuration.rb +56 -0
- data/lib/active_support/encrypted_file.rb +117 -0
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/error_reporter.rb +117 -0
- data/lib/active_support/evented_file_update_checker.rb +170 -0
- data/lib/active_support/execution_context/test_helper.rb +13 -0
- data/lib/active_support/execution_context.rb +53 -0
- data/lib/active_support/execution_wrapper.rb +151 -0
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/executor.rb +8 -0
- data/lib/active_support/file_update_checker.rb +62 -37
- data/lib/active_support/fork_tracker.rb +71 -0
- 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 +207 -54
- data/lib/active_support/html_safe_translation.rb +43 -0
- data/lib/active_support/i18n.rb +10 -6
- data/lib/active_support/i18n_railtie.rb +48 -19
- data/lib/active_support/inflections.rb +19 -12
- data/lib/active_support/inflector/inflections.rb +97 -37
- data/lib/active_support/inflector/methods.rb +192 -157
- data/lib/active_support/inflector/transliterate.rb +83 -33
- data/lib/active_support/inflector.rb +7 -5
- data/lib/active_support/isolated_execution_state.rb +64 -0
- data/lib/active_support/json/decoding.rb +37 -42
- data/lib/active_support/json/encoding.rb +93 -293
- data/lib/active_support/json.rb +4 -2
- data/lib/active_support/key_generator.rb +30 -47
- data/lib/active_support/lazy_load_hooks.rb +54 -21
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/locale/en.yml +10 -4
- data/lib/active_support/log_subscriber/test_helper.rb +14 -12
- data/lib/active_support/log_subscriber.rb +61 -18
- data/lib/active_support/logger.rb +40 -4
- data/lib/active_support/logger_silence.rb +17 -20
- data/lib/active_support/logger_thread_safe_level.rb +69 -0
- data/lib/active_support/message_encryptor.rb +178 -55
- data/lib/active_support/message_verifier.rb +195 -26
- data/lib/active_support/messages/metadata.rb +80 -0
- data/lib/active_support/messages/rotation_configuration.rb +23 -0
- data/lib/active_support/messages/rotator.rb +57 -0
- data/lib/active_support/multibyte/chars.rb +45 -92
- data/lib/active_support/multibyte/unicode.rb +44 -377
- data/lib/active_support/multibyte.rb +5 -3
- data/lib/active_support/notifications/fanout.rb +177 -44
- data/lib/active_support/notifications/instrumenter.rb +117 -17
- data/lib/active_support/notifications.rb +106 -39
- data/lib/active_support/number_helper/number_converter.rb +181 -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 +30 -0
- data/lib/active_support/number_helper/number_to_human_converter.rb +69 -0
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +60 -0
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
- data/lib/active_support/number_helper/number_to_phone_converter.rb +59 -0
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +59 -0
- data/lib/active_support/number_helper/rounding_helper.rb +46 -0
- data/lib/active_support/number_helper.rb +152 -394
- data/lib/active_support/option_merger.rb +18 -5
- data/lib/active_support/ordered_hash.rb +8 -6
- data/lib/active_support/ordered_options.rb +43 -7
- data/lib/active_support/parameter_filter.rb +138 -0
- data/lib/active_support/per_thread_registry.rb +24 -11
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/rails.rb +10 -11
- data/lib/active_support/railtie.rb +118 -12
- data/lib/active_support/reloader.rb +130 -0
- data/lib/active_support/rescuable.rb +112 -57
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/secure_compare_rotator.rb +51 -0
- data/lib/active_support/security_utils.rb +38 -0
- data/lib/active_support/string_inquirer.rb +11 -4
- data/lib/active_support/subscriber.rb +109 -39
- data/lib/active_support/tagged_logging.rb +54 -17
- data/lib/active_support/test_case.rb +121 -37
- data/lib/active_support/testing/assertions.rb +177 -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 +65 -11
- data/lib/active_support/testing/file_fixtures.rb +38 -0
- data/lib/active_support/testing/isolation.rb +56 -87
- data/lib/active_support/testing/method_call_assertions.rb +70 -0
- data/lib/active_support/testing/parallelization/server.rb +82 -0
- data/lib/active_support/testing/parallelization/worker.rb +103 -0
- data/lib/active_support/testing/parallelization.rb +55 -0
- data/lib/active_support/testing/parallelize_executor.rb +76 -0
- data/lib/active_support/testing/setup_and_teardown.rb +30 -10
- data/lib/active_support/testing/stream.rb +41 -0
- data/lib/active_support/testing/tagged_logging.rb +6 -4
- data/lib/active_support/testing/time_helpers.rb +246 -0
- data/lib/active_support/time.rb +13 -13
- data/lib/active_support/time_with_zone.rb +315 -90
- data/lib/active_support/values/time_zone.rb +306 -135
- data/lib/active_support/version.rb +6 -7
- data/lib/active_support/xml_mini/jdom.rb +117 -115
- data/lib/active_support/xml_mini/libxml.rb +22 -21
- data/lib/active_support/xml_mini/libxmlsax.rb +17 -19
- data/lib/active_support/xml_mini/nokogiri.rb +19 -19
- data/lib/active_support/xml_mini/nokogirisax.rb +16 -17
- data/lib/active_support/xml_mini/rexml.rb +25 -17
- data/lib/active_support/xml_mini.rb +67 -56
- data/lib/active_support.rb +58 -3
- metadata +125 -66
- 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/prepend_and_append.rb +0 -7
- 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/agnostics.rb +0 -11
- 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/marshal.rb +0 -21
- data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
- data/lib/active_support/core_ext/module/reachable.rb +0 -8
- 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/range/include_range.rb +0 -23
- 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/values/unicode_tables.dat +0 -0
@@ -1,18 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
begin
|
2
|
-
require
|
4
|
+
require "dalli"
|
3
5
|
rescue LoadError => e
|
4
6
|
$stderr.puts "You don't have dalli installed in your application. Please add it to your Gemfile and run bundle install"
|
5
7
|
raise e
|
6
8
|
end
|
7
9
|
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
10
|
+
require "delegate"
|
11
|
+
require "active_support/core_ext/enumerable"
|
12
|
+
require "active_support/core_ext/array/extract_options"
|
11
13
|
|
12
14
|
module ActiveSupport
|
13
15
|
module Cache
|
14
16
|
# A cache store implementation which stores data in Memcached:
|
15
|
-
#
|
17
|
+
# https://memcached.org
|
16
18
|
#
|
17
19
|
# This is currently the most popular cache store for production websites.
|
18
20
|
#
|
@@ -24,13 +26,76 @@ module ActiveSupport
|
|
24
26
|
# MemCacheStore implements the Strategy::LocalCache strategy which implements
|
25
27
|
# an in-memory cache inside of a block.
|
26
28
|
class MemCacheStore < Store
|
29
|
+
# Advertise cache versioning support.
|
30
|
+
def self.supports_cache_versioning?
|
31
|
+
true
|
32
|
+
end
|
33
|
+
|
34
|
+
prepend Strategy::LocalCache
|
35
|
+
|
36
|
+
module DupLocalCache
|
37
|
+
class DupLocalStore < DelegateClass(Strategy::LocalCache::LocalStore)
|
38
|
+
def write_entry(_key, entry)
|
39
|
+
if entry.is_a?(Entry)
|
40
|
+
entry.dup_value!
|
41
|
+
end
|
42
|
+
super
|
43
|
+
end
|
44
|
+
|
45
|
+
def fetch_entry(key)
|
46
|
+
entry = super do
|
47
|
+
new_entry = yield
|
48
|
+
if entry.is_a?(Entry)
|
49
|
+
new_entry.dup_value!
|
50
|
+
end
|
51
|
+
new_entry
|
52
|
+
end
|
53
|
+
entry = entry.dup
|
54
|
+
|
55
|
+
if entry.is_a?(Entry)
|
56
|
+
entry.dup_value!
|
57
|
+
end
|
58
|
+
|
59
|
+
entry
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
def local_cache
|
65
|
+
if ActiveSupport::Cache.format_version == 6.1
|
66
|
+
if local_cache = super
|
67
|
+
DupLocalStore.new(local_cache)
|
68
|
+
end
|
69
|
+
else
|
70
|
+
super
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
prepend DupLocalCache
|
75
|
+
|
27
76
|
ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
|
28
77
|
|
29
|
-
|
78
|
+
# Creates a new Dalli::Client instance with specified addresses and options.
|
79
|
+
# If no addresses are provided, we give nil to Dalli::Client, so it uses its fallbacks:
|
80
|
+
# - ENV["MEMCACHE_SERVERS"] (if defined)
|
81
|
+
# - "127.0.0.1:11211" (otherwise)
|
82
|
+
#
|
83
|
+
# ActiveSupport::Cache::MemCacheStore.build_mem_cache
|
84
|
+
# # => #<Dalli::Client:0x007f98a47d2028 @servers=["127.0.0.1:11211"], @options={}, @ring=nil>
|
85
|
+
# ActiveSupport::Cache::MemCacheStore.build_mem_cache('localhost:10290')
|
86
|
+
# # => #<Dalli::Client:0x007f98a47b3a60 @servers=["localhost:10290"], @options={}, @ring=nil>
|
87
|
+
def self.build_mem_cache(*addresses) # :nodoc:
|
30
88
|
addresses = addresses.flatten
|
31
89
|
options = addresses.extract_options!
|
32
|
-
addresses =
|
33
|
-
|
90
|
+
addresses = nil if addresses.compact.empty?
|
91
|
+
pool_options = retrieve_pool_options(options)
|
92
|
+
|
93
|
+
if pool_options.empty?
|
94
|
+
Dalli::Client.new(addresses, options)
|
95
|
+
else
|
96
|
+
ensure_connection_pool_added!
|
97
|
+
ConnectionPool.new(pool_options) { Dalli::Client.new(addresses, options.merge(threadsafe: false)) }
|
98
|
+
end
|
34
99
|
end
|
35
100
|
|
36
101
|
# Creates a new MemCacheStore object, with the given memcached server
|
@@ -39,162 +104,205 @@ module ActiveSupport
|
|
39
104
|
#
|
40
105
|
# ActiveSupport::Cache::MemCacheStore.new("localhost", "server-downstairs.localnetwork:8229")
|
41
106
|
#
|
42
|
-
# If no addresses are
|
43
|
-
#
|
44
|
-
#
|
45
|
-
# Instead of addresses one can pass in a MemCache-like object. For example:
|
46
|
-
#
|
47
|
-
# require 'memcached' # gem install memcached; uses C bindings to libmemcached
|
48
|
-
# ActiveSupport::Cache::MemCacheStore.new(Memcached::Rails.new("localhost:11211"))
|
107
|
+
# If no addresses are provided, but ENV['MEMCACHE_SERVERS'] is defined, it will be used instead. Otherwise,
|
108
|
+
# MemCacheStore will connect to localhost:11211 (the default memcached port).
|
49
109
|
def initialize(*addresses)
|
50
110
|
addresses = addresses.flatten
|
51
111
|
options = addresses.extract_options!
|
112
|
+
if options.key?(:cache_nils)
|
113
|
+
options[:skip_nil] = !options.delete(:cache_nils)
|
114
|
+
end
|
52
115
|
super(options)
|
53
116
|
|
54
|
-
|
117
|
+
unless [String, Dalli::Client, NilClass].include?(addresses.first.class)
|
118
|
+
raise ArgumentError, "First argument must be an empty array, an array of hosts or a Dalli::Client instance."
|
119
|
+
end
|
120
|
+
if addresses.first.is_a?(Dalli::Client)
|
55
121
|
@data = addresses.first
|
56
122
|
else
|
57
123
|
mem_cache_options = options.dup
|
58
|
-
|
124
|
+
# The value "compress: false" prevents duplicate compression within Dalli.
|
125
|
+
mem_cache_options[:compress] = false
|
126
|
+
(UNIVERSAL_OPTIONS - %i(compress)).each { |name| mem_cache_options.delete(name) }
|
59
127
|
@data = self.class.build_mem_cache(*(addresses + [mem_cache_options]))
|
60
128
|
end
|
61
|
-
|
62
|
-
extend Strategy::LocalCache
|
63
|
-
extend LocalCacheWithRaw
|
64
|
-
end
|
65
|
-
|
66
|
-
# Reads multiple values from the cache using a single call to the
|
67
|
-
# servers for all keys. Options can be passed in the last argument.
|
68
|
-
def read_multi(*names)
|
69
|
-
options = names.extract_options!
|
70
|
-
options = merged_options(options)
|
71
|
-
keys_to_names = Hash[names.map{|name| [escape_key(namespaced_key(name, options)), name]}]
|
72
|
-
raw_values = @data.get_multi(keys_to_names.keys, :raw => true)
|
73
|
-
values = {}
|
74
|
-
raw_values.each do |key, value|
|
75
|
-
entry = deserialize_entry(value)
|
76
|
-
values[keys_to_names[key]] = entry.value unless entry.expired?
|
77
|
-
end
|
78
|
-
values
|
79
129
|
end
|
80
130
|
|
81
131
|
# Increment a cached value. This method uses the memcached incr atomic
|
82
132
|
# operator and can only be used on values written with the :raw option.
|
83
133
|
# Calling it on a value not stored with :raw will initialize that value
|
84
134
|
# to zero.
|
85
|
-
def increment(name, amount = 1, options = nil)
|
135
|
+
def increment(name, amount = 1, options = nil)
|
86
136
|
options = merged_options(options)
|
87
|
-
instrument(:increment, name, :
|
88
|
-
|
137
|
+
instrument(:increment, name, amount: amount) do
|
138
|
+
rescue_error_with nil do
|
139
|
+
@data.with { |c| c.incr(normalize_key(name, options), amount, options[:expires_in]) }
|
140
|
+
end
|
89
141
|
end
|
90
|
-
rescue Dalli::DalliError => e
|
91
|
-
logger.error("DalliError (#{e}): #{e.message}") if logger
|
92
|
-
nil
|
93
142
|
end
|
94
143
|
|
95
144
|
# Decrement a cached value. This method uses the memcached decr atomic
|
96
145
|
# operator and can only be used on values written with the :raw option.
|
97
146
|
# Calling it on a value not stored with :raw will initialize that value
|
98
147
|
# to zero.
|
99
|
-
def decrement(name, amount = 1, options = nil)
|
148
|
+
def decrement(name, amount = 1, options = nil)
|
100
149
|
options = merged_options(options)
|
101
|
-
instrument(:decrement, name, :
|
102
|
-
|
150
|
+
instrument(:decrement, name, amount: amount) do
|
151
|
+
rescue_error_with nil do
|
152
|
+
@data.with { |c| c.decr(normalize_key(name, options), amount, options[:expires_in]) }
|
153
|
+
end
|
103
154
|
end
|
104
|
-
rescue Dalli::DalliError => e
|
105
|
-
logger.error("DalliError (#{e}): #{e.message}") if logger
|
106
|
-
nil
|
107
155
|
end
|
108
156
|
|
109
157
|
# Clear the entire cache on all memcached servers. This method should
|
110
158
|
# be used with care when shared cache is being used.
|
111
159
|
def clear(options = nil)
|
112
|
-
@data.flush_all
|
113
|
-
rescue Dalli::DalliError => e
|
114
|
-
logger.error("DalliError (#{e}): #{e.message}") if logger
|
115
|
-
nil
|
160
|
+
rescue_error_with(nil) { @data.with { |c| c.flush_all } }
|
116
161
|
end
|
117
162
|
|
118
163
|
# Get the statistics from the memcached servers.
|
119
164
|
def stats
|
120
|
-
@data.stats
|
165
|
+
@data.with { |c| c.stats }
|
121
166
|
end
|
122
167
|
|
123
|
-
|
168
|
+
private
|
169
|
+
module Coders # :nodoc:
|
170
|
+
class << self
|
171
|
+
def [](version)
|
172
|
+
case version
|
173
|
+
when 6.1
|
174
|
+
Rails61Coder
|
175
|
+
when 7.0
|
176
|
+
Rails70Coder
|
177
|
+
else
|
178
|
+
raise ArgumentError, "Unknown ActiveSupport::Cache.format_version #{Cache.format_version.inspect}"
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
module Loader
|
184
|
+
def load(payload)
|
185
|
+
if payload.is_a?(Entry)
|
186
|
+
payload
|
187
|
+
else
|
188
|
+
Cache::Coders::Loader.load(payload)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
module Rails61Coder
|
194
|
+
include Loader
|
195
|
+
extend self
|
196
|
+
|
197
|
+
def dump(entry)
|
198
|
+
entry
|
199
|
+
end
|
200
|
+
|
201
|
+
def dump_compressed(entry, threshold)
|
202
|
+
entry.compressed(threshold)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
module Rails70Coder
|
207
|
+
include Cache::Coders::Rails70Coder
|
208
|
+
include Loader
|
209
|
+
extend self
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def default_coder
|
214
|
+
Coders[Cache.format_version]
|
215
|
+
end
|
216
|
+
|
124
217
|
# Read an entry from the cache.
|
125
|
-
def read_entry(key, options)
|
126
|
-
deserialize_entry(
|
127
|
-
|
128
|
-
|
129
|
-
|
218
|
+
def read_entry(key, **options)
|
219
|
+
deserialize_entry(read_serialized_entry(key, **options), **options)
|
220
|
+
end
|
221
|
+
|
222
|
+
def read_serialized_entry(key, **options)
|
223
|
+
rescue_error_with(nil) do
|
224
|
+
@data.with { |c| c.get(key, options) }
|
225
|
+
end
|
130
226
|
end
|
131
227
|
|
132
228
|
# Write an entry to the cache.
|
133
|
-
def write_entry(key, entry, options)
|
134
|
-
|
135
|
-
|
229
|
+
def write_entry(key, entry, **options)
|
230
|
+
write_serialized_entry(key, serialize_entry(entry, **options), **options)
|
231
|
+
end
|
232
|
+
|
233
|
+
def write_serialized_entry(key, payload, **options)
|
234
|
+
method = options[:unless_exist] ? :add : :set
|
136
235
|
expires_in = options[:expires_in].to_i
|
137
|
-
if expires_in > 0 && !options[:raw]
|
236
|
+
if options[:race_condition_ttl] && expires_in > 0 && !options[:raw]
|
138
237
|
# Set the memcache expire a few minutes in the future to support race condition ttls on read
|
139
238
|
expires_in += 5.minutes
|
140
239
|
end
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
240
|
+
rescue_error_with false do
|
241
|
+
# Don't pass compress option to Dalli since we are already dealing with compression.
|
242
|
+
options.delete(:compress)
|
243
|
+
@data.with { |c| c.send(method, key, payload, expires_in, **options) }
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
# Reads multiple entries from the cache implementation.
|
248
|
+
def read_multi_entries(names, **options)
|
249
|
+
keys_to_names = names.index_by { |name| normalize_key(name, options) }
|
250
|
+
|
251
|
+
raw_values = @data.with { |c| c.get_multi(keys_to_names.keys) }
|
252
|
+
values = {}
|
253
|
+
|
254
|
+
raw_values.each do |key, value|
|
255
|
+
entry = deserialize_entry(value, raw: options[:raw])
|
256
|
+
|
257
|
+
unless entry.expired? || entry.mismatched?(normalize_version(keys_to_names[key], options))
|
258
|
+
values[keys_to_names[key]] = entry.value
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
values
|
145
263
|
end
|
146
264
|
|
147
265
|
# Delete an entry from the cache.
|
148
|
-
def delete_entry(key, options)
|
149
|
-
@data.delete(
|
150
|
-
rescue Dalli::DalliError => e
|
151
|
-
logger.error("DalliError (#{e}): #{e.message}") if logger
|
152
|
-
false
|
266
|
+
def delete_entry(key, **options)
|
267
|
+
rescue_error_with(false) { @data.with { |c| c.delete(key) } }
|
153
268
|
end
|
154
269
|
|
155
|
-
|
270
|
+
def serialize_entry(entry, raw: false, **options)
|
271
|
+
if raw
|
272
|
+
entry.value.to_s
|
273
|
+
else
|
274
|
+
super(entry, raw: raw, **options)
|
275
|
+
end
|
276
|
+
end
|
156
277
|
|
157
278
|
# Memcache keys are binaries. So we need to force their encoding to binary
|
158
279
|
# before applying the regular expression to ensure we are escaping all
|
159
280
|
# characters properly.
|
160
|
-
def
|
161
|
-
key =
|
162
|
-
|
163
|
-
|
164
|
-
|
281
|
+
def normalize_key(key, options)
|
282
|
+
key = super
|
283
|
+
if key
|
284
|
+
key = key.dup.force_encoding(Encoding::ASCII_8BIT)
|
285
|
+
key = key.gsub(ESCAPE_KEY_CHARS) { |match| "%#{match.getbyte(0).to_s(16).upcase}" }
|
286
|
+
key = "#{key[0, 212]}:hash:#{ActiveSupport::Digest.hexdigest(key)}" if key.size > 250
|
287
|
+
end
|
165
288
|
key
|
166
289
|
end
|
167
290
|
|
168
|
-
def deserialize_entry(
|
169
|
-
if
|
170
|
-
|
171
|
-
entry.is_a?(Entry) ? entry : Entry.new(entry)
|
291
|
+
def deserialize_entry(payload, raw: false, **)
|
292
|
+
if payload && raw
|
293
|
+
Entry.new(payload)
|
172
294
|
else
|
173
|
-
|
295
|
+
super(payload)
|
174
296
|
end
|
175
297
|
end
|
176
298
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
end
|
185
|
-
entry
|
186
|
-
end
|
187
|
-
|
188
|
-
def write_entry(key, entry, options) # :nodoc:
|
189
|
-
retval = super
|
190
|
-
if options[:raw] && local_cache && retval
|
191
|
-
raw_entry = Entry.new(entry.value.to_s)
|
192
|
-
raw_entry.expires_at = entry.expires_at
|
193
|
-
local_cache.write_entry(key, raw_entry, options)
|
194
|
-
end
|
195
|
-
retval
|
196
|
-
end
|
197
|
-
end
|
299
|
+
def rescue_error_with(fallback)
|
300
|
+
yield
|
301
|
+
rescue Dalli::DalliError => error
|
302
|
+
ActiveSupport.error_reporter&.report(error, handled: true, severity: :warning)
|
303
|
+
logger.error("DalliError (#{error}): #{error.message}") if logger
|
304
|
+
fallback
|
305
|
+
end
|
198
306
|
end
|
199
307
|
end
|
200
308
|
end
|
@@ -1,10 +1,12 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "monitor"
|
2
4
|
|
3
5
|
module ActiveSupport
|
4
6
|
module Cache
|
5
7
|
# A cache store implementation which stores everything into memory in the
|
6
8
|
# same process. If you're running multiple Ruby on Rails server processes
|
7
|
-
# (which is the case if you're using
|
9
|
+
# (which is the case if you're using Phusion Passenger or puma clustered mode),
|
8
10
|
# then this means that Rails server process instances won't be able
|
9
11
|
# to share cache data with each other and this may not be the most
|
10
12
|
# appropriate cache in that scenario.
|
@@ -14,13 +16,41 @@ module ActiveSupport
|
|
14
16
|
# a cleanup will occur which tries to prune the cache down to three quarters
|
15
17
|
# of the maximum size by removing the least recently used entries.
|
16
18
|
#
|
19
|
+
# Unlike other Cache store implementations, MemoryStore does not compress
|
20
|
+
# values by default. MemoryStore does not benefit from compression as much
|
21
|
+
# as other Store implementations, as it does not send data over a network.
|
22
|
+
# However, when compression is enabled, it still pays the full cost of
|
23
|
+
# compression in terms of cpu use.
|
24
|
+
#
|
17
25
|
# MemoryStore is thread-safe.
|
18
26
|
class MemoryStore < Store
|
27
|
+
module DupCoder # :nodoc:
|
28
|
+
extend self
|
29
|
+
|
30
|
+
def dump(entry)
|
31
|
+
entry.dup_value! unless entry.compressed?
|
32
|
+
entry
|
33
|
+
end
|
34
|
+
|
35
|
+
def dump_compressed(entry, threshold)
|
36
|
+
entry = entry.compressed(threshold)
|
37
|
+
entry.dup_value! unless entry.compressed?
|
38
|
+
entry
|
39
|
+
end
|
40
|
+
|
41
|
+
def load(entry)
|
42
|
+
entry = entry.dup
|
43
|
+
entry.dup_value!
|
44
|
+
entry
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
19
48
|
def initialize(options = nil)
|
20
49
|
options ||= {}
|
50
|
+
# Disable compression by default.
|
51
|
+
options[:compress] ||= false
|
21
52
|
super(options)
|
22
53
|
@data = {}
|
23
|
-
@key_access = {}
|
24
54
|
@max_size = options[:size] || 32.megabytes
|
25
55
|
@max_prune_time = options[:max_prune_time] || 2
|
26
56
|
@cache_size = 0
|
@@ -28,21 +58,27 @@ module ActiveSupport
|
|
28
58
|
@pruning = false
|
29
59
|
end
|
30
60
|
|
61
|
+
# Advertise cache versioning support.
|
62
|
+
def self.supports_cache_versioning?
|
63
|
+
true
|
64
|
+
end
|
65
|
+
|
66
|
+
# Delete all data stored in a given cache store.
|
31
67
|
def clear(options = nil)
|
32
68
|
synchronize do
|
33
69
|
@data.clear
|
34
|
-
@key_access.clear
|
35
70
|
@cache_size = 0
|
36
71
|
end
|
37
72
|
end
|
38
73
|
|
74
|
+
# Preemptively iterates through all stored keys and removes the ones which have expired.
|
39
75
|
def cleanup(options = nil)
|
40
76
|
options = merged_options(options)
|
41
|
-
instrument(:cleanup, :
|
42
|
-
keys = synchronize{ @data.keys }
|
77
|
+
instrument(:cleanup, size: @data.size) do
|
78
|
+
keys = synchronize { @data.keys }
|
43
79
|
keys.each do |key|
|
44
80
|
entry = @data[key]
|
45
|
-
delete_entry(key, options) if entry && entry.expired?
|
81
|
+
delete_entry(key, **options) if entry && entry.expired?
|
46
82
|
end
|
47
83
|
end
|
48
84
|
end
|
@@ -53,13 +89,13 @@ module ActiveSupport
|
|
53
89
|
return if pruning?
|
54
90
|
@pruning = true
|
55
91
|
begin
|
56
|
-
start_time =
|
92
|
+
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
57
93
|
cleanup
|
58
|
-
instrument(:prune, target_size, :
|
59
|
-
keys = synchronize{ @
|
94
|
+
instrument(:prune, target_size, from: @cache_size) do
|
95
|
+
keys = synchronize { @data.keys }
|
60
96
|
keys.each do |key|
|
61
|
-
delete_entry(key, options)
|
62
|
-
return if @cache_size <= target_size || (max_time &&
|
97
|
+
delete_entry(key, **options)
|
98
|
+
return if @cache_size <= target_size || (max_time && Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time > max_time)
|
63
99
|
end
|
64
100
|
end
|
65
101
|
ensure
|
@@ -74,45 +110,28 @@ module ActiveSupport
|
|
74
110
|
|
75
111
|
# Increment an integer value in the cache.
|
76
112
|
def increment(name, amount = 1, options = nil)
|
77
|
-
|
78
|
-
options = merged_options(options)
|
79
|
-
if num = read(name, options)
|
80
|
-
num = num.to_i + amount
|
81
|
-
write(name, num, options)
|
82
|
-
num
|
83
|
-
else
|
84
|
-
nil
|
85
|
-
end
|
86
|
-
end
|
113
|
+
modify_value(name, amount, options)
|
87
114
|
end
|
88
115
|
|
89
116
|
# Decrement an integer value in the cache.
|
90
117
|
def decrement(name, amount = 1, options = nil)
|
91
|
-
|
92
|
-
options = merged_options(options)
|
93
|
-
if num = read(name, options)
|
94
|
-
num = num.to_i - amount
|
95
|
-
write(name, num, options)
|
96
|
-
num
|
97
|
-
else
|
98
|
-
nil
|
99
|
-
end
|
100
|
-
end
|
118
|
+
modify_value(name, -amount, options)
|
101
119
|
end
|
102
120
|
|
121
|
+
# Deletes cache entries if the cache key matches a given pattern.
|
103
122
|
def delete_matched(matcher, options = nil)
|
104
123
|
options = merged_options(options)
|
105
124
|
instrument(:delete_matched, matcher.inspect) do
|
106
125
|
matcher = key_matcher(matcher, options)
|
107
126
|
keys = synchronize { @data.keys }
|
108
127
|
keys.each do |key|
|
109
|
-
delete_entry(key, options) if key.match(matcher)
|
128
|
+
delete_entry(key, **options) if key.match(matcher)
|
110
129
|
end
|
111
130
|
end
|
112
131
|
end
|
113
132
|
|
114
133
|
def inspect # :nodoc:
|
115
|
-
"
|
134
|
+
"#<#{self.class.name} entries=#{@data.size}, size=#{@cache_size}, options=#{@options.inspect}>"
|
116
135
|
end
|
117
136
|
|
118
137
|
# Synchronize calls to the cache. This should be called wherever the underlying cache implementation
|
@@ -121,49 +140,62 @@ module ActiveSupport
|
|
121
140
|
@monitor.synchronize(&block)
|
122
141
|
end
|
123
142
|
|
124
|
-
|
125
|
-
|
143
|
+
private
|
126
144
|
PER_ENTRY_OVERHEAD = 240
|
127
145
|
|
128
|
-
def
|
129
|
-
|
146
|
+
def default_coder
|
147
|
+
DupCoder
|
148
|
+
end
|
149
|
+
|
150
|
+
def cached_size(key, payload)
|
151
|
+
key.to_s.bytesize + payload.bytesize + PER_ENTRY_OVERHEAD
|
130
152
|
end
|
131
153
|
|
132
|
-
def read_entry(key, options)
|
133
|
-
entry =
|
154
|
+
def read_entry(key, **options)
|
155
|
+
entry = nil
|
134
156
|
synchronize do
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
157
|
+
payload = @data.delete(key)
|
158
|
+
if payload
|
159
|
+
@data[key] = payload
|
160
|
+
entry = deserialize_entry(payload)
|
139
161
|
end
|
140
162
|
end
|
141
163
|
entry
|
142
164
|
end
|
143
165
|
|
144
|
-
def write_entry(key, entry, options)
|
145
|
-
entry
|
166
|
+
def write_entry(key, entry, **options)
|
167
|
+
payload = serialize_entry(entry, **options)
|
146
168
|
synchronize do
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
169
|
+
return false if options[:unless_exist] && @data.key?(key)
|
170
|
+
|
171
|
+
old_payload = @data[key]
|
172
|
+
if old_payload
|
173
|
+
@cache_size -= (old_payload.bytesize - payload.bytesize)
|
151
174
|
else
|
152
|
-
@cache_size += cached_size(key,
|
175
|
+
@cache_size += cached_size(key, payload)
|
153
176
|
end
|
154
|
-
@
|
155
|
-
@data[key] = entry
|
177
|
+
@data[key] = payload
|
156
178
|
prune(@max_size * 0.75, @max_prune_time) if @cache_size > @max_size
|
157
179
|
true
|
158
180
|
end
|
159
181
|
end
|
160
182
|
|
161
|
-
def delete_entry(key, options)
|
183
|
+
def delete_entry(key, **options)
|
162
184
|
synchronize do
|
163
|
-
@
|
164
|
-
|
165
|
-
|
166
|
-
|
185
|
+
payload = @data.delete(key)
|
186
|
+
@cache_size -= cached_size(key, payload) if payload
|
187
|
+
!!payload
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def modify_value(name, amount, options)
|
192
|
+
options = merged_options(options)
|
193
|
+
synchronize do
|
194
|
+
if num = read(name, options)
|
195
|
+
num = num.to_i + amount
|
196
|
+
write(name, num, options)
|
197
|
+
num
|
198
|
+
end
|
167
199
|
end
|
168
200
|
end
|
169
201
|
end
|