Here's a patch that adds a failing test to the bundles branch. The test passes if you change BundleTest::setup() to enable the 'bundle_test_dependent' module, but the point of this test is to not do that. I think module_enable() needs to cause an immediate rebuild of the container and make the kernel use it. An example for why this is needed is suppose you use the admin/modules page to enable a module that depends on another module (e.g., forum on taxonomy). The hook_enable() implementation of the module that has the dependency (forum) should be able to use the dependent module's (taxonomy) services.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

effulgentsia’s picture

+++ b/core/modules/system/tests/modules/bundle_test/bundle_test.module
@@ -24,3 +30,10 @@ function bundle_test_callback() {
+/**
+ * Enables the bundle_test_dependent module and invokes one of its services.
+ */
+function bundle_test_dependent_callback() {
+  module_enable(array('bundle_test_dependent'));
+  return drupal_container()->get('bundle_test_dependent.test_service')->test();
+}

Apologies. I got my terminology wrong. bundle_test (or at least this callback) depends on bundle_test_dependent, which is therefore incorrectly named and should be bundle_test_dependency. i.e., if A depends on B, then B is the dependency and A is the dependent (I think, correct me if I'm wrong). Sorry if this caused any confusion.

katbailey’s picture

I think module_enable() needs to cause an immediate rebuild of the container and make the kernel use it

I have a feeling this might be in principle impossible. Rebuilding the container mid-request has to mean instantiating a brand new container, right? But the very HttpKernel instance that is handling the request is managing the scope of the old container in doing so. Thinking of making it use the new container makes me think of an Escherian hand drawing itself. If anyone can see a way around this that I'm not seeing, I'd love to hear it.

Crell’s picture

The only way to make this work, I think, is to Enable the module, regenerate the DIC, and then do a self-redirect to run the install/update hooks now that the DIC is updated. Which of course only works in HTTP mode, not CLI mode, although I think there's some trick to "reboot" a CLI, too.

Is there a specific use case that cannot be otherwise solved, rather than a "nice to have" that we get now by virtue of playing fast and loose with system state (which is something we're trying to get away from)?

lsmith77’s picture

i think its not wise to execute code synchronously by a process that is installing said code. it will always be very hard to ensure a defined behavior in this case since its quite common for boot strap processes to make the assumption that all pieces are available. breaking this assumption will always add a lot of complications to very core logic and i dont really see what use case requires the behavior illustrated by the failing test ..

effulgentsia’s picture

At this time, because #1599108: Allow modules to register services and subscriber services (events) doesn't add any module-specific DIC entries for any core modules, I don't think this issue needs to block that one from going in, but once that issue does go in, I think that some retitled version of this issue (e.g., "Integrate system_modules_submit() with DrupalKernel") will need to be a critical; otherwise once modules start adding module-specific DIC entries and using them within their API functions, those functions will fatal error when called from a dependent module's hook_enable().

Is there a specific use case that cannot be otherwise solved?

That will depend on what modules end up putting into their bundle classes. As an example, forum_enable() calls taxonomy_vocabulary_save() and node_types_rebuild()/node_type_get_types(). Will taxonomy_vocabulary_save() require DIC services from the taxonomy bundle, or will node_type_get_types() require DIC services from the node bundle? I don't know what our first actual use case will be, but I'm sure we'll hit many.

I think there's some trick to "reboot" a CLI, too.

If we decide that the solution we want for web-based triggers of module_enable() is to issue a self-redirect, then we'll need a separate issue for figuring out CLI. I think it makes sense to figure out the web-based issue first, because I'm assuming CLI scripts, if nothing else, can reinstantiate a new DrupalKernel when they need to. Despite lsmith77's warning in #4, I also don't want to prematurely rule out the possibility of adding a rebuildContainer() method to DrupalKernel, and preserving the synchronous module_enable() we have now. I'm not saying we should do that, but I see it as a legitimate option to have on the table if we run into too many difficulties with a self-redirect approach.

pounard’s picture

Agree with #4, maybe it's time for Drupal to rethink the way it handles modules. Modules probably should be installed/uninstalled without the need of being enabled, this cause various problems, at site install time where the site needs to be bootstrapped unfinished and when enabling multiple modules at once on a live site, etc.. due to all stuff that cores has to do, such as clearing all the caches, calling all possible hooks, enabling modules, rebuild the runtime environment at runtime...

In actual core, when you enable a module, it's hook_init() and hook_boot() has not been run, and so in bundles services are not registered, which seems totally valid to me. Modules should not need their own services when being installed, considering their aren't even configured yet.

catch’s picture

Modules should not need their own services when being installed, considering their aren't even configured yet.

In that case we'd need to remove hook_install(), hook_schema(), hook_enable() and any other hook that's invoked at install time. On the other hand I don't think anyone loves the module install process as it is at the moment so rethinking it a bit sounds good.

Dries’s picture

Project: WSCCI » Drupal core
Version: » 8.x-dev
Component: Code » base system
Priority: Normal » Critical

I committed #1599108: Allow modules to register services and subscriber services (events) after having given it a lot of thought and discussion, but decided that we need to escalate this to 'critical' as a result of that. I've also moved it into the core issue queue. Please don't demote the priority of this issue. Let's keep working on a good solution. Thanks for all your help! :-)

tim.plunkett’s picture

Status: Active » Needs review
Issue tags: +VDC
FileSize
4.28 KB

I'm reasonably sure this is causing all the failures I'm seeing in Views when we try to use bundles.

Rerolled after #1727538: WebTest tests should have access to the correct DIC.

Status: Needs review » Needs work

The last submitted patch, drupal-1708692-9.patch, failed testing.

moshe weitzman’s picture

Just to be clear, Tim has rerolled the test that proves that we have a critical bug. We are not any closer to solving it.

I'm curious what bundle services are added by Views and needed at module_enable() time.

tim.plunkett’s picture

Currently, most Views provide either a page callback or a block. hook_menu and hook_block_info are triggered at that time, and need to load Views.

See #1727266: Lazy load plugin managers with dependency injection for the code we're attempting.

sun’s picture

So I guess the essence of #12 is that drupal_flush_all_caches() is called in the same request in which the new module is enabled/disabled.

I also guess we only have two options:

1) Rebuild the service container within the same request, before invoking hook_enable() + friends, and recompiling it at the end of the request (or in the next).

2) Try to set a flag/marker or something to signify the enabling/disabling of a module for the next request and deleting the currently compiled container before the request ends, and lastly, also try to handle race conditions on large-scale/high-traffic sites appropriately (which sounds close to impossible to me).

chx’s picture

A twin (might need to be enjoined, even) #1759582: Figure out when to delete compiled DIC files

andypost’s picture

Another use case is ban module to hook into request object #1161486-25: Move IP blocking into its own module

chx’s picture

alippai wrote this http://privatepaste.com/9eec5e910b module, one wonders whether we could use the idea here.

Edit: this is essentially the same as 2.) from #13 , implemented in a module. As for the thundering herd problem, can't we use a lock / semaphore / something?

tim.plunkett’s picture

tim.plunkett’s picture

Title: Bundle services aren't available in the request that enables the module » Bundle services aren't available in the request that enables a module

Clarifying the title as I understand it. It's not just about bundles provided by the module being enabled, it's all bundles.

tim.plunkett’s picture

@katbailey asked for some more info on how we were using this, and how it was breaking.

Views provides many plugin types, currently all controlled by the ViewsPluginManager.

In order to get a plugin instance, we had a procedural function that looked like this:

function views_get_plugin($type, $plugin_id) {
  $manager = new ViewsPluginManager($type);
  return $manager->createInstance($plugin_id);
}

Now, as a deprecated wrapper (we have yet to phase it out), we have:

function views_get_plugin($type, $plugin_id) {
  return drupal_container()->get("plugin.manager.views.$type")->createInstance($plugin_id);
}

However, as we add more test coverage, we're seeing fails like this:

 Symfony\Component\DependencyInjection\Exception\InvalidArgumentException: The service definition "plugin.manager.views.display" does not exist. in Symfony\Component\DependencyInjection\ContainerBuilder->getDefinition() (line 693 of /Users/tim/www/d8/core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ContainerBuilder.php).

Here's the relevant call stack for one such occurence: https://privatepaste.com/ddf8081988
Note lines 13 and 14. l() is being called, which is calling theme_get_registry(), and then everything goes to hell.

So, I tried putting this into ViewTestBase:

  /**
   * Overrides TestBase::changeDatabasePrefix().
   *
   * This is the dirtiest hack. It is the only method called in
   * WebTestBase::setUp() that is after it resets $conf and before it calls
   * module_enable().
   */
  protected function changeDatabasePrefix() {
    variable_set('theme_link', FALSE);
    return parent::changeDatabasePrefix();
  }

And it all worked out.

Other issues, like #1763974: Convert entity type info into plugins, attempt to replace parts of hook_entity_info() with plugins. But entity_get_info() is called very early as well, and breaks similarly: https://privatepaste.com/f81a11a981

effulgentsia’s picture

Title: Bundle services aren't available in the request that enables a module » Bundle services aren't available in the request that enables the module

It's not just about bundles provided by the module being enabled, it's all bundles.

I don't think so. I think this issue is specifically about new modules enabled in module_enable() that then have DIC services consumed in the same request (e.g., #5), so reverting issue title to pre #18. #19 contains good info for #1786990: [Module]Bundle is registered too late in WebTestBase::setUp(), which is probably the more pressing problem to resolve for Views work in progress.

tim.plunkett’s picture

I agree with the title revert. Between this and the two issues I linked in #20, those are all of the problems we've seen.

tim.plunkett’s picture

#1786990: [Module]Bundle is registered too late in WebTestBase::setUp() was committed, which fixes half of VDC's problems with this.
Here is the current failure:

exception 'Symfony\Component\DependencyInjection\Exception\InvalidArgumentException' with message 'The service definition "plugin.manager.views.display" does not exist.' in /var/lib/drupaltestbot/sites/default/files/checkout/core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ContainerBuilder.php:690
Stack trace:
#0 /var/lib/drupaltestbot/sites/default/files/checkout/core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ContainerBuilder.php(338): Symfony\Component\DependencyInjection\ContainerBuilder->getDefinition('plugin.manager....')
#1 /var/lib/drupaltestbot/sites/default/files/checkout/core/modules/views/views.module(1297): Symfony\Component\DependencyInjection\ContainerBuilder->get('plugin.manager....')
#2 /var/lib/drupaltestbot/sites/default/files/checkout/core/modules/views/lib/Drupal/views/ViewExecutable.php(579): views_get_plugin('display', 'default')
#3 /var/lib/drupaltestbot/sites/default/files/checkout/core/modules/views/lib/Drupal/views/ViewStorage.php(160): Drupal\views\ViewExecutable->initDisplay()
#4 /var/lib/drupaltestbot/sites/default/files/checkout/core/modules/views/views.module(660): Drupal\views\ViewStorage->initDisplay()
#5 [internal function]: views_block_info()
#6 /var/lib/drupaltestbot/sites/default/files/checkout/core/includes/module.inc(957): call_user_func_array('views_block_inf...', Array)
#7 /var/lib/drupaltestbot/sites/default/files/checkout/core/modules/block/block.module(424): module_invoke('views', 'block_info')
#8 /var/lib/drupaltestbot/sites/default/files/checkout/core/modules/block/block.module(963): _block_rehash('bartik')
#9 [internal function]: block_rebuild()
#10 /var/lib/drupaltestbot/sites/default/files/checkout/core/includes/module.inc(981): call_user_func_array('block_rebuild', Array)
#11 /var/lib/drupaltestbot/sites/default/files/checkout/core/includes/common.inc(6848): module_invoke_all('rebuild')
#12 /var/lib/drupaltestbot/sites/default/files/checkout/core/includes/install.core.inc(1706): drupal_flush_all_caches()
#13 /var/lib/drupaltestbot/sites/default/files/checkout/core/includes/batch.inc(427): _install_profile_modules_finished(true, Array, Array, '0 sec')
#14 /var/lib/drupaltestbot/sites/default/files/checkout/core/includes/batch.inc(329): _batch_finished()
#15 /var/lib/drupaltestbot/sites/default/files/checkout/core/includes/form.inc(4938): _batch_process()
#16 /var/lib/drupaltestbot/sites/default/files/checkout/core/includes/install.core.inc(533): batch_process('core/install.ph...', 'http://drupalte...')
#17 /var/lib/drupaltestbot/sites/default/files/checkout/core/includes/install.core.inc(429): install_run_task(Array, Array)
#18 /var/lib/drupaltestbot/sites/default/files/checkout/core/includes/install.core.inc(85): install_run_tasks(Array)
#19 /var/lib/drupaltestbot/sites/default/files/checkout/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php(686): install_drupal(Array)
#20 /var/lib/drupaltestbot/sites/default/files/checkout/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php(629): Drupal\simpletest\WebTestBase->setUp()
#21 /var/lib/drupaltestbot/sites/default/files/checkout/core/scripts/run-tests.sh(381): Drupal\simpletest\TestBase->run()
#22 /var/lib/drupaltestbot/sites/default/files/checkout/core/scripts/run-tests.sh(22): simpletest_script_run_one_test('515', 'Drupal\user\Tes...')
#23 {main}FATAL Drupal\user\Tests\UserCancelTest: test runner returned a non-zero error code (1).
xjm’s picture

Clarifying #23, this straight up blocks #1805996: [META] Views in Drupal Core. Whenever you enable Views--not only in tests but in the actual site environment--you get the error above.

chx’s picture

Assigned: Unassigned » chx

Blocked Views is bad/

xjm’s picture

xjm’s picture

Assigned: Unassigned » chx

Oopsie.

katbailey’s picture

Also related: #1759582: Figure out when to delete compiled DIC files, which is a follow-up for #1706064: Compile the Injection Container to disk, which is hopefully going to be RTBC'd shortly :-)
I'm planning to reroll #1331486: Move module_invoke_*() and friends to an Extensions class today. That's not a blocker for this issue, it's just that if we're rethinking the whole module_enable process, it probably makes more sense to do so with the work in that patch in mind.

chx’s picture

Status: Needs work » Closed (duplicate)

This can't be solved without #1706064: Compile the Injection Container to disk but it's blatantly trivial with it so moving there.

chx’s picture

Status: Closed (duplicate) » Postponed

Ok let's not merge this yet. It needs to be postponed on that one, however. http://drupal.org/files/interdiff_1320.txt is the patch that will solve this issue, likely.

ybabel’s picture

Status: Postponed » Needs review

wscci-bundles-module_enable.patch queued for re-testing.

oops !
sorry, I was trying to figure out how to make VDC works.
I get that error when I try to install the sandbox :

    Symfony\Component\DependencyInjection\Exception\InvalidArgumentException: The service definition "plugin.manager.views.display" does not exist. in Symfony\Component\DependencyInjection\ContainerBuilder->getDefinition() (line 690 of /var/www/vdc/core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ContainerBuilder.php).
    Notice: Undefined index: backtrace in _drupal_log_error() (line 188 of core/includes/errors.inc).
    Symfony\Component\DependencyInjection\Exception\InvalidArgumentException: The service definition "plugin.manager.views.display" does not exist. in Symfony\Component\DependencyInjection\ContainerBuilder->getDefinition() (line 690 of core/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ContainerBuilder.php).
ybabel’s picture

Appliying http://drupal.org/files/interdiff_1320.txt work for me (with the last VDC sandbox)
even if it gives me that errors:

    Warning: Missing argument 1 for system_list(), called in /var/www/vdc/core/includes/module.inc on line 481 and defined in system_list() (line 142 of core/includes/module.inc).
    Notice: Undefined variable: type in system_list() (line 148 of core/includes/module.inc).
    Notice: Undefined variable: type in system_list() (line 263 of core/includes/module.inc).
    Notice: Undefined index: in system_list() (line 263 of core/includes/module.inc).

but now the views UI are accessible !!! I can use Views, which was impossible before this patch.
my frontpage is back also :-)

xjm’s picture

Status: Needs review » Postponed

Thanks for testing @ybabel! And yep, this is the issue currently blocking the sandbox from working smoothly.

Re-postponing on #1706064: Compile the Injection Container to disk. Once that is in, this issue can be fixed, and then we can continue work on the sandbox issues. You can help us discuss anything you encounter in the sandbox queue. :)

xjm’s picture

Status: Postponed » Needs review
Issue tags: -VDC

#9: drupal-1708692-9.patch queued for re-testing.

Status: Needs review » Needs work
Issue tags: +VDC

The last submitted patch, drupal-1708692-9.patch, failed testing.

xjm’s picture

Status: Needs work » Needs review
FileSize
4.28 KB

Rebased #9 and tweaked the docs.

Status: Needs review » Needs work

The last submitted patch, system-1708692-36.patch, failed testing.

fubhy’s picture

Status: Needs work » Needs review
FileSize
5.29 KB

Merged the test and a slight modification of @chx's solution from #30 and simplified the test a bit to just check for the existence of the service id. Also added a test for module disable (which also fails). Tried to rebuild the container as well but for some reason it did still not pass. Suggestions welcome :)

PS: I am not 100% sure if it is okay to go with $modules_installed instead of doing a fresh system_list/module_list call. It should be the same actually.

Status: Needs review » Needs work

The last submitted patch, 1708692-38.patch, failed testing.

chx’s picture

Assigned: chx » Unassigned
xjm’s picture

Assigned: Unassigned » xjm

Trying something.

xjm’s picture

Assigned: xjm » Unassigned
Status: Needs work » Needs review
FileSize
497 bytes
5.32 KB

Okay I am way out of my depth so I didn't get very far. But here's one fail fewer!

I tried to also do the rebuild in module_disable() but couldn't get that assertion to pass, so left that as a @todo for now.

Status: Needs review » Needs work

The last submitted patch, system-1708692-42.patch, failed testing.

Berdir’s picture

Status: Needs work » Needs review
FileSize
1.88 KB
5.98 KB

We need to pass in all modules, not just the one that we just enabled. This patch is based on the approach of chx's interdiff in #30 and adopted to the way kernel compilation works now.

effulgentsia’s picture

- Simplified the test to reuse the bundle_test module instead of adding a bundle_test_dependent module.
- Changed so that module_(en|dis)able() doesn't need to boot a new kernel (hard-coding constructor arguments that might not match the initial environment), but can reuse the same kernel.

The main difficulty in this issue though isn't the implementation: it's that several of the early comments in this thread expressed opposition to making container changes mid-request at all. But per #7, that would require a complete change to our module_enable() process to not call hooks or rebuild the theme registry in the same request, but instead immediately redirect and do those things in the following request. Until we fix this issue either with that or with something like this patch, we can't add Views to the Standard install profile. So, how should we proceed?

Berdir’s picture

Oh, yes, that looks much nicer ;) Wasn't aware that the kernel is in the container as well aka forgot that.

Yes, there's an issue to make an install-time kernel/router and and clean up our current mess.

Berdir’s picture

Also, I understand the problems outlined in those initial comments (I think) but changing module_install() to require a site redirect sounds like a huge change which would significantly change the way many things in Drupal work (like tests, for example). For me personally, that doesn't sound feasible at this point in time.

sun’s picture

Status: Needs review » Reviewed & tested by the community

This looks great to me.

Fixing the apparent problem will not disallow us from rethinking in-process/intra-request extension management. However, I do agree with previous posters that it appears rather unlikely for us to be able to completely revamp this logic for D8, if that is even possible in the first place. If someone wants to investigate that, create an issue for it. If not, well, we're good.

fubhy’s picture

Good job Alex. That's indeed much cleaner.

katbailey’s picture

This looks great - my main concern had been that you'd end up with a new container that wasn't the same one being referenced by the HttpKernel when managing scope. But I did a quick test calling drupal_container()->isScopeActive('request') after a request that enabled a module and everything seems to be in order, which has to mean that leaveScope('request') was called on the correct container. Nice one Alex! :-)

webchick’s picture

Status: Reviewed & tested by the community » Fixed

Looks like we have a winner! :) Great work, folks!

Committed and pushed to 8.x (with a minor tweak to remove the () from (array) in the @param docs in DrupalKernelInterface)

yched’s picture

+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -110,6 +110,20 @@ public function registerBundles() {
+  /**
+   * Implements Drupal\Core\DrupalKernelInterface::updateModules().
+   */
+  public function updateModules($module_list) {
+    $this->moduleList = $module_list;
+    // If we haven't yet booted, we don't need to do anything: the new module
+    // list will take effect when boot() is called. If we have already booted,
+    // then reboot in order to refresh the bundle list and container.
+    if ($this->booted) {
+      drupal_container(NULL, TRUE);
+      $this->booted = FALSE;
+      $this->boot();
+    }
+  }

Naive question, might very well be completely non-applicable: is there a way to rebuild the container only when needed, rather than force-rebuild for each module that gets enabled ?
I'm thinking of cases where you enable N modules at once, leading to N successive calls to kernel->boot().

I.e "setting 'menu_needs_rebuild' rather than calling menu_rebuild()" pattern.

tim.plunkett’s picture

IIRC, views UI needs bundle services from views, so that wouldn't work for us, while this does.

Thanks to everyone who worked on this!

Berdir’s picture

Title: Bundle services aren't available in the request that enables the module » Bundle services aren't available in the request that enables the module (Performance regression)
Status: Fixed » Active

I have to reopen this one, as it caused a huge performance decrease.

It's the reason test runs now take 40++ minutes.

The changes in #512026-87: Move $form_state storage from cache to new state/key-value system from @effulgentsia seem to bring test runs back to 34 minutes but also seems to break the tests while doing so and leads to segmentation faults.

We should try to fix that in here I think, without the additional complexity added over there to see if those errors are caused by the keyvalue stuff or this.

effulgentsia’s picture

Title: Bundle services aren't available in the request that enables the module (Performance regression) » Simpletest slow and other problems following Bundle services aren't available in the request that enables the module
Priority: Critical » Major

The performance decrease is only in simpletest, installation, or other scenarios where module_enable() is called a lot. That seems like more of a major than a critical to me.

Additionally, what may have been uncovered in the $form_state issue is something similar to Kat's original concern in #50, where previously initialized services in the old container get destroyed in problematic ways (e.g., a service that another service's destructor depends on is destroyed before the dependent one's destructor is called) during initialization of a new container. This may warrant this issue being critical again once we have more understanding about what triggers the problem: at this time, I don't know yet why HEAD passes bot, but the patches in #512026: Move $form_state storage from cache to new state/key-value system manage to trigger the problem.

@Berdir: from #512026-85: Move $form_state storage from cache to new state/key-value system:

I think we should not do the compilation during installation, sounds like this is a serious slowdown even when it works? Any pointers on how to do that?

In the Drupal issue queue, we've been using the word "compile" to refer to two distinct operations. There's the $container->compile() step and there's the "dump to PHP file" step so that following requests are faster. It's already the case that we don't do the "dump to PHP file" step during installation (by not passing cache('bootstrap') to the kernel's constructor). The $container->compile() step is semi-necessary though, because it's not just an optimization step, it also adds functionality to the container, like wiring up event subscribers. It's possible that our installation process is controlled enough that we can decide to lose out on all that functionality, but I'm not convinced it's worth it yet: rather, if the new DrupalKernel::updateModules() function is having nasty side effects by its implementation, it may be worth getting to the bottom of them and fix them directly.

Berdir’s picture

I think it doesn't really matter if it's critical or major, it being major is right now actually a bigger problem because we "only" have 11 critical bugs but 102 major ones :)

Thanks for the clarification on compile vs. dump. I agree that it makes sense to first fix (and actually understand) the problem and only then optimize it. Still, we're talking about a 30% performance decrease on the test execution time, that's serious.

Crell’s picture

Related: #1530756: [meta] Use a proper kernel for the installer

The goal is to make the installer its own micro-app, which would, hopefully, eliminate some of those issues. (It wouldn't help with enabling modules post-install, of course.)

Berdir’s picture

Status: Active » Needs review
FileSize
1.34 KB

Re-uploading a slightly modified version of effulgentsia's interdiff/patch from the form_state that should pass the tests, to see how much the difference is of this.

array_diff() is ... interesting.

array_diff($this->getBundleClasses($this->moduleList), $this->getBundleClasses($old_module_list)) is not the same as array_diff($this->getBundleClasses($old_module_list), $this->getBundleClasses($this->moduleList)).

What array_diff() seems to do is return the array values of the first array that are not in the second, but not the other way round. "$this->getBundleClasses($old_module_list) != $this->getBundleClasses($this->moduleList)" on the other side, seems to be working as expected.

tim.plunkett’s picture

FileSize
1.89 KB

This includes an issue I've found with old compiled containers being used when enabling, disabling, then re-enabling a module that provides a bundle.
It fixes failures in EnableDisableTest for the blocks-as-plugins patch.

I also added doc blocks.

tim.plunkett’s picture

xjm’s picture

Status: Needs review » Needs work
Issue tags: +Needs reroll

I guess that #58 needs a reroll now.

Berdir’s picture

I tried to do that but failed :)

As far as I can see, a similar check is now built into initializeContainer() and we do not attempt to rebuild if we either already have a dumped container (I don't quite understand yet how that plays together with $this->newModules ?) or the new modules differ from the old ones.

Maybe @chx can clarify...?

Fabianx’s picture

As discussed in IRC with berdir, the check inside of initializeContainer needs to be moved to the updateModules to not rebuild the container in case nothing has changed.

So this patch is still valid.

xjm’s picture

Aside from the not applying part?...

Berdir’s picture

not the patch itself is still valid, but the idea of it :)

Berdir’s picture

Status: Needs work » Needs review
FileSize
3.48 KB

Ok, here is an attempt to do that. If we don't want that, because we also want to execute the second check ther, then an alternative would be to keep that helper function (added api docs from timplunkett's patch, thanks!) and use it for the existing check + make sure that the current container is only thrown away when we actually want to rebuild. Or so...

BundleTest passed, let's see about everything else.

Status: Needs review » Needs work

The last submitted patch, only-reboot-kernel-if-necessary-1708692-66.patch, failed testing.

Fabianx’s picture

Minimal change, for testbot only:

This is definitely still wrong, but the logic is flawed for rebooting anyway:

    // Merge in the minimal bootstrap container.
    if ($bootstrap_container = drupal_container()) {

At this point however drupal_container() contains our complete rebuild container ... (which will be merged in and not the Bootstrap Container)

I vote for a container_needs_rebuild flag in the Kernel, which updateModules can set and initializeContainer can use and then call drupal_container() with the right flag.

Fabianx’s picture

Status: Needs work » Needs review

for testbot

Fabianx’s picture

And another patch that might work better:

Status: Needs review » Needs work

The last submitted patch, core--only-reboot-kernel-if-necessary--1708692--70.diff, failed testing.

Fabianx’s picture

Status: Needs work » Needs review
FileSize
989 bytes

And another patch

Status: Needs review » Needs work

The last submitted patch, core--only-reboot-kernel-if-necessary--1708692--72.diff, failed testing.

Fabianx’s picture

Status: Needs work » Needs review
FileSize
810 bytes

Give me a green light ... please :)

Fabianx’s picture

Testbot: I need another result, pleeeeeeease?

Fabianx’s picture

Really, saving the moduleListChanged as a separate var is way cleaner and more inline with the original code, while still preventing the rebuild :-).

Berdir’s picture

Is there a reason you left out the getBundleClasses() part? That allows us to only do a reboot if the changed modules actually are providing bundles.

Fabianx’s picture

#77: Yes, the getBundleClasses was not working and I was trying to understand the logic ...

Fabianx’s picture

Patch with re-included getBundleClasses(), but new logic from #76.

Passes the relevant tests locally and seems faster. Lets see about the rest of Tests.

tim.plunkett’s picture

+++ b/core/lib/Drupal/Core/DrupalKernel.phpundefined
@@ -203,11 +212,36 @@ public function updateModules(array $module_list, array $module_paths = array())
     if ($this->booted) {
-      drupal_container(NULL, TRUE);
-      $this->booted = FALSE;
-      $this->boot();
+      if ($this->moduleListChanged) {
+        drupal_container(NULL, TRUE);
+        $this->booted = FALSE;
+        $this->boot();

If you combine these two conditionals into one, then you don't need to indent. Otherwise this looks good. Do we have any benchmarks to prove it actually helps?

Fabianx’s picture

If you combine these two conditionals into one, then you don't need to indent. Otherwise this looks good. Do we have any benchmarks to prove it actually helps?

Good catch! Done :)

How do you benchmark _that_?

sun’s picture

Status: Needs review » Needs work

The issue title already states how this is to be benchmarked.

Unfortunately, the latest patch has zero impact on the total test suite time.

Berdir’s picture

Status: Needs work » Needs review
FileSize
96.15 KB

Actually, it works just fine. It's just that it doesn't have a big impact anymore* and the testbots aren't a reliable indicator.

Confirmed with xhprof, see attached screenshot. Did run the same test with and without this patch, both had 7 calls to this function and without the patch, this resulted in 7 boot() calls. With the patch applied, only 3 calls to boot(). The inclusive wall time difference however is just 3% to 1,5%. And this is a relatively fast test (Actions configuration, first in the list) so the actual setUp() makes up a large amount of the total time (70%, to be exact).

I think this can be changed to priority normal, atleast the simpletest part of it. And we don't have a clear definition for the "other problems" except that the the additional container rebuilds (which are necessary) might or might not be causing my segfaults.

The only thing that could maybe be improved here is saving the bundle classes list of the current module list so that we don't have to re-check for that, which should remove half of the calls to getBundleLList().

*The reason for this is that the kernel patch that went in already had a check for exactly this, we don't really save much here except of an unecessary rebuild of the bootstrap container.

effulgentsia’s picture

And we don't have a clear definition for the "other problems" except that the the additional container rebuilds (which are necessary) might or might not be causing my segfaults

I suspect what's happening is that when a container is rebuilt, the already instantiated instances inside the old container are not immediately destroyed. If there are many rebuilds in a single PHP request, then depending on how the instances reference each other, PHP is either able to garbage collect or not. If PHP isn't able to garbage collect, that could lead to an out of memory error. If it is, it might garbage collect, say the 'database' service prior to some other service that has a __destruct() that expects the 'database' service to exist. But I agree that all this is still supposition, and we have not yet confirmed it with clear reproducible steps.

chx’s picture

I am fairly confident that if we want to speed up simpletest then we need to save the list of profiles and as much of modules as we can to stop the astonishing amount of file scanning we do. This would require to remove the info handling from system_rebuild_module_data , or , indeed the removal of system_rebuild_module_data as it is... stay tuned, working on that.

andypost’s picture

so what is needed here to fix?

Maybe this change would help to catch the actual errors that could be tested only manually for #1919002: Upgrade to D8 broken when D7 has more then one language enabled

dcam’s picture

http://drupal.org/node/1427826 contains instructions for updating the issue summary with the summary template.

The summary may need to be updated with information from comments.

Pancho’s picture

#2033567: Remove TestBase::rebuildContainer() is a followup on the original issue here, though it doesn't seem that "module enable/disable changes are immediately reflected in drupal_container()" as it was expected in TestBase::rebuildContainer().

Pancho’s picture

WTH? I didn't remove that tag.

Pancho’s picture

Status: Needs review » Needs work
Issue tags: +Needs issue summary update, +Needs reroll, +VDC

The last submitted patch, core--only-reboot-kernel-if-necessary--1708692--81.diff, failed testing.

dlu’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
FileSize
2.79 KB

Reroll of #81.

Status: Needs review » Needs work

The last submitted patch, core--only-reboot-kernel-if-necessary--1708692--92.diff, failed testing.

dlu’s picture

Seems that HEAD may be broken. On both my local dev machine and on simplytest.me I get this doing a fresh install of 8.x – I think that is why the patch fails.

This is the message I get:

Screen Shot 2013-08-05 at 21.11.58.png

Fabianx’s picture

Status: Needs work » Needs review
Issue tags: -Needs issue summary update, -VDC

Status: Needs review » Needs work
Issue tags: +Needs issue summary update, +VDC

The last submitted patch, core--only-reboot-kernel-if-necessary--1708692--92.diff, failed testing.

Fabianx’s picture

Nope, 8.x works fine. The patch has a problem.

Berdir’s picture

That's because a lot has changed since that patch was written, multiple times :)

Bundle classes don't exist anymore, instead we have services.yml files and service provider classes. And more importantly, the container contains a list of module namespaces, used to look for plugins. I don't think what this patch is trying to do is still possible.

dlu’s picture

Component: base system » simpletest.module

Moved to simpletest.module per #2050763: Refine "base system" component.

xjm’s picture

Component: simpletest.module » base system
Assigned: Unassigned » effulgentsia

@Berdir made the case that this doesn't actually have anything to do with SimpleTest, so we agreed in IRC to move it back to base system for now.

@effulgentsia is also going to reassess this issue in light of the complete change to the affected architecture, so assigning to him. Thanks everyone!

tim.plunkett’s picture

Issue summary: View changes
Status: Needs work » Postponed (maintainer needs more info)

Is this still relevant?
If so, can we consider opening a new issue? This was committed in #51 (October 2012!), and it's hard to understand the current status of the issue.

effulgentsia’s picture

Title: Simpletest slow and other problems following Bundle services aren't available in the request that enables the module » Bundle services aren't available in the request that enables the module
Assigned: effulgentsia » Unassigned
Priority: Major » Critical
Status: Postponed (maintainer needs more info) » Fixed
Issue tags: -Needs issue summary update

Agreed. Simpletest runs are about 40 minutes these days, which isn't that bad, and we can continue improving via conversions to PHPUnit and other optimizations. #84 might still be a theoretical problem, but there haven't been clearly reproducible steps reported, and if someone manages to find them, we can open a new issue for that. Therefore, restoring title and attributes of this issue prior to #54.

Status: Fixed » Closed (fixed)

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