]> source.dussan.org Git - nextcloud-server.git/commitdiff
Make Cache::removeChildren non recursive
authorRobin Appelman <robin@icewind.nl>
Wed, 29 Apr 2020 14:07:51 +0000 (16:07 +0200)
committerMorris Jobke <hey@morrisjobke.de>
Thu, 20 Aug 2020 13:37:02 +0000 (15:37 +0200)
Currently the "add new files during scanning" call stack is smaller than
the "remove deleted files during scanning" call stack. This can lead to
the scanner adding folders in the folder tree that are to deep to be
removed.

This changes the `removeChildren` logic to be non recursive so there is
no limit to the depth of the folder tree during removal

Signed-off-by: Robin Appelman <robin@icewind.nl>
lib/private/Files/Cache/Cache.php
lib/private/Files/Cache/CacheQueryBuilder.php

index de807421d2666a4032782da2ca754cfcf894060d..77289e674b3e9fd590b9fb69a56fcaf91ff5bf77 100644 (file)
@@ -553,25 +553,35 @@ class Cache implements ICache {
         * @throws \OC\DatabaseException
         */
        private function removeChildren(ICacheEntry $entry) {
-               $children = $this->getFolderContentsById($entry->getId());
-               $childIds = array_map(function (ICacheEntry $cacheEntry) {
-                       return $cacheEntry->getId();
-               }, $children);
-               $childFolders = array_filter($children, function ($child) {
-                       return $child->getMimeType() == FileInfo::MIMETYPE_FOLDER;
-               });
-               foreach ($childFolders as $folder) {
-                       $this->removeChildren($folder);
+               $parentIds = [$entry->getId()];
+               $queue = [$entry->getId()];
+
+               // we walk depth first trough the file tree, removing all filecache_extended attributes while we walk
+               // and collecting all folder ids to later use to delete the filecache entries
+               while ($entryId = array_pop($queue)) {
+                       $children = $this->getFolderContentsById($entryId);
+                       $childIds = array_map(function (ICacheEntry $cacheEntry) {
+                               return $cacheEntry->getId();
+                       }, $children);
+
+                       $query = $this->getQueryBuilder();
+                       $query->delete('filecache_extended')
+                               ->where($query->expr()->in('fileid', $query->createNamedParameter($childIds, IQueryBuilder::PARAM_INT_ARRAY)));
+                       $query->execute();
+
+                       /** @var ICacheEntry[] $childFolders */
+                       $childFolders = array_filter($children, function ($child) {
+                               return $child->getMimeType() == FileInfo::MIMETYPE_FOLDER;
+                       });
+                       foreach ($childFolders as $folder) {
+                               $parentIds[] = $folder->getId();
+                               $queue[] = $folder->getId();
+                       }
                }
 
                $query = $this->getQueryBuilder();
                $query->delete('filecache')
-                       ->whereParent($entry->getId());
-               $query->execute();
-
-               $query = $this->getQueryBuilder();
-               $query->delete('filecache_extended')
-                       ->where($query->expr()->in('fileid', $query->createNamedParameter($childIds, IQueryBuilder::PARAM_INT_ARRAY)));
+                       ->whereParentIn($parentIds);
                $query->execute();
        }
 
index 332274eda2a20a90b8a92cb3335ec191ec29c45f..ac17cfaffb2343de5cc332646bd3cdbe25b71826 100644 (file)
@@ -94,4 +94,17 @@ class CacheQueryBuilder extends QueryBuilder {
 
                return $this;
        }
+
+       public function whereParentIn(array $parents) {
+               $alias = $this->alias;
+               if ($alias) {
+                       $alias .= '.';
+               } else {
+                       $alias = '';
+               }
+
+               $this->andWhere($this->expr()->in("{$alias}parent", $this->createNamedParameter($parents, IQueryBuilder::PARAM_INT_ARRAY)));
+
+               return $this;
+       }
 }