Skip to content

Commit

Permalink
Drop the FKs for relations.targetId and structureelements.elementId
Browse files Browse the repository at this point in the history
Fixes #9905 - where a deadlock error would occur when updating a row referencing an elements table row, which may be locked by another request
  • Loading branch information
brandonkelly committed Nov 18, 2022
1 parent fe305cf commit 45d7895
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 4 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG-WIP.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@

### System
- Improved element deletion performance. ([#12223](https://github.com/craftcms/cms/pull/12223))
- Updated LitEmoji to v4. ([#12226](https://github.com/craftcms/cms/discussions/12226))
- Updated LitEmoji to v4. ([#12226](https://github.com/craftcms/cms/discussions/12226))
- Fixed a database deadlock error that could occur when updating a relation or structure position for an element that was simultaneously being saved. ([#9905](https://github.com/craftcms/cms/issues/9905))
2 changes: 1 addition & 1 deletion src/config/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
'id' => 'CraftCMS',
'name' => 'Craft CMS',
'version' => '4.3.3',
'schemaVersion' => '4.4.0.0',
'schemaVersion' => '4.4.0.1',
'minVersionRequired' => '3.7.11',
'basePath' => dirname(__DIR__), // Defines the @app alias
'runtimePath' => '@storage/runtime', // Defines the @runtime alias
Expand Down
2 changes: 0 additions & 2 deletions src/migrations/Install.php
Original file line number Diff line number Diff line change
Expand Up @@ -1045,7 +1045,6 @@ public function addForeignKeys(): void
$this->addForeignKey(null, Table::RELATIONS, ['fieldId'], Table::FIELDS, ['id'], 'CASCADE', null);
$this->addForeignKey(null, Table::RELATIONS, ['sourceId'], Table::ELEMENTS, ['id'], 'CASCADE', null);
$this->addForeignKey(null, Table::RELATIONS, ['sourceSiteId'], Table::SITES, ['id'], 'CASCADE', 'CASCADE');
$this->addForeignKey(null, Table::RELATIONS, ['targetId'], Table::ELEMENTS, ['id'], 'CASCADE', null);
$this->addForeignKey(null, Table::REVISIONS, ['creatorId'], Table::USERS, ['id'], 'SET NULL', null);
$this->addForeignKey(null, Table::REVISIONS, ['canonicalId'], Table::ELEMENTS, ['id'], 'CASCADE', null);
$this->addForeignKey(null, Table::SECTIONS, ['structureId'], Table::STRUCTURES, ['id'], 'SET NULL', null);
Expand All @@ -1054,7 +1053,6 @@ public function addForeignKeys(): void
$this->addForeignKey(null, Table::SESSIONS, ['userId'], Table::USERS, ['id'], 'CASCADE', null);
$this->addForeignKey(null, Table::SHUNNEDMESSAGES, ['userId'], Table::USERS, ['id'], 'CASCADE', null);
$this->addForeignKey(null, Table::SITES, ['groupId'], Table::SITEGROUPS, ['id'], 'CASCADE', null);
$this->addForeignKey(null, Table::STRUCTUREELEMENTS, ['elementId'], Table::ELEMENTS, ['id'], 'CASCADE', null);
$this->addForeignKey(null, Table::STRUCTUREELEMENTS, ['structureId'], Table::STRUCTURES, ['id'], 'CASCADE', null);
$this->addForeignKey(null, Table::TAGGROUPS, ['fieldLayoutId'], Table::FIELDLAYOUTS, ['id'], 'SET NULL', null);
$this->addForeignKey(null, Table::TAGS, ['groupId'], Table::TAGGROUPS, ['id'], 'CASCADE', null);
Expand Down
32 changes: 32 additions & 0 deletions src/migrations/m221118_003031_drop_element_fks.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace craft\migrations;

use craft\db\Migration;
use craft\db\Table;

/**
* m221118_003031_drop_element_fks migration.
*/
class m221118_003031_drop_element_fks extends Migration
{
/**
* @inheritdoc
*/
public function safeUp(): bool
{
$this->dropForeignKeyIfExists(Table::RELATIONS, ['targetId']);
$this->dropForeignKeyIfExists(Table::STRUCTUREELEMENTS, ['elementId']);
return true;
}

/**
* @inheritdoc
*/
public function safeDown(): bool
{
$this->addForeignKey(null, Table::RELATIONS, ['targetId'], Table::ELEMENTS, ['id'], 'CASCADE');
$this->addForeignKey(null, Table::STRUCTUREELEMENTS, ['elementId'], Table::ELEMENTS, ['id'], 'CASCADE');
return true;
}
}
52 changes: 52 additions & 0 deletions src/services/Gc.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ public function run(bool $force = false): void

$this->_deleteOrphanedDraftsAndRevisions();
$this->_deleteOrphanedSearchIndexes();
$this->_deleteOrphanedRelations();
$this->_deleteOrphanedStructureElements();

// Fire a 'run' event
if ($this->hasEventHandlers(self::EVENT_RUN)) {
Expand Down Expand Up @@ -454,6 +456,56 @@ private function _deleteOrphanedSearchIndexes(): void
$this->_stdout("done\n", Console::FG_GREEN);
}

private function _deleteOrphanedRelations(): void
{
$this->_stdout(' > deleting orphaned relations ... ');
$relationsTable = Table::RELATIONS;
$elementsTable = Table::ELEMENTS;

if ($this->db->getIsMysql()) {
$sql = <<<SQL
DELETE [[r]].* FROM $relationsTable [[r]]
LEFT JOIN $elementsTable [[e]] ON [[e.id]] = [[r.targetId]]
WHERE [[e.id]] IS NULL
SQL;
} else {
$sql = <<<SQL
DELETE FROM $relationsTable
USING $relationsTable [[r]]
LEFT JOIN $elementsTable [[e]] ON [[e.id]] = [[r.targetId]]
WHERE [[e.id]] IS NULL
SQL;
}

$this->db->createCommand($sql)->execute();
$this->_stdout("done\n", Console::FG_GREEN);
}

private function _deleteOrphanedStructureElements(): void
{
$this->_stdout(' > deleting orphaned structure elements ... ');
$structureElementsTable = Table::STRUCTUREELEMENTS;
$elementsTable = Table::ELEMENTS;

if ($this->db->getIsMysql()) {
$sql = <<<SQL
DELETE [[se]].* FROM $structureElementsTable [[se]]
LEFT JOIN $elementsTable [[e]] ON [[e.id]] = [[se.elementId]]
WHERE [[se.elementId]] IS NOT NULL AND [[e.id]] IS NULL
SQL;
} else {
$sql = <<<SQL
DELETE FROM $structureElementsTable
USING $structureElementsTable [[se]]
LEFT JOIN $elementsTable [[e]] ON [[e.id]] = [[se.elementId]]
WHERE [[se.elementId]] IS NOT NULL AND [[e.id]] IS NULL
SQL;
}

$this->db->createCommand($sql)->execute();
$this->_stdout("done\n", Console::FG_GREEN);
}

private function _gcCache(): void
{
$cache = Craft::$app->getCache();
Expand Down

0 comments on commit 45d7895

Please sign in to comment.