Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
CacheArray is a neat trick that was introduced in 7.x to introduce backwards compatible partially loaded large cache arrays.
As discussed in #1786490: Add caching to the state system, there is no need for that in 8.x for at least the new implementations, so let's make this implementation with interface that we can use elsewhere too.
The long term goal is probably to get rid of CacheArray completely but that doesn't need to happen here.
Follow up: #2185015: Remove SchemaCache and CacheArray
Comment | File | Size | Author |
---|---|---|---|
#27 | cache-collector-1858616-27.patch | 43.59 KB | Berdir |
#27 | cache-collector-1858616-27-interdiff.txt | 4.76 KB | Berdir |
#18 | cache-collector-1858616-18.patch | 41.05 KB | Berdir |
#18 | cache-collector-1858616-18-interdiff.txt | 1.95 KB | Berdir |
#16 | cache-collector-lazyload-1858616-16.patch | 40.63 KB | Berdir |
Comments
Comment #1
catchYes anything that doesn't need backwards compatibility with array syntax shouldn't be using ArrayAccess really, we should also be able to see a very small performance improvement here by skipping the magic methods.
On top of this there's the potential to have alternative implementations of the base class (like LRU instead of additive, although that's going to be hard to get right without too many writes but someone could try).
Comment #2
BerdirHere's a first attempt. Defined the interface and the implementation and also reworked the existing documentation in CacheArray, moved generic documentation to the interface and implementation specific stuff to the class. Likely needs more work.
I've prepared it for the ServiceTerminator pattern introduced in the form_state issue and it also gets cache and lock injected.
I initially planned to refactor CacheArray to use the implementation provided by this but this turned out to be not as easy as I hoped, mostly because ThemeRegistry contains quite some overrides that would have to be changed as well.
No tests yet. Not sure if I should re-introduce some or just merge this back into #1786490: Add caching to the state system and write coverage for that. As everything is injected now it should actually be possible to write fast unit tests for this that don't have to touch the database. But doing it here would require us to write a test implementation that implements the abstract method.
Comment #3
Fabianx CreditAttribution: Fabianx commentedTagging
Comment #4
BerdirClosing this, integrated and improved the patch here into #1786490: Add caching to the state system.
Comment #5
BerdirReviving this, as suggested by catch, fighting with the state cache and not making progress.
We have multiple CacheArray implementations in HEAD now that live in the container, updated path whitelist cache as a first example. Tests seem to almost pass except one case in PathLanguageTest that I haven't figured out yet.
Comment #7
BerdirOk, we also need a method to actually clear the cache, not just reset the currently loaded cache entry. Also converted the locale stuff over.
Comment #9
BerdirThis should be better.
Comment #10
ParisLiakos CreditAttribution: ParisLiakos commentedthis looks great! most of them are nitpicks:)
full namespace needed
maybe a protected method invalidate to avoid duplication?
Probably the comma here should be a dot
we should use the full namespace to CacheCollector
lowercase first on Interface
uh just noticed we have the wrong object name here. could we fix this since we are here?
Comment #11
BerdirThanks, fixed those things and added a method.
Comment #12
ParisLiakos CreditAttribution: ParisLiakos commentedthis needs some unit tests, probably on AliasWhitelist, tagging
Comment #13
catchSince the cache object is injected should the comment be updated as well?
Comment #14
BerdirOk. Fixed those comments and wrote a ton of unit tests. The method names and documentation there needs work, but I have 100% code coverage of the CacheCollector class.
Found one issue, when you only did a delete() and no set(), then it didn't update the cache.
Comment #15
ParisLiakos CreditAttribution: ParisLiakos commentednot very thorough review, but they look great!
lets add some visibility here
i see you do this on most tests..why not put it in setUp() ? and still call it when you want to override it later
you set $key and $value twice
Comment #16
BerdirThanks for the review.
- Made them public
- Fixed the double-definition, that uncovered that the test method and has() was actually broken, fixed.
- The reason for constructCollector() was that in some cases, I set up the cache mock first. I could have re-created it but thought that to be a bit weird.
- This patches switches to lazy-loading, which allows us to not initially get the cache but only when we need it. That also fixes the reset() weirdness and it allows me to kill constructCollector().
Comment #17
dawehnerI really like to have @see \Drupal\Core\Cache\CacheCollector so you can switch between them really easy.
This is an amazing test!!
All the other tests actually document on the actual interface/class which is mocked, which gives you a better understanding what is going on.
The setup method is called for each test methods, so I don't understand why this i needed.
Comment #18
BerdirAdded the @see and a comment line to explain the destruct. It's not clean-up/tear down, updateData() is a protected method called by destruct(), so the call to it triggers the actual thing we're testing in those methods.
Not sure about the @var. Documenting it as a mock object made it possible for me to have autocomplete on it for expects(), which is the only way I'm interacting with it within the test. As the tests are now written, I don't care which one it is, but using what I have in the patch makes more sense to me :)
Comment #19
ParisLiakos CreditAttribution: ParisLiakos commentedi agree about the @var with berdir
i think i am not the right person to rtbc this, but imo its ready
Comment #20
dawehnerYeah I don't care that much either.
Oh i guess it should be one @inheritdoc?
Comment #21
BerdirWell, then we can't have the additional documentation that's below it in the method docblock and would have to move it inline, where it's harder to find.
I know @timplunkett wants to allow partial inheritdoc and extend it, but I'm not sure if that makes sense conceptually for cases like this (I don't want to have both things merged together somehow, a reference to the interface and this information below seems like exactly what I want here).
So, I'd rather not touch that.
Comment #22
BerdirThis is blocking major/critical performance issues, e.g. state caching and if we want to remove CacheArray, this needs to go on, asap.
Comment #23
ParisLiakos CreditAttribution: ParisLiakos commentedlets get it in then
Comment #24
Berdir#18: cache-collector-1858616-18.patch queued for re-testing.
Comment #26
catchAfter this->get() the array_key_exists() will always return TRUE, because items that don't exist get stored as NULL at least with the default implementation. Shouldn't this just be an isset()?
This comment is just from CacheArray, but it's no longer accurate now that the cache item is loaded in lazyLoadCache.
Shouldn't this be deleteTags() if tags were passed in? At the moment it looks like if you have multiple cache items with tags, and a process calls delete on one of them, the rest won't be invalidated.
Yes! I was so pleased to get CacheArray into Drupal 8/7, but it's so good we can remove it from Drupal 8.
Incomplete comment: there is a?
Really nice tests except possibly for the multiple cache + tags case.
Comment #27
BerdirRe-roll.
Hm. The array_key_exists() check is taken from CacheArray. I'm not sure what the expected behavior should be there. The check makes sense because it allows to set values to NULL and avoid to re-trigger cache misses for those on future requests. That said, this doesn't happen by default and is the main reason why subclasses currently need to set/persist their stuff in resolveCacheMiss() themself.
I added a basic test for that. I'm happy to change it, just not quite sure what would be a sane behavior? Maybe store NULL's by default (and therefore simplify resolveCacheMiss() implementations) but keep returning FALSE in has()? Right now, subclasses can already do that but they explicitly need to chose to do so.
Added cache delete support for tags and tests for it, updated the comment.
Yes and yes to that :)
Comment #28
ParisLiakos CreditAttribution: ParisLiakos commentedback to catch then!:)
Comment #29
catchHmm. I guess either way is fine for has(), and it's only used in tests in the patch, so as long as we pick one it's up to implementations to figure that out anyway.
Committed/pushed to 8.x, will need a change notice.
Comment #30
catchTagging.
Comment #31
catch#2083415: [META] Write up all outstanding change notices before release
Comment #32
cosmicdreams CreditAttribution: cosmicdreams commentedSoooooooooo, I was just about to open an issue about removing CacheArray because I noticed it was deprecated and still used in ModuleInfo.php and SchemaCache.php. Also it was included in code comments in AliasWhitelist.php and TestBase.php. Also the CacheArray class still exists.
So is it better to create a follow up issue for the elimination of CacheArray from Drupal or is it better to piggyback onto here?
Comment #33
cosmicdreams CreditAttribution: cosmicdreams commentedAlso, I suppose I could try to write a change notice for this one once we clean up.
Comment #34
cosmicdreams CreditAttribution: cosmicdreams commentedComment #35
xjmTagging "Missing change record", as completing the change record updates here blocks a beta: #2083415: [META] Write up all outstanding change notices before release
The patch for this issue was committed on June 21, 2013, meaning that the change record has been missing for more than seven months.
Comment #36
BerdirWow, I completely forgot about this one.
Tried to make up for it by providing a detailed change notice, we can probably more or less move that 1:1 to a documentation page somewhere, just no idea where ;)
https://drupal.org/node/2186501
Comment #37
Berdir@xjm verified that the change notice is ok, so closing this.