diff -u b/core/includes/bootstrap.inc b/core/includes/bootstrap.inc --- b/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -217,13 +217,13 @@ // drupal_static(). static $files = array(); - // We use drupal static for the bad records so we can test it. + // We use drupal static for the missing records so we can test it. // Drupal static fast pattern is used as this function may be called often. static $drupal_static_fast; if (!isset($drupal_static_fast)) { - $drupal_static_fast['bad'] = &drupal_static(__FUNCTION__ . ':bad'); + $drupal_static_fast['missing'] = &drupal_static(__FUNCTION__ . ':missing'); } - $bad = &$drupal_static_fast['bad']; + $missing = &$drupal_static_fast['missing']; // Type 'core' only exists to simplify application-level logic; it always maps // to the /core directory, whereas $name is ignored. It is only requested via @@ -264,16 +264,16 @@ } // If still unknown, perform a filesystem scan. if (!isset($files[$type][$name])) { - if (is_null($bad)) { - $bad = array(); + if (is_null($missing)) { + $missing = array(); if (\Drupal::hasService('cache.bootstrap')) { - $cache = Drupal::cache('bootstrap')->get('drupal_get_filename:bad', TRUE); + $cache = \Drupal::cache('bootstrap')->get('drupal_get_filename:missing', TRUE); if ($cache && $cache->data) { - $bad = $cache->data; + $missing = $cache->data; } } } - if (!isset($bad[$type][$name])) { + if (!isset($missing[$type][$name])) { $listing = new ExtensionDiscovery(DRUPAL_ROOT); // Prevent an infinite recursion by this legacy function. if ($original_type == 'profile') { @@ -289,11 +289,13 @@ if (isset($files[$type][$name])) { return $files[$type][$name]; } - elseif (!isset($bad[$type][$name])) { - // Add the missing file to a temporary cache and throw an alert. - $bad[$type][$name] = TRUE; + elseif (!isset($missing[$type][$name])) { + // Add the missing file to a temporary cache and throw an alert. This cache + // will be cleared on cron runs as well as when visiting the module and + // theme list pages. + $missing[$type][$name] = TRUE; if (\Drupal::hasService('cache.bootstrap')) { - \Drupal::cache('bootstrap')->set('drupal_get_filename:bad', $bad, REQUEST_TIME); + \Drupal::cache('bootstrap')->set('drupal_get_filename:missing', $missing, REQUEST_TIME); } if (\Drupal::hasService('logger.factory')) { \Drupal::logger('system')->error('The following @type is missing from the file system: @name', array('@type' => $type, '@name' => $name)); diff -u b/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php b/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php --- b/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php +++ b/core/modules/system/src/Tests/Bootstrap/GetFilenameUnitTest.php @@ -77,9 +77,9 @@ $this->assertNull(drupal_get_filename('module', $non_existing_module), 'Searching for an item that does not exist returns NULL.'); - // Get the bad records static from drupal_get_filename. - $bad = &drupal_static('drupal_get_filename:bad'); + // Get the missing records static from drupal_get_filename. + $missing = &drupal_static('drupal_get_filename:missing'); // Searching for an item that does not exist creates a static record in drupal_get_filename. - $this->assertTrue($bad['module'][$non_existing_module], 'Searching for an item that does not exist creates a static record in drupal_get_filename.'); + $this->assertTrue($missing['module'][$non_existing_module], 'Searching for an item that does not exist creates a static record in drupal_get_filename.'); } } only in patch2: unchanged: --- a/core/modules/system/src/Controller/SystemController.php +++ b/core/modules/system/src/Controller/SystemController.php @@ -186,6 +186,11 @@ public function systemAdminMenuBlockPage() { * @todo Move into ThemeController. */ public function themesPage() { + // Clean up the bootstrap "missing files" cache when listing themes. + if (\Drupal::hasService('cache.bootstrap')) { + \Drupal::cache('bootstrap')->invalidate('drupal_get_filename:missing'); + } + $config = $this->config('system.theme'); // Get all available themes. $themes = $this->themeHandler->rebuildThemeData(); only in patch2: unchanged: --- a/core/modules/system/src/Form/ModulesListForm.php +++ b/core/modules/system/src/Form/ModulesListForm.php @@ -174,6 +174,11 @@ public function buildForm(array $form, FormStateInterface $form_state) { // Include system.admin.inc so we can use the sort callbacks. $this->moduleHandler->loadInclude('system', 'inc', 'system.admin'); + // Clean up the "missing files" cache when listing modules. + if (\Drupal::hasService('cache.bootstrap')) { + \Drupal::cache('bootstrap')->invalidate('drupal_get_filename:missing'); + } + $form['filters'] = array( '#type' => 'container', '#attributes' => array( only in patch2: unchanged: --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -1201,6 +1201,11 @@ function system_cron() { $cache_backend->garbageCollection(); } + // Clean up the bootstrap "missing files" cache when running cron. + if (\Drupal::hasService('cache.bootstrap')) { + \Drupal::cache('bootstrap')->invalidate('drupal_get_filename:missing'); + } + // Clean up the expirable key value database store. if (\Drupal::service('keyvalue.expirable.database') instanceof KeyValueDatabaseExpirableFactory) { \Drupal::service('keyvalue.expirable.database')->garbageCollection();