Commit 9a16601a authored by catch's avatar catch

Issue #2869568 by Berdir, dagmar, tstoeckler: Upgrade path: Clean up deleted...

Issue #2869568 by Berdir, dagmar, tstoeckler: Upgrade path: Clean up deleted revisions from {node_field_revision}
parent 4689d736
<?php
namespace Drupal\system\Tests\Entity\Update;
use Drupal\system\Tests\Update\UpdatePathTestBase;
/**
* Tests cleaning up revision data tables.
*
* @group Entity
* @group Update
*/
class SqlContentEntityStorageRevisionDataCleanupTest extends UpdatePathTestBase {
/**
* {@inheritdoc}
*/
protected function setDatabaseDumpFiles() {
$this->databaseDumpFiles = [
__DIR__ . '/../../../../tests/fixtures/update/drupal-8.filled.standard.php.gz',
__DIR__ . '/../../../../tests/fixtures/update/drupal-8.entity-revision-data-cleanup-2869568.php',
];
}
/**
* Tests that stale rows in the revision data table are deleted.
*/
public function testRevisionDataCleanup() {
// Ensure the test data exists.
$connection = \Drupal::database();
$result = $connection->query('SELECT nid, vid FROM {node_field_revision} WHERE nid = :nid AND vid = :vid', ['nid' => 8, 'vid' => 8])->fetchAll();
$this->assertEqual($result, [(object) ['nid' => '8', 'vid' => '8']]);
$this->runUpdates();
// Ensure the correct rows were deleted and only those.
$result = $connection->query('SELECT nid, vid FROM {node_field_revision} WHERE nid = :nid AND vid = :vid', ['nid' => 8, 'vid' => 8])->fetchAll();
$this->assertTrue(empty($result));
$result = $connection->query('SELECT nid, vid FROM {node_field_revision} WHERE nid = :nid AND vid = :vid', ['nid' => 8, 'vid' => 9])->fetchAll();
$this->assertEqual($result, [(object) ['nid' => '8', 'vid' => '9']]);
// Revision 10 has two translations, ensure both records still exist.
$result = $connection->query('SELECT nid, vid, langcode FROM {node_field_revision} WHERE nid = :nid AND vid = :vid', ['nid' => 8, 'vid' => 10])->fetchAll();
$this->assertEqual($result, [(object) ['nid' => '8', 'vid' => '10', 'langcode' => 'es'], (object) ['nid' => '8', 'vid' => '10', 'langcode' => 'en']]);
}
}
......@@ -1927,3 +1927,86 @@ function system_update_8400(&$sandbox) {
$sandbox['#finished'] = $sandbox['current'] == $sandbox['max'];
}
/**
* Clear left over entries in the revision data table.
*/
function system_update_8401(&$sandbox) {
$entity_type_manager = \Drupal::entityTypeManager();
$entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager();
$database = \Drupal::database();
// Initialize the sandbox. Store a list of entity types that need to be
// cleaned up in a list, then keep track of the current entity type by
// its numeric index.
if (!isset($sandbox['current_key'])) {
// This must be the first run. Initialize the sandbox.
$sandbox['current_key'] = 0;
// Filter the entity types for those that need to be cleaned up.
$definitions = array_filter($entity_type_manager->getDefinitions(), function (EntityTypeInterface $entity_type) use ($entity_definition_update_manager, $database) {
// Use the last installed entity type definition for the filtering, as
// some might not have been installed yet or are only being made
// revisionable or translatable in a later update function.
$entity_type = $entity_definition_update_manager->getEntityType($entity_type->id());
if (!$entity_type) {
// New entity type that is not installed yet, nothing to clean up, skip.
return FALSE;
}
if (!$entity_type->getKey('revision') || !$entity_type->isRevisionable() || !$entity_type->isTranslatable()) {
// Entity type is either not revisionable or not translatable.
return FALSE;
}
// Ensure the revision and revision data tables really exist.
$entity_type_id = $entity_type->id();
$revision_table = $entity_type->getRevisionTable() ?: $entity_type_id . '_revision';
$revision_data_table = $entity_type->getRevisionDataTable() ?: $entity_type_id . '_field_revision';
return $database->schema()->tableExists($revision_table) && $database->schema()->tableExists($revision_data_table);
});
if (empty($definitions)) {
$sandbox['#finished'] = TRUE;
return;
}
$sandbox['entity_type_ids'] = array_keys($definitions);
$sandbox['max'] = count($sandbox['entity_type_ids']);
}
// Get the current entity type. Fetch 100 records that should be deleted. Order
// them by entity ID to optimize the amount of delete queries that need to
// be executed.
$entity_type_id = $sandbox['entity_type_ids'][$sandbox['current_key']];
/** @var \Drupal\Core\Entity\ContentEntityTypeInterface $entity_type */
$entity_type = $entity_definition_update_manager->getEntityType($entity_type_id);
$revision_table = $entity_type->getRevisionTable() ?: $entity_type_id . '_revision';
$revision_data_table = $entity_type->getRevisionDataTable() ?: $entity_type_id . '_field_revision';
$revision_field = $entity_type->getKey('revision');
$query = $database->select($revision_data_table, 'rd');
$query->leftJoin($revision_table, 'r', 'r.' . $revision_field . ' = rd.' . $revision_field);
$query->addField('rd', $revision_field, 'revision');
$revision_ids = $query
->isNull('r.' . $revision_field)
->range(0, 100)
->execute()
->fetchCol();
if ($revision_ids) {
$database->delete($revision_data_table)
->condition($revision_field, $revision_ids, 'IN')
->execute();
}
// If there are less than 100 rows, the entity type was cleaned up, move on
// to the next one.
if (count($revision_ids) < 100) {
$sandbox['current_key']++;
}
$sandbox['#finished'] = $sandbox['current_key'] == $sandbox['max'];
}
<?php
/**
* @file
* Contains database additions to drupal-8.filled.standard.php.gz for testing
* the upgrade path of https://www.drupal.org/node/2869568.
*/
use Drupal\Core\Database\Database;
use Drupal\Core\Language\LanguageInterface;
$connection = Database::getConnection();
// Manually add a record to the node_revision
$connection->insert('node_field_revision')
->fields([
'nid' => 8,
'vid' => 8,
'langcode' => 'en',
'title' => 'Deleted revision',
'uid' => 1,
'status' => 1,
'created' => 1439731773,
'changed' => 1439732036,
'promote' => 1,
'sticky' => 0,
'revision_translation_affected' => 1,
'default_langcode' => 1,
'content_translation_source' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
'content_translation_outdated' => 0,
])
->execute();
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