Problem/Motivation
The RouteBuildEvent allows different subscribers to alter the routes in a RouteCollection object.
Some subscribers (in particular for views) pass the route collection to a number of child objects, which can alter it (views Drupal\views\Plugin\views\display\PathPluginBase->alterRoutes()
).
Subscribers that want to alter a specific route by route id are quite fast.
Subscribers that need to find routes by path need to check all routes in the route collection.
If there are many such subscribers, it can be quite slow.
It has a cost of O(n*m), with factors n and m that can both grow with the site complexity.
(n = number of routes, m = number of subscribers that need to scan all routes)
This happens only on cache rebuild, but still it is not good.
In
π
\Drupal\views\Plugin\views\display\PathPluginBase::alterRoutes() can become very slow on a site with lots of entities and JsonAPI
Fixed
there was already an attempt to optimize the route subscribers for views, but we are still at O(n*m) as before.
Steps to reproduce
Install opensocial distro, check the output from xdebug profiler on cache rebuild.
Or check on a custom project with many views displays that use a path plugin.
Proposed resolution
To push the cost to O(n * log n), we need to be able to pick a route by path _or_ by id.
So instead of a foreach($collection->all()) over all routes, it would just call $collection->getRoutesByPath($path)
and only deal with these routes. The path can be a "normalized" version of the path as in RouteCompiler::getPathWithoutDefaults()
and RouteCompiler::getPatternOutline()
.
The first id would be to add an index to RouteCollection. But this is not reliable, because the path in a route object can change during the altering, and the index won't know when it needs to be updated.
Some ideas:
- Route objects that ping the route collection whenever they change. This could be a wrapper of regular route objects, or a subclass.
- A new event type where instead of the regular RouteCollection, we pass around an IndexedRouteCollection. The route objects in that collection are immutable, and to change them we have to set the modified route object in the collection. This way the collection knows when to update the respective entries in the index.
Remaining tasks
User interface changes
API changes
Data model changes
Release notes snippet