Issue #3055443 by alexpott, amateescu, catch, chr.fritsch, Berdir, oknate, Wim Leers: Switch to a null backend for all caches for running the database updates
							parent
							
								
									5448b07b67
								
							
						
					
					
						commit
						80a307dc69
					
				| 
						 | 
				
			
			@ -0,0 +1,54 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Core\Update;
 | 
			
		||||
 | 
			
		||||
use Drupal\Core\Cache\CacheBackendInterface;
 | 
			
		||||
use Drupal\Core\Cache\NullBackend;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Defines a cache backend for use during Drupal database updates.
 | 
			
		||||
 *
 | 
			
		||||
 * Passes on deletes to another backend while extending the NullBackend to avoid
 | 
			
		||||
 * using anything cached prior to running updates.
 | 
			
		||||
 */
 | 
			
		||||
class UpdateBackend extends NullBackend {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * The regular runtime cache backend.
 | 
			
		||||
   *
 | 
			
		||||
   * @var \Drupal\Core\Cache\CacheBackendInterface
 | 
			
		||||
   */
 | 
			
		||||
  protected $backend;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * UpdateBackend constructor.
 | 
			
		||||
   *
 | 
			
		||||
   * @param \Drupal\Core\Cache\CacheBackendInterface $backend
 | 
			
		||||
   *   The regular runtime cache backend.
 | 
			
		||||
   */
 | 
			
		||||
  public function __construct(CacheBackendInterface $backend) {
 | 
			
		||||
    $this->backend = $backend;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function delete($cid) {
 | 
			
		||||
    $this->backend->delete($cid);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function deleteMultiple(array $cids) {
 | 
			
		||||
    $this->backend->deleteMultiple($cids);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function deleteAll() {
 | 
			
		||||
    $this->backend->deleteAll();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,51 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Core\Update;
 | 
			
		||||
 | 
			
		||||
use Drupal\Core\Cache\CacheFactoryInterface;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Cache factory implementation for use during Drupal database updates.
 | 
			
		||||
 *
 | 
			
		||||
 * Decorates the regular runtime cache_factory service so that caches use
 | 
			
		||||
 * \Drupal\Core\Update\UpdateBackend.
 | 
			
		||||
 *
 | 
			
		||||
 * @see \Drupal\Core\Update\UpdateServiceProvider::register()
 | 
			
		||||
 */
 | 
			
		||||
class UpdateCacheBackendFactory implements CacheFactoryInterface {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * The regular runtime cache_factory service.
 | 
			
		||||
   *
 | 
			
		||||
   * @var \Drupal\Core\Cache\CacheFactoryInterface
 | 
			
		||||
   */
 | 
			
		||||
  protected $cacheFactory;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Instantiated update cache bins.
 | 
			
		||||
   *
 | 
			
		||||
   * @var \Drupal\Core\Update\UpdateBackend[]
 | 
			
		||||
   */
 | 
			
		||||
  protected $bins = [];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * UpdateCacheBackendFactory constructor.
 | 
			
		||||
   *
 | 
			
		||||
   * @param \Drupal\Core\Cache\CacheFactoryInterface $cache_factory
 | 
			
		||||
   *   The regular runtime cache_factory service.
 | 
			
		||||
   */
 | 
			
		||||
  public function __construct(CacheFactoryInterface $cache_factory) {
 | 
			
		||||
    $this->cacheFactory = $cache_factory;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function get($bin) {
 | 
			
		||||
    if (!isset($this->bins[$bin])) {
 | 
			
		||||
      $this->bins[$bin] = new UpdateBackend($this->cacheFactory->get($bin), $bin);
 | 
			
		||||
    }
 | 
			
		||||
    return $this->bins[$bin];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -19,8 +19,16 @@ class UpdateServiceProvider implements ServiceProviderInterface, ServiceModifier
 | 
			
		|||
   */
 | 
			
		||||
  public function register(ContainerBuilder $container) {
 | 
			
		||||
    $definition = new Definition('Drupal\Core\Cache\NullBackend', ['null']);
 | 
			
		||||
    $definition->setDeprecated(TRUE, 'The "%service_id%\" service is deprecated. While updating Drupal all caches use \Drupal\Core\Update\UpdateBackend. See https://www.drupal.org/node/3066407');
 | 
			
		||||
    $container->setDefinition('cache.null', $definition);
 | 
			
		||||
 | 
			
		||||
    // Decorate the cache factory in order to use
 | 
			
		||||
    // \Drupal\Core\Update\UpdateBackend while running updates.
 | 
			
		||||
    $container
 | 
			
		||||
      ->register('update.cache_factory', UpdateCacheBackendFactory::class)
 | 
			
		||||
      ->setDecoratedService('cache_factory')
 | 
			
		||||
      ->addArgument(new Reference('update.cache_factory.inner'));
 | 
			
		||||
 | 
			
		||||
    $container->addCompilerPass(new UpdateCompilerPass(), PassConfig::TYPE_REMOVE, 128);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -28,25 +36,6 @@ class UpdateServiceProvider implements ServiceProviderInterface, ServiceModifier
 | 
			
		|||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function alter(ContainerBuilder $container) {
 | 
			
		||||
    // Ensures for some services that they don't cache.
 | 
			
		||||
    $null_cache_service = new Reference('cache.null');
 | 
			
		||||
 | 
			
		||||
    $definition = $container->getDefinition('asset.resolver');
 | 
			
		||||
    $definition->replaceArgument(5, $null_cache_service);
 | 
			
		||||
 | 
			
		||||
    $definition = $container->getDefinition('library.discovery.collector');
 | 
			
		||||
    $definition->replaceArgument(0, $null_cache_service);
 | 
			
		||||
 | 
			
		||||
    $definition = $container->getDefinition('theme.registry');
 | 
			
		||||
    $definition->replaceArgument(1, $null_cache_service);
 | 
			
		||||
    $definition->replaceArgument(7, $null_cache_service);
 | 
			
		||||
 | 
			
		||||
    $definition = $container->getDefinition('theme.initialization');
 | 
			
		||||
    $definition->replaceArgument(2, $null_cache_service);
 | 
			
		||||
 | 
			
		||||
    $definition = $container->getDefinition('plugin.manager.element_info');
 | 
			
		||||
    $definition->replaceArgument(1, $null_cache_service);
 | 
			
		||||
 | 
			
		||||
    // Prevent the alias-based path processor, which requires a path_alias db
 | 
			
		||||
    // table, from being registered to the path processor manager. We do this by
 | 
			
		||||
    // removing the tags that the compiler pass looks for. This means the url
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1859,20 +1859,20 @@ function system_update_8011() {
 | 
			
		|||
 * Enable automated cron module and move the config into it.
 | 
			
		||||
 */
 | 
			
		||||
function system_update_8013() {
 | 
			
		||||
  $config_factory = \Drupal::configFactory();
 | 
			
		||||
  $system_cron_config = $config_factory->getEditable('system.cron');
 | 
			
		||||
  if ($autorun = $system_cron_config->get('threshold.autorun')) {
 | 
			
		||||
  $autorun = \Drupal::configFactory()->getEditable('system.cron')->get('threshold.autorun');
 | 
			
		||||
  if ($autorun) {
 | 
			
		||||
    // Install 'automated_cron' module.
 | 
			
		||||
    \Drupal::service('module_installer')->install(['automated_cron'], FALSE);
 | 
			
		||||
 | 
			
		||||
    // Copy 'autorun' value into the new module's 'interval' setting.
 | 
			
		||||
    $config_factory->getEditable('automated_cron.settings')
 | 
			
		||||
    \Drupal::configFactory()->getEditable('automated_cron.settings')
 | 
			
		||||
      ->set('interval', $autorun)
 | 
			
		||||
      ->save(TRUE);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Remove the 'autorun' key in system module config.
 | 
			
		||||
  $system_cron_config
 | 
			
		||||
  \Drupal::configFactory()
 | 
			
		||||
    ->getEditable('system.cron')
 | 
			
		||||
    ->clear('threshold.autorun')
 | 
			
		||||
    ->save(TRUE);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,44 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\system\Functional\Update;
 | 
			
		||||
 | 
			
		||||
use Drupal\Core\Url;
 | 
			
		||||
use Drupal\Tests\BrowserTestBase;
 | 
			
		||||
use Drupal\Tests\RequirementsPageTrait;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests caches during updates.
 | 
			
		||||
 *
 | 
			
		||||
 * @group Update
 | 
			
		||||
 */
 | 
			
		||||
class UpdateCacheTest extends BrowserTestBase {
 | 
			
		||||
  use RequirementsPageTrait;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests that caches are cleared during updates.
 | 
			
		||||
   *
 | 
			
		||||
   * @see \Drupal\Core\Update\UpdateServiceProvider
 | 
			
		||||
   * @see \Drupal\Core\Update\UpdateBackend
 | 
			
		||||
   */
 | 
			
		||||
  public function testCaches() {
 | 
			
		||||
    \Drupal::cache()->set('will_not_exist_after_update', TRUE);
 | 
			
		||||
    // The site might be broken at the time so logging in using the UI might
 | 
			
		||||
    // not work, so we use the API itself.
 | 
			
		||||
    $this->writeSettings([
 | 
			
		||||
      'settings' => [
 | 
			
		||||
        'update_free_access' => (object) [
 | 
			
		||||
          'value' => TRUE,
 | 
			
		||||
          'required' => TRUE,
 | 
			
		||||
        ],
 | 
			
		||||
      ],
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    // Clicking continue should clear the caches.
 | 
			
		||||
    $this->drupalGet(Url::fromRoute('system.db_update', [], ['path_processing' => FALSE]));
 | 
			
		||||
    $this->updateRequirementsProblem();
 | 
			
		||||
    $this->clickLink(t('Continue'));
 | 
			
		||||
 | 
			
		||||
    $this->assertFalse(\Drupal::cache()->get('will_not_exist_after_update', FALSE));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue