Fix MemoryCache discovery and DX

Created on 20 November 2023, about 1 year ago
Updated 19 July 2024, 5 months ago

Problem/Motivation

We currently have a few cache bins that behave like proper cache bins. I.e.: when you request an entry you get a freshly loaded object. Then we have MemoryCache which always returns the same object. For this reason we cannot tag any cache service using MemoryCache as 'cache.bin' and we don't have a factory for MemoryCache either.

This leads to weird scenarios where people use a MemoryCache in a ChainedBackend and then tag said CB as 'cache.bin', which is wrong because the collective does not behave like a proper cache bin. It also leads to people tagging their MemoryCache services as 'cache_tags_invalidator', which works, but then see random test fails because we do not properly reset these services in RefreshVariablesTrait.

Proposed resolution

  1. Add one new types of services alongside cache.backend.FOO, namely cache.backend.memory.FOO and implement a factory for MemoryCache that is called cache.backend.memory.memory
  2. Add a new tag alongside cache.bin, namely cache.bin.memory and fix places where cache.bin was used incorrectly
  3. Discover these "memory bins" the same way we discover regular bins
  4. Make CacheTagsInvalidator also call these memory bins upon cache tag invalidation
  5. Make CacheFactory also check memory default backends
  6. Make RefreshVariablesTrait also reset memory cache bins

API changes

  1. New service tag 'cache.bin.memory'
πŸ“Œ Task
Status

Fixed

Version

11.0 πŸ”₯

Component
CacheΒ  β†’

Last updated about 5 hours ago

Created by

πŸ‡§πŸ‡ͺBelgium kristiaanvandeneynde Antwerp, Belgium

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @kristiaanvandeneynde
  • πŸ‡§πŸ‡ͺBelgium kristiaanvandeneynde Antwerp, Belgium

    See #2973286-54: [PP-1] Clean up MemoryCache and MemoryBackend naming issues β†’ for more information if needed. Will post a POC soon.

  • Issue was unassigned.
  • Status changed to Needs review about 1 year ago
  • πŸ‡§πŸ‡ͺBelgium kristiaanvandeneynde Antwerp, Belgium

    PoC in MR now

  • Merge request !5479Proof of concept β†’ (Open) created by kristiaanvandeneynde
  • πŸ‡¬πŸ‡§United Kingdom catch

    One small comment on the MR but overall looks like a good improvement to me.

    What about using 'memory' instead of 'static' in the various places this is wired up. There's potential confusion with APCu or even memcache, but less confusion with PHP statics.

  • πŸ‡§πŸ‡ͺBelgium kristiaanvandeneynde Antwerp, Belgium

    Sure, I'm not married to any name here. Will look at the test fails and change the name.

  • πŸ‡§πŸ‡ͺBelgium kristiaanvandeneynde Antwerp, Belgium

    Fixed two causes of test failures and renamed everything to "memory", will update IS. We do get the ugly cache.backend.memory.memory service name that way, though.

  • πŸ‡§πŸ‡ͺBelgium kristiaanvandeneynde Antwerp, Belgium

    All green now :)

  • Status changed to Needs work about 1 year ago
  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    Did a quick look to the best of my ability with caching.

    Believe we may have to do the backward compatibility dance now right?

    Also may need a change record for the new parameter.

    Not sure if there is concern for contrib that could be using Drupal\Core\Cache\MemoryCache\MemoryCache and not the interface?

  • Status changed to Needs review about 1 year ago
  • πŸ‡§πŸ‡ͺBelgium kristiaanvandeneynde Antwerp, Belgium

    I've addressed the feedback. Can add the typehint if you want, I'm fine either way but curious about what the policy is for adding methods on an existing class that doesn't have typehints on its other methods.

  • Status changed to Needs work about 1 year ago
  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    Thanks for following up on my thread.

    So don't need a change record for the new parameter but imagine for the new MemoryCacheFactory? For other contrib modules can take advantage.

  • Status changed to Needs review about 1 year ago
  • πŸ‡§πŸ‡ͺBelgium kristiaanvandeneynde Antwerp, Belgium

    Added CR here: https://www.drupal.org/node/3409455 β†’

    I'm interpreting catch's latest comment on the MR as if we should add the typehint here as it's new code. I could be mistaken in case he meant a completely new class with "new code", but can always easily revert. So will add the typehint.

    Also noticed that the service book.memory_cache is actually poorly named as it gets the bin name "memory_cache" which is very ambiguous. We should consider renaming this to cache.book_memory when we move Book to contrib in D11. Will find the right issue for that and add that comment.

  • Status changed to RTBC about 1 year ago
  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    CR reads well.

    In regards to the book rename, think you can open a ticket for the book module and put into postponed. Then when book is deprecated that ticket will be brought over.

  • Status changed to Needs work about 1 year ago
  • πŸ‡¬πŸ‡§United Kingdom catch

    I'm interpreting catch's latest comment on the MR as if we should add the typehint here as it's new code

    Yes sorry that's what I meant - even though it's inconsistent within the class, it is much easier to add when it's new, than trying to add retrospectively, which we are only just figuring out how to do at all.

    I found one more small issue in the MR (which I was planning to commit until I spotted it) - I think it is just removing that part of the comment so should be straightforward to resolve - nearly did it on commit but wasn't sure exactly the best place to snip it from.

  • Status changed to Needs review about 1 year ago
  • πŸ‡§πŸ‡ͺBelgium kristiaanvandeneynde Antwerp, Belgium

    Re #13 I added a comment on πŸ“Œ [11.x] [Meta] Tasks to remove Book Active

    Re #14 I think I cut it off at the right spot if I understood your reservations regarding the example correctly. It's still valid to state that it can be overwritten in settings.php (which it can), but I dropped the copy-pasted example from the original method as that doesn't use the memory cache.

  • Status changed to RTBC about 1 year ago
  • πŸ‡¬πŸ‡§United Kingdom catch

    Yes I think that's good!

    • catch β†’ committed 2e73418c on 11.x
      Issue #3402850 by kristiaanvandeneynde, catch, smustgrave: Fix...
  • Status changed to Fixed about 1 year ago
  • πŸ‡¬πŸ‡§United Kingdom catch

    Committed/pushed to 11.x, thanks!

  • Automatically closed - issue fixed for 2 weeks with no activity.

  • πŸ‡¨πŸ‡­Switzerland berdir Switzerland

    I'm a bit confused by this change.

      # Cache.
      cache.jsonapi_memory:
        class: Drupal\Core\Cache\MemoryCache\MemoryCacheInterface
        tags:
          - { name: cache.bin.memory, default_backend: cache.backend.memory.memory }
        factory: ['@cache_factory', 'get']
        arguments: [jsonapi_memory]
    
      cache.jsonapi_resource_types:
        class: Drupal\Core\Cache\BackendChain
        calls:
          - [appendBackend, ['@cache.jsonapi_memory']]
          - [appendBackend, ['@cache.default']]
        tags: [{ name: cache.bin.memory }]
    

    BackendChain passes cache tag invalidations through to the inner bins. That means any cache tag invalidations are now processed twice by cache.jsonapi_memory.

    I can see that \Drupal\Core\Test\RefreshVariablesTrait::refreshVariables() calls a special reset() method that is not on the interface and only some memory implementations have that, but couldn't we have "just" implemented that on BackendChain and pass it through as well?

  • πŸ‡§πŸ‡ͺBelgium kristiaanvandeneynde Antwerp, Belgium

    We can still tag that cache as private again, I suppose.

    That tags in the memory cache get invalidated twice is a bit unfortunate, I agree. But wasn't that always the case to begin with for the regular cache? Not saying one wrong justifies the other, just trying to point out that BackendChain is easily misused because it can take any backend regardless of how it was declared. Most caches you'd feed into it are persistent/static pairs where the persistent is tagged as cache.bin, also leading to double invalidation.

    Perhaps we should open a follow-up to discuss these findings.

Production build 0.71.5 2024