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>
This commit is contained in:
Robin Appelman 2020-04-29 16:07:51 +02:00 committed by Morris Jobke
parent 03603db486
commit 5af7d921a9
No known key found for this signature in database
GPG Key ID: FE03C3A163FEDE68
2 changed files with 38 additions and 15 deletions

View 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();
}

View 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;
}
}