Problem/Motivation

\Drupal\Core\DrupalKernel::preHandle currently does a config get, really early in the bootstrap,
for something which is not even configurable via the UI and is quite low level and is not changed really on deployment

What you see in there is the time spend in the preHandle function, which for example consists of ~0.5 % inside the config get
+ the container->get() call for the first initialized config factory, so solving this issue would solve that 0.5% + move the config get call more away from early bootstrap.

Function Name Calls Calls% Incl. Wall Time
(microsec)
IWall% Incl.
MemUse
(bytes)
IMemUse% Incl.
PeakMemUse
(bytes)
IPeakMemUse%
Current Function
Drupal\Core\DrupalKernel::preHandle 1 4.3% 3,859 4.1% 1,032,104 6.2% 1,032,160 6.2%
Exclusive Metrics for Current Function 30 0.8% 4,864 0.5% 4,672 0.5%
Parent function
Drupal\Core\StackMiddleware\KernelPreHandle::handle 1 100.0% 3,859 100.0% 1,032,104 100.0% 1,032,160 100.0%
Child functions
Symfony\Component\DependencyInjection\Container::get 4 26.7% 1,942 50.3% 632,728 61.3% 650,840 63.1%
Drupal\Core\Extension\ModuleHandler::loadAll 1 6.7% 788 20.4% 111,840 10.8% 95,920 9.3%
Drupal\Core\Config\ConfigFactory::get 1 6.7% 557 14.4% 143,600 13.9% 144,768 14.0%
Drupal\Core\DrupalKernel::loadLegacyIncludes 1 6.7% 239 6.2% 47,352 4.6% 47,008 4.6%
Drupal\Core\File\MimeType\MimeTypeGuesser::registerWithSymfonyGuesser 1 6.7% 143 3.7% 42,440 4.1% 41,568 4.0%
Drupal\Core\DrupalKernel::initializeRequestGlobals 1 6.7% 68 1.8% 19,008 1.8% 17,384 1.7%
spl_autoload_call 2 13.3% 58 1.5% 17,992 1.7% 19,040 1.8%
Drupal\Core\StreamWrapper\StreamWrapperManager::register 1 6.7% 24 0.6% 7,344 0.7% 6,184 0.6%
Drupal\Core\Config\Config::get 1 6.7% 8 0.2% 3,744 0.4% 3,552 0.3%
Symfony\Component\HttpFoundation\RequestStack::push 1 6.7% 1 0.0% 992 0.1% 848 0.1%
Drupal\Component\Utility\UrlHelper::setAllowedProtocols 1 6.7% 1 0.0% 200 0.0% 376 0.0%

Proposed resolution

Move it to a container parameter to avoid early config instantiation.

This has the advantage of being much faster than a configuration that early in the bootstrap. In an ideal world together with smart cache pages should be potentially
able to serve without invoking config. This issue is a small step in that direction.

Remaining tasks

User interface changes

API changes

Data model changes

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
Issue category Task, because nothing is broken.
Issue priority Major because it is in the critical performance path.
Prioritized changes The main goal of this issue is performance.
Disruption Potentially disruptive for existing sites that had customized this configuration. Usually this was set via settings.php in D7 and given there is no UI a config override is way more likely, so it is easy to move over to settings.yml

Comments

fabianx’s picture

dawehner’s picture

Status: Active » Needs review
StatusFileSize
new2.95 KB

Just a start.

Status: Needs review » Needs work

The last submitted patch, 2: 2529514-2.patch, failed testing.

dawehner’s picture

Issue summary: View changes

Added a profiling of HEAD into the issue summary.

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new10.3 KB
new8.01 KB

Some work on it.

Status: Needs review » Needs work

The last submitted patch, 5: 2529514-5.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new10.3 KB
new649 bytes

Ups.

Status: Needs review » Needs work

The last submitted patch, 7: 2529514-7.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new10.28 KB
new631 bytes

.

Status: Needs review » Needs work

The last submitted patch, 9: 2529514-9.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new12.3 KB
new5.31 KB

I think Drupal\migrate_drupal\Tests\d6\MigrateSystemFilterTest is kinda wrong, as it just migrates the default variables ...
so even if it should not pass, it does now.

ideally we would have a container parameter migration destination.

Status: Needs review » Needs work

The last submitted patch, 11: 2529514-11.patch, failed testing.

wim leers’s picture

Just a migrate test failure. Easy fix? :)

+++ b/core/lib/Drupal/Core/Routing/UrlGenerator.php
@@ -72,19 +72,18 @@ class UrlGenerator implements UrlGeneratorInterface {
+   *   An array of protocols allowed for url generation.

+++ b/core/lib/Drupal/Core/Utility/UnroutedUrlAssembler.php
@@ -40,14 +40,13 @@ class UnroutedUrlAssembler implements UnroutedUrlAssemblerInterface {
+   *   An array of protocols allowed for url generation.

s/url/URL/

dawehner’s picture

Just a migrate test failure. Easy fix? :)

Well, we just need to write a migration destination for services.yml files.

berdir’s picture

As mentioned, I think we should simply drop that from the migration. We did that as well for the private file path for example which is now in $settings.php

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new13.06 KB
new3.37 KB

Sure let's do that.

@chx recommended to to add it to https://www.drupal.org/node/2167633, so this is done.

Status: Needs review » Needs work

The last submitted patch, 16: 2529514-16.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new13.04 KB
new669 bytes

Ups, let's fix the merge error

Status: Needs review » Needs work

The last submitted patch, 18: 2529514-18.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new14.01 KB
new986 bytes

Meh.

dawehner’s picture

Issue summary: View changes

Improved the IS a bit

wim leers’s picture

This looks great!

Just one last question before this is RTBC:

+++ b/core/lib/Drupal/Core/Routing/UrlGenerator.php
@@ -72,19 +72,18 @@ class UrlGenerator implements UrlGeneratorInterface {
+    UrlHelper::setAllowedProtocols($filter_protocols ?: ['http', 'https']);

+++ b/core/lib/Drupal/Core/Utility/UnroutedUrlAssembler.php
@@ -40,14 +40,13 @@ class UnroutedUrlAssembler implements UnroutedUrlAssemblerInterface {
+    UrlHelper::setAllowedProtocols($filter_protocols ?: ['http', 'https']);

Should we document why we need the fallback here?

dawehner’s picture

Should we document why we need the fallback here?

Well, in cases like tests, not sure what exactly we would gain. Those tests would fail then, but for runtime this doesn't matter.

dawehner’s picture

Wrote a change record.

wim leers’s picture

Status: Needs review » Reviewed & tested by the community

I personally think it'd be great if #23 would be added as a comment to the patch, to explain the need for #22. But since @dawehner doesn't feel the same way AFAICT, let's see what a committer thinks. Because other than that, this is ready.

dawehner’s picture

Mh, I see your point, I just can't form some proper sentence which makes sense.

fabianx’s picture

RTBC + 1, I think it is fine to have a safe fallback.

dawehner’s picture

StatusFileSize
new14.29 KB
new1.54 KB

Ha, that triggered something in me :)

fabianx’s picture

#26: What about:

During tests the ContainerParameter filter.protocols might not be available, in that case use a fallback.

However that is wrong, too as getParameter() throws an Exception when a parameter cannot be found, so either we write a wrapper that works like variable_get() / config() with default values or we catch the Exception ...

(See: https://github.com/symfony/DependencyInjection/blob/master/ParameterBag/...)

So currently the fallback should never be used anyway ...

Edit: X-post with #28

dawehner’s picture

One the the test failures on https://qa.drupal.org/pifr/test/1094313 caused me to add it. But well, in general think being always able to render HTTP/HTTPs links isn't such a bad idea to start with.

fabianx’s picture

Status: Reviewed & tested by the community » Needs work

Discussed in IRC:

CNW as resolveValue() / getParameter() of ParameterBag clearly throws an Exception and that parameter should never be empty.

If we wanted a fallback, then we should add a generic Drupal::getParameter() function or a parameter service or such, that allows to specify a default value as fallback.

But then we are again way on our way to re-invent config, so probably not worth it ...

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new14.03 KB
new2.8 KB

Let's see whether it still passes. I might have changed UrlGenerator before moving the information for default.services.yml to core.services.yml

fabianx’s picture

Status: Needs review » Reviewed & tested by the community

Thanks, back to RTBC

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 32: 2529514-31.patch, failed testing.

dawehner’s picture

Status: Needs work » Reviewed & tested by the community
StatusFileSize
new13.63 KB

Just an ordinary reroll.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

This issue is a major task that will improve performance significantly and the disruption it introduces is limited. Per https://www.drupal.org/core/beta-changes, this is a good change to complete during the Drupal 8 beta phase. Committed 0613685 and pushed to 8.0.x. Thanks!

+++ b/core/tests/Drupal/Tests/Core/Utility/UnroutedUrlAssemblerTest.php
diff --git a/sites/default/default.services.yml b/sites/default/default.services.yml
old mode 100644
new mode 100755

Fixed the mode change on commit.

  • alexpott committed 0613685 on 8.0.x
    Issue #2529514 by dawehner, Fabianx, Wim Leers: Replace system.filter::...
yched’s picture

+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -466,8 +466,8 @@ public function preHandle(Request $request) {
     // Set the allowed protocols once we have the config available.
-    $allowed_protocols = $this->container->get('config.factory')->get('system.filter')->get('protocols');
-    if (!isset($allowed_protocols)) {
+    $allowed_protocols = $this->container->getParameter('filter_protocols');
+    if (!$allowed_protocols) {
       // \Drupal\Component\Utility\UrlHelper::filterBadProtocol() is called by
       // the installer and update.php, in which case the configuration may not
       // exist (yet). Provide a minimal default set of allowed protocols for
       $allowed_protocols = array('http', 'https');
     }
     UrlHelper::setAllowedProtocols($allowed_protocols);

The code comment still talks about the *config* possibly not existing yet.
Is that "if" case still relevant ? (the parameter not existing in $this->container ?) Not sure about the installer, but probably not true for update.php now that it's a regular route & controller ?

dawehner’s picture

Is that "if" case still relevant ? (the parameter not existing in $this->container ?) Not sure about the installer, but probably not true for update.php now that it's a regular route & controller ?

Well it is relevant for sites which did not had yet a container rebuild, as they will temporarily not have this parameter in the container, so you really want to ensure that at least simple links always work, as otherwise you might have problems for itself.

fabianx’s picture

#38 The parameter not existing would be an Exception, so the only case when it could be NULL or FALSE or '' is if its NULL or FALSE or '' in the container.

Not sure if that can happen during installation.

yched’s picture

@FabianX is right, looks like that snippet had a straighforward conversion from "if (!config->get())" to "if (!container->getParameter())", but both sources don't behave the same on "doesn't exist" (and that "doesn't exist" doesn't occur on the same cases regarding install.php / update.php)

If I get the current situation right, It seems this "if (not exists)" is currently dead code, since the "not exists" case would throw an exception one line above, which doesn't seem to happen since we're currently green ?

fabianx’s picture

#41: That is correct.

yched’s picture

neclimdul’s picture

This removed a migration. I don't see anyone from the migration team weighing in here so should there be a follow up to make sure this is addressed or are we just not going to support upgrading them?

dawehner’s picture

This removed a migration. I don't see anyone from the migration team weighing in here so should there be a follow up to make sure this is addressed or are we just not going to support upgrading them?

Let me quote myself earlier in the issue:

@chx recommended to to add it to https://www.drupal.org/node/2167633, so this is done.

  • alexpott committed e50271a on 8.0.x
    Issue #2541560 by yched, dawehner, Fabianx: Followup for [#2529514] -...

Status: Fixed » Closed (fixed)

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