Skip to content

Fix ActiveSupport::Cache compression#32539

Merged
rafaelfranca merged 2 commits into
rails:masterfrom
chancancode:anticompress
Apr 12, 2018
Merged

Fix ActiveSupport::Cache compression#32539
rafaelfranca merged 2 commits into
rails:masterfrom
chancancode:anticompress

Conversation

@chancancode

Copy link
Copy Markdown
Member

On Rails 5.2, when compression is enabled (which it is by default), the actual value being written to the underlying storage is actually bigger than the uncompressed raw value.

This is because the @marshaled_value instance variable (typically) gets serialized with the entry object, which is then written to the underlying storage, essentially double-storing every value (once uncompressed, once possibly compressed).

This regression was introduced in #32254.

Fix incoming.

On Rails 5.2, when compression is enabled (which it is by default),
the actual value being written to the underlying storage is actually
_bigger_ than the uncompressed raw value.

This is because the `@marshaled_value` instance variable (typically)
gets serialized with the entry object, which is then written to the
underlying storage, essentially double-storing every value (once
uncompressed, once possibly compressed).

This regression was introduced in rails#32254.
(See previous commit for a description of the issue)
@chancancode chancancode changed the title [WIP] Fix ActiveSupport::Cache compression Fix ActiveSupport::Cache compression Apr 12, 2018
@chancancode

Copy link
Copy Markdown
Member Author

Ready for review!

@dhh dhh assigned jeremy and sgrif Apr 12, 2018
@rafaelfranca rafaelfranca merged commit b7760eb into rails:master Apr 12, 2018
rafaelfranca added a commit that referenced this pull request Apr 12, 2018
Fix ActiveSupport::Cache compression
@rafaelfranca

Copy link
Copy Markdown
Member

Thank you! As always, outstanding PR and investigation.

@chancancode chancancode deleted the anticompress branch April 12, 2018 18:50
def compress!
@value = Zlib::Deflate.deflate(marshaled_value)
@compressed = true
defined?(@compressed)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was it changed intentionally since defined?(@compressed) ? @compressed : false looks correct?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Ruby semantics of query methods don't require us to return false or true so nil is totally fine and inline with our guidelines.

@bogdanvlviv bogdanvlviv Apr 18, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rafaelfranca
Ruby semantics is fine. I have another concern here since I see that behavior of this method is changed here.
defined? returns a string describing its argument by http://ruby-doc.org/core-2.5.0/doc/keywords_rdoc.html
Example:

@compressed = nil # or @compressed = false
defined? @compressed # => "instance-variable"

That means if we used @compressed like nil or false, we would need to change this method to the previous version in order to get right behavior.
I would recomend to initialize @compressed in the controller in order to get rid of using defined? there.
if it is a good reason, I'll send a patch?

diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb
index d769e2c..317723b 100644
--- a/activesupport/lib/active_support/cache.rb
+++ b/activesupport/lib/active_support/cache.rb
@@ -719,6 +719,7 @@ def initialize(value, compress: true, compress_threshold: DEFAULT_COMPRESS_LIMIT
         @version    = version
         @created_at = Time.now.to_f
         @expires_in = expires_in && expires_in.to_f
+        @compressed = nil

         compress!(compress_threshold) if compress
       end
@@ -798,7 +799,7 @@ def compress!(compress_threshold)
         end

         def compressed?
-          defined?(@compressed)
+          @compressed
         end

         def uncompress(value)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current implementation is fine. A string is a truthy value and that is only want we need. @compressed will never be @nil or @false because we serialize this instance using marshal and we don't want to always serialize @compressed and your implementation always serialize @compressed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. Sorry for distraction.

@rafaelfranca rafaelfranca Apr 18, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem! thank you for double checking the implementation.

@zquestz

zquestz commented Jul 25, 2018

Copy link
Copy Markdown

PLEASE cut a 5.2.1 release with this fix. It is blocking our upgrade path to Rails 5.2.x...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants