Problem/Motivation

The whole way that we have to explicitly clear plugin managers in drupal_flush_all_caches() on top of the actual cache clears is questionable - cache tables are cleared and any class properties get reset by the container rebuild. Removing it shows that the original reason for adding it is no longer necessary.

Steps to reproduce

Proposed resolution

Remaining tasks

User interface changes

Introduced terminology

API changes

Data model changes

Release notes snippet

Issue fork drupal-3593202

Command icon 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

catch created an issue. See original summary.

longwave’s picture

Could we swap the $themeHandler argument in the constructor for the parameter, because the theme handler isn't needed otherwise.

longwave’s picture

Alternatively, we could do this with cache tags? (which means injecting the invalidator instead)

catch’s picture

Status: Active » Needs work

Oh good spot, I initially wondered about that then quickly convinced myself that that theme handler is the same as the theme manager... which it obviously isn't. I think we can swap it yeah and check the type in the constructor.

Using cache tags we used to do until #3335768: Manually clear cache keys from plugin managers with finite variations instead of using cache tags and I think we should still err on not using them for these nearly but not quite 1-1 caches.

longwave’s picture

drupal_flush_all_caches():

  foreach (Cache::getBins() as $cache_backend) {
    $cache_backend->deleteAll();
  }

...

  \Drupal::service('plugin.cache_clearer')->clearCachedDefinitions();

Why do we need the plugin cache clear after we just wiped all bins?

edit: and given that we clear statics and rebuild the container if no kernel is passed in:

  // Reset all static caches.
  drupal_static_reset();

...

  if (!$kernel instanceof DrupalKernel) {
    $kernel = \Drupal::service('kernel');
    $kernel->invalidateContainer();
    $kernel->rebuildContainer();
  }

then any static caches inside plugin manager services should be gone too.

longwave’s picture

I just did some manual instrumentation and by the time we get to

\Drupal::service('plugin.cache_clearer')->clearCachedDefinitions();

the only plugin manager with any data is the entity type manager, and that's only because BlockHooks::rebuild() validates regions for all blocks.

So, perhaps we can just drop this?!

catch’s picture

It may possibly be worth switching to the container extension list anyway, but we probably can't eliminate it on these requests so it may not make any appreciable difference.

Dropping this entirely sounds great, I started to look at that but missed that the container rebuild would drop everything before we get here.

The block hooks one is a reload so that's OK, and also opened #3593204: Remove BlockHooks::rebuild() for that too because it's quite strange code (that we added in 2008).

longwave’s picture

If we don't do that we should try reordering as follows:

  // Clear all plugin caches.
  \Drupal::service('plugin.cache_clearer')->clearCachedDefinitions();

  // Rebuild all information based on new module data.
  \Drupal::moduleHandler()->invokeAll('rebuild');

  // Rebuild the menu router based on all rebuilt data.
  // Important: This rebuild must happen last, so the menu router is guaranteed
  // to be based on up to date information.
  \Drupal::service('router.builder')->rebuild();

This is because hook_rebuild primes the entity type manager cache (and perhaps others, depending on what's installed), then that immediately gets cleared again, then during route rebuild the entity type manager (and again, maybe others) are primed for a second time.

This is also out of scope for this particular issue and I should just create a followup :)

catch’s picture

Pushed a commit with just the plugin cache clear removal to see what happens to our wonderful test suite.

It looks like we can nearly deprecate/remove the plugin cache clearer service if it works. One usage in search help but that probably should be clearing the search plugin cache or similar.

longwave’s picture

This is green! But we should probably look why this was added where it was, in case there is some edge case we're missing...

longwave’s picture

I asked Claude to do some research, here's a summary of what it found:

2013:

#1892462: EntityManager should use the CacheDecorator added plugin.manager.entity->clearCachedDefinitions() under a comment @todo Rebuild the kernel/container

#1982984: Create Drupal::entityManager for improved DX changed this to Drupal::entityManager()->clearCachedDefinitions()

2014:

#2155635: Allow plugin managers to opt in to cache clear during module install adds the plugin.cache_clearer service

#2326409: Annotate render element plugins generalises the single entity manager flush to use plugin.cache_clearer instead

2015:

#2493665: Add centralized container invalidation method fixes the original @todo

Now that we rebuild the container on cache clear and also module install, it looks like the original reason for plugin.cache_clearer to exist might be gone.

longwave’s picture

No, we still need the plugin cache clearer for the module/theme install/uninstall scenarios, because those don't wipe the discovery cache bins. But I still think it's safe to drop from drupal_flush_all_caches().

catch’s picture

No, we still need the plugin cache clearer for the module/theme install/uninstall scenarios, because those don't wipe the discovery cache bins

I think we could do that in a follow-up - discovery tables are largely plugins, not a lot else in them.

catch’s picture

Title: Don't rebuild the theme extension list twice when clearing caches » Drop the explicit clear of plugin caches in drupal_flush_all_caches()
Issue summary: View changes
Status: Needs work » Needs review
longwave’s picture

Status: Needs review » Reviewed & tested by the community
catch’s picture

alexpott’s picture

I've had a think about drupal_rebuild() and the way it passes the kernel into drupal_flush_all_caches (to prevent unnecessary rebuilds). I think this is fine because there is no way for services to pollute their statics from cache here. Well there is one potential place - there's the \Drupal\Core\DrupalKernelInterface::CONTAINER_INITIALIZE_SUBREQUEST_FINISHED event - this event is very poorly named - but it does not trigger on rebuild.php because the request is not on the stack when the container is rebuilt.

alexpott’s picture

Version: main » 11.4.x-dev
Status: Reviewed & tested by the community » Fixed

Committed and pushed 0394ef0b0ab to main and f0da424363b to 11.x and e94fef706cf to 11.4.x. Thanks!

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

  • alexpott committed e94fef70 on 11.4.x
    perf: #3593202 Drop the explicit clear of plugin caches in...

  • alexpott committed f0da4243 on 11.x
    perf: #3593202 Drop the explicit clear of plugin caches in...

  • alexpott committed 0394ef0b on main
    perf: #3593202 Drop the explicit clear of plugin caches in...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.