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'

Issue fork drupal-3402850

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

kristiaanvandeneynde created an issue. See original summary.

kristiaanvandeneynde’s picture

kristiaanvandeneynde’s picture

Assigned: kristiaanvandeneynde » Unassigned
Status: Active » Needs review

PoC in MR now

catch’s picture

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.

kristiaanvandeneynde’s picture

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

kristiaanvandeneynde’s picture

Issue summary: View changes

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.

kristiaanvandeneynde’s picture

All green now :)

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs Review Queue Initiative, +Needs change record

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?

kristiaanvandeneynde’s picture

Status: Needs work » Needs review

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.

smustgrave’s picture

Status: Needs review » Needs work

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.

kristiaanvandeneynde’s picture

Status: Needs work » Needs review
Issue tags: -Needs change record

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.

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

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.

catch’s picture

Status: Reviewed & tested by the community » Needs work

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.

kristiaanvandeneynde’s picture

Status: Needs work » Needs review

Re #13 I added a comment on #3376101: [11.x] [Meta] Tasks to remove Book

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.

catch’s picture

Status: Needs review » Reviewed & tested by the community

Yes I think that's good!

  • catch committed 2e73418c on 11.x
    Issue #3402850 by kristiaanvandeneynde, catch, smustgrave: Fix...
catch’s picture

Status: Reviewed & tested by the community » Fixed

Committed/pushed to 11.x (which is also still 10.3.x at the moment), thanks!

Status: Fixed » Closed (fixed)

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

berdir’s picture

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?

This made cache.jsonapi_memory public but that feels wrong to me as it never should be used directly, only through the chain?

kristiaanvandeneynde’s picture

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.

Edit: I'd even argue we could investigate whether ChainBackend even needs to be tagged anymore as both its inner backends are now properly tagged.