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
- 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 - Add a new tag alongside cache.bin, namely
cache.bin.memoryand fix places where cache.bin was used incorrectly - Discover these "memory bins" the same way we discover regular bins
- Make CacheTagsInvalidator also call these memory bins upon cache tag invalidation
- Make CacheFactory also check memory default backends
- Make RefreshVariablesTrait also reset memory cache bins
API changes
- New service tag 'cache.bin.memory'
Issue fork drupal-3402850
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
Comment #2
kristiaanvandeneyndeSee #2973286-54: Clean up MemoryCache and MemoryBackend naming issues for more information if needed. Will post a POC soon.
Comment #3
kristiaanvandeneyndePoC in MR now
Comment #5
catchOne 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.
Comment #6
kristiaanvandeneyndeSure, I'm not married to any name here. Will look at the test fails and change the name.
Comment #7
kristiaanvandeneyndeFixed two causes of test failures and renamed everything to "memory", will update IS. We do get the ugly
cache.backend.memory.memoryservice name that way, though.Comment #8
kristiaanvandeneyndeAll green now :)
Comment #9
smustgrave commentedDid 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?
Comment #10
kristiaanvandeneyndeI'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.
Comment #11
smustgrave commentedThanks 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.
Comment #12
kristiaanvandeneyndeAdded 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_cacheis actually poorly named as it gets the bin name "memory_cache" which is very ambiguous. We should consider renaming this tocache.book_memorywhen we move Book to contrib in D11. Will find the right issue for that and add that comment.Comment #13
smustgrave commentedCR 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.
Comment #14
catchYes 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.
Comment #15
kristiaanvandeneyndeRe #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.
Comment #16
catchYes I think that's good!
Comment #18
catchCommitted/pushed to 11.x (which is also still 10.3.x at the moment), thanks!
Comment #20
berdirI'm a bit confused by this change.
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?
Comment #21
kristiaanvandeneyndeWe 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.