40
40
41
41
namespace OC \Files \Cache ;
42
42
43
+ use Doctrine \DBAL \Exception \RetryableException ;
43
44
use Doctrine \DBAL \Exception \UniqueConstraintViolationException ;
44
45
use OC \Files \Search \SearchComparison ;
45
46
use OC \Files \Search \SearchQuery ;
@@ -692,7 +693,6 @@ public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) {
692
693
throw new \Exception ('Invalid target storage id: ' . $ targetStorageId );
693
694
}
694
695
695
- $ this ->connection ->beginTransaction ();
696
696
if ($ sourceData ['mimetype ' ] === 'httpd/unix-directory ' ) {
697
697
//update all child entries
698
698
$ sourceLength = mb_strlen ($ sourcePath );
@@ -715,12 +715,31 @@ public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) {
715
715
$ query ->set ('encrypted ' , $ query ->createNamedParameter (0 , IQueryBuilder::PARAM_INT ));
716
716
}
717
717
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
+ }
723
740
}
741
+ } else {
742
+ $ this ->connection ->beginTransaction ();
724
743
}
725
744
726
745
$ query = $ this ->getQueryBuilder ();
0 commit comments