activesupport 4.2.0 → 5.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +366 -232
- data/MIT-LICENSE +2 -2
- data/README.rdoc +4 -5
- data/lib/active_support.rb +17 -7
- data/lib/active_support/all.rb +5 -3
- data/lib/active_support/array_inquirer.rb +48 -0
- data/lib/active_support/backtrace_cleaner.rb +7 -5
- data/lib/active_support/benchmarkable.rb +6 -4
- data/lib/active_support/builder.rb +3 -1
- data/lib/active_support/cache.rb +271 -177
- data/lib/active_support/cache/file_store.rb +41 -35
- data/lib/active_support/cache/mem_cache_store.rb +97 -88
- data/lib/active_support/cache/memory_store.rb +27 -30
- data/lib/active_support/cache/null_store.rb +7 -8
- data/lib/active_support/cache/redis_cache_store.rb +454 -0
- data/lib/active_support/cache/strategy/local_cache.rb +67 -34
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
- data/lib/active_support/callbacks.rb +654 -560
- data/lib/active_support/concern.rb +5 -3
- 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.rb +3 -1
- data/lib/active_support/core_ext/array.rb +9 -6
- data/lib/active_support/core_ext/array/access.rb +29 -1
- data/lib/active_support/core_ext/array/conversions.rb +22 -18
- 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 +5 -3
- data/lib/active_support/core_ext/array/wrap.rb +7 -4
- data/lib/active_support/core_ext/benchmark.rb +3 -1
- data/lib/active_support/core_ext/big_decimal.rb +3 -1
- data/lib/active_support/core_ext/big_decimal/conversions.rb +10 -12
- data/lib/active_support/core_ext/class.rb +4 -3
- data/lib/active_support/core_ext/class/attribute.rb +41 -22
- data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
- data/lib/active_support/core_ext/class/subclasses.rb +20 -8
- data/lib/active_support/core_ext/date.rb +6 -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 +11 -9
- data/lib/active_support/core_ext/date/conversions.rb +31 -23
- data/lib/active_support/core_ext/date/zones.rb +4 -2
- data/lib/active_support/core_ext/date_and_time/calculations.rb +179 -56
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +16 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +12 -12
- data/lib/active_support/core_ext/date_time.rb +7 -4
- 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 +58 -20
- data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +16 -12
- data/lib/active_support/core_ext/digest/uuid.rb +7 -5
- data/lib/active_support/core_ext/enumerable.rb +107 -28
- data/lib/active_support/core_ext/file.rb +3 -1
- data/lib/active_support/core_ext/file/atomic.rb +38 -31
- data/lib/active_support/core_ext/hash.rb +11 -9
- data/lib/active_support/core_ext/hash/compact.rb +24 -15
- data/lib/active_support/core_ext/hash/conversions.rb +63 -43
- data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
- data/lib/active_support/core_ext/hash/except.rb +11 -8
- data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -3
- data/lib/active_support/core_ext/hash/keys.rb +33 -27
- data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
- data/lib/active_support/core_ext/hash/slice.rb +8 -8
- data/lib/active_support/core_ext/hash/transform_values.rb +16 -7
- data/lib/active_support/core_ext/integer.rb +5 -3
- 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/kernel.rb +6 -5
- data/lib/active_support/core_ext/kernel/agnostics.rb +2 -0
- data/lib/active_support/core_ext/kernel/concern.rb +5 -1
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -83
- data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
- data/lib/active_support/core_ext/load_error.rb +3 -22
- data/lib/active_support/core_ext/marshal.rb +13 -10
- data/lib/active_support/core_ext/module.rb +14 -11
- 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 +43 -40
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +150 -0
- data/lib/active_support/core_ext/module/concerning.rb +11 -12
- data/lib/active_support/core_ext/module/delegation.rb +121 -39
- data/lib/active_support/core_ext/module/deprecation.rb +4 -2
- data/lib/active_support/core_ext/module/introspection.rb +9 -9
- 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/name_error.rb +22 -2
- data/lib/active_support/core_ext/numeric.rb +6 -3
- 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 +35 -38
- data/lib/active_support/core_ext/object.rb +14 -13
- data/lib/active_support/core_ext/object/acts_like.rb +12 -1
- data/lib/active_support/core_ext/object/blank.rb +29 -4
- 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 +98 -45
- 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 +49 -19
- data/lib/active_support/core_ext/object/to_param.rb +3 -1
- data/lib/active_support/core_ext/object/to_query.rb +6 -4
- data/lib/active_support/core_ext/object/try.rb +70 -22
- data/lib/active_support/core_ext/object/with_options.rb +16 -3
- data/lib/active_support/core_ext/range.rb +7 -4
- 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 +21 -19
- 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/regexp.rb +6 -0
- data/lib/active_support/core_ext/securerandom.rb +25 -0
- data/lib/active_support/core_ext/string.rb +15 -13
- data/lib/active_support/core_ext/string/access.rb +9 -7
- data/lib/active_support/core_ext/string/behavior.rb +3 -1
- data/lib/active_support/core_ext/string/conversions.rb +8 -5
- data/lib/active_support/core_ext/string/exclude.rb +2 -0
- data/lib/active_support/core_ext/string/filters.rb +10 -8
- data/lib/active_support/core_ext/string/indent.rb +6 -4
- data/lib/active_support/core_ext/string/inflections.rb +61 -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 +35 -35
- 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 -2
- data/lib/active_support/core_ext/time.rb +7 -5
- data/lib/active_support/core_ext/time/acts_like.rb +3 -1
- data/lib/active_support/core_ext/time/calculations.rb +101 -51
- data/lib/active_support/core_ext/time/compatibility.rb +16 -0
- 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/uri.rb +5 -4
- data/lib/active_support/current_attributes.rb +195 -0
- data/lib/active_support/dependencies.rb +143 -160
- data/lib/active_support/dependencies/autoload.rb +2 -0
- data/lib/active_support/dependencies/interlock.rb +57 -0
- data/lib/active_support/deprecation.rb +12 -9
- data/lib/active_support/deprecation/behaviors.rb +41 -12
- 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 +54 -21
- data/lib/active_support/deprecation/proxy_wrappers.rb +56 -28
- data/lib/active_support/deprecation/reporting.rb +32 -12
- data/lib/active_support/descendants_tracker.rb +2 -0
- data/lib/active_support/digest.rb +20 -0
- data/lib/active_support/duration.rb +326 -30
- data/lib/active_support/duration/iso8601_parser.rb +125 -0
- data/lib/active_support/duration/iso8601_serializer.rb +55 -0
- 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 +4 -2
- data/lib/active_support/gzip.rb +7 -5
- data/lib/active_support/hash_with_indifferent_access.rb +130 -30
- data/lib/active_support/i18n.rb +8 -6
- data/lib/active_support/i18n_railtie.rb +34 -14
- data/lib/active_support/inflections.rb +13 -11
- data/lib/active_support/inflector.rb +7 -5
- data/lib/active_support/inflector/inflections.rb +61 -12
- data/lib/active_support/inflector/methods.rb +161 -136
- data/lib/active_support/inflector/transliterate.rb +48 -27
- data/lib/active_support/json.rb +4 -2
- data/lib/active_support/json/decoding.rb +16 -13
- data/lib/active_support/json/encoding.rb +15 -57
- data/lib/active_support/key_generator.rb +25 -25
- data/lib/active_support/lazy_load_hooks.rb +50 -20
- data/lib/active_support/locale/en.yml +2 -0
- data/lib/active_support/log_subscriber.rb +13 -10
- data/lib/active_support/log_subscriber/test_helper.rb +14 -12
- 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 +33 -0
- data/lib/active_support/message_encryptor.rb +173 -51
- data/lib/active_support/message_verifier.rb +150 -17
- 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.rb +4 -2
- data/lib/active_support/multibyte/chars.rb +37 -24
- data/lib/active_support/multibyte/unicode.rb +100 -96
- data/lib/active_support/notifications.rb +11 -7
- data/lib/active_support/notifications/fanout.rb +10 -8
- data/lib/active_support/notifications/instrumenter.rb +27 -7
- data/lib/active_support/number_helper.rb +94 -68
- data/lib/active_support/number_helper/number_converter.rb +13 -11
- data/lib/active_support/number_helper/number_to_currency_converter.rb +9 -9
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +9 -3
- data/lib/active_support/number_helper/number_to_human_converter.rb +11 -9
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +9 -8
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +13 -4
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +23 -56
- data/lib/active_support/number_helper/rounding_helper.rb +66 -0
- 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 +22 -4
- data/lib/active_support/per_thread_registry.rb +13 -6
- 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 +17 -6
- data/lib/active_support/string_inquirer.rb +11 -3
- data/lib/active_support/subscriber.rb +15 -14
- data/lib/active_support/tagged_logging.rb +14 -11
- data/lib/active_support/test_case.rb +18 -46
- data/lib/active_support/testing/assertions.rb +137 -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 +14 -10
- data/lib/active_support/testing/file_fixtures.rb +36 -0
- data/lib/active_support/testing/isolation.rb +34 -25
- data/lib/active_support/testing/method_call_assertions.rb +43 -0
- data/lib/active_support/testing/setup_and_teardown.rb +12 -3
- data/lib/active_support/testing/stream.rb +44 -0
- data/lib/active_support/testing/tagged_logging.rb +3 -1
- data/lib/active_support/testing/time_helpers.rb +96 -27
- data/lib/active_support/time.rb +14 -12
- data/lib/active_support/time_with_zone.rb +195 -53
- data/lib/active_support/values/time_zone.rb +200 -61
- data/lib/active_support/values/unicode_tables.dat +0 -0
- data/lib/active_support/version.rb +3 -1
- data/lib/active_support/xml_mini.rb +69 -51
- 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
- metadata +55 -43
- data/lib/active_support/concurrency/latch.rb +0 -27
- data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -14
- 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/debugger.rb +0 -10
- data/lib/active_support/core_ext/module/method_transplanting.rb +0 -11
- 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
@@ -1,7 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/marshal"
|
4
|
+
require "active_support/core_ext/file/atomic"
|
5
|
+
require "active_support/core_ext/string/conversions"
|
6
|
+
require "uri/common"
|
5
7
|
|
6
8
|
module ActiveSupport
|
7
9
|
module Cache
|
@@ -10,34 +12,35 @@ module ActiveSupport
|
|
10
12
|
# FileStore implements the Strategy::LocalCache strategy which implements
|
11
13
|
# an in-memory cache inside of a block.
|
12
14
|
class FileStore < Store
|
15
|
+
prepend Strategy::LocalCache
|
13
16
|
attr_reader :cache_path
|
14
17
|
|
15
18
|
DIR_FORMATTER = "%03X"
|
16
19
|
FILENAME_MAX_SIZE = 228 # max filename size on file system is 255, minus room for timestamp and random characters appended by Tempfile (used by atomic write)
|
17
20
|
FILEPATH_MAX_SIZE = 900 # max is 1024, plus some room
|
18
|
-
EXCLUDED_DIRS = [
|
21
|
+
EXCLUDED_DIRS = [".", ".."].freeze
|
22
|
+
GITKEEP_FILES = [".gitkeep", ".keep"].freeze
|
19
23
|
|
20
24
|
def initialize(cache_path, options = nil)
|
21
25
|
super(options)
|
22
26
|
@cache_path = cache_path.to_s
|
23
|
-
extend Strategy::LocalCache
|
24
27
|
end
|
25
28
|
|
26
29
|
# Deletes all items from the cache. In this case it deletes all the entries in the specified
|
27
|
-
# file store directory except for .gitkeep. Be careful which directory is specified in your
|
30
|
+
# file store directory except for .keep or .gitkeep. Be careful which directory is specified in your
|
28
31
|
# config file when using +FileStore+ because everything in that directory will be deleted.
|
29
32
|
def clear(options = nil)
|
30
|
-
root_dirs =
|
31
|
-
FileUtils.rm_r(root_dirs.collect{|f| File.join(cache_path, f)})
|
33
|
+
root_dirs = exclude_from(cache_path, EXCLUDED_DIRS + GITKEEP_FILES)
|
34
|
+
FileUtils.rm_r(root_dirs.collect { |f| File.join(cache_path, f) })
|
35
|
+
rescue Errno::ENOENT
|
32
36
|
end
|
33
37
|
|
34
38
|
# Preemptively iterates through all stored keys and removes the ones which have expired.
|
35
39
|
def cleanup(options = nil)
|
36
40
|
options = merged_options(options)
|
37
41
|
search_dir(cache_path) do |fname|
|
38
|
-
|
39
|
-
|
40
|
-
delete_entry(key, options) if entry && entry.expired?
|
42
|
+
entry = read_entry(fname, options)
|
43
|
+
delete_entry(fname, options) if entry && entry.expired?
|
41
44
|
end
|
42
45
|
end
|
43
46
|
|
@@ -59,17 +62,16 @@ module ActiveSupport
|
|
59
62
|
matcher = key_matcher(matcher, options)
|
60
63
|
search_dir(cache_path) do |path|
|
61
64
|
key = file_path_key(path)
|
62
|
-
delete_entry(
|
65
|
+
delete_entry(path, options) if key.match(matcher)
|
63
66
|
end
|
64
67
|
end
|
65
68
|
end
|
66
69
|
|
67
|
-
|
70
|
+
private
|
68
71
|
|
69
72
|
def read_entry(key, options)
|
70
|
-
|
71
|
-
|
72
|
-
File.open(file_name) { |f| Marshal.load(f) }
|
73
|
+
if File.exist?(key)
|
74
|
+
File.open(key) { |f| Marshal.load(f) }
|
73
75
|
end
|
74
76
|
rescue => e
|
75
77
|
logger.error("FileStoreError (#{e}): #{e.message}") if logger
|
@@ -77,33 +79,30 @@ module ActiveSupport
|
|
77
79
|
end
|
78
80
|
|
79
81
|
def write_entry(key, entry, options)
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
File.atomic_write(file_name, cache_path) {|f| Marshal.dump(entry, f)}
|
82
|
+
return false if options[:unless_exist] && File.exist?(key)
|
83
|
+
ensure_cache_path(File.dirname(key))
|
84
|
+
File.atomic_write(key, cache_path) { |f| Marshal.dump(entry, f) }
|
84
85
|
true
|
85
86
|
end
|
86
87
|
|
87
88
|
def delete_entry(key, options)
|
88
|
-
|
89
|
-
if File.exist?(file_name)
|
89
|
+
if File.exist?(key)
|
90
90
|
begin
|
91
|
-
File.delete(
|
92
|
-
delete_empty_directories(File.dirname(
|
91
|
+
File.delete(key)
|
92
|
+
delete_empty_directories(File.dirname(key))
|
93
93
|
true
|
94
94
|
rescue => e
|
95
95
|
# Just in case the error was caused by another process deleting the file first.
|
96
|
-
raise e if File.exist?(
|
96
|
+
raise e if File.exist?(key)
|
97
97
|
false
|
98
98
|
end
|
99
99
|
end
|
100
100
|
end
|
101
101
|
|
102
|
-
private
|
103
102
|
# Lock a file for a block so only one process can modify it at a time.
|
104
|
-
def lock_file(file_name, &block)
|
103
|
+
def lock_file(file_name, &block)
|
105
104
|
if File.exist?(file_name)
|
106
|
-
File.open(file_name,
|
105
|
+
File.open(file_name, "r+") do |f|
|
107
106
|
begin
|
108
107
|
f.flock File::LOCK_EX
|
109
108
|
yield
|
@@ -117,12 +116,14 @@ module ActiveSupport
|
|
117
116
|
end
|
118
117
|
|
119
118
|
# Translate a key into a file path.
|
120
|
-
def
|
121
|
-
|
122
|
-
|
119
|
+
def normalize_key(key, options)
|
120
|
+
key = super
|
121
|
+
fname = URI.encode_www_form_component(key)
|
122
|
+
|
123
|
+
if fname.size > FILEPATH_MAX_SIZE
|
124
|
+
fname = ActiveSupport::Digest.hexdigest(key)
|
123
125
|
end
|
124
126
|
|
125
|
-
fname = URI.encode_www_form_component(key)
|
126
127
|
hash = Zlib.adler32(fname)
|
127
128
|
hash, dir_1 = hash.divmod(0x1000)
|
128
129
|
dir_2 = hash.modulo(0x1000)
|
@@ -146,7 +147,7 @@ module ActiveSupport
|
|
146
147
|
# Delete empty directories in the cache.
|
147
148
|
def delete_empty_directories(dir)
|
148
149
|
return if File.realpath(dir) == File.realpath(cache_path)
|
149
|
-
if
|
150
|
+
if exclude_from(dir, EXCLUDED_DIRS).empty?
|
150
151
|
Dir.delete(dir) rescue nil
|
151
152
|
delete_empty_directories(File.dirname(dir))
|
152
153
|
end
|
@@ -173,7 +174,7 @@ module ActiveSupport
|
|
173
174
|
# Modifies the amount of an already existing integer value that is stored in the cache.
|
174
175
|
# If the key is not found nothing is done.
|
175
176
|
def modify_value(name, amount, options)
|
176
|
-
file_name =
|
177
|
+
file_name = normalize_key(name, options)
|
177
178
|
|
178
179
|
lock_file(file_name) do
|
179
180
|
options = merged_options(options)
|
@@ -185,6 +186,11 @@ module ActiveSupport
|
|
185
186
|
end
|
186
187
|
end
|
187
188
|
end
|
189
|
+
|
190
|
+
# Exclude entries from source directory
|
191
|
+
def exclude_from(source, excludes)
|
192
|
+
Dir.entries(source).reject { |f| excludes.include?(f) }
|
193
|
+
end
|
188
194
|
end
|
189
195
|
end
|
190
196
|
end
|
@@ -1,18 +1,19 @@
|
|
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 'active_support/core_ext/array/extract_options'
|
10
|
+
require "active_support/core_ext/marshal"
|
11
|
+
require "active_support/core_ext/array/extract_options"
|
11
12
|
|
12
13
|
module ActiveSupport
|
13
14
|
module Cache
|
14
15
|
# A cache store implementation which stores data in Memcached:
|
15
|
-
#
|
16
|
+
# https://memcached.org
|
16
17
|
#
|
17
18
|
# This is currently the most popular cache store for production websites.
|
18
19
|
#
|
@@ -24,13 +25,52 @@ module ActiveSupport
|
|
24
25
|
# MemCacheStore implements the Strategy::LocalCache strategy which implements
|
25
26
|
# an in-memory cache inside of a block.
|
26
27
|
class MemCacheStore < Store
|
28
|
+
# Provide support for raw values in the local cache strategy.
|
29
|
+
module LocalCacheWithRaw # :nodoc:
|
30
|
+
private
|
31
|
+
def read_entry(key, options)
|
32
|
+
entry = super
|
33
|
+
if options[:raw] && local_cache && entry
|
34
|
+
entry = deserialize_entry(entry.value)
|
35
|
+
end
|
36
|
+
entry
|
37
|
+
end
|
38
|
+
|
39
|
+
def write_entry(key, entry, options)
|
40
|
+
if options[:raw] && local_cache
|
41
|
+
raw_entry = Entry.new(entry.value.to_s)
|
42
|
+
raw_entry.expires_at = entry.expires_at
|
43
|
+
super(key, raw_entry, options)
|
44
|
+
else
|
45
|
+
super
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
prepend Strategy::LocalCache
|
51
|
+
prepend LocalCacheWithRaw
|
52
|
+
|
27
53
|
ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
|
28
54
|
|
29
|
-
|
55
|
+
# Creates a new Dalli::Client instance with specified addresses and options.
|
56
|
+
# By default address is equal localhost:11211.
|
57
|
+
#
|
58
|
+
# ActiveSupport::Cache::MemCacheStore.build_mem_cache
|
59
|
+
# # => #<Dalli::Client:0x007f98a47d2028 @servers=["localhost:11211"], @options={}, @ring=nil>
|
60
|
+
# ActiveSupport::Cache::MemCacheStore.build_mem_cache('localhost:10290')
|
61
|
+
# # => #<Dalli::Client:0x007f98a47b3a60 @servers=["localhost:10290"], @options={}, @ring=nil>
|
62
|
+
def self.build_mem_cache(*addresses) # :nodoc:
|
30
63
|
addresses = addresses.flatten
|
31
64
|
options = addresses.extract_options!
|
32
65
|
addresses = ["localhost:11211"] if addresses.empty?
|
33
|
-
|
66
|
+
pool_options = retrieve_pool_options(options)
|
67
|
+
|
68
|
+
if pool_options.empty?
|
69
|
+
Dalli::Client.new(addresses, options)
|
70
|
+
else
|
71
|
+
ensure_connection_pool_added!
|
72
|
+
ConnectionPool.new(pool_options) { Dalli::Client.new(addresses, options.merge(threadsafe: false)) }
|
73
|
+
end
|
34
74
|
end
|
35
75
|
|
36
76
|
# Creates a new MemCacheStore object, with the given memcached server
|
@@ -53,82 +93,56 @@ module ActiveSupport
|
|
53
93
|
@data = addresses.first
|
54
94
|
else
|
55
95
|
mem_cache_options = options.dup
|
56
|
-
UNIVERSAL_OPTIONS.each{|name| mem_cache_options.delete(name)}
|
96
|
+
UNIVERSAL_OPTIONS.each { |name| mem_cache_options.delete(name) }
|
57
97
|
@data = self.class.build_mem_cache(*(addresses + [mem_cache_options]))
|
58
98
|
end
|
59
|
-
|
60
|
-
extend Strategy::LocalCache
|
61
|
-
extend LocalCacheWithRaw
|
62
|
-
end
|
63
|
-
|
64
|
-
# Reads multiple values from the cache using a single call to the
|
65
|
-
# servers for all keys. Options can be passed in the last argument.
|
66
|
-
def read_multi(*names)
|
67
|
-
options = names.extract_options!
|
68
|
-
options = merged_options(options)
|
69
|
-
keys_to_names = Hash[names.map{|name| [escape_key(namespaced_key(name, options)), name]}]
|
70
|
-
raw_values = @data.get_multi(keys_to_names.keys, :raw => true)
|
71
|
-
values = {}
|
72
|
-
raw_values.each do |key, value|
|
73
|
-
entry = deserialize_entry(value)
|
74
|
-
values[keys_to_names[key]] = entry.value unless entry.expired?
|
75
|
-
end
|
76
|
-
values
|
77
99
|
end
|
78
100
|
|
79
101
|
# Increment a cached value. This method uses the memcached incr atomic
|
80
102
|
# operator and can only be used on values written with the :raw option.
|
81
103
|
# Calling it on a value not stored with :raw will initialize that value
|
82
104
|
# to zero.
|
83
|
-
def increment(name, amount = 1, options = nil)
|
105
|
+
def increment(name, amount = 1, options = nil)
|
84
106
|
options = merged_options(options)
|
85
|
-
instrument(:increment, name, :
|
86
|
-
|
107
|
+
instrument(:increment, name, amount: amount) do
|
108
|
+
rescue_error_with nil do
|
109
|
+
@data.with { |c| c.incr(normalize_key(name, options), amount, options[:expires_in]) }
|
110
|
+
end
|
87
111
|
end
|
88
|
-
rescue Dalli::DalliError => e
|
89
|
-
logger.error("DalliError (#{e}): #{e.message}") if logger
|
90
|
-
nil
|
91
112
|
end
|
92
113
|
|
93
114
|
# Decrement a cached value. This method uses the memcached decr atomic
|
94
115
|
# operator and can only be used on values written with the :raw option.
|
95
116
|
# Calling it on a value not stored with :raw will initialize that value
|
96
117
|
# to zero.
|
97
|
-
def decrement(name, amount = 1, options = nil)
|
118
|
+
def decrement(name, amount = 1, options = nil)
|
98
119
|
options = merged_options(options)
|
99
|
-
instrument(:decrement, name, :
|
100
|
-
|
120
|
+
instrument(:decrement, name, amount: amount) do
|
121
|
+
rescue_error_with nil do
|
122
|
+
@data.with { |c| c.decr(normalize_key(name, options), amount, options[:expires_in]) }
|
123
|
+
end
|
101
124
|
end
|
102
|
-
rescue Dalli::DalliError => e
|
103
|
-
logger.error("DalliError (#{e}): #{e.message}") if logger
|
104
|
-
nil
|
105
125
|
end
|
106
126
|
|
107
127
|
# Clear the entire cache on all memcached servers. This method should
|
108
128
|
# be used with care when shared cache is being used.
|
109
129
|
def clear(options = nil)
|
110
|
-
@data.flush_all
|
111
|
-
rescue Dalli::DalliError => e
|
112
|
-
logger.error("DalliError (#{e}): #{e.message}") if logger
|
113
|
-
nil
|
130
|
+
rescue_error_with(nil) { @data.with { |c| c.flush_all } }
|
114
131
|
end
|
115
132
|
|
116
133
|
# Get the statistics from the memcached servers.
|
117
134
|
def stats
|
118
|
-
@data.stats
|
135
|
+
@data.with { |c| c.stats }
|
119
136
|
end
|
120
137
|
|
121
|
-
|
138
|
+
private
|
122
139
|
# Read an entry from the cache.
|
123
|
-
def read_entry(key, options)
|
124
|
-
deserialize_entry(@data.get(
|
125
|
-
rescue Dalli::DalliError => e
|
126
|
-
logger.error("DalliError (#{e}): #{e.message}") if logger
|
127
|
-
nil
|
140
|
+
def read_entry(key, options)
|
141
|
+
rescue_error_with(nil) { deserialize_entry(@data.with { |c| c.get(key, options) }) }
|
128
142
|
end
|
129
143
|
|
130
144
|
# Write an entry to the cache.
|
131
|
-
def write_entry(key, entry, options)
|
145
|
+
def write_entry(key, entry, options)
|
132
146
|
method = options && options[:unless_exist] ? :add : :set
|
133
147
|
value = options[:raw] ? entry.value.to_s : entry
|
134
148
|
expires_in = options[:expires_in].to_i
|
@@ -136,30 +150,42 @@ module ActiveSupport
|
|
136
150
|
# Set the memcache expire a few minutes in the future to support race condition ttls on read
|
137
151
|
expires_in += 5.minutes
|
138
152
|
end
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
false
|
153
|
+
rescue_error_with false do
|
154
|
+
@data.with { |c| c.send(method, key, value, expires_in, options) }
|
155
|
+
end
|
143
156
|
end
|
144
157
|
|
145
|
-
#
|
146
|
-
def
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
158
|
+
# Reads multiple entries from the cache implementation.
|
159
|
+
def read_multi_entries(names, options)
|
160
|
+
keys_to_names = Hash[names.map { |name| [normalize_key(name, options), name] }]
|
161
|
+
|
162
|
+
raw_values = @data.with { |c| c.get_multi(keys_to_names.keys) }
|
163
|
+
values = {}
|
164
|
+
|
165
|
+
raw_values.each do |key, value|
|
166
|
+
entry = deserialize_entry(value)
|
167
|
+
|
168
|
+
unless entry.expired? || entry.mismatched?(normalize_version(keys_to_names[key], options))
|
169
|
+
values[keys_to_names[key]] = entry.value
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
values
|
151
174
|
end
|
152
175
|
|
153
|
-
|
176
|
+
# Delete an entry from the cache.
|
177
|
+
def delete_entry(key, options)
|
178
|
+
rescue_error_with(false) { @data.with { |c| c.delete(key) } }
|
179
|
+
end
|
154
180
|
|
155
181
|
# Memcache keys are binaries. So we need to force their encoding to binary
|
156
182
|
# before applying the regular expression to ensure we are escaping all
|
157
183
|
# characters properly.
|
158
|
-
def
|
159
|
-
key =
|
184
|
+
def normalize_key(key, options)
|
185
|
+
key = super.dup
|
160
186
|
key = key.force_encoding(Encoding::ASCII_8BIT)
|
161
|
-
key = key.gsub(ESCAPE_KEY_CHARS){ |match| "%#{match.getbyte(0).to_s(16).upcase}" }
|
162
|
-
key = "#{key[0, 213]}:md5:#{Digest
|
187
|
+
key = key.gsub(ESCAPE_KEY_CHARS) { |match| "%#{match.getbyte(0).to_s(16).upcase}" }
|
188
|
+
key = "#{key[0, 213]}:md5:#{ActiveSupport::Digest.hexdigest(key)}" if key.size > 250
|
163
189
|
key
|
164
190
|
end
|
165
191
|
|
@@ -167,32 +193,15 @@ module ActiveSupport
|
|
167
193
|
if raw_value
|
168
194
|
entry = Marshal.load(raw_value) rescue raw_value
|
169
195
|
entry.is_a?(Entry) ? entry : Entry.new(entry)
|
170
|
-
else
|
171
|
-
nil
|
172
196
|
end
|
173
197
|
end
|
174
198
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
entry = deserialize_entry(entry.value)
|
182
|
-
end
|
183
|
-
entry
|
184
|
-
end
|
185
|
-
|
186
|
-
def write_entry(key, entry, options) # :nodoc:
|
187
|
-
retval = super
|
188
|
-
if options[:raw] && local_cache && retval
|
189
|
-
raw_entry = Entry.new(entry.value.to_s)
|
190
|
-
raw_entry.expires_at = entry.expires_at
|
191
|
-
local_cache.write_entry(key, raw_entry, options)
|
192
|
-
end
|
193
|
-
retval
|
194
|
-
end
|
195
|
-
end
|
199
|
+
def rescue_error_with(fallback)
|
200
|
+
yield
|
201
|
+
rescue Dalli::DalliError => e
|
202
|
+
logger.error("DalliError (#{e}): #{e.message}") if logger
|
203
|
+
fallback
|
204
|
+
end
|
196
205
|
end
|
197
206
|
end
|
198
207
|
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.
|
@@ -28,6 +30,7 @@ module ActiveSupport
|
|
28
30
|
@pruning = false
|
29
31
|
end
|
30
32
|
|
33
|
+
# Delete all data stored in a given cache store.
|
31
34
|
def clear(options = nil)
|
32
35
|
synchronize do
|
33
36
|
@data.clear
|
@@ -39,8 +42,8 @@ module ActiveSupport
|
|
39
42
|
# Preemptively iterates through all stored keys and removes the ones which have expired.
|
40
43
|
def cleanup(options = nil)
|
41
44
|
options = merged_options(options)
|
42
|
-
instrument(:cleanup, :
|
43
|
-
keys = synchronize{ @data.keys }
|
45
|
+
instrument(:cleanup, size: @data.size) do
|
46
|
+
keys = synchronize { @data.keys }
|
44
47
|
keys.each do |key|
|
45
48
|
entry = @data[key]
|
46
49
|
delete_entry(key, options) if entry && entry.expired?
|
@@ -56,8 +59,8 @@ module ActiveSupport
|
|
56
59
|
begin
|
57
60
|
start_time = Time.now
|
58
61
|
cleanup
|
59
|
-
instrument(:prune, target_size, :
|
60
|
-
keys = synchronize{ @key_access.keys.sort{|a,b| @key_access[a].to_f <=> @key_access[b].to_f} }
|
62
|
+
instrument(:prune, target_size, from: @cache_size) do
|
63
|
+
keys = synchronize { @key_access.keys.sort { |a, b| @key_access[a].to_f <=> @key_access[b].to_f } }
|
61
64
|
keys.each do |key|
|
62
65
|
delete_entry(key, options)
|
63
66
|
return if @cache_size <= target_size || (max_time && Time.now - start_time > max_time)
|
@@ -75,32 +78,15 @@ module ActiveSupport
|
|
75
78
|
|
76
79
|
# Increment an integer value in the cache.
|
77
80
|
def increment(name, amount = 1, options = nil)
|
78
|
-
|
79
|
-
options = merged_options(options)
|
80
|
-
if num = read(name, options)
|
81
|
-
num = num.to_i + amount
|
82
|
-
write(name, num, options)
|
83
|
-
num
|
84
|
-
else
|
85
|
-
nil
|
86
|
-
end
|
87
|
-
end
|
81
|
+
modify_value(name, amount, options)
|
88
82
|
end
|
89
83
|
|
90
84
|
# Decrement an integer value in the cache.
|
91
85
|
def decrement(name, amount = 1, options = nil)
|
92
|
-
|
93
|
-
options = merged_options(options)
|
94
|
-
if num = read(name, options)
|
95
|
-
num = num.to_i - amount
|
96
|
-
write(name, num, options)
|
97
|
-
num
|
98
|
-
else
|
99
|
-
nil
|
100
|
-
end
|
101
|
-
end
|
86
|
+
modify_value(name, -amount, options)
|
102
87
|
end
|
103
88
|
|
89
|
+
# Deletes cache entries if the cache key matches a given pattern.
|
104
90
|
def delete_matched(matcher, options = nil)
|
105
91
|
options = merged_options(options)
|
106
92
|
instrument(:delete_matched, matcher.inspect) do
|
@@ -122,7 +108,7 @@ module ActiveSupport
|
|
122
108
|
@monitor.synchronize(&block)
|
123
109
|
end
|
124
110
|
|
125
|
-
|
111
|
+
private
|
126
112
|
|
127
113
|
PER_ENTRY_OVERHEAD = 240
|
128
114
|
|
@@ -130,7 +116,7 @@ module ActiveSupport
|
|
130
116
|
key.to_s.bytesize + entry.size + PER_ENTRY_OVERHEAD
|
131
117
|
end
|
132
118
|
|
133
|
-
def read_entry(key, options)
|
119
|
+
def read_entry(key, options)
|
134
120
|
entry = @data[key]
|
135
121
|
synchronize do
|
136
122
|
if entry
|
@@ -142,7 +128,7 @@ module ActiveSupport
|
|
142
128
|
entry
|
143
129
|
end
|
144
130
|
|
145
|
-
def write_entry(key, entry, options)
|
131
|
+
def write_entry(key, entry, options)
|
146
132
|
entry.dup_value!
|
147
133
|
synchronize do
|
148
134
|
old_entry = @data[key]
|
@@ -159,7 +145,7 @@ module ActiveSupport
|
|
159
145
|
end
|
160
146
|
end
|
161
147
|
|
162
|
-
def delete_entry(key, options)
|
148
|
+
def delete_entry(key, options)
|
163
149
|
synchronize do
|
164
150
|
@key_access.delete(key)
|
165
151
|
entry = @data.delete(key)
|
@@ -167,6 +153,17 @@ module ActiveSupport
|
|
167
153
|
!!entry
|
168
154
|
end
|
169
155
|
end
|
156
|
+
|
157
|
+
def modify_value(name, amount, options)
|
158
|
+
synchronize do
|
159
|
+
options = merged_options(options)
|
160
|
+
if num = read(name, options)
|
161
|
+
num = num.to_i + amount
|
162
|
+
write(name, num, options)
|
163
|
+
num
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
170
167
|
end
|
171
168
|
end
|
172
169
|
end
|