Problem/Motivation
Another approach to solve the same problems that https://www.drupal.org/node/2348245 tried to tackle. We have things like views that have twelve plugin managers (and six handler managers) Whenever we use them we are getting the cached definitions individually for each manager, when we always need almost all of them for a view to work.
I think more import here is making less calls to the cache, rather than shaving lots of time off the page load. If a site comes under a lot of load, lots of more calls to your cache/database etc.. is not good news.
Proposed resolution
Create a backend that all plugin managers can use that collects cids for each plugin definition and loads them all in one getMultiple() call. Subsequent calls to get() individual definitions will then fetch it from the already loaded data.
Remaining tasks
Is this concept ligit? tests, reviews, settle on plan - all the things.
User interface changes
None
API changes
None
| Comment | File | Size | Author |
|---|---|---|---|
| #23 | XHProf__Hierarchical_Profiler_Report.png | 319.9 KB | damiankloip |
| #23 | interdiff-2473205-23.txt | 636 bytes | damiankloip |
| #23 | 2473205-23.patch | 17.66 KB | damiankloip |
| #22 | interdiff-2473205-22.txt | 885 bytes | damiankloip |
| #22 | 2473205-22.patch | 17.66 KB | damiankloip |
Comments
Comment #1
damiankloip commentedHere is an initial rough patch with this idea. Still needs some work of course.
Comment #2
damiankloip commentedComment #3
damiankloip commentedComment #4
wim leersComment #5
damiankloip commentedWorking on some more improvements and tests.
Comment #6
dawehnerJust some really quick review.
Do we really want to have an entire bin per wrapped bin?
Shouldn't we otherwise call out to the wrapped cache backend, if we can't find some entry?
any reason to not call out to deleteMultiple? I guess deleting doesn't happen that often?
Comment #7
damiankloip commentedThanks for taking a look, there is much work to do :) But you know this:
1. This is poorly named right now, this is not wrapping a bin as such, this is just used as the cache key for the list or items to be pre loaded.
2. This is a good point, I think we will want to do something like that in case an item is missing for that request to avoid rebuilding when we don't need to.
3. Mehh. Not sure :)
Comment #8
damiankloip commentedComment #9
damiankloip commentedThis should be a bit more complete, with passing tests. Some questions/todo's:
Comment #10
jibranWow it's green. Nice work @damiankloip
and
setMultiplecode I think this should be$this->cacheItems[$cid] = $this->createCacheObject($cid, $data, $expire, $tags);Isn't this call redundant after above call? We can copy the return value of set in $return[$cid].
If we are calling $this->set then this is also useless.
@inheritdoc
Description block missing.
Comment #11
damiankloip commentedThanks Jibran. I think multiple should just not be calling set (). I'll make these changes along with some of the other stuff I mentioned in #9.
Comment #12
damiankloip commentedA few more changes, based on the feedback above and a couple of other things, such as delegating get() calls to the storage backend if no preloaded item is found in get() and getMultiple().
IMO only keys that are explicitly set() on the backend should be stored for preloading. Thoughts? The get() delegation just covers us a bit better.
Also added views handler to use this same service.
Comment #13
damiankloip commentedComment #15
dawehnerDo you mind added an explanation about the strategies used internally and maybe usecases of that implementation?
Should we maybe make the CID overridable as well? This sounds like it could potentially easily collide.
It feels like its wrong to do it that early
I guess we can mark this service as not public
Comment #16
damiankloip commentedThanks Daniel!
1. Added. Needs a review.
2. I added a $multi_cid_prefix parameter for the bin. This seems better than a method and having to subclass the cache backend. Although we could have a method too?
3. Yep, removed the @todo and added calls to this in get() and getMultiple(). I also added an internal $preloaded property
4. Done, good idea!
I will work on some tests, as we could maybe do with a separate unit test to test E.g. that things are just preloaded once. I don't think a full unit test is necessary as we have the GenericCacheBackendUnitTestBase implementation that covers a lot.
Also, MutliBackend I am pretty sure is not the best name. So a better name is welcome.
Comment #17
damiankloip commentedCouple of other smaller fixes.
Comment #18
dawehnerA quick review
Where ... view, that sentence sounds kinda wrong
+1
Comment #19
damiankloip commentedWorking on some tests, will also look at locking for set() calls.
Comment #20
catchAs well as locking, we need to ensure the list is always additive to avoid race conditions.
So lock -> get existing entry -> add items -> set.
Then no cross-request flip-flopping for different sets of items in the list. This is the same approach that CacheCollector takes. I think that's equally necessary whether we write on every set or at end of request.
And also need to lock when deleting with the same lock name as set uses.
Comment #21
damiankloip commentedAgree totally, we need the list to be additive so one request cannot completely overwrite another one.
Here is a new patch with locking similar to cache collector. setting gets cached items, adds, sets again. Delete gets cached items > removes items > sets again.
We still need to decide if we want to move all of this to destruct. We can then just write back if set or setMultiple has been called during that request. It would probably make things more efficient as the current method will lock > load > update > write on every set() call. So with cold caches...
Comment #22
damiankloip commentedNot sure how those changes got lost.
Comment #23
damiankloip commentedUgh, and this one. Did some quick xhprofing too, profiling a whole page load - admin/content:
Comment #24
dawehnerso DestructableInterface? Well the question is whether we want to propagate that information rather earlier than later to potential new requests
What is the idea for that? Maybe some docs?
Comment #25
catchI think destructable interface is OK here. In the case of a cache miss, it just means we fetch individual cache items instead of the multiple get. That is probably not much more expensive (or could even be cheaper) than trying to acquire/release the lock several times in a request.
Comment #26
damiankloip commentedYes, I agree. I like your thinking.
Comment #27
webchickJust doing some D8 Accelerate house-cleaning. Any update as to where this is at? I don't see a report at https://assoc.drupal.org/d8-accelerate-awarded-grants and there hasn't been movement here in a couple of months.
Comment #28
damiankloip commentedcatch has a report about this issue I think, I sent him one a while ago, which I think he forwarded on to the DA.
Comment #40
smustgrave commentedSince this hasn't been updated in 7 years wonder if this is still a valid task.
If so think an issue summary update could help + there is feedback requested in #24
Comment #42
smustgrave commentedSince there hasn't been a follow up in 11 months and 7 years before that going to close as outdated for now.
If still valid though please reopen.