diff --git a/lib/private/DB/ConnectionAdapter.php b/lib/private/DB/ConnectionAdapter.php index d9ccb3c54f219..4afd1f2e2f526 100644 --- a/lib/private/DB/ConnectionAdapter.php +++ b/lib/private/DB/ConnectionAdapter.php @@ -26,6 +26,13 @@ class ConnectionAdapter implements IDBConnection { /** @var Connection */ private $inner; + /** + * The currently active transaction isolation level or NULL before it has been determined. + * + * @var \Doctrine\DBAL\TransactionIsolationLevel::*|null + */ + private ?int $transactionIsolationLevel = null; + public function __construct(Connection $inner) { $this->inner = $inner; } @@ -262,4 +269,14 @@ public function getShardDefinition(string $name): ?ShardDefinition { public function getCrossShardMoveHelper(): CrossShardMoveHelper { return $this->inner->getCrossShardMoveHelper(); } + + public function setTransactionIsolation(int $level): int { + $this->transactionIsolationLevel = $level; + + return $this->executeStatement($this->getDatabasePlatform()->getSetTransactionIsolationSQL($level)); + } + + public function getTransactionIsolation(): int { + return $this->transactionIsolationLevel ??= $this->getDatabasePlatform()->getDefaultTransactionIsolationLevel(); + } } diff --git a/lib/private/Files/Config/UserMountCache.php b/lib/private/Files/Config/UserMountCache.php index 7cffc01b6f281..52b1aa85c3cd0 100644 --- a/lib/private/Files/Config/UserMountCache.php +++ b/lib/private/Files/Config/UserMountCache.php @@ -7,6 +7,7 @@ */ namespace OC\Files\Config; +use Doctrine\DBAL\TransactionIsolationLevel; use OC\User\LazyUser; use OCP\Cache\CappedMemoryCache; use OCP\DB\QueryBuilder\IQueryBuilder; @@ -99,6 +100,8 @@ public function registerMounts(IUser $user, array $mounts, ?array $mountProvider $changedMounts = $this->findChangedMounts($newMounts, $cachedMounts); if ($addedMounts || $removedMounts || $changedMounts) { + $this->connection->setTransactionIsolation(TransactionIsolationLevel::REPEATABLE_READ); + $this->connection->beginTransaction(); $userUID = $user->getUID(); try { @@ -124,6 +127,8 @@ public function registerMounts(IUser $user, array $mounts, ?array $mountProvider } catch (\Throwable $e) { $this->connection->rollBack(); throw $e; + } finally { + $this->connection->setTransactionIsolation(TransactionIsolationLevel::READ_COMMITTED); } // Only fire events after all mounts have already been adjusted in the database. diff --git a/lib/public/IDBConnection.php b/lib/public/IDBConnection.php index 05ac0da2d7a2e..a1418afd06819 100644 --- a/lib/public/IDBConnection.php +++ b/lib/public/IDBConnection.php @@ -388,4 +388,26 @@ public function getShardDefinition(string $name): ?ShardDefinition; * @since 30.0.0 */ public function getCrossShardMoveHelper(): CrossShardMoveHelper; + + /** + * Sets the transaction isolation level. + * + * @param \Doctrine\DBAL\TransactionIsolationLevel::* $level The level to set. + * + * @throws \Doctrine\DBAL\Exception + * + * @since 33.0.0 + */ + public function setTransactionIsolation(int $level): int; + + /** + * Gets the currently active transaction isolation level. + * + * @return \Doctrine\DBAL\TransactionIsolationLevel::* The current transaction isolation level. + * + * @throws \Doctrine\DBAL\Exception + * + * @since 33.0.0 + */ + public function getTransactionIsolation(): int; }