4040
4141namespace OC \Files \Cache ;
4242
43+ use Doctrine \DBAL \Exception \RetryableException ;
4344use Doctrine \DBAL \Exception \UniqueConstraintViolationException ;
4445use OC \Files \Search \SearchComparison ;
4546use 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