Skip to content
Snippets Groups Projects
Commit 6ba1da1c authored by catch's avatar catch
Browse files

Issue #2205527 by cilefen, alexpott, martin107, Xen, Gaelan,...

Issue #2205527 by cilefen, alexpott, martin107, Xen, Gaelan, clintrandall777@gmail.com: Fixed Move configuration import lock to lock.persistent service since a lock can not exist beyond a single request.
parent cfd30d63
No related branches found
No related tags found
2 merge requests!7452Issue #1797438. HTML5 validation is preventing form submit and not fully...,!789Issue #3210310: Adjust Database API to remove deprecated Drupal 9 code in Drupal 10
Showing with 132 additions and 17 deletions
...@@ -450,6 +450,9 @@ services: ...@@ -450,6 +450,9 @@ services:
arguments: ['@database'] arguments: ['@database']
tags: tags:
- { name: backend_overridable } - { name: backend_overridable }
lock.persistent:
class: Drupal\Core\Lock\PersistentDatabaseLockBackend
arguments: ['@database']
router.request_context: router.request_context:
class: Drupal\Core\Routing\RequestContext class: Drupal\Core\Routing\RequestContext
tags: tags:
......
...@@ -44,7 +44,7 @@ class ConfigImporter { ...@@ -44,7 +44,7 @@ class ConfigImporter {
/** /**
* The name used to identify the lock. * The name used to identify the lock.
*/ */
const LOCK_ID = 'config_importer'; const LOCK_NAME = 'config_importer';
/** /**
* The storage comparer used to discover configuration changes. * The storage comparer used to discover configuration changes.
...@@ -512,9 +512,9 @@ public function initialize() { ...@@ -512,9 +512,9 @@ public function initialize() {
// Ensure that the changes have been validated. // Ensure that the changes have been validated.
$this->validate(); $this->validate();
if (!$this->lock->acquire(static::LOCK_ID)) { if (!$this->lock->acquire(static::LOCK_NAME)) {
// Another process is synchronizing configuration. // Another process is synchronizing configuration.
throw new ConfigImporterException(sprintf('%s is already importing', static::LOCK_ID)); throw new ConfigImporterException(sprintf('%s is already importing', static::LOCK_NAME));
} }
$sync_steps = array(); $sync_steps = array();
...@@ -611,7 +611,7 @@ protected function processConfigurations(array &$context) { ...@@ -611,7 +611,7 @@ protected function processConfigurations(array &$context) {
protected function finish(array &$context) { protected function finish(array &$context) {
$this->eventDispatcher->dispatch(ConfigEvents::IMPORT, new ConfigImporterEvent($this)); $this->eventDispatcher->dispatch(ConfigEvents::IMPORT, new ConfigImporterEvent($this));
// The import is now complete. // The import is now complete.
$this->lock->release(static::LOCK_ID); $this->lock->release(static::LOCK_NAME);
$this->reset(); $this->reset();
$context['message'] = t('Finalizing configuration synchronization.'); $context['message'] = t('Finalizing configuration synchronization.');
$context['finished'] = 1; $context['finished'] = 1;
...@@ -996,7 +996,7 @@ protected function importInvokeRename($collection, $rename_name) { ...@@ -996,7 +996,7 @@ protected function importInvokeRename($collection, $rename_name) {
* TRUE if an import is already running, FALSE if not. * TRUE if an import is already running, FALSE if not.
*/ */
public function alreadyImporting() { public function alreadyImporting() {
return !$this->lock->lockMayBeAvailable(static::LOCK_ID); return !$this->lock->lockMayBeAvailable(static::LOCK_NAME);
} }
/** /**
...@@ -1007,13 +1007,13 @@ public function alreadyImporting() { ...@@ -1007,13 +1007,13 @@ public function alreadyImporting() {
* keep the services used by the importer in sync. * keep the services used by the importer in sync.
*/ */
protected function reInjectMe() { protected function reInjectMe() {
$this->eventDispatcher = \Drupal::service('event_dispatcher'); $this->_serviceIds = array();
$this->configManager = \Drupal::service('config.manager'); $vars = get_object_vars($this);
$this->lock = \Drupal::lock(); foreach ($vars as $key => $value) {
$this->typedConfigManager = \Drupal::service('config.typed'); if (is_object($value) && isset($value->_serviceId)) {
$this->moduleHandler = \Drupal::moduleHandler(); $this->$key = \Drupal::service($value->_serviceId);
$this->themeHandler = \Drupal::service('theme_handler'); }
$this->stringTranslation = \Drupal::service('string_translation'); }
} }
} }
<?php
/**
* @file
* Contains \Drupal\Core\Lock\PersistentDatabaseLockBackend.
*/
namespace Drupal\Core\Lock;
use Drupal\Core\Database\Connection;
/**
* Defines the persistent database lock backend. This backend is global for this
* Drupal installation.
*
* @ingroup lock
*/
class PersistentDatabaseLockBackend extends DatabaseLockBackend {
/**
* Constructs a new PersistentDatabaseLockBackend.
*
* @param \Drupal\Core\Database\Connection $database
* The database connection.
*/
public function __construct(Connection $database) {
// Do not call the parent constructor to avoid registering a shutdown
// function that releases all the locks at the end of a request.
$this->database = $database;
// Set the lockId to a fixed string to make the lock ID the same across
// multiple requests. The lock ID is used as a page token to relate all the
// locks set during a request to each other.
// @see \Drupal\Core\Lock\LockBackendInterface::getLockId()
$this->lockId = 'persistent';
}
}
...@@ -134,7 +134,7 @@ public static function create(ContainerInterface $container) { ...@@ -134,7 +134,7 @@ public static function create(ContainerInterface $container) {
$container->get('config.storage.staging'), $container->get('config.storage.staging'),
$container->get('config.storage'), $container->get('config.storage'),
$container->get('config.storage.snapshot'), $container->get('config.storage.snapshot'),
$container->get('lock'), $container->get('lock.persistent'),
$container->get('event_dispatcher'), $container->get('event_dispatcher'),
$container->get('config.manager'), $container->get('config.manager'),
$container->get('config.typed'), $container->get('config.typed'),
......
...@@ -55,7 +55,7 @@ protected function setUp() { ...@@ -55,7 +55,7 @@ protected function setUp() {
$storage_comparer->createChangelist(), $storage_comparer->createChangelist(),
$this->container->get('event_dispatcher'), $this->container->get('event_dispatcher'),
$this->container->get('config.manager'), $this->container->get('config.manager'),
$this->container->get('lock'), $this->container->get('lock.persistent'),
$this->container->get('config.typed'), $this->container->get('config.typed'),
$this->container->get('module_handler'), $this->container->get('module_handler'),
$this->container->get('theme_handler'), $this->container->get('theme_handler'),
......
...@@ -228,14 +228,14 @@ function testImportLock() { ...@@ -228,14 +228,14 @@ function testImportLock() {
// Acquire a fake-lock on the import mechanism. // Acquire a fake-lock on the import mechanism.
$config_importer = $this->configImporter(); $config_importer = $this->configImporter();
$this->container->get('lock')->acquire($config_importer::LOCK_ID); $this->container->get('lock.persistent')->acquire($config_importer::LOCK_NAME);
// Attempt to import configuration and verify that an error message appears. // Attempt to import configuration and verify that an error message appears.
$this->drupalPostForm(NULL, array(), t('Import all')); $this->drupalPostForm(NULL, array(), t('Import all'));
$this->assertText(t('Another request may be synchronizing configuration already.')); $this->assertText(t('Another request may be synchronizing configuration already.'));
// Release the lock, just to keep testing sane. // Release the lock, just to keep testing sane.
$this->container->get('lock')->release($config_importer::LOCK_ID); $this->container->get('lock.persistent')->release($config_importer::LOCK_NAME);
// Verify site name has not changed. // Verify site name has not changed.
$this->assertNotEqual($new_site_name, \Drupal::config('system.site')->get('name')); $this->assertNotEqual($new_site_name, \Drupal::config('system.site')->get('name'));
......
...@@ -527,4 +527,3 @@ function testUpdated() { ...@@ -527,4 +527,3 @@ function testUpdated() {
$this->assertEqual(count($logs), 0); $this->assertEqual(count($logs), 0);
} }
} }
...@@ -59,4 +59,29 @@ public function testLockAcquire() { ...@@ -59,4 +59,29 @@ public function testLockAcquire() {
$this->assertText($lock_acquired_exit, 'Lock acquired by the other request before exit.', 'Lock'); $this->assertText($lock_acquired_exit, 'Lock acquired by the other request before exit.', 'Lock');
$this->assertTrue($lock->acquire('system_test_lock_exit'), 'Lock acquired by this request after the other request exits.', 'Lock'); $this->assertTrue($lock->acquire('system_test_lock_exit'), 'Lock acquired by this request after the other request exits.', 'Lock');
} }
/**
* Tests that the persistent lock is persisted between requests.
*/
public function testPersistentLock() {
$persistent_lock = $this->container->get('lock.persistent');
// Get a persistent lock.
$this->drupalGet('system-test/lock-persist/lock1');
$this->assertText('TRUE: Lock successfully acquired in SystemTestController::lockPersist()');
// Ensure that a shutdown function has not released the lock.
$this->assertFalse($persistent_lock->lockMayBeAvailable('lock1'));
$this->drupalGet('system-test/lock-persist/lock1');
$this->assertText('FALSE: Lock not acquired in SystemTestController::lockPersist()');
// Get another persistent lock.
$this->drupalGet('system-test/lock-persist/lock2');
$this->assertText('TRUE: Lock successfully acquired in SystemTestController::lockPersist()');
$this->assertFalse($persistent_lock->lockMayBeAvailable('lock2'));
// Release the first lock and try getting it again.
$persistent_lock->release('lock1');
$this->drupalGet('system-test/lock-persist/lock1');
$this->assertText('TRUE: Lock successfully acquired in SystemTestController::lockPersist()');
}
} }
...@@ -10,12 +10,38 @@ ...@@ -10,12 +10,38 @@
use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Drupal\Core\Lock\LockBackendInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/** /**
* Controller routines for system_test routes. * Controller routines for system_test routes.
*/ */
class SystemTestController extends ControllerBase { class SystemTestController extends ControllerBase {
/**
* The persistent lock service.
*
* @var \Drupal\Core\Lock\LockBackendInterface
*/
protected $persistentLock;
/**
* Constructs the SystemTestController.
*
* @param \Drupal\Core\Lock\LockBackendInterface $persistent_lock
* The persistent lock service.
*/
public function __construct(LockBackendInterface $persistent_lock) {
$this->persistentLock = $persistent_lock;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static($container->get('lock.persistent'));
}
/** /**
* Tests main content fallback. * Tests main content fallback.
* *
...@@ -56,6 +82,24 @@ public function lockExit() { ...@@ -56,6 +82,24 @@ public function lockExit() {
return system_test_lock_exit(); return system_test_lock_exit();
} }
/**
* Creates a lock that will persist across requests.
*
* @param string $lock_name
* The name of the persistent lock to acquire.
*
* @return string
* The text to display.
*/
public function lockPersist($lock_name) {
if ($this->persistentLock->acquire($lock_name)) {
return 'TRUE: Lock successfully acquired in SystemTestController::lockPersist()';
}
else {
return 'FALSE: Lock not acquired in SystemTestController::lockPersist()';
}
}
/** /**
* Set cache tag on on the returned render array. * Set cache tag on on the returned render array.
*/ */
......
...@@ -53,6 +53,14 @@ system_test.lock_exit: ...@@ -53,6 +53,14 @@ system_test.lock_exit:
requirements: requirements:
_access: 'TRUE' _access: 'TRUE'
system_test.lock_persist:
path: '/system-test/lock-persist/{lock_name}'
defaults:
_title: 'Persistent lock acquire'
_content: '\Drupal\system_test\Controller\SystemTestController::lockPersist'
requirements:
_access: 'TRUE'
system_test.cache_tags_page: system_test.cache_tags_page:
path: '/system-test/cache_tags_page' path: '/system-test/cache_tags_page'
defaults: defaults:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment