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.
We have facets with a lot of values and have noticed a performance problem. Url::createFromRequest is called 1,200 times. That is due mostly to 600 calls to \Drupal\facets\Plugin\facets\url_processor\QueryString::buildUrls.
The offending line seems to be:
$request = $this->request;
if ($facet->getFacetSource()->getPath()) {
$request = Request::create($facet->getFacetSource()->getPath());
$request->attributes->set('_format', $this->request->get('_format'));
}
Instead of recreating the request for each path, we could see if the new request object has been created before. This would act like a static cache of requests and add a performance boost.
Sample Blackfire.io output:
Comment | File | Size | Author |
---|---|---|---|
#21 | 3013991-21.patch | 5.46 KB | legolasbo |
#17 | 3013991-17.patch | 4.68 KB | michaellenahan |
#14 | 3013991-14.patch | 4.39 KB | chr.fritsch |
Comments
Comment #2
mglamanComment #3
mglamanThe fix looks something like this:
Git is currently down. I'll roll a patch later.
Comment #4
mglamanHere is a patch. I'll deploy it and run Blackfire.
Comment #5
borisson_This looks very good, thank you! Setting this to rtbc - will probably commit this and tag a new release during drupalcamp belgium next week.
Comment #6
mglamanGreat! I've been getting a regular release for the project out. I'm still aiming to post an "after" profile.
Comment #7
mglamanSorry, I don't know what i'm thinking. ignore this comment.
Comment #8
mglamanComment #9
mglamanOkay, I'm not crazy. The original patch did not work. The class is always instantiated as a new object, blowing the cache. We need a static variable in the method itself to preserve the cache.
Comment #10
mglamanOkay, there is more to it. It's also the large amount of calls to Url::createFromRequest.
This patch uses more caching, but it isn't elegant. I need to use this for now, but I'd like to find a better approach.
Maybe injecting
cache.static
? Or just a more elegant way of handling the checks.The problem is this:
Comment #11
borisson_It doesn't bother me too much that is not elegant, but i guess it does need some inline documentation to explain what is going :)
Comment #12
mglamanOkay, I'll clean it up so it makes more sense. We've had this in production for a week or so now. With 600 Facet objects the page went from 13s to 9s in Blackfire.
Comment #13
mglamanOkay, here is a cleaned up patch. Instead of stuffing
static
entries into the one method, I broke things out a bit. I felt like this made it easier to document and a less confusing. Otherwise, we would be definingstatic
variables at the beginning of the method and using them sometime after, making it hard to comprehend -- especially since this pattern is not as common in Drupal as it is in PHP as a whole.Comment #14
chr.fritschRerolled
Comment #15
chr.fritschOne question. Why is it called so often for you? For me QueryString::buildUrls is only called once per facet on every page load.
Comment #16
borisson_Patch doesn't apply anymore as I committed other stuff first. Sorry about that.
Comment #17
michaellenahan CreditAttribution: michaellenahan at Hubert Burda Media commentedRerolled
Comment #18
michaellenahan CreditAttribution: michaellenahan at Hubert Burda Media commentedComment #20
borisson_The patch in #17 seems to break some of our testcoverage. This could possibly be because our testcoverage isn't that great. But it could also be a legit issue. I don't really have the time to investigate that now.
Comment #21
legolasboThe patch was using regular static variables, which caused interference when running tests because static variables are not reset within tests. I used drupal_static instead to ensure that the tests never run into a cached instance.
Comment #22
borisson_Awesome - this should still be a lot faster.
Comment #24
borisson_Committed and pushed, thanks everyone.