activesupport 5.0.0 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

Files changed (268) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +343 -590
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -4
  5. data/lib/active_support/actionable_error.rb +48 -0
  6. data/lib/active_support/all.rb +5 -3
  7. data/lib/active_support/array_inquirer.rb +11 -5
  8. data/lib/active_support/backtrace_cleaner.rb +33 -5
  9. data/lib/active_support/benchmarkable.rb +5 -3
  10. data/lib/active_support/builder.rb +3 -1
  11. data/lib/active_support/cache/file_store.rb +45 -53
  12. data/lib/active_support/cache/mem_cache_store.rb +81 -79
  13. data/lib/active_support/cache/memory_store.rb +69 -41
  14. data/lib/active_support/cache/null_store.rb +11 -4
  15. data/lib/active_support/cache/redis_cache_store.rb +493 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +74 -37
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
  18. data/lib/active_support/cache.rb +332 -161
  19. data/lib/active_support/callbacks.rb +657 -586
  20. data/lib/active_support/concern.rb +79 -6
  21. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -0
  22. data/lib/active_support/concurrency/share_lock.rb +59 -19
  23. data/lib/active_support/configurable.rb +15 -17
  24. data/lib/active_support/configuration_file.rb +46 -0
  25. data/lib/active_support/core_ext/array/access.rb +21 -7
  26. data/lib/active_support/core_ext/array/conversions.rb +20 -18
  27. data/lib/active_support/core_ext/array/extract.rb +21 -0
  28. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  29. data/lib/active_support/core_ext/array/grouping.rb +3 -1
  30. data/lib/active_support/core_ext/array/inquiry.rb +3 -1
  31. data/lib/active_support/core_ext/array/wrap.rb +2 -0
  32. data/lib/active_support/core_ext/array.rb +9 -7
  33. data/lib/active_support/core_ext/benchmark.rb +5 -3
  34. data/lib/active_support/core_ext/big_decimal/conversions.rb +6 -6
  35. data/lib/active_support/core_ext/big_decimal.rb +3 -1
  36. data/lib/active_support/core_ext/class/attribute.rb +52 -49
  37. data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
  38. data/lib/active_support/core_ext/class/subclasses.rb +18 -26
  39. data/lib/active_support/core_ext/class.rb +4 -2
  40. data/lib/active_support/core_ext/date/acts_like.rb +3 -1
  41. data/lib/active_support/core_ext/date/blank.rb +3 -1
  42. data/lib/active_support/core_ext/date/calculations.rb +16 -13
  43. data/lib/active_support/core_ext/date/conversions.rb +23 -21
  44. data/lib/active_support/core_ext/date/zones.rb +4 -2
  45. data/lib/active_support/core_ext/date.rb +7 -5
  46. data/lib/active_support/core_ext/date_and_time/calculations.rb +82 -53
  47. data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -5
  48. data/lib/active_support/core_ext/date_and_time/zones.rb +9 -9
  49. data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
  50. data/lib/active_support/core_ext/date_time/blank.rb +3 -1
  51. data/lib/active_support/core_ext/date_time/calculations.rb +23 -11
  52. data/lib/active_support/core_ext/date_time/compatibility.rb +15 -2
  53. data/lib/active_support/core_ext/date_time/conversions.rb +14 -13
  54. data/lib/active_support/core_ext/date_time.rb +7 -5
  55. data/lib/active_support/core_ext/digest/uuid.rb +7 -5
  56. data/lib/active_support/core_ext/digest.rb +3 -0
  57. data/lib/active_support/core_ext/enumerable.rb +165 -29
  58. data/lib/active_support/core_ext/file/atomic.rb +7 -5
  59. data/lib/active_support/core_ext/file.rb +3 -1
  60. data/lib/active_support/core_ext/hash/conversions.rb +40 -39
  61. data/lib/active_support/core_ext/hash/deep_merge.rb +8 -12
  62. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  63. data/lib/active_support/core_ext/hash/except.rb +4 -2
  64. data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -2
  65. data/lib/active_support/core_ext/hash/keys.rb +9 -36
  66. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  67. data/lib/active_support/core_ext/hash/slice.rb +8 -29
  68. data/lib/active_support/core_ext/hash.rb +10 -9
  69. data/lib/active_support/core_ext/integer/inflections.rb +3 -1
  70. data/lib/active_support/core_ext/integer/multiple.rb +3 -1
  71. data/lib/active_support/core_ext/integer/time.rb +11 -18
  72. data/lib/active_support/core_ext/integer.rb +5 -3
  73. data/lib/active_support/core_ext/kernel/concern.rb +3 -1
  74. data/lib/active_support/core_ext/kernel/reporting.rb +3 -1
  75. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  76. data/lib/active_support/core_ext/kernel.rb +5 -4
  77. data/lib/active_support/core_ext/load_error.rb +2 -23
  78. data/lib/active_support/core_ext/marshal.rb +6 -2
  79. data/lib/active_support/core_ext/module/aliasing.rb +5 -48
  80. data/lib/active_support/core_ext/module/anonymous.rb +2 -0
  81. data/lib/active_support/core_ext/module/attr_internal.rb +7 -5
  82. data/lib/active_support/core_ext/module/attribute_accessors.rb +53 -59
  83. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +31 -24
  84. data/lib/active_support/core_ext/module/concerning.rb +16 -11
  85. data/lib/active_support/core_ext/module/delegation.rb +159 -44
  86. data/lib/active_support/core_ext/module/deprecation.rb +2 -0
  87. data/lib/active_support/core_ext/module/introspection.rb +23 -26
  88. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  89. data/lib/active_support/core_ext/module/remove_method.rb +5 -23
  90. data/lib/active_support/core_ext/module.rb +13 -12
  91. data/lib/active_support/core_ext/name_error.rb +36 -2
  92. data/lib/active_support/core_ext/numeric/bytes.rb +2 -0
  93. data/lib/active_support/core_ext/numeric/conversions.rb +129 -134
  94. data/lib/active_support/core_ext/numeric/time.rb +18 -26
  95. data/lib/active_support/core_ext/numeric.rb +5 -4
  96. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  97. data/lib/active_support/core_ext/object/blank.rb +14 -2
  98. data/lib/active_support/core_ext/object/conversions.rb +6 -4
  99. data/lib/active_support/core_ext/object/deep_dup.rb +4 -2
  100. data/lib/active_support/core_ext/object/duplicable.rb +13 -62
  101. data/lib/active_support/core_ext/object/inclusion.rb +3 -1
  102. data/lib/active_support/core_ext/object/instance_variables.rb +2 -0
  103. data/lib/active_support/core_ext/object/json.rb +42 -15
  104. data/lib/active_support/core_ext/object/to_param.rb +3 -1
  105. data/lib/active_support/core_ext/object/to_query.rb +10 -5
  106. data/lib/active_support/core_ext/object/try.rb +20 -8
  107. data/lib/active_support/core_ext/object/with_options.rb +15 -2
  108. data/lib/active_support/core_ext/object.rb +14 -12
  109. data/lib/active_support/core_ext/range/compare_range.rb +82 -0
  110. data/lib/active_support/core_ext/range/conversions.rb +35 -25
  111. data/lib/active_support/core_ext/range/each.rb +5 -2
  112. data/lib/active_support/core_ext/range/include_time_with_zone.rb +28 -0
  113. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  114. data/lib/active_support/core_ext/range.rb +7 -4
  115. data/lib/active_support/core_ext/regexp.rb +10 -1
  116. data/lib/active_support/core_ext/securerandom.rb +28 -6
  117. data/lib/active_support/core_ext/string/access.rb +9 -18
  118. data/lib/active_support/core_ext/string/behavior.rb +2 -0
  119. data/lib/active_support/core_ext/string/conversions.rb +5 -2
  120. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  121. data/lib/active_support/core_ext/string/filters.rb +47 -4
  122. data/lib/active_support/core_ext/string/indent.rb +6 -4
  123. data/lib/active_support/core_ext/string/inflections.rb +78 -29
  124. data/lib/active_support/core_ext/string/inquiry.rb +4 -1
  125. data/lib/active_support/core_ext/string/multibyte.rb +10 -5
  126. data/lib/active_support/core_ext/string/output_safety.rb +86 -31
  127. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
  128. data/lib/active_support/core_ext/string/strip.rb +5 -1
  129. data/lib/active_support/core_ext/string/zones.rb +4 -2
  130. data/lib/active_support/core_ext/string.rb +15 -13
  131. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  132. data/lib/active_support/core_ext/symbol.rb +3 -0
  133. data/lib/active_support/core_ext/time/acts_like.rb +3 -1
  134. data/lib/active_support/core_ext/time/calculations.rb +117 -45
  135. data/lib/active_support/core_ext/time/compatibility.rb +13 -2
  136. data/lib/active_support/core_ext/time/conversions.rb +18 -12
  137. data/lib/active_support/core_ext/time/zones.rb +9 -7
  138. data/lib/active_support/core_ext/time.rb +7 -5
  139. data/lib/active_support/core_ext/uri.rb +12 -7
  140. data/lib/active_support/core_ext.rb +3 -2
  141. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  142. data/lib/active_support/current_attributes.rb +208 -0
  143. data/lib/active_support/dependencies/autoload.rb +2 -0
  144. data/lib/active_support/dependencies/interlock.rb +7 -1
  145. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  146. data/lib/active_support/dependencies.rb +172 -98
  147. data/lib/active_support/deprecation/behaviors.rb +45 -13
  148. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  149. data/lib/active_support/deprecation/disallowed.rb +56 -0
  150. data/lib/active_support/deprecation/instance_delegator.rb +16 -2
  151. data/lib/active_support/deprecation/method_wrappers.rb +32 -17
  152. data/lib/active_support/deprecation/proxy_wrappers.rb +35 -7
  153. data/lib/active_support/deprecation/reporting.rb +61 -16
  154. data/lib/active_support/deprecation.rb +17 -9
  155. data/lib/active_support/descendants_tracker.rb +61 -9
  156. data/lib/active_support/digest.rb +20 -0
  157. data/lib/active_support/duration/iso8601_parser.rb +67 -66
  158. data/lib/active_support/duration/iso8601_serializer.rb +25 -17
  159. data/lib/active_support/duration.rb +349 -46
  160. data/lib/active_support/encrypted_configuration.rb +45 -0
  161. data/lib/active_support/encrypted_file.rb +117 -0
  162. data/lib/active_support/environment_inquirer.rb +20 -0
  163. data/lib/active_support/evented_file_update_checker.rb +88 -112
  164. data/lib/active_support/execution_wrapper.rb +25 -13
  165. data/lib/active_support/executor.rb +3 -1
  166. data/lib/active_support/file_update_checker.rb +56 -51
  167. data/lib/active_support/fork_tracker.rb +62 -0
  168. data/lib/active_support/gem_version.rb +4 -2
  169. data/lib/active_support/gzip.rb +7 -5
  170. data/lib/active_support/hash_with_indifferent_access.rb +153 -49
  171. data/lib/active_support/i18n.rb +9 -6
  172. data/lib/active_support/i18n_railtie.rb +30 -20
  173. data/lib/active_support/inflections.rb +13 -11
  174. data/lib/active_support/inflector/inflections.rb +28 -15
  175. data/lib/active_support/inflector/methods.rb +120 -109
  176. data/lib/active_support/inflector/transliterate.rb +60 -25
  177. data/lib/active_support/inflector.rb +7 -5
  178. data/lib/active_support/json/decoding.rb +30 -29
  179. data/lib/active_support/json/encoding.rb +22 -11
  180. data/lib/active_support/json.rb +4 -2
  181. data/lib/active_support/key_generator.rb +6 -36
  182. data/lib/active_support/lazy_load_hooks.rb +53 -20
  183. data/lib/active_support/locale/en.rb +33 -0
  184. data/lib/active_support/locale/en.yml +7 -3
  185. data/lib/active_support/log_subscriber/test_helper.rb +11 -9
  186. data/lib/active_support/log_subscriber.rb +51 -18
  187. data/lib/active_support/logger.rb +9 -22
  188. data/lib/active_support/logger_silence.rb +14 -21
  189. data/lib/active_support/logger_thread_safe_level.rb +55 -8
  190. data/lib/active_support/message_encryptor.rb +170 -53
  191. data/lib/active_support/message_verifier.rb +91 -20
  192. data/lib/active_support/messages/metadata.rb +80 -0
  193. data/lib/active_support/messages/rotation_configuration.rb +23 -0
  194. data/lib/active_support/messages/rotator.rb +57 -0
  195. data/lib/active_support/multibyte/chars.rb +24 -78
  196. data/lib/active_support/multibyte/unicode.rb +21 -352
  197. data/lib/active_support/multibyte.rb +4 -2
  198. data/lib/active_support/notifications/fanout.rb +121 -19
  199. data/lib/active_support/notifications/instrumenter.rb +78 -14
  200. data/lib/active_support/notifications.rb +80 -12
  201. data/lib/active_support/number_helper/number_converter.rb +17 -16
  202. data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -9
  203. data/lib/active_support/number_helper/number_to_delimited_converter.rb +5 -3
  204. data/lib/active_support/number_helper/number_to_human_converter.rb +13 -12
  205. data/lib/active_support/number_helper/number_to_human_size_converter.rb +11 -13
  206. data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
  207. data/lib/active_support/number_helper/number_to_phone_converter.rb +5 -4
  208. data/lib/active_support/number_helper/number_to_rounded_converter.rb +18 -55
  209. data/lib/active_support/number_helper/rounding_helper.rb +50 -0
  210. data/lib/active_support/number_helper.rb +45 -16
  211. data/lib/active_support/option_merger.rb +25 -4
  212. data/lib/active_support/ordered_hash.rb +6 -4
  213. data/lib/active_support/ordered_options.rb +23 -9
  214. data/lib/active_support/parameter_filter.rb +133 -0
  215. data/lib/active_support/per_thread_registry.rb +7 -5
  216. data/lib/active_support/proxy_object.rb +2 -0
  217. data/lib/active_support/rails.rb +8 -9
  218. data/lib/active_support/railtie.rb +62 -11
  219. data/lib/active_support/reloader.rb +12 -11
  220. data/lib/active_support/rescuable.rb +20 -11
  221. data/lib/active_support/secure_compare_rotator.rb +51 -0
  222. data/lib/active_support/security_utils.rb +26 -15
  223. data/lib/active_support/string_inquirer.rb +12 -3
  224. data/lib/active_support/subscriber.rb +77 -23
  225. data/lib/active_support/tagged_logging.rb +52 -17
  226. data/lib/active_support/test_case.rb +106 -29
  227. data/lib/active_support/testing/assertions.rb +144 -8
  228. data/lib/active_support/testing/autorun.rb +5 -10
  229. data/lib/active_support/testing/constant_lookup.rb +2 -1
  230. data/lib/active_support/testing/declarative.rb +3 -1
  231. data/lib/active_support/testing/deprecation.rb +4 -2
  232. data/lib/active_support/testing/file_fixtures.rb +4 -0
  233. data/lib/active_support/testing/isolation.rb +19 -24
  234. data/lib/active_support/testing/method_call_assertions.rb +31 -2
  235. data/lib/active_support/testing/parallelization/server.rb +78 -0
  236. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  237. data/lib/active_support/testing/parallelization.rb +51 -0
  238. data/lib/active_support/testing/setup_and_teardown.rb +13 -8
  239. data/lib/active_support/testing/stream.rb +30 -29
  240. data/lib/active_support/testing/tagged_logging.rb +3 -1
  241. data/lib/active_support/testing/time_helpers.rb +125 -24
  242. data/lib/active_support/time.rb +14 -12
  243. data/lib/active_support/time_with_zone.rb +142 -55
  244. data/lib/active_support/values/time_zone.rb +160 -53
  245. data/lib/active_support/version.rb +3 -1
  246. data/lib/active_support/xml_mini/jdom.rb +115 -114
  247. data/lib/active_support/xml_mini/libxml.rb +15 -14
  248. data/lib/active_support/xml_mini/libxmlsax.rb +16 -18
  249. data/lib/active_support/xml_mini/nokogiri.rb +13 -13
  250. data/lib/active_support/xml_mini/nokogirisax.rb +15 -16
  251. data/lib/active_support/xml_mini/rexml.rb +18 -9
  252. data/lib/active_support/xml_mini.rb +44 -42
  253. data/lib/active_support.rb +19 -10
  254. metadata +79 -37
  255. data/lib/active_support/concurrency/latch.rb +0 -19
  256. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
  257. data/lib/active_support/core_ext/hash/compact.rb +0 -20
  258. data/lib/active_support/core_ext/hash/transform_values.rb +0 -29
  259. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  260. data/lib/active_support/core_ext/kernel/debugger.rb +0 -3
  261. data/lib/active_support/core_ext/module/method_transplanting.rb +0 -3
  262. data/lib/active_support/core_ext/module/qualified_const.rb +0 -70
  263. data/lib/active_support/core_ext/module/reachable.rb +0 -8
  264. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -26
  265. data/lib/active_support/core_ext/range/include_range.rb +0 -23
  266. data/lib/active_support/core_ext/struct.rb +0 -3
  267. data/lib/active_support/core_ext/time/marshal.rb +0 -3
  268. 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 'dalli'
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 'digest/md5'
9
- require 'active_support/core_ext/marshal'
10
- require 'active_support/core_ext/array/extract_options'
10
+ require "active_support/core_ext/enumerable"
11
+ require "active_support/core_ext/marshal"
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
- # http://memcached.org/
17
+ # https://memcached.org
16
18
  #
17
19
  # This is currently the most popular cache store for production websites.
18
20
  #
@@ -24,26 +26,25 @@ 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
+ DEFAULT_CODER = NullCoder # Dalli automatically Marshal values
30
+
27
31
  # Provide support for raw values in the local cache strategy.
28
32
  module LocalCacheWithRaw # :nodoc:
29
- protected
30
- def read_entry(key, options)
31
- entry = super
32
- if options[:raw] && local_cache && entry
33
- entry = deserialize_entry(entry.value)
33
+ private
34
+ def write_entry(key, entry, **options)
35
+ if options[:raw] && local_cache
36
+ raw_entry = Entry.new(entry.value.to_s)
37
+ raw_entry.expires_at = entry.expires_at
38
+ super(key, raw_entry, **options)
39
+ else
40
+ super
41
+ end
34
42
  end
35
- entry
36
- end
43
+ end
37
44
 
38
- def write_entry(key, entry, options) # :nodoc:
39
- if options[:raw] && local_cache
40
- raw_entry = Entry.new(entry.value.to_s)
41
- raw_entry.expires_at = entry.expires_at
42
- super(key, raw_entry, options)
43
- else
44
- super
45
- end
46
- end
45
+ # Advertise cache versioning support.
46
+ def self.supports_cache_versioning?
47
+ true
47
48
  end
48
49
 
49
50
  prepend Strategy::LocalCache
@@ -52,17 +53,26 @@ module ActiveSupport
52
53
  ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
53
54
 
54
55
  # Creates a new Dalli::Client instance with specified addresses and options.
55
- # By default address is equal localhost:11211.
56
+ # If no addresses are provided, we give nil to Dalli::Client, so it uses its fallbacks:
57
+ # - ENV["MEMCACHE_SERVERS"] (if defined)
58
+ # - "127.0.0.1:11211" (otherwise)
56
59
  #
57
60
  # ActiveSupport::Cache::MemCacheStore.build_mem_cache
58
- # # => #<Dalli::Client:0x007f98a47d2028 @servers=["localhost:11211"], @options={}, @ring=nil>
61
+ # # => #<Dalli::Client:0x007f98a47d2028 @servers=["127.0.0.1:11211"], @options={}, @ring=nil>
59
62
  # ActiveSupport::Cache::MemCacheStore.build_mem_cache('localhost:10290')
60
63
  # # => #<Dalli::Client:0x007f98a47b3a60 @servers=["localhost:10290"], @options={}, @ring=nil>
61
64
  def self.build_mem_cache(*addresses) # :nodoc:
62
65
  addresses = addresses.flatten
63
66
  options = addresses.extract_options!
64
- addresses = ["localhost:11211"] if addresses.empty?
65
- Dalli::Client.new(addresses, options)
67
+ addresses = nil if addresses.empty?
68
+ pool_options = retrieve_pool_options(options)
69
+
70
+ if pool_options.empty?
71
+ Dalli::Client.new(addresses, options)
72
+ else
73
+ ensure_connection_pool_added!
74
+ ConnectionPool.new(pool_options) { Dalli::Client.new(addresses, options.merge(threadsafe: false)) }
75
+ end
66
76
  end
67
77
 
68
78
  # Creates a new MemCacheStore object, with the given memcached server
@@ -71,8 +81,8 @@ module ActiveSupport
71
81
  #
72
82
  # ActiveSupport::Cache::MemCacheStore.new("localhost", "server-downstairs.localnetwork:8229")
73
83
  #
74
- # If no addresses are specified, then MemCacheStore will connect to
75
- # localhost port 11211 (the default memcached port).
84
+ # If no addresses are provided, but ENV['MEMCACHE_SERVERS'] is defined, it will be used instead. Otherwise,
85
+ # MemCacheStore will connect to localhost:11211 (the default memcached port).
76
86
  def initialize(*addresses)
77
87
  addresses = addresses.flatten
78
88
  options = addresses.extract_options!
@@ -85,36 +95,20 @@ module ActiveSupport
85
95
  @data = addresses.first
86
96
  else
87
97
  mem_cache_options = options.dup
88
- UNIVERSAL_OPTIONS.each{|name| mem_cache_options.delete(name)}
98
+ UNIVERSAL_OPTIONS.each { |name| mem_cache_options.delete(name) }
89
99
  @data = self.class.build_mem_cache(*(addresses + [mem_cache_options]))
90
100
  end
91
101
  end
92
102
 
93
- # Reads multiple values from the cache using a single call to the
94
- # servers for all keys. Options can be passed in the last argument.
95
- def read_multi(*names)
96
- options = names.extract_options!
97
- options = merged_options(options)
98
-
99
- keys_to_names = Hash[names.map{|name| [normalize_key(name, options), name]}]
100
- raw_values = @data.get_multi(keys_to_names.keys, :raw => true)
101
- values = {}
102
- raw_values.each do |key, value|
103
- entry = deserialize_entry(value)
104
- values[keys_to_names[key]] = entry.value unless entry.expired?
105
- end
106
- values
107
- end
108
-
109
103
  # Increment a cached value. This method uses the memcached incr atomic
110
104
  # operator and can only be used on values written with the :raw option.
111
105
  # Calling it on a value not stored with :raw will initialize that value
112
106
  # to zero.
113
- def increment(name, amount = 1, options = nil) # :nodoc:
107
+ def increment(name, amount = 1, options = nil)
114
108
  options = merged_options(options)
115
- instrument(:increment, name, :amount => amount) do
109
+ instrument(:increment, name, amount: amount) do
116
110
  rescue_error_with nil do
117
- @data.incr(normalize_key(name, options), amount)
111
+ @data.with { |c| c.incr(normalize_key(name, options), amount, options[:expires_in]) }
118
112
  end
119
113
  end
120
114
  end
@@ -123,11 +117,11 @@ module ActiveSupport
123
117
  # operator and can only be used on values written with the :raw option.
124
118
  # Calling it on a value not stored with :raw will initialize that value
125
119
  # to zero.
126
- def decrement(name, amount = 1, options = nil) # :nodoc:
120
+ def decrement(name, amount = 1, options = nil)
127
121
  options = merged_options(options)
128
- instrument(:decrement, name, :amount => amount) do
122
+ instrument(:decrement, name, amount: amount) do
129
123
  rescue_error_with nil do
130
- @data.decr(normalize_key(name, options), amount)
124
+ @data.with { |c| c.decr(normalize_key(name, options), amount, options[:expires_in]) }
131
125
  end
132
126
  end
133
127
  end
@@ -135,40 +129,57 @@ module ActiveSupport
135
129
  # Clear the entire cache on all memcached servers. This method should
136
130
  # be used with care when shared cache is being used.
137
131
  def clear(options = nil)
138
- rescue_error_with(nil) { @data.flush_all }
132
+ rescue_error_with(nil) { @data.with { |c| c.flush_all } }
139
133
  end
140
134
 
141
135
  # Get the statistics from the memcached servers.
142
136
  def stats
143
- @data.stats
137
+ @data.with { |c| c.stats }
144
138
  end
145
139
 
146
- protected
140
+ private
147
141
  # Read an entry from the cache.
148
- def read_entry(key, options) # :nodoc:
149
- rescue_error_with(nil) { deserialize_entry(@data.get(key, options)) }
142
+ def read_entry(key, **options)
143
+ rescue_error_with(nil) { deserialize_entry(@data.with { |c| c.get(key, options) }) }
150
144
  end
151
145
 
152
146
  # Write an entry to the cache.
153
- def write_entry(key, entry, options) # :nodoc:
154
- method = options && options[:unless_exist] ? :add : :set
155
- value = options[:raw] ? entry.value.to_s : entry
147
+ def write_entry(key, entry, **options)
148
+ method = options[:unless_exist] ? :add : :set
149
+ value = options[:raw] ? entry.value.to_s : serialize_entry(entry)
156
150
  expires_in = options[:expires_in].to_i
157
- if expires_in > 0 && !options[:raw]
151
+ if options[:race_condition_ttl] && expires_in > 0 && !options[:raw]
158
152
  # Set the memcache expire a few minutes in the future to support race condition ttls on read
159
153
  expires_in += 5.minutes
160
154
  end
161
155
  rescue_error_with false do
162
- @data.send(method, key, value, expires_in, options)
156
+ # The value "compress: false" prevents duplicate compression within Dalli.
157
+ @data.with { |c| c.send(method, key, value, expires_in, **options, compress: false) }
163
158
  end
164
159
  end
165
160
 
166
- # Delete an entry from the cache.
167
- def delete_entry(key, options) # :nodoc:
168
- rescue_error_with(false) { @data.delete(key) }
161
+ # Reads multiple entries from the cache implementation.
162
+ def read_multi_entries(names, **options)
163
+ keys_to_names = names.index_by { |name| normalize_key(name, options) }
164
+
165
+ raw_values = @data.with { |c| c.get_multi(keys_to_names.keys) }
166
+ values = {}
167
+
168
+ raw_values.each do |key, value|
169
+ entry = deserialize_entry(value)
170
+
171
+ unless entry.expired? || entry.mismatched?(normalize_version(keys_to_names[key], options))
172
+ values[keys_to_names[key]] = entry.value
173
+ end
174
+ end
175
+
176
+ values
169
177
  end
170
178
 
171
- private
179
+ # Delete an entry from the cache.
180
+ def delete_entry(key, **options)
181
+ rescue_error_with(false) { @data.with { |c| c.delete(key) } }
182
+ end
172
183
 
173
184
  # Memcache keys are binaries. So we need to force their encoding to binary
174
185
  # before applying the regular expression to ensure we are escaping all
@@ -176,24 +187,15 @@ module ActiveSupport
176
187
  def normalize_key(key, options)
177
188
  key = super.dup
178
189
  key = key.force_encoding(Encoding::ASCII_8BIT)
179
- key = key.gsub(ESCAPE_KEY_CHARS){ |match| "%#{match.getbyte(0).to_s(16).upcase}" }
180
- key = "#{key[0, 213]}:md5:#{Digest::MD5.hexdigest(key)}" if key.size > 250
181
- key
182
- end
183
-
184
- def escape_key(key)
185
- ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
186
- `escape_key` is deprecated and will be removed from Rails 5.1.
187
- Please use `normalize_key` which will return a fully resolved key or nothing.
188
- MESSAGE
190
+ key = key.gsub(ESCAPE_KEY_CHARS) { |match| "%#{match.getbyte(0).to_s(16).upcase}" }
191
+ key = "#{key[0, 213]}:md5:#{ActiveSupport::Digest.hexdigest(key)}" if key.size > 250
189
192
  key
190
193
  end
191
194
 
192
- def deserialize_entry(raw_value)
193
- if raw_value
194
- entry = Marshal.load(raw_value) rescue raw_value
195
- entry.is_a?(Entry) ? entry : Entry.new(entry)
196
- end
195
+ def deserialize_entry(payload)
196
+ entry = super
197
+ entry = Entry.new(entry, compress: false) if entry && !entry.is_a?(Entry)
198
+ entry
197
199
  end
198
200
 
199
201
  def rescue_error_with(fallback)
@@ -1,10 +1,12 @@
1
- require 'monitor'
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 mongrel_cluster or Phusion Passenger),
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,37 @@ 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
+ class << self
29
+ def load(entry)
30
+ entry = entry.dup
31
+ entry.dup_value!
32
+ entry
33
+ end
34
+
35
+ def dump(entry)
36
+ entry.dup_value!
37
+ entry
38
+ end
39
+ end
40
+ end
41
+
42
+ DEFAULT_CODER = DupCoder
43
+
19
44
  def initialize(options = nil)
20
45
  options ||= {}
46
+ # Disable compression by default.
47
+ options[:compress] ||= false
21
48
  super(options)
22
49
  @data = {}
23
- @key_access = {}
24
50
  @max_size = options[:size] || 32.megabytes
25
51
  @max_prune_time = options[:max_prune_time] || 2
26
52
  @cache_size = 0
@@ -28,10 +54,15 @@ module ActiveSupport
28
54
  @pruning = false
29
55
  end
30
56
 
57
+ # Advertise cache versioning support.
58
+ def self.supports_cache_versioning?
59
+ true
60
+ end
61
+
62
+ # Delete all data stored in a given cache store.
31
63
  def clear(options = nil)
32
64
  synchronize do
33
65
  @data.clear
34
- @key_access.clear
35
66
  @cache_size = 0
36
67
  end
37
68
  end
@@ -39,11 +70,11 @@ module ActiveSupport
39
70
  # Preemptively iterates through all stored keys and removes the ones which have expired.
40
71
  def cleanup(options = nil)
41
72
  options = merged_options(options)
42
- instrument(:cleanup, :size => @data.size) do
43
- keys = synchronize{ @data.keys }
73
+ instrument(:cleanup, size: @data.size) do
74
+ keys = synchronize { @data.keys }
44
75
  keys.each do |key|
45
76
  entry = @data[key]
46
- delete_entry(key, options) if entry && entry.expired?
77
+ delete_entry(key, **options) if entry && entry.expired?
47
78
  end
48
79
  end
49
80
  end
@@ -54,13 +85,13 @@ module ActiveSupport
54
85
  return if pruning?
55
86
  @pruning = true
56
87
  begin
57
- start_time = Time.now
88
+ start_time = Concurrent.monotonic_time
58
89
  cleanup
59
- instrument(:prune, target_size, :from => @cache_size) do
60
- keys = synchronize{ @key_access.keys.sort{|a,b| @key_access[a].to_f <=> @key_access[b].to_f} }
90
+ instrument(:prune, target_size, from: @cache_size) do
91
+ keys = synchronize { @data.keys }
61
92
  keys.each do |key|
62
- delete_entry(key, options)
63
- return if @cache_size <= target_size || (max_time && Time.now - start_time > max_time)
93
+ delete_entry(key, **options)
94
+ return if @cache_size <= target_size || (max_time && Concurrent.monotonic_time - start_time > max_time)
64
95
  end
65
96
  end
66
97
  ensure
@@ -83,19 +114,20 @@ module ActiveSupport
83
114
  modify_value(name, -amount, options)
84
115
  end
85
116
 
117
+ # Deletes cache entries if the cache key matches a given pattern.
86
118
  def delete_matched(matcher, options = nil)
87
119
  options = merged_options(options)
88
120
  instrument(:delete_matched, matcher.inspect) do
89
121
  matcher = key_matcher(matcher, options)
90
122
  keys = synchronize { @data.keys }
91
123
  keys.each do |key|
92
- delete_entry(key, options) if key.match(matcher)
124
+ delete_entry(key, **options) if key.match(matcher)
93
125
  end
94
126
  end
95
127
  end
96
128
 
97
129
  def inspect # :nodoc:
98
- "<##{self.class.name} entries=#{@data.size}, size=#{@cache_size}, options=#{@options.inspect}>"
130
+ "#<#{self.class.name} entries=#{@data.size}, size=#{@cache_size}, options=#{@options.inspect}>"
99
131
  end
100
132
 
101
133
  # Synchronize calls to the cache. This should be called wherever the underlying cache implementation
@@ -104,57 +136,53 @@ module ActiveSupport
104
136
  @monitor.synchronize(&block)
105
137
  end
106
138
 
107
- protected
108
-
139
+ private
109
140
  PER_ENTRY_OVERHEAD = 240
110
141
 
111
- def cached_size(key, entry) # :nodoc:
112
- key.to_s.bytesize + entry.size + PER_ENTRY_OVERHEAD
142
+ def cached_size(key, payload)
143
+ key.to_s.bytesize + payload.bytesize + PER_ENTRY_OVERHEAD
113
144
  end
114
145
 
115
- def read_entry(key, options) # :nodoc:
116
- entry = @data[key]
146
+ def read_entry(key, **options)
147
+ entry = nil
117
148
  synchronize do
118
- if entry
119
- @key_access[key] = Time.now.to_f
120
- else
121
- @key_access.delete(key)
149
+ payload = @data.delete(key)
150
+ if payload
151
+ @data[key] = payload
152
+ entry = deserialize_entry(payload)
122
153
  end
123
154
  end
124
155
  entry
125
156
  end
126
157
 
127
- def write_entry(key, entry, options) # :nodoc:
128
- entry.dup_value!
158
+ def write_entry(key, entry, **options)
159
+ payload = serialize_entry(entry)
129
160
  synchronize do
130
- old_entry = @data[key]
131
- return false if @data.key?(key) && options[:unless_exist]
132
- if old_entry
133
- @cache_size -= (old_entry.size - entry.size)
161
+ return false if options[:unless_exist] && @data.key?(key)
162
+
163
+ old_payload = @data[key]
164
+ if old_payload
165
+ @cache_size -= (old_payload.bytesize - payload.bytesize)
134
166
  else
135
- @cache_size += cached_size(key, entry)
167
+ @cache_size += cached_size(key, payload)
136
168
  end
137
- @key_access[key] = Time.now.to_f
138
- @data[key] = entry
169
+ @data[key] = payload
139
170
  prune(@max_size * 0.75, @max_prune_time) if @cache_size > @max_size
140
171
  true
141
172
  end
142
173
  end
143
174
 
144
- def delete_entry(key, options) # :nodoc:
175
+ def delete_entry(key, **options)
145
176
  synchronize do
146
- @key_access.delete(key)
147
- entry = @data.delete(key)
148
- @cache_size -= cached_size(key, entry) if entry
149
- !!entry
177
+ payload = @data.delete(key)
178
+ @cache_size -= cached_size(key, payload) if payload
179
+ !!payload
150
180
  end
151
181
  end
152
182
 
153
- private
154
-
155
183
  def modify_value(name, amount, options)
184
+ options = merged_options(options)
156
185
  synchronize do
157
- options = merged_options(options)
158
186
  if num = read(name, options)
159
187
  num = num.to_i + amount
160
188
  write(name, num, options)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveSupport
2
4
  module Cache
3
5
  # A cache store implementation which doesn't actually store anything. Useful in
@@ -10,6 +12,11 @@ module ActiveSupport
10
12
  class NullStore < Store
11
13
  prepend Strategy::LocalCache
12
14
 
15
+ # Advertise cache versioning support.
16
+ def self.supports_cache_versioning?
17
+ true
18
+ end
19
+
13
20
  def clear(options = nil)
14
21
  end
15
22
 
@@ -25,15 +32,15 @@ module ActiveSupport
25
32
  def delete_matched(matcher, options = nil)
26
33
  end
27
34
 
28
- protected
29
- def read_entry(key, options) # :nodoc:
35
+ private
36
+ def read_entry(key, **options)
30
37
  end
31
38
 
32
- def write_entry(key, entry, options) # :nodoc:
39
+ def write_entry(key, entry, **options)
33
40
  true
34
41
  end
35
42
 
36
- def delete_entry(key, options) # :nodoc:
43
+ def delete_entry(key, **options)
37
44
  false
38
45
  end
39
46
  end