diff --git a/lib/private/DB/QueryBuilder/QueryBuilder.php b/lib/private/DB/QueryBuilder/QueryBuilder.php index c2818911ccf88..8a31e475007de 100644 --- a/lib/private/DB/QueryBuilder/QueryBuilder.php +++ b/lib/private/DB/QueryBuilder/QueryBuilder.php @@ -30,6 +30,7 @@ */ namespace OC\DB\QueryBuilder; +use Doctrine\DBAL\Exception\RetryableException; use Doctrine\DBAL\Platforms\MySQLPlatform; use Doctrine\DBAL\Platforms\OraclePlatform; use Doctrine\DBAL\Platforms\PostgreSQL94Platform; @@ -76,6 +77,8 @@ class QueryBuilder implements IQueryBuilder { /** @var string */ protected $lastInsertedTable; + private $retryLimit = 4; + /** * Initializes a new QueryBuilder. * @@ -277,13 +280,34 @@ public function execute() { ]); } - $result = $this->queryBuilder->execute(); + for ($i = 1; $i <= $this->retryLimit; $i++) { + try { + $result = $this->queryBuilder->execute(); + break; + } catch (RetryableException $e) { + // Throw if we reached retryLimit. + if ($i === $this->retryLimit) { + throw $e; + } + + // Sleep a bit to give some time to the other transaction to finish. + usleep(100 * 1000 * $i); + } + } + if (is_int($result)) { return $result; } return new ResultAdapter($result); } + /** + * @param int $retryLimit - Retry the query up to $retryLimit times in case of a RetryableException. Initially equal to 4. + */ + public function setRetryLimit(int $retryLimit): void { + $this->retryLimit = $retryLimit; + } + public function executeQuery(): IResult { if ($this->getType() !== \Doctrine\DBAL\Query\QueryBuilder::SELECT) { throw new \RuntimeException('Invalid query type, expected SELECT query'); diff --git a/lib/private/Files/Cache/Cache.php b/lib/private/Files/Cache/Cache.php index 8f0f962a3b771..a5e63875ede64 100644 --- a/lib/private/Files/Cache/Cache.php +++ b/lib/private/Files/Cache/Cache.php @@ -40,7 +40,6 @@ namespace OC\Files\Cache; -use Doctrine\DBAL\Exception\RetryableException; use Doctrine\DBAL\Exception\UniqueConstraintViolationException; use OC\Files\Search\SearchComparison; use OC\Files\Search\SearchQuery; @@ -715,28 +714,12 @@ public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) { $query->set('encrypted', $query->createNamedParameter(0, IQueryBuilder::PARAM_INT)); } - // Retry transaction in case of RetryableException like deadlocks. - // Retry up to 4 times because we should receive up to 4 concurrent requests from the frontend - $retryLimit = 4; - for ($i = 1; $i <= $retryLimit; $i++) { - try { - $this->connection->beginTransaction(); - $query->executeStatement(); - break; - } catch (\OC\DatabaseException $e) { - $this->connection->rollBack(); - throw $e; - } catch (RetryableException $e) { - // Simply throw if we already retried 4 times. - if ($i === $retryLimit) { - throw $e; - } - - $this->connection->rollBack(); - - // Sleep a bit to give some time to the other transaction to finish. - usleep(100 * 1000 * $i); - } + try { + $this->connection->beginTransaction(); + $query->executeStatement(4); + } catch (\OC\DatabaseException $e) { + $this->connection->rollBack(); + throw $e; } } else { $this->connection->beginTransaction();