Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MySQL + deadlock leads to SAVEPOINT DOCTRINE_x does not exist #6651

Open
nikophil opened this issue Dec 18, 2024 · 5 comments
Open

MySQL + deadlock leads to SAVEPOINT DOCTRINE_x does not exist #6651

nikophil opened this issue Dec 18, 2024 · 5 comments

Comments

@nikophil
Copy link
Contributor

nikophil commented Dec 18, 2024

Bug Report

Q A
Version any

Summary

Hello,

this issue is a follow up of doctrine/orm#11230: in MySQL, when a deadlock occurs because of concurrency, the system tries to rollback, and then an error "SAVEPOINT DOCTRINE_x does not exist" occurs.

At first, the savepoint error did hide the original deadlock error. This has been fixed thanks to doctrine/orm#11646 - and this will soon be fixed as well in symfony/messenger.

Nevertheless, doctrine/orm#11230 has been closed, but the original problem is not fixed, and the rollback still fails, which results in closing the EM, and breaking the worker.

Since the dbal is the only one aware of savepoints, I think this should be fixed here.

Current behavior

When a deadlock occur, within a transaction with savepoints in MySQL, the rollback fails with SAVEPOINT DOCTRINE_x does not exist

Expected behavior

No error on roll back 😅

From MySQL doc:

When deadlock detection is enabled (the default) and a deadlock does occur, InnoDB detects the condition and rolls back one of the transactions (the victim).

So maybe when a deadlock occurs, DBAL should be resilient when the rollback fails? Or it should check the existence of the given savepoint/transaction before rolling back?

@petermanders89
Copy link

I am not sure how related this issue is; but I experience the following. I get the same error related to the doctrine:migrations:migrate command.

I am using symfony with doctrine. I have a symfony command that prepares the application. My installation command is pretty simple. I run: doctrine:migrations:migrate --no-interaction and in the same command I load an entity; persist and flush. This gives me the similair error: 1305 SAVEPOINT DOCTRINE_2 does not exist. I use Doctrine\ORM\EntityManagerInterface with dependency injection as variable entityManager. The initial database is empty.

$this->getApplication()->setAutoExit(false);
$this->getApplication()->run(new StringInput('doctrine:migrations:migrate --no-interaction'), $output);

$post = new Post();
$post->setTitle('this is a title');

$this->entityManager->persist($policy);
$this->entityManager->flush();

If I put $this->entityManager->getConnection()->isTransactionActive() after the migrations command, this returns true.

If I run the command twice, there is no error due to the fact that the migrations are already executed and up to date. Even if I add multiple new entities, persist and flush them there are no issues if I run the migrations first.

This issue only occurs after I updated from doctrine/dbal: 3.* to doctrine/dbal: 4.*.

I have create an repo to reproduce this issue: https://github.com/petermanders89/dbal-issue. This is repo created with symfony new my_project_directory --webapp. I modified it slightly.

When running the install command; in this case with symfony console app:install it'll throw this same error.

@nikophil
Copy link
Contributor Author

hey @petermanders89

if using MySQL, you should try to declare your migrations as "non transactional". In MySQL, "ALTER TABLE" statements, and all other statements which modify the db structure implicitly closes the transaction. Connection::isTransactionActive() does not check the DB to see if a transaction is actually active.

At the end, when doctrine commits the changes, it tries to commit a non-existent transaction, and your migration fails 💥
I think you're facing this problem with migration to dbal 4, because dbal 4 forces usage of savepoints, but I think it's actually not the same problem than the one I'm talking about.

@petermanders89
Copy link

Hey @nikophil . Thank you! That indeed solves all my issues related to this. Sorry to mess up your issue.

@morozov
Copy link
Member

morozov commented Dec 22, 2024

@nikophil please provide a sample script or other instructions that will reproduce your issue. Ideally, it should use only DBAL as a dependency.

@nikophil
Copy link
Contributor Author

nikophil commented Dec 23, 2024

Hi @morozov

here it is: https://github.com/nikophil/dbal-repro

you can run it by:

  • set the DSN of a MySQL connection in src/create-connection.php
  • run composer install
  • run php ./src/create-deadlock.php

I've somehow reproduced a concurrency problem by running twice src/update-line.php at the same time, using symfony/process

The concurrency creates a deadlock. On my machine, I have a deadlock, and an error on rollback every time I'm running the script.

The script outputs the error, basically:

PHP Fatal error:  Uncaught PDOException: SQLSTATE[42000]: Syntax error or access violation: 1305 SAVEPOINT DOCTRINE_2 does not exist in /home/nicolas/works/github.com/nikophil/dbal-repro/vendor/doctrine/dbal/src/Driver/PDO/Connection.php:27
Stack trace:
#0 /home/nicolas/works/github.com/nikophil/dbal-repro/vendor/doctrine/dbal/src/Driver/PDO/Connection.php(27): PDO->exec()
#1 /home/nicolas/works/github.com/nikophil/dbal-repro/vendor/doctrine/dbal/src/Connection.php(878): Doctrine\DBAL\Driver\PDO\Connection->exec()
#2 /home/nicolas/works/github.com/nikophil/dbal-repro/vendor/doctrine/dbal/src/Connection.php(1140): Doctrine\DBAL\Connection->executeStatement()
#3 /home/nicolas/works/github.com/nikophil/dbal-repro/vendor/doctrine/dbal/src/Connection.php(1080): Doctrine\DBAL\Connection->rollbackSavepoint()
#4 /home/nicolas/works/github.com/nikophil/dbal-repro/src/update-line.php(32): Doctrine\DBAL\Connection->rollBack()
#5 {main}

Next Doctrine\DBAL\Driver\PDO\Exception: SQLSTATE[42000]: Syntax error or access violation: 1305 SAVEPOINT DOCTRINE_2 does not exist in /home/nicolas/works/github.com/nikophil/dbal-repro/vendor/doctrine/dbal/src/Driver/PDO/Exception.php:28
Stack trace:
#0 /home/nicolas/works/github.com/nikophil/dbal-repro/vendor/doctrine/dbal/src/Driver/PDO/Connection.php(33): Doctrine\DBAL\Driver\PDO\Exception::new()
#1 /home/nicolas/works/github.com/nikophil/dbal-repro/vendor/doctrine/dbal/src/Connection.php(878): Doctrine\DBAL\Driver\PDO\Connection->exec()
#2 /home/nicolas/works/github.com/nikophil/dbal-repro/vendor/doctrine/dbal/src/Connection.php(1140): Doctrine\DBAL\Connection->executeStatement()
#3 /home/nicolas/works/github.com/nikophil/dbal-repro/vendor/doctrine/dbal/src/Connection.php(1080): Doctrine\DBAL\Connection->rollbackSavepoint()
#4 /home/nicolas/works/github.com/nikophil/dbal-repro/src/update-line.php(32): Doctrine\DBAL\Connection->rollBack()
#5 {main}

Next Doctrine\DBAL\Exception\DriverException: An exception occurred while executing a query: SQLSTATE[42000]: Syntax error or access violation: 1305 SAVEPOINT DOCTRINE_2 does not exist in /home/nicolas/works/github.com/nikophil/dbal-repro/vendor/doctrine/dbal/src/Driver/API/MySQL/ExceptionConverter.php:91
Stack trace:
#0 /home/nicolas/works/github.com/nikophil/dbal-repro/vendor/doctrine/dbal/src/Connection.php(1373): Doctrine\DBAL\Driver\API\MySQL\ExceptionConverter->convert()
#1 /home/nicolas/works/github.com/nikophil/dbal-repro/vendor/doctrine/dbal/src/Connection.php(1315): Doctrine\DBAL\Connection->handleDriverException()
#2 /home/nicolas/works/github.com/nikophil/dbal-repro/vendor/doctrine/dbal/src/Connection.php(880): Doctrine\DBAL\Connection->convertExceptionDuringQuery()
#3 /home/nicolas/works/github.com/nikophil/dbal-repro/vendor/doctrine/dbal/src/Connection.php(1140): Doctrine\DBAL\Connection->executeStatement()
#4 /home/nicolas/works/github.com/nikophil/dbal-repro/vendor/doctrine/dbal/src/Connection.php(1080): Doctrine\DBAL\Connection->rollbackSavepoint()
#5 /home/nicolas/works/github.com/nikophil/dbal-repro/src/update-line.php(32): Doctrine\DBAL\Connection->rollBack()
#6 {main}
thrown in /home/nicolas/works/github.com/nikophil/dbal-repro/vendor/doctrine/dbal/src/Driver/API/MySQL/ExceptionConverter.php on line 91

as you can see, the rollback throws an error, and the problem occurs for both dbal 3 et 4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants