activesupport 6.1.3.1 → 7.0.0.alpha1

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 (131) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +151 -485
  3. data/MIT-LICENSE +1 -1
  4. data/lib/active_support/actionable_error.rb +1 -1
  5. data/lib/active_support/array_inquirer.rb +0 -2
  6. data/lib/active_support/benchmarkable.rb +2 -2
  7. data/lib/active_support/cache/file_store.rb +16 -10
  8. data/lib/active_support/cache/mem_cache_store.rb +119 -28
  9. data/lib/active_support/cache/memory_store.rb +21 -13
  10. data/lib/active_support/cache/null_store.rb +10 -2
  11. data/lib/active_support/cache/redis_cache_store.rb +39 -59
  12. data/lib/active_support/cache/strategy/local_cache.rb +29 -49
  13. data/lib/active_support/cache.rb +196 -46
  14. data/lib/active_support/callbacks.rb +35 -31
  15. data/lib/active_support/concern.rb +5 -5
  16. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
  17. data/lib/active_support/concurrency/share_lock.rb +2 -2
  18. data/lib/active_support/configurable.rb +6 -3
  19. data/lib/active_support/configuration_file.rb +7 -2
  20. data/lib/active_support/core_ext/array/access.rb +1 -5
  21. data/lib/active_support/core_ext/array/conversions.rb +6 -6
  22. data/lib/active_support/core_ext/array/grouping.rb +6 -6
  23. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  24. data/lib/active_support/core_ext/date/blank.rb +1 -1
  25. data/lib/active_support/core_ext/date/calculations.rb +2 -2
  26. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  27. data/lib/active_support/core_ext/digest/uuid.rb +13 -12
  28. data/lib/active_support/core_ext/enumerable.rb +64 -12
  29. data/lib/active_support/core_ext/file/atomic.rb +1 -1
  30. data/lib/active_support/core_ext/hash/keys.rb +1 -1
  31. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  32. data/lib/active_support/core_ext/module/delegation.rb +2 -8
  33. data/lib/active_support/core_ext/name_error.rb +2 -8
  34. data/lib/active_support/core_ext/numeric/conversions.rb +2 -2
  35. data/lib/active_support/core_ext/object/blank.rb +2 -2
  36. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  37. data/lib/active_support/core_ext/object/duplicable.rb +11 -0
  38. data/lib/active_support/core_ext/object/json.rb +29 -24
  39. data/lib/active_support/core_ext/object/to_query.rb +2 -2
  40. data/lib/active_support/core_ext/object/try.rb +20 -20
  41. data/lib/active_support/core_ext/range/compare_range.rb +0 -25
  42. data/lib/active_support/core_ext/range/each.rb +1 -1
  43. data/lib/active_support/core_ext/range/include_time_with_zone.rb +1 -1
  44. data/lib/active_support/core_ext/string/filters.rb +1 -1
  45. data/lib/active_support/core_ext/string/inflections.rb +1 -1
  46. data/lib/active_support/core_ext/string/output_safety.rb +60 -36
  47. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
  48. data/lib/active_support/core_ext/time/calculations.rb +5 -9
  49. data/lib/active_support/core_ext/time/zones.rb +2 -17
  50. data/lib/active_support/core_ext/uri.rb +1 -15
  51. data/lib/active_support/current_attributes.rb +18 -1
  52. data/lib/active_support/dependencies/interlock.rb +10 -18
  53. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  54. data/lib/active_support/dependencies.rb +58 -788
  55. data/lib/active_support/deprecation/behaviors.rb +4 -1
  56. data/lib/active_support/deprecation/method_wrappers.rb +3 -3
  57. data/lib/active_support/deprecation/proxy_wrappers.rb +1 -1
  58. data/lib/active_support/deprecation.rb +1 -1
  59. data/lib/active_support/descendants_tracker.rb +12 -9
  60. data/lib/active_support/digest.rb +5 -3
  61. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  62. data/lib/active_support/duration/iso8601_serializer.rb +9 -1
  63. data/lib/active_support/duration.rb +77 -48
  64. data/lib/active_support/encrypted_configuration.rb +11 -1
  65. data/lib/active_support/encrypted_file.rb +1 -1
  66. data/lib/active_support/environment_inquirer.rb +1 -1
  67. data/lib/active_support/evented_file_update_checker.rb +1 -1
  68. data/lib/active_support/fork_tracker.rb +2 -2
  69. data/lib/active_support/gem_version.rb +4 -4
  70. data/lib/active_support/hash_with_indifferent_access.rb +8 -1
  71. data/lib/active_support/i18n.rb +1 -0
  72. data/lib/active_support/inflector/inflections.rb +11 -4
  73. data/lib/active_support/inflector/methods.rb +23 -47
  74. data/lib/active_support/json/encoding.rb +3 -3
  75. data/lib/active_support/key_generator.rb +18 -1
  76. data/lib/active_support/locale/en.yml +2 -2
  77. data/lib/active_support/log_subscriber.rb +13 -3
  78. data/lib/active_support/logger_thread_safe_level.rb +5 -13
  79. data/lib/active_support/message_encryptor.rb +3 -3
  80. data/lib/active_support/message_verifier.rb +4 -4
  81. data/lib/active_support/messages/metadata.rb +2 -2
  82. data/lib/active_support/multibyte/chars.rb +10 -11
  83. data/lib/active_support/multibyte/unicode.rb +2 -2
  84. data/lib/active_support/multibyte.rb +1 -1
  85. data/lib/active_support/notifications/fanout.rb +31 -11
  86. data/lib/active_support/notifications/instrumenter.rb +17 -0
  87. data/lib/active_support/notifications.rb +10 -0
  88. data/lib/active_support/number_helper/number_converter.rb +1 -3
  89. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  90. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  91. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  92. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
  93. data/lib/active_support/number_helper/number_to_rounded_converter.rb +10 -6
  94. data/lib/active_support/number_helper/rounding_helper.rb +2 -6
  95. data/lib/active_support/number_helper.rb +0 -2
  96. data/lib/active_support/option_merger.rb +4 -16
  97. data/lib/active_support/ordered_hash.rb +1 -1
  98. data/lib/active_support/parameter_filter.rb +5 -0
  99. data/lib/active_support/per_thread_registry.rb +1 -0
  100. data/lib/active_support/railtie.rb +34 -11
  101. data/lib/active_support/rescuable.rb +2 -2
  102. data/lib/active_support/secure_compare_rotator.rb +1 -1
  103. data/lib/active_support/security_utils.rb +1 -1
  104. data/lib/active_support/string_inquirer.rb +0 -2
  105. data/lib/active_support/subscriber.rb +5 -0
  106. data/lib/active_support/tagged_logging.rb +1 -1
  107. data/lib/active_support/test_case.rb +9 -21
  108. data/lib/active_support/testing/assertions.rb +35 -5
  109. data/lib/active_support/testing/deprecation.rb +1 -1
  110. data/lib/active_support/testing/isolation.rb +1 -1
  111. data/lib/active_support/testing/method_call_assertions.rb +5 -5
  112. data/lib/active_support/testing/parallelization/server.rb +4 -0
  113. data/lib/active_support/testing/parallelization/worker.rb +3 -0
  114. data/lib/active_support/testing/parallelization.rb +4 -0
  115. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  116. data/lib/active_support/testing/stream.rb +3 -5
  117. data/lib/active_support/testing/tagged_logging.rb +1 -1
  118. data/lib/active_support/testing/time_helpers.rb +13 -2
  119. data/lib/active_support/time_with_zone.rb +19 -6
  120. data/lib/active_support/values/time_zone.rb +25 -9
  121. data/lib/active_support/xml_mini/jdom.rb +1 -1
  122. data/lib/active_support/xml_mini/libxml.rb +5 -5
  123. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  124. data/lib/active_support/xml_mini/nokogiri.rb +4 -4
  125. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  126. data/lib/active_support/xml_mini/rexml.rb +1 -1
  127. data/lib/active_support/xml_mini.rb +2 -1
  128. data/lib/active_support.rb +14 -1
  129. metadata +11 -25
  130. data/lib/active_support/core_ext/marshal.rb +0 -26
  131. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
@@ -34,57 +34,40 @@ module ActiveSupport
34
34
 
35
35
  # Simple memory backed cache. This cache is not thread safe and is intended only
36
36
  # for serving as a temporary memory cache for a single thread.
37
- class LocalStore < Store
37
+ class LocalStore
38
38
  def initialize
39
- super
40
39
  @data = {}
41
40
  end
42
41
 
43
- # Don't allow synchronizing since it isn't thread safe.
44
- def synchronize # :nodoc:
45
- yield
46
- end
47
-
48
42
  def clear(options = nil)
49
43
  @data.clear
50
44
  end
51
45
 
52
- def read_entry(key, **options)
46
+ def read_entry(key)
53
47
  @data[key]
54
48
  end
55
49
 
56
- def read_multi_entries(keys, **options)
57
- values = {}
58
-
59
- keys.each do |name|
60
- entry = read_entry(name, **options)
61
- values[name] = entry.value if entry
62
- end
63
-
64
- values
50
+ def read_multi_entries(keys)
51
+ @data.slice(*keys)
65
52
  end
66
53
 
67
- def write_entry(key, entry, **options)
68
- entry.dup_value!
54
+ def write_entry(key, entry)
69
55
  @data[key] = entry
70
56
  true
71
57
  end
72
58
 
73
- def delete_entry(key, **options)
59
+ def delete_entry(key)
74
60
  !!@data.delete(key)
75
61
  end
76
62
 
77
- def fetch_entry(key, options = nil) # :nodoc:
78
- entry = @data.fetch(key) { @data[key] = yield }
79
- dup_entry = entry.dup
80
- dup_entry&.dup_value!
81
- dup_entry
63
+ def fetch_entry(key) # :nodoc:
64
+ @data.fetch(key) { @data[key] = yield }
82
65
  end
83
66
  end
84
67
 
85
68
  # Use a local cache for the duration of block.
86
- def with_local_cache
87
- use_temporary_local_cache(LocalStore.new) { yield }
69
+ def with_local_cache(&block)
70
+ use_temporary_local_cache(LocalStore.new, &block)
88
71
  end
89
72
 
90
73
  # Middleware class can be inserted as a Rack handler to be local cache for the
@@ -116,27 +99,27 @@ module ActiveSupport
116
99
  def increment(name, amount = 1, **options) # :nodoc:
117
100
  return super unless local_cache
118
101
  value = bypass_local_cache { super }
119
- write_cache_value(name, value, **options)
102
+ write_cache_value(name, value, raw: true, **options)
120
103
  value
121
104
  end
122
105
 
123
106
  def decrement(name, amount = 1, **options) # :nodoc:
124
107
  return super unless local_cache
125
108
  value = bypass_local_cache { super }
126
- write_cache_value(name, value, **options)
109
+ write_cache_value(name, value, raw: true, **options)
127
110
  value
128
111
  end
129
112
 
130
113
  private
131
- def read_entry(key, **options)
114
+ def read_serialized_entry(key, raw: false, **options)
132
115
  if cache = local_cache
133
116
  hit = true
134
- value = cache.fetch_entry(key) do
117
+ entry = cache.fetch_entry(key) do
135
118
  hit = false
136
119
  super
137
120
  end
138
121
  options[:event][:store] = cache.class.name if hit && options[:event]
139
- value
122
+ entry
140
123
  else
141
124
  super
142
125
  end
@@ -145,7 +128,7 @@ module ActiveSupport
145
128
  def read_multi_entries(keys, **options)
146
129
  return super unless local_cache
147
130
 
148
- local_entries = local_cache.read_multi_entries(keys, **options)
131
+ local_entries = local_cache.read_multi_entries(keys)
149
132
  missed_keys = keys - local_entries.keys
150
133
 
151
134
  if missed_keys.any?
@@ -155,30 +138,27 @@ module ActiveSupport
155
138
  end
156
139
  end
157
140
 
158
- def write_entry(key, entry, **options)
159
- if options[:unless_exist]
160
- local_cache.delete_entry(key, **options) if local_cache
141
+ def write_serialized_entry(key, payload, **)
142
+ if return_value = super
143
+ local_cache.write_entry(key, payload) if local_cache
161
144
  else
162
- local_cache.write_entry(key, entry, **options) if local_cache
145
+ local_cache.delete_entry(key) if local_cache
163
146
  end
164
-
165
- super
147
+ return_value
166
148
  end
167
149
 
168
- def delete_entry(key, **options)
169
- local_cache.delete_entry(key, **options) if local_cache
150
+ def delete_entry(key, **)
151
+ local_cache.delete_entry(key) if local_cache
170
152
  super
171
153
  end
172
154
 
173
155
  def write_cache_value(name, value, **options)
174
156
  name = normalize_key(name, options)
175
157
  cache = local_cache
176
- cache.mute do
177
- if value
178
- cache.write(name, value, options)
179
- else
180
- cache.delete(name, **options)
181
- end
158
+ if value
159
+ cache.write_entry(name, serialize_entry(new_entry(value, **options), **options))
160
+ else
161
+ cache.delete_entry(name)
182
162
  end
183
163
  end
184
164
 
@@ -190,8 +170,8 @@ module ActiveSupport
190
170
  LocalCacheRegistry.cache_for(local_cache_key)
191
171
  end
192
172
 
193
- def bypass_local_cache
194
- use_temporary_local_cache(nil) { yield }
173
+ def bypass_local_cache(&block)
174
+ use_temporary_local_cache(nil, &block)
195
175
  end
196
176
 
197
177
  def use_temporary_local_cache(temporary_cache)
@@ -22,13 +22,24 @@ module ActiveSupport
22
22
 
23
23
  # These options mean something to all cache implementations. Individual cache
24
24
  # implementations may support additional options.
25
- UNIVERSAL_OPTIONS = [:namespace, :compress, :compress_threshold, :expires_in, :race_condition_ttl, :coder]
25
+ UNIVERSAL_OPTIONS = [:namespace, :compress, :compress_threshold, :expires_in, :expire_in, :expired_in, :race_condition_ttl, :coder, :skip_nil]
26
+
27
+ DEFAULT_COMPRESS_LIMIT = 1.kilobyte
28
+
29
+ # Mapping of canonical option names to aliases that a store will recognize.
30
+ OPTION_ALIASES = {
31
+ expires_in: [:expire_in, :expired_in]
32
+ }.freeze
26
33
 
27
34
  module Strategy
28
35
  autoload :LocalCache, "active_support/cache/strategy/local_cache"
29
36
  end
30
37
 
38
+ @format_version = 6.1
39
+
31
40
  class << self
41
+ attr_accessor :format_version
42
+
32
43
  # Creates a new Store object according to the given options.
33
44
  #
34
45
  # If no arguments are passed to this method, then a new
@@ -58,7 +69,13 @@ module ActiveSupport
58
69
  case store
59
70
  when Symbol
60
71
  options = parameters.extract_options!
61
- retrieve_store_class(store).new(*parameters, **options)
72
+ # clean this up once Ruby 2.7 support is dropped
73
+ # see https://github.com/rails/rails/pull/41522#discussion_r581186602
74
+ if options.empty?
75
+ retrieve_store_class(store).new(*parameters)
76
+ else
77
+ retrieve_store_class(store).new(*parameters, **options)
78
+ end
62
79
  when Array
63
80
  lookup_store(*store)
64
81
  when nil
@@ -158,8 +175,6 @@ module ActiveSupport
158
175
  # threshold is configurable with the <tt>:compress_threshold</tt> option,
159
176
  # specified in bytes.
160
177
  class Store
161
- DEFAULT_CODER = Marshal
162
-
163
178
  cattr_accessor :logger, instance_writer: true
164
179
 
165
180
  attr_reader :silence, :options
@@ -186,8 +201,12 @@ module ActiveSupport
186
201
  # except for <tt>:namespace</tt> which can be used to set the global
187
202
  # namespace for the cache.
188
203
  def initialize(options = nil)
189
- @options = options ? options.dup : {}
190
- @coder = @options.delete(:coder) { self.class::DEFAULT_CODER } || NullCoder
204
+ @options = options ? normalize_options(options) : {}
205
+ @options[:compress] = true unless @options.key?(:compress)
206
+ @options[:compress_threshold] = DEFAULT_COMPRESS_LIMIT unless @options.key?(:compress_threshold)
207
+
208
+ @coder = @options.delete(:coder) { default_coder } || NullCoder
209
+ @coder_supports_compression = @coder.respond_to?(:dump_compressed)
191
210
  end
192
211
 
193
212
  # Silences the logger.
@@ -249,11 +268,21 @@ module ActiveSupport
249
268
  # All caches support auto-expiring content after a specified number of
250
269
  # seconds. This value can be specified as an option to the constructor
251
270
  # (in which case all entries will be affected), or it can be supplied to
252
- # the +fetch+ or +write+ method to effect just one entry.
271
+ # the +fetch+ or +write+ method to affect just one entry.
272
+ # <tt>:expire_in</tt> and <tt>:expired_in</tt> are aliases for
273
+ # <tt>:expires_in</tt>.
253
274
  #
254
275
  # cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 5.minutes)
255
276
  # cache.write(key, value, expires_in: 1.minute) # Set a lower value for one entry
256
277
  #
278
+ # Setting <tt>:expires_at</tt> will set an absolute expiration time on the cache.
279
+ # All caches support auto-expiring content after a specified number of
280
+ # seconds. This value can only be supplied to the +fetch+ or +write+ method to
281
+ # affect just one entry.
282
+ #
283
+ # cache = ActiveSupport::Cache::MemoryStore.new
284
+ # cache.write(key, value, expires_at: Time.now.at_end_of_hour)
285
+ #
257
286
  # Setting <tt>:version</tt> verifies the cache stored under <tt>name</tt>
258
287
  # is of the same version. nil is returned on mismatches despite contents.
259
288
  # This feature is used to support recyclable cache keys.
@@ -506,6 +535,10 @@ module ActiveSupport
506
535
  end
507
536
  end
508
537
 
538
+ def new_entry(value, options = nil) # :nodoc:
539
+ Entry.new(value, **merged_options(options))
540
+ end
541
+
509
542
  # Deletes all entries with keys matching the pattern.
510
543
  #
511
544
  # Options are passed to the underlying cache implementation.
@@ -553,6 +586,10 @@ module ActiveSupport
553
586
  end
554
587
 
555
588
  private
589
+ def default_coder
590
+ Coders[Cache.format_version]
591
+ end
592
+
556
593
  # Adds the namespace defined in the options to a pattern designed to
557
594
  # match keys. Implementations that support delete_matched should call
558
595
  # this method to translate a pattern that matches names into one that
@@ -584,8 +621,13 @@ module ActiveSupport
584
621
  raise NotImplementedError.new
585
622
  end
586
623
 
587
- def serialize_entry(entry)
588
- @coder.dump(entry)
624
+ def serialize_entry(entry, **options)
625
+ options = merged_options(options)
626
+ if @coder_supports_compression && options[:compress]
627
+ @coder.dump_compressed(entry, options[:compress_threshold] || DEFAULT_COMPRESS_LIMIT)
628
+ else
629
+ @coder.dump(entry)
630
+ end
589
631
  end
590
632
 
591
633
  def deserialize_entry(payload)
@@ -634,6 +676,7 @@ module ActiveSupport
634
676
  # Merges the default options with ones specific to a method call.
635
677
  def merged_options(call_options)
636
678
  if call_options
679
+ call_options = normalize_options(call_options)
637
680
  if options.empty?
638
681
  call_options
639
682
  else
@@ -644,6 +687,18 @@ module ActiveSupport
644
687
  end
645
688
  end
646
689
 
690
+ # Normalize aliased options to their canonical form
691
+ def normalize_options(options)
692
+ options = options.dup
693
+ OPTION_ALIASES.each do |canonical_name, aliases|
694
+ alias_key = aliases.detect { |key| options.key?(key) }
695
+ options[canonical_name] ||= options[alias_key] if alias_key
696
+ options.except!(*aliases)
697
+ end
698
+
699
+ options
700
+ end
701
+
647
702
  # Expands and namespaces the cache key. May be overridden by
648
703
  # cache stores to do additional normalization.
649
704
  def normalize_key(key, options = nil)
@@ -726,7 +781,7 @@ module ActiveSupport
726
781
  if (race_ttl > 0) && (Time.now.to_f - entry.expires_at <= race_ttl)
727
782
  # When an entry has a positive :race_condition_ttl defined, put the stale entry back into the cache
728
783
  # for a brief period while the entry is being recalculated.
729
- entry.expires_at = Time.now + race_ttl
784
+ entry.expires_at = Time.now.to_f + race_ttl
730
785
  write_entry(key, entry, expires_in: race_ttl * 2)
731
786
  else
732
787
  delete_entry(key, **options)
@@ -752,13 +807,93 @@ module ActiveSupport
752
807
  end
753
808
 
754
809
  module NullCoder # :nodoc:
810
+ extend self
811
+
812
+ def dump(entry)
813
+ entry
814
+ end
815
+
816
+ def dump_compressed(entry, threshold)
817
+ entry.compressed(threshold)
818
+ end
819
+
820
+ def load(payload)
821
+ payload
822
+ end
823
+ end
824
+
825
+ module Coders # :nodoc:
826
+ MARK_61 = "\x04\b".b.freeze # The one set by Marshal.
827
+ MARK_70_UNCOMPRESSED = "\x00".b.freeze
828
+ MARK_70_COMPRESSED = "\x01".b.freeze
829
+
755
830
  class << self
831
+ def [](version)
832
+ case version
833
+ when 6.1
834
+ Rails61Coder
835
+ when 7.0
836
+ Rails70Coder
837
+ else
838
+ raise ArgumentError, "Unknown ActiveSupport::Cache.format_version #{Cache.format_version.inspect}"
839
+ end
840
+ end
841
+ end
842
+
843
+ module Loader
844
+ extend self
845
+
756
846
  def load(payload)
757
- payload
847
+ if !payload.is_a?(String)
848
+ ActiveSupport::Cache::Store.logger&.warn %{Payload wasn't a string, was #{payload.class.name} - couldn't unmarshal, so returning nil."}
849
+
850
+ return nil
851
+ elsif payload.start_with?(MARK_70_UNCOMPRESSED)
852
+ members = Marshal.load(payload.byteslice(1..-1))
853
+ elsif payload.start_with?(MARK_70_COMPRESSED)
854
+ members = Marshal.load(Zlib::Inflate.inflate(payload.byteslice(1..-1)))
855
+ elsif payload.start_with?(MARK_61)
856
+ return Marshal.load(payload)
857
+ else
858
+ ActiveSupport::Cache::Store.logger&.warn %{Invalid cache prefix: #{payload.byteslice(0).inspect}, expected "\\x00" or "\\x01"}
859
+
860
+ return nil
861
+ end
862
+ Entry.unpack(members)
758
863
  end
864
+ end
865
+
866
+ module Rails61Coder
867
+ include Loader
868
+ extend self
759
869
 
760
870
  def dump(entry)
761
- entry
871
+ Marshal.dump(entry)
872
+ end
873
+
874
+ def dump_compressed(entry, threshold)
875
+ Marshal.dump(entry.compressed(threshold))
876
+ end
877
+ end
878
+
879
+ module Rails70Coder
880
+ include Loader
881
+ extend self
882
+
883
+ def dump(entry)
884
+ MARK_70_UNCOMPRESSED + Marshal.dump(entry.pack)
885
+ end
886
+
887
+ def dump_compressed(entry, threshold)
888
+ payload = Marshal.dump(entry.pack)
889
+ if payload.bytesize >= threshold
890
+ compressed_payload = Zlib::Deflate.deflate(payload)
891
+ if compressed_payload.bytesize < payload.bytesize
892
+ return MARK_70_COMPRESSED + compressed_payload
893
+ end
894
+ end
895
+
896
+ MARK_70_UNCOMPRESSED + payload
762
897
  end
763
898
  end
764
899
  end
@@ -771,19 +906,22 @@ module ActiveSupport
771
906
  # Since cache entries in most instances will be serialized, the internals of this class are highly optimized
772
907
  # using short instance variable names that are lazily defined.
773
908
  class Entry # :nodoc:
774
- attr_reader :version
909
+ class << self
910
+ def unpack(members)
911
+ new(members[0], expires_at: members[1], version: members[2])
912
+ end
913
+ end
775
914
 
776
- DEFAULT_COMPRESS_LIMIT = 1.kilobyte
915
+ attr_reader :version
777
916
 
778
917
  # Creates a new cache entry for the specified value. Options supported are
779
- # +:compress+, +:compress_threshold+, +:version+ and +:expires_in+.
780
- def initialize(value, compress: true, compress_threshold: DEFAULT_COMPRESS_LIMIT, version: nil, expires_in: nil, **)
918
+ # +:compressed+, +:version+, +:expires_at+ and +:expires_in+.
919
+ def initialize(value, compressed: false, version: nil, expires_in: nil, expires_at: nil, **)
781
920
  @value = value
782
921
  @version = version
783
- @created_at = Time.now.to_f
784
- @expires_in = expires_in && expires_in.to_f
785
-
786
- compress!(compress_threshold) if compress
922
+ @created_at = 0.0
923
+ @expires_in = expires_at&.to_f || expires_in && (expires_in.to_f + Time.now.to_f)
924
+ @compressed = true if compressed
787
925
  end
788
926
 
789
927
  def value
@@ -825,6 +963,38 @@ module ActiveSupport
825
963
  end
826
964
  end
827
965
 
966
+ def compressed? # :nodoc:
967
+ defined?(@compressed)
968
+ end
969
+
970
+ def compressed(compress_threshold)
971
+ return self if compressed?
972
+
973
+ case @value
974
+ when nil, true, false, Numeric
975
+ uncompressed_size = 0
976
+ when String
977
+ uncompressed_size = @value.bytesize
978
+ else
979
+ serialized = Marshal.dump(@value)
980
+ uncompressed_size = serialized.bytesize
981
+ end
982
+
983
+ if uncompressed_size >= compress_threshold
984
+ serialized ||= Marshal.dump(@value)
985
+ compressed = Zlib::Deflate.deflate(serialized)
986
+
987
+ if compressed.bytesize < uncompressed_size
988
+ return Entry.new(compressed, compressed: true, expires_at: expires_at, version: version)
989
+ end
990
+ end
991
+ self
992
+ end
993
+
994
+ def local?
995
+ false
996
+ end
997
+
828
998
  # Duplicates the value in a class. This is used by cache implementations that don't natively
829
999
  # serialize entries to protect against accidental cache modifications.
830
1000
  def dup_value!
@@ -837,33 +1007,13 @@ module ActiveSupport
837
1007
  end
838
1008
  end
839
1009
 
840
- private
841
- def compress!(compress_threshold)
842
- case @value
843
- when nil, true, false, Numeric
844
- uncompressed_size = 0
845
- when String
846
- uncompressed_size = @value.bytesize
847
- else
848
- serialized = Marshal.dump(@value)
849
- uncompressed_size = serialized.bytesize
850
- end
851
-
852
- if uncompressed_size >= compress_threshold
853
- serialized ||= Marshal.dump(@value)
854
- compressed = Zlib::Deflate.deflate(serialized)
855
-
856
- if compressed.bytesize < uncompressed_size
857
- @value = compressed
858
- @compressed = true
859
- end
860
- end
861
- end
862
-
863
- def compressed?
864
- defined?(@compressed)
865
- end
1010
+ def pack
1011
+ members = [value, expires_at, version]
1012
+ members.pop while !members.empty? && members.last.nil?
1013
+ members
1014
+ end
866
1015
 
1016
+ private
867
1017
  def uncompress(value)
868
1018
  Marshal.load(Zlib::Inflate.inflate(value))
869
1019
  end