From ac9da6eaa076013edf9a97c08388197fe63e3b73 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Tue, 14 Apr 2026 22:09:54 +0200 Subject: [PATCH] perf: only load possible results in UserMountCache::getMountForPath Signed-off-by: Robin Appelman --- lib/private/Files/Config/UserMountCache.php | 46 +++++++++++++++------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/lib/private/Files/Config/UserMountCache.php b/lib/private/Files/Config/UserMountCache.php index 8bc04c62b33..5e0653b1c63 100644 --- a/lib/private/Files/Config/UserMountCache.php +++ b/lib/private/Files/Config/UserMountCache.php @@ -488,21 +488,13 @@ class UserMountCache implements IUserMountCache { } public function getMountForPath(IUser $user, string $path): ICachedMountInfo { - $mounts = []; - foreach ($this->getMountsForUser($user) as $mount) { - $mounts[$mount->getMountPoint()] = $mount; - } - + $searchPaths = []; $current = rtrim($path, '/'); - // walk up the directory tree until we find a path that has a mountpoint set - // the loop will return if a mountpoint is found or break if none are found - while (true) { + // get all paths that we are interested in, $path and all it's parents + while ($current !== '') { $mountPoint = $current . '/'; - if (isset($mounts[$mountPoint])) { - return $mounts[$mountPoint]; - } elseif ($current === '') { - break; - } + + $searchPaths[] = $mountPoint; $current = dirname($current); if ($current === '.' || $current === '/') { @@ -510,6 +502,34 @@ class UserMountCache implements IUserMountCache { } } + $mounts = []; + if (isset($this->mountsForUsers[$user->getUID()])) { + foreach ($this->mountsForUsers[$user->getUID()] as $mount) { + $mounts[$mount->getMountPoint()] = $mount; + } + } else { + $searchPathHashes = array_map(static fn (string $path) => hash('xxh128', $path), $searchPaths); + + $builder = $this->connection->getQueryBuilder(); + $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path', 'mount_provider_class') + ->from('mounts', 'm') + ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid')) + ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($user->getUID()))) + ->andWhere($builder->expr()->in('mount_point_hash', $builder->createNamedParameter($searchPathHashes, IQueryBuilder::PARAM_STR_ARRAY))); + + foreach ($query->executeQuery()->fetchAll() as $row) { + $mount = $this->dbRowToMountInfo($row); + $mounts[$mount->getMountPoint()] = $mount; + } + } + + // note that $searchPaths is sorted deepest path first + foreach ($searchPaths as $searchPath) { + if (isset($mounts[$searchPath])) { + return $mounts[$searchPath]; + } + } + throw new NotFoundException('No cached mount for path ' . $path); }