diff --git a/lib/private/Files/Cache/Cache.php b/lib/private/Files/Cache/Cache.php index b148e0f7476de..0586bec91462a 100644 --- a/lib/private/Files/Cache/Cache.php +++ b/lib/private/Files/Cache/Cache.php @@ -702,6 +702,11 @@ public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) { if ($sourceData['mimetype'] === 'httpd/unix-directory') { //update all child entries $sourceLength = mb_strlen($sourcePath); + + $childIds = $this->getChildIds($sourceStorageId, $sourcePath); + + $childChunks = array_chunk($childIds, 1000); + $query = $this->connection->getQueryBuilder(); $fun = $query->func(); @@ -714,7 +719,7 @@ public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) { ->set('path_hash', $fun->md5($newPathFunction)) ->set('path', $newPathFunction) ->where($query->expr()->eq('storage', $query->createNamedParameter($sourceStorageId, IQueryBuilder::PARAM_INT))) - ->andWhere($query->expr()->like('path', $query->createNamedParameter($this->connection->escapeLikeParameter($sourcePath) . '/%'))); + ->andWhere($query->expr()->in('fileid', $query->createParameter('files'))); // when moving from an encrypted storage to a non-encrypted storage remove the `encrypted` mark if ($sourceCache->hasEncryptionWrapper() && !$this->hasEncryptionWrapper()) { @@ -727,12 +732,17 @@ public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) { for ($i = 1; $i <= $retryLimit; $i++) { try { $this->connection->beginTransaction(); - $query->executeStatement(); + foreach ($childChunks as $chunk) { + $query->setParameter('files', $chunk, IQueryBuilder::PARAM_INT_ARRAY); + $query->executeStatement(); + } break; } catch (\OC\DatabaseException $e) { $this->connection->rollBack(); throw $e; } catch (DbalException $e) { + $this->connection->rollBack(); + if (!$e->isRetryable()) { throw $e; } @@ -742,8 +752,6 @@ public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) { throw $e; } - $this->connection->rollBack(); - // Sleep a bit to give some time to the other transaction to finish. usleep(100 * 1000 * $i); } @@ -785,6 +793,15 @@ public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) { } } + private function getChildIds(int $storageId, string $path): array { + $query = $this->connection->getQueryBuilder(); + $query->select('fileid') + ->from('filecache') + ->where($query->expr()->eq('storage', $query->createNamedParameter($storageId, IQueryBuilder::PARAM_INT))) + ->andWhere($query->expr()->like('path', $query->createNamedParameter($this->connection->escapeLikeParameter($path) . '/%'))); + return $query->executeQuery()->fetchAll(\PDO::FETCH_COLUMN); + } + /** * remove all entries for files that are stored on the storage from the cache */