diff --git a/lib/private/DB/Connection.php b/lib/private/DB/Connection.php index 0ad9886e7c05d..c04c75df2d7fb 100644 --- a/lib/private/DB/Connection.php +++ b/lib/private/DB/Connection.php @@ -14,6 +14,7 @@ use Doctrine\DBAL\Configuration; use Doctrine\DBAL\Connections\PrimaryReadReplicaConnection; use Doctrine\DBAL\Driver; +use Doctrine\DBAL\Driver\Exception as DriverException; use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\Exception; use Doctrine\DBAL\Exception\ConnectionLost; @@ -854,7 +855,14 @@ public function beginTransaction() { #[\Override] public function commit() { - $result = parent::commit(); + try { + $result = parent::commit(); + } catch (DriverException $e) { + // DBAL converts driver exceptions for queries, but not for COMMIT. Without + // this, a deadlock or a Galera certification failure raised at commit time + // escapes as a raw PDOException that no caller recognises as retryable. + throw $this->getDriver()->getExceptionConverter()->convert($e, null); + } if ($this->getTransactionNestingLevel() === 0) { $timeTook = microtime(true) - $this->transactionActiveSince; $this->transactionBacktrace = null; diff --git a/lib/private/Files/Cache/Propagator.php b/lib/private/Files/Cache/Propagator.php index 2f8cf909ed03e..26aca124e1109 100644 --- a/lib/private/Files/Cache/Propagator.php +++ b/lib/private/Files/Cache/Propagator.php @@ -138,7 +138,8 @@ public function propagateChange(string $internalPath, int $time, int $sizeDiffer } break; } catch (DbalException $e) { - if ($this->connection->getDatabaseProvider() !== IDBConnection::PLATFORM_SQLITE) { + // a failed commit already ended the transaction, so only roll back an open one + if ($this->connection->inTransaction()) { $this->connection->rollBack(); } if (!$e->isRetryable()) { @@ -292,7 +293,9 @@ public function commitBatch(): void { $this->connection->commit(); } catch (\Exception $e) { - $this->connection->rollback(); + if ($this->connection->inTransaction()) { + $this->connection->rollback(); + } throw $e; } }