Commit 71479932 authored by alexpott's avatar alexpott

Issue #2834580 by Berdir: Move locale.translation_status state key to a...

Issue #2834580 by Berdir: Move locale.translation_status state key to a separate key/value collection
parent 716fe713
......@@ -427,7 +427,9 @@ services:
factory: Drupal\Core\Site\Settings::getInstance
state:
class: Drupal\Core\State\State
arguments: ['@keyvalue']
arguments: ['@keyvalue', '@cache.bootstrap', '@lock']
tags:
- { name: needs_destruction }
queue:
class: Drupal\Core\Queue\QueueFactory
arguments: ['@settings']
......
......@@ -150,7 +150,9 @@ public function invalidate($cid) {
*/
public function invalidateMultiple(array $cids) {
foreach ($cids as $cid) {
$this->cache[$cid]->expire = $this->getRequestTime() - 1;
if (isset($this->cache[$cid])) {
$this->cache[$cid]->expire = $this->getRequestTime() - 1;
}
}
}
......
......@@ -59,7 +59,10 @@ public function onKernelTerminate(PostResponseEvent $event) {
* An array of event listener definitions.
*/
static function getSubscribedEvents() {
$events[KernelEvents::TERMINATE][] = array('onKernelTerminate', 100);
// Run this subscriber after others as those might use services that need
// to be terminated as well or run code that needs to run before
// termination.
$events[KernelEvents::TERMINATE][] = array('onKernelTerminate', -100);
return $events;
}
......
......@@ -2,12 +2,15 @@
namespace Drupal\Core\State;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Cache\CacheCollector;
use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
use Drupal\Core\Lock\LockBackendInterface;
/**
* Provides the state system using a key value store.
*/
class State implements StateInterface {
class State extends CacheCollector implements StateInterface {
/**
* The key value store to use.
......@@ -16,20 +19,18 @@ class State implements StateInterface {
*/
protected $keyValueStore;
/**
* Static state cache.
*
* @var array
*/
protected $cache = array();
/**
* Constructs a State object.
*
* @param \Drupal\Core\KeyValueStore\KeyValueFactoryInterface $key_value_factory
* The key value store to use.
* @param \Drupal\Core\Cache\CacheBackendInterface $cache
* The cache backend.
* @param \Drupal\Core\Lock\LockBackendInterface $lock
* The lock backend.
*/
function __construct(KeyValueFactoryInterface $key_value_factory) {
public function __construct(KeyValueFactoryInterface $key_value_factory, CacheBackendInterface $cache, LockBackendInterface $lock) {
parent::__construct('state', $cache, $lock);
$this->keyValueStore = $key_value_factory->get('state');
}
......@@ -37,8 +38,18 @@ function __construct(KeyValueFactoryInterface $key_value_factory) {
* {@inheritdoc}
*/
public function get($key, $default = NULL) {
$values = $this->getMultiple(array($key));
return isset($values[$key]) ? $values[$key] : $default;
$value = parent::get($key);
return $value !== NULL ? $value : $default;
}
/**
* {@inheritdoc}
*/
protected function resolveCacheMiss($key) {
$value = $this->keyValueStore->get($key);
$this->storage[$key] = $value;
$this->persist($key);
return $value;
}
/**
......@@ -46,33 +57,9 @@ public function get($key, $default = NULL) {
*/
public function getMultiple(array $keys) {
$values = array();
$load = array();
foreach ($keys as $key) {
// Check if we have a value in the cache.
if (isset($this->cache[$key])) {
$values[$key] = $this->cache[$key];
}
// Load the value if we don't have an explicit NULL value.
elseif (!array_key_exists($key, $this->cache)) {
$load[] = $key;
}
$values[$key] = $this->get($key);
}
if ($load) {
$loaded_values = $this->keyValueStore->getMultiple($load);
foreach ($load as $key) {
// If we find a value, even one that is NULL, add it to the cache and
// return it.
if (isset($loaded_values[$key]) || array_key_exists($key, $loaded_values)) {
$values[$key] = $loaded_values[$key];
$this->cache[$key] = $loaded_values[$key];
}
else {
$this->cache[$key] = NULL;
}
}
}
return $values;
}
......@@ -80,7 +67,7 @@ public function getMultiple(array $keys) {
* {@inheritdoc}
*/
public function set($key, $value) {
$this->cache[$key] = $value;
parent::set($key, $value);
$this->keyValueStore->set($key, $value);
}
......@@ -89,7 +76,7 @@ public function set($key, $value) {
*/
public function setMultiple(array $data) {
foreach ($data as $key => $value) {
$this->cache[$key] = $value;
parent::set($key, $value);
}
$this->keyValueStore->setMultiple($data);
}
......@@ -98,6 +85,7 @@ public function setMultiple(array $data) {
* {@inheritdoc}
*/
public function delete($key) {
parent::delete($key);
$this->deleteMultiple(array($key));
}
......@@ -106,7 +94,7 @@ public function delete($key) {
*/
public function deleteMultiple(array $keys) {
foreach ($keys as $key) {
unset($this->cache[$key]);
parent::delete($key);
}
$this->keyValueStore->deleteMultiple($keys);
}
......@@ -115,7 +103,7 @@ public function deleteMultiple(array $keys) {
* {@inheritdoc}
*/
public function resetCache() {
$this->cache = array();
$this->clear();
}
}
......@@ -294,3 +294,21 @@ function locale_requirements($phase) {
}
return $requirements;
}
/**
* @addtogroup updates-8.3.x
* @{
*/
/**
* Delete translation status data in state.
*/
function locale_update_8300() {
// Delete the old translation status data, it will be rebuilt and stored in
// the new key value collection.
\Drupal::state()->delete('locale.translation_status');
}
/**
* @} End of "addtogroup updates-8.3.x".
*/
......@@ -881,7 +881,7 @@ function locale_translation_file_history_delete($projects = array(), $langcodes
*/
function locale_translation_get_status($projects = NULL, $langcodes = NULL) {
$result = array();
$status = \Drupal::state()->get('locale.translation_status');
$status = \Drupal::keyValue('locale.translation_status')->getAll();
module_load_include('translation.inc', 'locale');
$projects = $projects ? $projects : array_keys(locale_translation_get_projects());
$langcodes = $langcodes ? $langcodes : array_keys(locale_translatable_language_list());
......@@ -917,10 +917,6 @@ function locale_translation_get_status($projects = NULL, $langcodes = NULL) {
* File object also containing timestamp when the translation is last updated.
*/
function locale_translation_status_save($project, $langcode, $type, $data) {
// Follow-up issue: https://www.drupal.org/node/1842362.
// Split status storage per module/language and expire individually. This will
// improve performance for large sites.
// Load the translation status or build it if not already available.
module_load_include('translation.inc', 'locale');
$status = locale_translation_get_status();
......@@ -959,7 +955,7 @@ function locale_translation_status_save($project, $langcode, $type, $data) {
break;
}
\Drupal::state()->set('locale.translation_status', $status);
\Drupal::keyValue('locale.translation_status')->set($project, $status[$project]);
\Drupal::state()->set('locale.translation_last_checked', REQUEST_TIME);
}
}
......@@ -978,8 +974,8 @@ function locale_translation_status_delete_languages($langcodes) {
unset($status[$project][$langcode]);
}
}
\Drupal::keyValue('locale.translation_status')->set($project, $status[$project]);
}
\Drupal::state()->set('locale.translation_status', $status);
}
}
......@@ -990,21 +986,14 @@ function locale_translation_status_delete_languages($langcodes) {
* Project name(s) to be deleted from the cache.
*/
function locale_translation_status_delete_projects($projects) {
$status = locale_translation_get_status();
foreach ($status as $project => $languages) {
if (in_array($project, $projects)) {
unset($status[$project]);
}
}
\Drupal::state()->set('locale.translation_status', $status);
\Drupal::keyValue('locale.translation_status')->deleteMultiple($projects);
}
/**
* Clear the translation status cache.
*/
function locale_translation_clear_status() {
\Drupal::state()->delete('locale.translation_status');
\Drupal::keyValue('locale.translation_status')->deleteAll();
\Drupal::state()->delete('locale.translation_last_checked');
}
......
......@@ -49,7 +49,7 @@ public function testInterface() {
// Override Drupal core translation status as 'up-to-date'.
$status = locale_translation_get_status();
$status['drupal']['de']->type = 'current';
\Drupal::state()->set('locale.translation_status', $status);
\Drupal::keyValue('locale.translation_status')->set('drupal', $status['drupal']);
// One language added, all translations up to date.
$this->drupalGet('admin/reports/status');
......@@ -61,7 +61,7 @@ public function testInterface() {
// Set locale_test_translate module to have a local translation available.
$status = locale_translation_get_status();
$status['locale_test_translate']['de']->type = 'local';
\Drupal::state()->set('locale.translation_status', $status);
\Drupal::keyValue('locale.translation_status')->set('locale_test_translate', $status['locale_test_translate']);
// Check if updates are available for German.
$this->drupalGet('admin/reports/status');
......@@ -75,7 +75,7 @@ public function testInterface() {
$status = locale_translation_get_status();
$status['locale_test_translate']['de']->version = '1.3-dev';
$status['locale_test_translate']['de']->type = '';
\Drupal::state()->set('locale.translation_status', $status);
\Drupal::keyValue('locale.translation_status')->set('locale_test_translate', $status['locale_test_translate']);
// Check if no updates were found.
$this->drupalGet('admin/reports/status');
......@@ -95,7 +95,7 @@ public function testInterface() {
$status['drupal']['de']->type = '';
$status['drupal']['de']->timestamp = 0;
$status['drupal']['de']->version = '8.1.1';
\Drupal::state()->set('locale.translation_status', $status);
\Drupal::keyValue('locale.translation_status')->set('drupal', $status['drupal']);
// Check if Drupal core is not translated.
$this->drupalGet('admin/reports/translations');
......@@ -107,7 +107,7 @@ public function testInterface() {
$status['drupal']['de']->type = 'local';
$status['drupal']['de']->files['local']->timestamp = REQUEST_TIME;
$status['drupal']['de']->files['local']->info['version'] = '8.1.1';
\Drupal::state()->set('locale.translation_status', $status);
\Drupal::keyValue('locale.translation_status')->set('drupal', $status['drupal']);
// Check if translations are available for Drupal core.
$this->drupalGet('admin/reports/translations');
......
......@@ -2,7 +2,9 @@
namespace Drupal\KernelTests\Core\Routing;
use Drupal\Core\Cache\MemoryBackend;
use Drupal\Core\KeyValueStore\KeyValueMemoryFactory;
use Drupal\Core\Lock\NullLockBackend;
use Drupal\Core\State\State;
use Drupal\KernelTests\KernelTestBase;
use Symfony\Component\Routing\Route;
......@@ -36,7 +38,7 @@ protected function setUp() {
parent::setUp();
$this->fixtures = new RoutingFixtures();
$this->state = new State(new KeyValueMemoryFactory());
$this->state = new State(new KeyValueMemoryFactory(), new MemoryBackend('test'), new NullLockBackend());
}
/**
......
......@@ -11,6 +11,7 @@
use Drupal\Core\Database\Database;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\KeyValueStore\KeyValueMemoryFactory;
use Drupal\Core\Lock\NullLockBackend;
use Drupal\Core\Path\CurrentPathStack;
use Drupal\Core\Routing\MatcherDumper;
use Drupal\Core\Routing\RouteProvider;
......@@ -81,7 +82,7 @@ class RouteProviderTest extends KernelTestBase {
protected function setUp() {
parent::setUp();
$this->fixtures = new RoutingFixtures();
$this->state = new State(new KeyValueMemoryFactory());
$this->state = new State(new KeyValueMemoryFactory(), new MemoryBackend('test'), new NullLockBackend());
$this->currentPath = new CurrentPathStack(new RequestStack());
$this->cache = new MemoryBackend();
$this->pathProcessor = \Drupal::service('path_processor_manager');
......
......@@ -7,10 +7,12 @@
namespace Drupal\Tests\Core\Extension;
use Drupal\Core\Cache\MemoryBackend;
use Drupal\Core\Extension\Extension;
use Drupal\Core\Extension\InfoParser;
use Drupal\Core\Extension\ThemeHandler;
use Drupal\Core\KeyValueStore\KeyValueMemoryFactory;
use Drupal\Core\Lock\NullLockBackend;
use Drupal\Core\State\State;
use Drupal\Tests\UnitTestCase;
......@@ -78,7 +80,7 @@ protected function setUp() {
),
));
$this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
$this->state = new State(new KeyValueMemoryFactory());
$this->state = new State(new KeyValueMemoryFactory(), new MemoryBackend('test'), new NullLockBackend());
$this->infoParser = $this->getMock('Drupal\Core\Extension\InfoParserInterface');
$this->extensionDiscovery = $this->getMockBuilder('Drupal\Core\Extension\ExtensionDiscovery')
->disableOriginalConstructor()
......
......@@ -9,6 +9,7 @@
use Drupal\Core\Cache\MemoryBackend;
use Drupal\Core\KeyValueStore\KeyValueMemoryFactory;
use Drupal\Core\Lock\NullLockBackend;
use Drupal\Core\State\State;
use Drupal\Core\Cache\Cache;
......@@ -502,7 +503,7 @@ public function testBubblingWithPrerender($test_element) {
$this->setupMemoryCache();
// Mock the State service.
$memory_state = new State(new KeyValueMemoryFactory());;
$memory_state = new State(new KeyValueMemoryFactory(), new MemoryBackend('test'), new NullLockBackend());
\Drupal::getContainer()->set('state', $memory_state);
$this->controllerResolver->expects($this->any())
->method('getControllerFromDefinition')
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment