From 5bcf37b7ffacba181212956eac85910f095adf07 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 8 Feb 2023 14:34:40 +0100 Subject: [PATCH] only fetch the data for mounts inside a folder when needed for most operations we don't actually care about any mounts inside a folder, only for metadata that needs to propagate across storage boundaries (size, etag, mtime) do we need all the submount info. By only loading this data when needed we can save a bunch of storage setup in a number of cases Signed-off-by: Robin Appelman --- lib/private/Files/Node/File.php | 2 +- lib/private/Files/Node/Folder.php | 8 ++--- lib/private/Files/Node/Node.php | 56 +++++++++++++++++-------------- lib/private/Files/Node/Root.php | 4 +-- lib/private/Files/View.php | 17 +++++++--- 5 files changed, 50 insertions(+), 37 deletions(-) diff --git a/lib/private/Files/Node/File.php b/lib/private/Files/Node/File.php index d8a6741dc6ee2..475930b361a48 100644 --- a/lib/private/Files/Node/File.php +++ b/lib/private/Files/Node/File.php @@ -37,7 +37,7 @@ class File extends Node implements \OCP\Files\File { * Creates a Folder that represents a non-existing path * * @param string $path path - * @return string non-existing node class + * @return NonExistingFile non-existing node */ protected function createNonExistingNode($path) { return new NonExistingFile($this->root, $this->view, $path); diff --git a/lib/private/Files/Node/Folder.php b/lib/private/Files/Node/Folder.php index bf9ae3c148d5c..90aed642a2d19 100644 --- a/lib/private/Files/Node/Folder.php +++ b/lib/private/Files/Node/Folder.php @@ -54,7 +54,7 @@ class Folder extends Node implements \OCP\Files\Folder { * Creates a Folder that represents a non-existing path * * @param string $path path - * @return string non-existing node class + * @return NonExistingFolder non-existing node */ protected function createNonExistingNode($path) { return new NonExistingFolder($this->root, $this->view, $path); @@ -98,7 +98,7 @@ public function isSubNode($node) { * @throws \OCP\Files\NotFoundException */ public function getDirectoryListing() { - $folderContent = $this->view->getDirectoryContent($this->path, '', $this->getFileInfo()); + $folderContent = $this->view->getDirectoryContent($this->path, '', $this->getFileInfo(false)); return array_map(function (FileInfo $info) { if ($info->getMimetype() === FileInfo::MIMETYPE_FOLDER) { @@ -114,7 +114,7 @@ public function getDirectoryListing() { * @param FileInfo $info * @return File|Folder */ - protected function createNode($path, FileInfo $info = null) { + protected function createNode($path, FileInfo $info = null, bool $infoHasSubMountsIncluded = true) { if (is_null($info)) { $isDir = $this->view->is_dir($path); } else { @@ -122,7 +122,7 @@ protected function createNode($path, FileInfo $info = null) { } $parent = dirname($path) === $this->getPath() ? $this : null; if ($isDir) { - return new Folder($this->root, $this->view, $path, $info, $parent); + return new Folder($this->root, $this->view, $path, $info, $parent, $infoHasSubMountsIncluded); } else { return new File($this->root, $this->view, $path, $info, $parent); } diff --git a/lib/private/Files/Node/Node.php b/lib/private/Files/Node/Node.php index 6c4e0b0f9085f..2f88cc3a15acd 100644 --- a/lib/private/Files/Node/Node.php +++ b/lib/private/Files/Node/Node.php @@ -56,35 +56,35 @@ class Node implements \OCP\Files\Node { */ protected $path; - /** - * @var \OCP\Files\FileInfo - */ - protected $fileInfo; + protected ?FileInfo $fileInfo; /** * @var Node|null */ protected $parent; + private bool $infoHasSubMountsIncluded; + /** * @param \OC\Files\View $view * @param \OCP\Files\IRootFolder $root * @param string $path * @param FileInfo $fileInfo */ - public function __construct($root, $view, $path, $fileInfo = null, ?Node $parent = null) { + public function __construct($root, $view, $path, $fileInfo = null, ?Node $parent = null, bool $infoHasSubMountsIncluded = true) { $this->view = $view; $this->root = $root; $this->path = $path; $this->fileInfo = $fileInfo; $this->parent = $parent; + $this->infoHasSubMountsIncluded = $infoHasSubMountsIncluded; } /** * Creates a Node of the same type that represents a non-existing path * * @param string $path path - * @return string non-existing node class + * @return Node non-existing node * @throws \Exception */ protected function createNonExistingNode($path) { @@ -98,17 +98,23 @@ protected function createNonExistingNode($path) { * @throws InvalidPathException * @throws NotFoundException */ - public function getFileInfo() { + public function getFileInfo(bool $includeMountPoint = true) { if (!$this->fileInfo) { if (!Filesystem::isValidPath($this->path)) { throw new InvalidPathException(); } - $fileInfo = $this->view->getFileInfo($this->path); + $fileInfo = $this->view->getFileInfo($this->path, $includeMountPoint); + $this->infoHasSubMountsIncluded = $includeMountPoint; if ($fileInfo instanceof FileInfo) { $this->fileInfo = $fileInfo; } else { throw new NotFoundException(); } + } elseif ($includeMountPoint && !$this->infoHasSubMountsIncluded && $this instanceof Folder) { + if ($this->fileInfo instanceof \OC\Files\FileInfo) { + $this->view->addSubMounts($this->fileInfo); + } + $this->infoHasSubMountsIncluded = true; } return $this->fileInfo; } @@ -179,7 +185,7 @@ public function getPath() { * @return string */ public function getInternalPath() { - return $this->getFileInfo()->getInternalPath(); + return $this->getFileInfo(false)->getInternalPath(); } /** @@ -188,7 +194,7 @@ public function getInternalPath() { * @throws NotFoundException */ public function getId() { - return $this->getFileInfo()->getId(); + return $this->getFileInfo(false)->getId() ?? -1; } /** @@ -232,7 +238,7 @@ public function getEtag() { * @throws NotFoundException */ public function getPermissions() { - return $this->getFileInfo()->getPermissions(); + return $this->getFileInfo(false)->getPermissions(); } /** @@ -241,7 +247,7 @@ public function getPermissions() { * @throws NotFoundException */ public function isReadable() { - return $this->getFileInfo()->isReadable(); + return $this->getFileInfo(false)->isReadable(); } /** @@ -250,7 +256,7 @@ public function isReadable() { * @throws NotFoundException */ public function isUpdateable() { - return $this->getFileInfo()->isUpdateable(); + return $this->getFileInfo(false)->isUpdateable(); } /** @@ -259,7 +265,7 @@ public function isUpdateable() { * @throws NotFoundException */ public function isDeletable() { - return $this->getFileInfo()->isDeletable(); + return $this->getFileInfo(false)->isDeletable(); } /** @@ -268,7 +274,7 @@ public function isDeletable() { * @throws NotFoundException */ public function isShareable() { - return $this->getFileInfo()->isShareable(); + return $this->getFileInfo(false)->isShareable(); } /** @@ -277,7 +283,7 @@ public function isShareable() { * @throws NotFoundException */ public function isCreatable() { - return $this->getFileInfo()->isCreatable(); + return $this->getFileInfo(false)->isCreatable(); } /** @@ -328,42 +334,42 @@ public function isValidPath($path) { } public function isMounted() { - return $this->getFileInfo()->isMounted(); + return $this->getFileInfo(false)->isMounted(); } public function isShared() { - return $this->getFileInfo()->isShared(); + return $this->getFileInfo(false)->isShared(); } public function getMimeType() { - return $this->getFileInfo()->getMimetype(); + return $this->getFileInfo(false)->getMimetype(); } public function getMimePart() { - return $this->getFileInfo()->getMimePart(); + return $this->getFileInfo(false)->getMimePart(); } public function getType() { - return $this->getFileInfo()->getType(); + return $this->getFileInfo(false)->getType(); } public function isEncrypted() { - return $this->getFileInfo()->isEncrypted(); + return $this->getFileInfo(false)->isEncrypted(); } public function getMountPoint() { - return $this->getFileInfo()->getMountPoint(); + return $this->getFileInfo(false)->getMountPoint(); } public function getOwner() { - return $this->getFileInfo()->getOwner(); + return $this->getFileInfo(false)->getOwner(); } public function getChecksum() { } public function getExtension(): string { - return $this->getFileInfo()->getExtension(); + return $this->getFileInfo(false)->getExtension(); } /** diff --git a/lib/private/Files/Node/Root.php b/lib/private/Files/Node/Root.php index 8d0a65d2a68fc..29cdbb987c350 100644 --- a/lib/private/Files/Node/Root.php +++ b/lib/private/Files/Node/Root.php @@ -202,9 +202,9 @@ public function get($path) { $path = $this->normalizePath($path); if ($this->isValidPath($path)) { $fullPath = $this->getFullPath($path); - $fileInfo = $this->view->getFileInfo($fullPath); + $fileInfo = $this->view->getFileInfo($fullPath, false); if ($fileInfo) { - return $this->createNode($fullPath, $fileInfo); + return $this->createNode($fullPath, $fileInfo, false); } else { throw new NotFoundException($path); } diff --git a/lib/private/Files/View.php b/lib/private/Files/View.php index f79a992c77372..456f804ee5617 100644 --- a/lib/private/Files/View.php +++ b/lib/private/Files/View.php @@ -1412,11 +1412,7 @@ public function getFileInfo($path, $includeMountPoints = true) { if ($includeMountPoints and $data['mimetype'] === 'httpd/unix-directory') { //add the sizes of other mount points to the folder $extOnly = ($includeMountPoints === 'ext'); - $mounts = Filesystem::getMountManager()->findIn($path); - $info->setSubMounts(array_filter($mounts, function (IMountPoint $mount) use ($extOnly) { - $subStorage = $mount->getStorage(); - return !($extOnly && $subStorage instanceof \OCA\Files_Sharing\SharedStorage); - })); + $this->addSubMounts($info, $extOnly); } } @@ -1428,6 +1424,17 @@ public function getFileInfo($path, $includeMountPoints = true) { return false; } + /** + * Extend a FileInfo that was previously requested with `$includeMountPoints = false` to include the sub mounts + */ + public function addSubMounts(FileInfo $info, $extOnly = false): void { + $mounts = Filesystem::getMountManager()->findIn($info->getPath()); + $info->setSubMounts(array_filter($mounts, function (IMountPoint $mount) use ($extOnly) { + $subStorage = $mount->getStorage(); + return !($extOnly && $subStorage instanceof \OCA\Files_Sharing\SharedStorage); + })); + } + /** * get the content of a directory *