Skip to content

Commit 28c8a46

Browse files
authored
Merge pull request #44504 from nextcloud/artonge/feat/retry_cache_operations_on_deadlock
Add retry logic to cover deadlock situations during move operations
2 parents 0847425 + 7517959 commit 28c8a46

File tree

1 file changed

+25
-6
lines changed

1 file changed

+25
-6
lines changed

lib/private/Files/Cache/Cache.php

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040

4141
namespace OC\Files\Cache;
4242

43+
use Doctrine\DBAL\Exception\RetryableException;
4344
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
4445
use OC\Files\Search\SearchComparison;
4546
use OC\Files\Search\SearchQuery;
@@ -692,7 +693,6 @@ public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) {
692693
throw new \Exception('Invalid target storage id: ' . $targetStorageId);
693694
}
694695

695-
$this->connection->beginTransaction();
696696
if ($sourceData['mimetype'] === 'httpd/unix-directory') {
697697
//update all child entries
698698
$sourceLength = mb_strlen($sourcePath);
@@ -715,12 +715,31 @@ public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) {
715715
$query->set('encrypted', $query->createNamedParameter(0, IQueryBuilder::PARAM_INT));
716716
}
717717

718-
try {
719-
$query->execute();
720-
} catch (\OC\DatabaseException $e) {
721-
$this->connection->rollBack();
722-
throw $e;
718+
// Retry transaction in case of RetryableException like deadlocks.
719+
// Retry up to 4 times because we should receive up to 4 concurrent requests from the frontend
720+
$retryLimit = 4;
721+
for ($i = 1; $i <= $retryLimit; $i++) {
722+
try {
723+
$this->connection->beginTransaction();
724+
$query->executeStatement();
725+
break;
726+
} catch (\OC\DatabaseException $e) {
727+
$this->connection->rollBack();
728+
throw $e;
729+
} catch (RetryableException $e) {
730+
// Simply throw if we already retried 4 times.
731+
if ($i === $retryLimit) {
732+
throw $e;
733+
}
734+
735+
$this->connection->rollBack();
736+
737+
// Sleep a bit to give some time to the other transaction to finish.
738+
usleep(100 * 1000 * $i);
739+
}
723740
}
741+
} else {
742+
$this->connection->beginTransaction();
724743
}
725744

726745
$query = $this->getQueryBuilder();

0 commit comments

Comments
 (0)