From 27339601f61b6600859d7d2058f146df5380f39a Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Wed, 14 Jan 2026 16:06:09 +0100 Subject: [PATCH] perf(View): Optimize getDirectoryContent hot-loop Signed-off-by: Carl Schwan --- lib/private/Files/Cache/CacheEntry.php | 2 +- lib/private/Files/Mount/Manager.php | 12 +++--- lib/private/Files/View.php | 55 +++++++++++++------------- 3 files changed, 33 insertions(+), 36 deletions(-) diff --git a/lib/private/Files/Cache/CacheEntry.php b/lib/private/Files/Cache/CacheEntry.php index c558ec7721e8f..220763f773bb6 100644 --- a/lib/private/Files/Cache/CacheEntry.php +++ b/lib/private/Files/Cache/CacheEntry.php @@ -90,7 +90,7 @@ public function getEtag() { return $this->data['etag']; } - public function getPermissions() { + public function getPermissions(): int { return $this->data['permissions']; } diff --git a/lib/private/Files/Mount/Manager.php b/lib/private/Files/Mount/Manager.php index 55de488c726cd..c38fefab734f4 100644 --- a/lib/private/Files/Mount/Manager.php +++ b/lib/private/Files/Mount/Manager.php @@ -110,7 +110,6 @@ public function find(string $path): IMountPoint { /** * Find all mounts in $path * - * @param string $path * @return IMountPoint[] */ public function findIn(string $path): array { @@ -122,11 +121,10 @@ public function findIn(string $path): array { } $result = []; - $pathLength = \strlen($path); - $mountPoints = array_keys($this->mounts); - foreach ($mountPoints as $mountPoint) { - if (substr($mountPoint, 0, $pathLength) === $path && \strlen($mountPoint) > $pathLength) { - $result[] = $this->mounts[$mountPoint]; + $pathLen = strlen($path); + foreach ($this->mounts as $mountPoint => $mount) { + if (strlen($mountPoint) > $pathLen && strncmp($mountPoint, $path, $pathLen) === 0) { + $result[] = $mount; } } @@ -134,7 +132,7 @@ public function findIn(string $path): array { return $result; } - public function clear() { + public function clear(): void { $this->mounts = []; $this->pathCache->clear(); $this->inPathCache->clear(); diff --git a/lib/private/Files/View.php b/lib/private/Files/View.php index f731da58b677d..4a9ef9f813814 100644 --- a/lib/private/Files/View.php +++ b/lib/private/Files/View.php @@ -31,6 +31,8 @@ use OCP\Files\Mount\IMountPoint; use OCP\Files\NotFoundException; use OCP\Files\ReservedWordException; +use OCP\Files\StorageInvalidException; +use OCP\Files\StorageNotAvailableException; use OCP\IUser; use OCP\IUserManager; use OCP\L10N\IFactory; @@ -1350,11 +1352,7 @@ public function hasUpdated($path, $time) { return $this->basicOperation('hasUpdated', $path, [], $time); } - /** - * @param string $ownerId - * @return IUser - */ - private function getUserObjectForOwner(string $ownerId) { + private function getUserObjectForOwner(string $ownerId): IUser { return new LazyUser($ownerId, $this->userManager); } @@ -1511,35 +1509,38 @@ public function getDirectoryContent($directory, $mimetype_filter = '', ?\OCP\Fil $contents = $cache->getFolderContentsById($folderId); //TODO: mimetype_filter $sharingDisabled = \OCP\Util::isSharingDisabledForUser(); + $permissionsMask = ~\OCP\Constants::PERMISSION_SHARE; + + $files = []; + foreach ($contents as $content) { + $name = $content->getName(); + $contentPath = $content->getPath(); - $fileNames = array_map(function (ICacheEntry $content) { - return $content->getName(); - }, $contents); - /** - * @var \OC\Files\FileInfo[] $fileInfos - */ - $fileInfos = array_map(function (ICacheEntry $content) use ($path, $storage, $mount, $sharingDisabled) { if ($sharingDisabled) { - $content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE; - } - $ownerId = $storage->getOwner($content['path']); - if ($ownerId !== false) { - $owner = $this->getUserObjectForOwner($ownerId); - } else { - $owner = null; + $content['permissions'] = $content->getPermissions() & $permissionsMask; } - return new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content, $mount, $owner); - }, $contents); - $files = array_combine($fileNames, $fileInfos); + + $ownerId = $storage->getOwner($contentPath); + $owner = $ownerId !== false + ? $this->getUserObjectForOwner($ownerId) + : null; + + $files[$name] = new FileInfo( + $path . '/' . $name, + $storage, + $contentPath, + $content, + $mount, + $owner + ); + } //add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders $mounts = Filesystem::getMountManager()->findIn($path); // make sure nested mounts are sorted after their parent mounts // otherwise doesn't propagate the etag across storage boundaries correctly - usort($mounts, function (IMountPoint $a, IMountPoint $b) { - return $a->getMountPoint() <=> $b->getMountPoint(); - }); + usort($mounts, static fn (IMountPoint $a, IMountPoint $b): int => $a->getMountPoint() <=> $b->getMountPoint()); $dirLength = strlen($path); foreach ($mounts as $mount) { @@ -1553,9 +1554,7 @@ public function getDirectoryContent($directory, $mimetype_filter = '', ?\OCP\Fil $subScanner = $subStorage->getScanner(); try { $subScanner->scanFile(''); - } catch (\OCP\Files\StorageNotAvailableException $e) { - continue; - } catch (\OCP\Files\StorageInvalidException $e) { + } catch (StorageNotAvailableException|StorageInvalidException) { continue; } catch (\Exception $e) { // sometimes when the storage is not available it can be any exception