Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/server.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Appelman <robin@icewind.nl>2020-04-29 17:07:51 +0300
committerMorris Jobke <hey@morrisjobke.de>2020-08-20 16:37:02 +0300
commit5af7d921a9dcbd03b739d612af203b3d5b9b3605 (patch)
treeec3ace427c66d695817c4ec71db2439a98b247a9
parent03603db486debbb31dfa05486f3b10338a28b50c (diff)
Make Cache::removeChildren non recursive
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>
-rw-r--r--lib/private/Files/Cache/Cache.php40
-rw-r--r--lib/private/Files/Cache/CacheQueryBuilder.php13
2 files changed, 38 insertions, 15 deletions
diff --git a/lib/private/Files/Cache/Cache.php b/lib/private/Files/Cache/Cache.php
index de807421d26..77289e674b3 100644
--- a/lib/private/Files/Cache/Cache.php
+++ b/lib/private/Files/Cache/Cache.php
@@ -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();
}
diff --git a/lib/private/Files/Cache/CacheQueryBuilder.php b/lib/private/Files/Cache/CacheQueryBuilder.php
index 332274eda2a..ac17cfaffb2 100644
--- a/lib/private/Files/Cache/CacheQueryBuilder.php
+++ b/lib/private/Files/Cache/CacheQueryBuilder.php
@@ -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;
+ }
}