Problem/Motivation

#3259188: Extend post update system to provide themes a way to install newly-required dependencies had a big impact on site install and test performance on sites with a large number of modules as it exponentially increased the number of times extensions are scanned and update files are loaded.

While patch #10 in #3294299: Regression in functional test performance with a large number of modules brought some partial improvement, it couldn't get our running times back to what they were before #3259188 was introduced. Even though file cache for ExtensionDiscovery was enabled, it keeps spending a lot of time scanning for individual extensions (exponentially to the number of extensions installed).

This means that either the cache isn't working as expected or there are other underlying issues, because when refactoring the code in a way that scanning of extensions is being skipped (see patch), I saw significant improvements in performance (saving 2 minutes on an otherwise 6min long job).

Steps to reproduce

Run a site install or InstallTest with 150+ modules enabled. Especially in an environment with slower I/O like docker/WSL2.

Proposed resolution

  • Optimizing code by decoupling scanning for extensions and loading update files.
  • Fix any issues with caching in case there are.

Remaining tasks

Get some real world testing as to how bad the problem actually is (maybe it's an issue on our end?). Find a solution that adds less complexity and is cleaner than the workaround (see patch).

User interface changes

None

API changes

Loading update files is possible without scanning for extensions.

Data model changes

None

Release notes snippet

Issue fork drupal-3303751

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

phma created an issue. See original summary.

phma’s picture

Issue summary: View changes

Fixing issue links.

phma’s picture

Issue summary: View changes

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.9 was released on December 7, 2022 and is the final full bugfix release for the Drupal 9.4.x series. Drupal 9.4.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.5.x-dev branch from now on, and new development or disruptive changes should be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

nicxvan’s picture

I'd love ideas for how to optimize this.

When testing an issue I output the number of scans for a single kernel test and it was dozens.

nicxvan’s picture

Priority: Normal » Major

I think this might qualify for major.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.

nicxvan’s picture

nicxvan’s picture

Rerolled the patch so we can review the tests.

I didn't review it just applied it and resolved conflicts.

nicxvan’s picture

Title: Reduce the number of times Drupal scans for extensions » [pp-1] Reduce the number of times Drupal scans for extensions
Status: Active » Postponed
Related issues: +#3618545: Always use infoParser in ExtensionDiscovery
catch’s picture

I tried profiling this in combination with #3618545: Always use infoParser in ExtensionDiscovery and it's not reducing the extension scanning yet. Still 9 calls to ExtensionDiscovery::scanDirectory() when running a curtailed version of node module's GenericTest.

It might be different with a real install via dr or drush (or the UI) which I did not try to profile yet.

longwave-bot made their first commit to this issue’s fork.

longwave’s picture

Title: [pp-1] Reduce the number of times Drupal scans for extensions » Reduce the number of times Drupal scans for extensions
Status: Postponed » Needs review

Tried an alternative approach in MR!16818 which avoids threading a boolean flag through several methods, and includes test coverage to prove that we discover once and then cache.

nicxvan’s picture

That does look a lot better, is there a reason we shouldn't use a memory cache though?

I hid the other MR.

nicxvan’s picture

longwave’s picture

Switched to a memory cache, which means we can remove the explicit invalidation and use cache tags. Also rearranged the test coverage a bit to show that installing a module invalidates the cache correctly.

longwave’s picture

Category: Feature request » Task
catch’s picture

Profiled a curtailed version of node module's GenericTest again and this time looked for the right method in the profiling data, #13 was just looking for the wrong thing.

As far as I can tell, this is saving 20 calls to ExtensionDiscovery::scan(), which works out about 15ms or half the time spent in UpdateRegistry::getUpdateFunctions(). Uploading xhgui screenshots.

On a real test run we're doing this hundreds/thousands of times so it will add up.

nicxvan’s picture

Status: Needs review » Needs work

Got a few suggestions I added to the MR, I switched to MemoryCacheInterface since #3590964: Update/Install-time service overrides for cache should support MemoryCacheInterface landed.
I also removed the constructor comment.

The bigger change though was I moved the caching logic to discoverExtensions so that if we ever call that elsewhere the calls are cached as well.

I also had one question on the test I'm not sure about.

longwave’s picture

Status: Needs work » Needs review
nicxvan’s picture

Status: Needs review » Needs work

I think you might have accidentally force pushed over the changes we made this morning, UpdateRegistry is back to CacheBackendInterface and the cache set is back in the call site instead of in discoverExtensions.

longwave’s picture

Status: Needs work » Needs review

Sorry for making a mess here, trying to do too many things at once, hopefully this is better.

nicxvan’s picture

Status: Needs review » Needs work

No worries, we've all done it, I use --force-with-lease now to prevent overwriting commits upstream.

There is a failing test though:

Service Provider (Drupal\KernelTests\Core\ServiceProvider\ServiceProvider)
     ✔ Service provider registration
     ✘ Service provider registration dynamic
       ┐
       ├ TypeError: Drupal\Core\Update\UpdateRegistry::__construct(): Argument #6 ($memoryCache) must be of type Drupal\Core\Cache\MemoryCache\MemoryCacheInterface, Drupal\Core\Cache\DatabaseBackend given
longwave’s picture

Status: Needs work » Needs review
nicxvan’s picture

Status: Needs review » Reviewed & tested by the community

This looks great now!

I don't think we need a CR for this.

nicxvan’s picture

Title: Reduce the number of times Drupal scans for extensions » Reduce the number of times UpdateRegistry scans for extensions
longwave’s picture

Wondering if we need constructor BC because I think that drush also uses the update registry for deploy hooks.

nicxvan’s picture

longwave’s picture

Status: Reviewed & tested by the community » Needs review
Issue tags: +Needs change record
nicxvan’s picture

Constructor parameters usually become required in the next version so 12, not 13.

longwave’s picture

Status: Needs review » Needs work

NW for #33 and the change record.

nicxvan’s picture

I took a pass at the CR, it could use another set of eyes.

I added a suggestion for the CR update and version.

If the CR looks good I think this is RTBC assuming that test failure is random.

longwave’s picture

Status: Needs work » Reviewed & tested by the community

Added a line to the CR that explicitly mentions who is affected, accepted the suggestion, edited the test for the same change.

  • catch committed d4d0ac45 on 11.x
    task: #3303751 Reduce the number of times UpdateRegistry scans for...

  • catch committed ee7c7d2d on main
    task: #3303751 Reduce the number of times UpdateRegistry scans for...
catch’s picture

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

Committed/pushed to main and 11.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.

amateescu made their first commit to this issue’s fork.

amateescu’s picture

Status: Fixed » Needs review

Core tests are failing since this was merged, opened a quick followup MR.

nicxvan’s picture

Status: Needs review » Reviewed & tested by the community

That change looks right, I actually came here to open the follow up fix.

Sorry I don't think I clear in 35, when I said:

I think this is RTBC assuming that test failure is random.

I was trying to flag it was failing and if it passed on rerun it was random since I couldn't rerun it.

  • alexpott committed 765a0b9c on 11.x
    fix: #3303751 (follow-up) Reduce the number of times UpdateRegistry...

  • alexpott committed 15fda93c on main
    fix: #3303751 (follow-up) Reduce the number of times UpdateRegistry...
alexpott’s picture

Status: Reviewed & tested by the community » Fixed

I pushed the test fix to 11.x and main - thanks @amateescu and @nicxvan

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.

catch’s picture

Ah sorry I missed the failing test but also thanks for fixing it while I was out at the shops for 20 minutes...

quietone’s picture

Issue tags: -Needs change record

Published change record