Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimized Cache::Entry should support old dalli_store values #42566

Merged
merged 1 commit into from Jun 22, 2021

Conversation

ghiculescu
Copy link
Member

@ghiculescu ghiculescu commented Jun 22, 2021

Same bug as #42559, but a very different fix due to #42025. To recap, the issue:

  • While using the dalli_store, you set any value in the Rails cache with no expiry.
  • You change to the mem_cache_store.
  • You upgrade to Rails 7.
  • You try to read the same cache key you set in step 1, and it crashes on read.

#42025 was backward compatible with entries written using the mem_cache_store, but not the dalli_store which did not use ActiveSupport::Cache::Entry. So this is actually worse than #42559 in that it would impact any key that was written by the dalli_store and then was read by Rails 7.

This PR fixes that by rescuing when a value can't be handled by the new coder system and falling back to just returning an Entry.


@cache.instance_variable_get(:@data).with { |c| c.set(@cache.send(:normalize_key, key, nil), false, 0, compress: false) }
@cache.with_local_cache do
assert_equal false, @cache.read(key)
Copy link
Member Author

Choose a reason for hiding this comment

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

without the fixes in this PR, this raises with

NoMethodError: undefined method `start_with?' for false:FalseClass
    /Users/alex/code/rails/activesupport/lib/active_support/cache.rb:851:in `load'

key = "test-with-value-the-way-the-dalli-store-did"

@cache.instance_variable_get(:@data).with { |c| c.set(@cache.send(:normalize_key, key, nil), "value", 0, compress: false) }
assert_equal "value", @cache.read(key)
Copy link
Member Author

Choose a reason for hiding this comment

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

without the fixes in this PR, this raises with

ActiveSupport::Cache::InvalidCacheItemError: Invalid cache prefix: "v", expected "\x00" or "\x01"
    /Users/alex/code/rails/activesupport/lib/active_support/cache.rb:858:in `load'

@ghiculescu
Copy link
Member Author

@byroot thanks for nudging me to add a test, turns out there was a bigger issue lurking here! Would love your input on this one, hopefully this is the last PR I tag you in today 😆

@ghiculescu ghiculescu requested a review from byroot June 22, 2021 19:12
Copy link
Member

@byroot byroot left a comment

Choose a reason for hiding this comment

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

LGTM, but I think I'd directly cast to Entry rather than go through raising an exception.

activesupport/lib/active_support/cache.rb Outdated Show resolved Hide resolved
activesupport/lib/active_support/cache.rb Outdated Show resolved Hide resolved
@byroot
Copy link
Member

byroot commented Jun 22, 2021

hopefully this is the last PR I tag you in today 😆

No worries, feel free to tag me as much as you want.

# You should use the `raw:` option if you know this is not the case. But this may
# happen in cases you can't control, eg. if upgrading from an old version of
# the dalli_store. We return an Entry as a fallback.
return Entry.new(payload) unless Cache::Coders::Loader.valid_format?(payload)
Copy link
Member

Choose a reason for hiding this comment

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

Please just check is_a?(String) here.

In the future if someone were to upgrade incorrectly (e.g deploy new Rails version using the new format immediately), it's important that we fail rather than to return the serialized payload as a value.

Copy link
Member Author

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

Your point is valid though 🤔

Copy link
Member

Choose a reason for hiding this comment

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

I see. Then rather than raise an ArgumentError, we should return nil. It's actually better for people messing their upgrades, they'll just get a few misses. Maybe with a Rails.logger.warn()?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, nils are better than cache reads crashing. I'll upgrade it to do that in all cases where it would currently raise.

@ghiculescu ghiculescu force-pushed the dalli-store-optimised-cache branch 3 times, most recently from 1828ae1 to dca9200 Compare June 22, 2021 19:49
@@ -844,14 +844,18 @@ module Loader
extend self

def load(payload)
return nil unless payload.is_a?(String)
Copy link
Member

Choose a reason for hiding this comment

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

I think this line could be surprising enough to warrant a comment.

Copy link
Member Author

Choose a reason for hiding this comment

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

Made it log as well.

Same bug as rails#42559, but a very different fix due to rails#42025. To recap, the issue:

- While using the `dalli_store`, you set any value in the Rails cache with no expiry.
- You change to the `mem_cache_store`.
- You upgrade to Rails 7.
- You try to read the same cache key you set in step 1, and it crashes on read.

rails#42025 was backward compatible with entries written using the `mem_cache_store`, but *not* the `dalli_store` which did not use `ActiveSupport::Cache::Entry`. This PR attempts to fix that.
Copy link
Member

@byroot byroot left a comment

Choose a reason for hiding this comment

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

Looks good to me. I'll merge on green if that's good with you.

@ghiculescu
Copy link
Member Author

thanks for all your help!

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.

None yet

2 participants