aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private
diff options
context:
space:
mode:
authorRobin Appelman <robin@icewind.nl>2024-03-05 17:26:25 +0100
committerGitHub <noreply@github.com>2024-03-05 17:26:25 +0100
commitfd4ca13867de94e3afc5cac55ac39c4235d6b737 (patch)
tree55687140e7a7ec2f3612092f5be291ed698d0337 /lib/private
parentc18ffe0cad13dc5903cbb08ffbdb787f01db5e35 (diff)
parenta9ee278ec6059d164ed2f45b0eb304e940ffd588 (diff)
downloadnextcloud-server-fd4ca13867de94e3afc5cac55ac39c4235d6b737.tar.gz
nextcloud-server-fd4ca13867de94e3afc5cac55ac39c4235d6b737.zip
Merge pull request #43471 from nextcloud/cache-path-by-id
Cache path by id
Diffstat (limited to 'lib/private')
-rw-r--r--lib/private/Collaboration/Reference/File/FileReferenceProvider.php8
-rw-r--r--lib/private/DirectEditing/Manager.php6
-rw-r--r--lib/private/Files/Config/CachedMountInfo.php7
-rw-r--r--lib/private/Files/Node/Folder.php6
-rw-r--r--lib/private/Files/Node/LazyFolder.php6
-rw-r--r--lib/private/Files/Node/LazyRoot.php5
-rw-r--r--lib/private/Files/Node/LazyUserFolder.php12
-rw-r--r--lib/private/Files/Node/NonExistingFolder.php4
-rw-r--r--lib/private/Files/Node/Root.php32
-rw-r--r--lib/private/FilesMetadata/Job/UpdateSingleMetadata.php7
-rw-r--r--lib/private/Server.php5
-rw-r--r--lib/private/Share20/Manager.php6
-rw-r--r--lib/private/Share20/Share.php14
-rw-r--r--lib/private/SpeechToText/TranscriptionJob.php2
14 files changed, 75 insertions, 45 deletions
diff --git a/lib/private/Collaboration/Reference/File/FileReferenceProvider.php b/lib/private/Collaboration/Reference/File/FileReferenceProvider.php
index 5f384213976..125649246df 100644
--- a/lib/private/Collaboration/Reference/File/FileReferenceProvider.php
+++ b/lib/private/Collaboration/Reference/File/FileReferenceProvider.php
@@ -31,7 +31,6 @@ use OCP\Collaboration\Reference\Reference;
use OCP\Files\IMimeTypeDetector;
use OCP\Files\InvalidPathException;
use OCP\Files\IRootFolder;
-use OCP\Files\Node;
use OCP\Files\NotFoundException;
use OCP\Files\NotPermittedException;
use OCP\IL10N;
@@ -121,15 +120,12 @@ class FileReferenceProvider extends ADiscoverableReferenceProvider {
try {
$userFolder = $this->rootFolder->getUserFolder($this->userId);
- $files = $userFolder->getById($fileId);
+ $file = $userFolder->getFirstNodeById($fileId);
- if (empty($files)) {
+ if (!$file) {
throw new NotFoundException();
}
- /** @var Node $file */
- $file = array_shift($files);
-
$reference->setTitle($file->getName());
$reference->setDescription($file->getMimetype());
$reference->setUrl($this->urlGenerator->getAbsoluteURL('/index.php/f/' . $fileId));
diff --git a/lib/private/DirectEditing/Manager.php b/lib/private/DirectEditing/Manager.php
index d1be1f50330..da4811589da 100644
--- a/lib/private/DirectEditing/Manager.php
+++ b/lib/private/DirectEditing/Manager.php
@@ -310,11 +310,11 @@ class Manager implements IManager {
if ($filePath !== null) {
return $userFolder->get($filePath);
}
- $files = $userFolder->getById($fileId);
- if (count($files) === 0) {
+ $file = $userFolder->getFirstNodeById($fileId);
+ if (!$file) {
throw new NotFoundException('File nound found by id ' . $fileId);
}
- return $files[0];
+ return $file;
}
public function isEnabled(): bool {
diff --git a/lib/private/Files/Config/CachedMountInfo.php b/lib/private/Files/Config/CachedMountInfo.php
index 7c97135a565..19fa87aa090 100644
--- a/lib/private/Files/Config/CachedMountInfo.php
+++ b/lib/private/Files/Config/CachedMountInfo.php
@@ -97,12 +97,7 @@ class CachedMountInfo implements ICachedMountInfo {
// TODO injection etc
Filesystem::initMountPoints($this->getUser()->getUID());
$userNode = \OC::$server->getUserFolder($this->getUser()->getUID());
- $nodes = $userNode->getParent()->getById($this->getRootId());
- if (count($nodes) > 0) {
- return $nodes[0];
- } else {
- return null;
- }
+ return $userNode->getParent()->getFirstNodeById($this->getRootId());
}
/**
diff --git a/lib/private/Files/Node/Folder.php b/lib/private/Files/Node/Folder.php
index c7462572fed..014b66fdf63 100644
--- a/lib/private/Files/Node/Folder.php
+++ b/lib/private/Files/Node/Folder.php
@@ -307,12 +307,16 @@ class Folder extends Node implements \OCP\Files\Folder {
/**
* @param int $id
- * @return \OC\Files\Node\Node[]
+ * @return \OCP\Files\Node[]
*/
public function getById($id) {
return $this->root->getByIdInPath((int)$id, $this->getPath());
}
+ public function getFirstNodeById(int $id): ?\OCP\Files\Node {
+ return current($this->getById($id)) ?: null;
+ }
+
protected function getAppDataDirectoryName(): string {
$instanceId = \OC::$server->getConfig()->getSystemValueString('instanceid');
return 'appdata_' . $instanceId;
diff --git a/lib/private/Files/Node/LazyFolder.php b/lib/private/Files/Node/LazyFolder.php
index e30cfea693e..4aae5cf9804 100644
--- a/lib/private/Files/Node/LazyFolder.php
+++ b/lib/private/Files/Node/LazyFolder.php
@@ -492,7 +492,11 @@ class LazyFolder implements Folder {
* @inheritDoc
*/
public function getById($id) {
- return $this->__call(__FUNCTION__, func_get_args());
+ return $this->getRootFolder()->getByIdInPath((int)$id, $this->getPath());
+ }
+
+ public function getFirstNodeById(int $id): ?\OCP\Files\Node {
+ return $this->getRootFolder()->getFirstNodeByIdInPath($id, $this->getPath());
}
/**
diff --git a/lib/private/Files/Node/LazyRoot.php b/lib/private/Files/Node/LazyRoot.php
index 680e80cb45e..dd1596319fa 100644
--- a/lib/private/Files/Node/LazyRoot.php
+++ b/lib/private/Files/Node/LazyRoot.php
@@ -25,6 +25,7 @@ namespace OC\Files\Node;
use OCP\Files\Cache\ICacheEntry;
use OCP\Files\IRootFolder;
use OCP\Files\Mount\IMountPoint;
+use OCP\Files\Node;
use OCP\Files\Node as INode;
/**
@@ -56,6 +57,10 @@ class LazyRoot extends LazyFolder implements IRootFolder {
return $this->__call(__FUNCTION__, func_get_args());
}
+ public function getFirstNodeByIdInPath(int $id, string $path): ?Node {
+ return $this->__call(__FUNCTION__, func_get_args());
+ }
+
public function getNodeFromCacheEntryAndMount(ICacheEntry $cacheEntry, IMountPoint $mountPoint): INode {
return $this->getRootFolder()->getNodeFromCacheEntryAndMount($cacheEntry, $mountPoint);
}
diff --git a/lib/private/Files/Node/LazyUserFolder.php b/lib/private/Files/Node/LazyUserFolder.php
index 917ab80f366..3cb840ccb6d 100644
--- a/lib/private/Files/Node/LazyUserFolder.php
+++ b/lib/private/Files/Node/LazyUserFolder.php
@@ -68,18 +68,6 @@ class LazyUserFolder extends LazyFolder {
]);
}
- public function get($path) {
- return $this->getRootFolder()->get('/' . $this->user->getUID() . '/files/' . ltrim($path, '/'));
- }
-
- /**
- * @param int $id
- * @return \OCP\Files\Node[]
- */
- public function getById($id) {
- return $this->getRootFolder()->getByIdInPath((int)$id, $this->getPath());
- }
-
public function getMountPoint() {
if ($this->folder !== null) {
return $this->folder->getMountPoint();
diff --git a/lib/private/Files/Node/NonExistingFolder.php b/lib/private/Files/Node/NonExistingFolder.php
index 34621b18f19..af0ad002f24 100644
--- a/lib/private/Files/Node/NonExistingFolder.php
+++ b/lib/private/Files/Node/NonExistingFolder.php
@@ -162,6 +162,10 @@ class NonExistingFolder extends Folder {
throw new NotFoundException();
}
+ public function getFirstNodeById(int $id): ?\OCP\Files\Node {
+ throw new NotFoundException();
+ }
+
public function getFreeSpace() {
throw new NotFoundException();
}
diff --git a/lib/private/Files/Node/Root.php b/lib/private/Files/Node/Root.php
index 9bfb610199b..71bc7a6da6b 100644
--- a/lib/private/Files/Node/Root.php
+++ b/lib/private/Files/Node/Root.php
@@ -49,6 +49,8 @@ use OCP\Files\Mount\IMountPoint;
use OCP\Files\Node as INode;
use OCP\Files\NotFoundException;
use OCP\Files\NotPermittedException;
+use OCP\ICache;
+use OCP\ICacheFactory;
use OCP\IUser;
use OCP\IUserManager;
use Psr\Log\LoggerInterface;
@@ -81,6 +83,7 @@ class Root extends Folder implements IRootFolder {
private LoggerInterface $logger;
private IUserManager $userManager;
private IEventDispatcher $eventDispatcher;
+ private ICache $pathByIdCache;
/**
* @param Manager $manager
@@ -94,7 +97,8 @@ class Root extends Folder implements IRootFolder {
IUserMountCache $userMountCache,
LoggerInterface $logger,
IUserManager $userManager,
- IEventDispatcher $eventDispatcher
+ IEventDispatcher $eventDispatcher,
+ ICacheFactory $cacheFactory,
) {
parent::__construct($this, $view, '');
$this->mountManager = $manager;
@@ -107,6 +111,7 @@ class Root extends Folder implements IRootFolder {
$eventDispatcher->addListener(FilesystemTornDownEvent::class, function () {
$this->userFolderCache = new CappedMemoryCache();
});
+ $this->pathByIdCache = $cacheFactory->createLocal('path-by-id');
}
/**
@@ -405,6 +410,31 @@ class Root extends Folder implements IRootFolder {
return $this->userMountCache;
}
+ public function getFirstNodeByIdInPath(int $id, string $path): ?INode {
+ // scope the cache by user, so we don't return nodes for different users
+ if ($this->user) {
+ $cachedPath = $this->pathByIdCache->get($this->user->getUID() . '::' . $id);
+ if ($cachedPath && str_starts_with($path, $cachedPath)) {
+ // getting the node by path is significantly cheaper than finding it by id
+ $node = $this->get($cachedPath);
+ // by validating that the cached path still has the requested fileid we can work around the need to invalidate the cached path
+ // if the cached path is invalid or a different file now we fall back to the uncached logic
+ if ($node && $node->getId() === $id) {
+ return $node;
+ }
+ }
+ }
+ $node = current($this->getByIdInPath($id, $path));
+ if (!$node) {
+ return null;
+ }
+
+ if ($this->user) {
+ $this->pathByIdCache->set($this->user->getUID() . '::' . $id, $node->getPath());
+ }
+ return $node;
+ }
+
/**
* @param int $id
* @return Node[]
diff --git a/lib/private/FilesMetadata/Job/UpdateSingleMetadata.php b/lib/private/FilesMetadata/Job/UpdateSingleMetadata.php
index d18c8aa3680..3a3b35ce205 100644
--- a/lib/private/FilesMetadata/Job/UpdateSingleMetadata.php
+++ b/lib/private/FilesMetadata/Job/UpdateSingleMetadata.php
@@ -55,10 +55,9 @@ class UpdateSingleMetadata extends QueuedJob {
[$userId, $fileId] = $argument;
try {
- $node = $this->rootFolder->getUserFolder($userId)->getById($fileId);
- if (count($node) > 0) {
- $file = array_shift($node);
- $this->filesMetadataManager->refreshMetadata($file, IFilesMetadataManager::PROCESS_BACKGROUND);
+ $node = $this->rootFolder->getUserFolder($userId)->getFirstNodeById($fileId);
+ if ($node) {
+ $this->filesMetadataManager->refreshMetadata($node, IFilesMetadataManager::PROCESS_BACKGROUND);
}
} catch (\Exception $e) {
$this->logger->warning('issue while running UpdateSingleMetadata', ['exception' => $e, 'userId' => $userId, 'fileId' => $fileId]);
diff --git a/lib/private/Server.php b/lib/private/Server.php
index df267839160..40c226bdf81 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -450,14 +450,17 @@ class Server extends ServerContainer implements IServerContainer {
$this->registerService('RootFolder', function (ContainerInterface $c) {
$manager = \OC\Files\Filesystem::getMountManager();
$view = new View();
+ /** @var IUserSession $userSession */
+ $userSession = $c->get(IUserSession::class);
$root = new Root(
$manager,
$view,
- null,
+ $userSession->getUser(),
$c->get(IUserMountCache::class),
$this->get(LoggerInterface::class),
$this->get(IUserManager::class),
$this->get(IEventDispatcher::class),
+ $this->get(ICacheFactory::class),
);
$previewConnector = new \OC\Preview\WatcherConnector(
diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php
index 53f88cf14ce..c1abaff2ec0 100644
--- a/lib/private/Share20/Manager.php
+++ b/lib/private/Share20/Manager.php
@@ -311,8 +311,7 @@ class Manager implements IManager {
$mount = $userMount->getMountPoint();
// When it's a reshare use the parent share permissions as maximum
$userMountPointId = $mount->getStorageRootId();
- $userMountPoints = $userFolder->getById($userMountPointId);
- $userMountPoint = array_shift($userMountPoints);
+ $userMountPoint = $userFolder->getFirstNodeById($userMountPointId);
if ($userMountPoint === null) {
throw new GenericShareException('Could not get proper user mount for ' . $userMountPointId . '. Failing since else the next calls are called with null');
@@ -1723,8 +1722,7 @@ class Manager implements IManager {
//Get node for the owner and correct the owner in case of external storage
$userFolder = $this->rootFolder->getUserFolder($owner);
if ($path->getId() !== $userFolder->getId() && !$userFolder->isSubNode($path)) {
- $nodes = $userFolder->getById($path->getId());
- $path = array_shift($nodes);
+ $path = $userFolder->getFirstNodeById($path->getId());
if ($path === null || $path->getOwner() === null) {
return [];
}
diff --git a/lib/private/Share20/Share.php b/lib/private/Share20/Share.php
index c80d332e9db..19b36cb60e8 100644
--- a/lib/private/Share20/Share.php
+++ b/lib/private/Share20/Share.php
@@ -188,12 +188,12 @@ class Share implements IShare {
$userFolder = $this->rootFolder->getUserFolder($this->sharedBy);
}
- $nodes = $userFolder->getById($this->fileId);
- if (empty($nodes)) {
+ $node = $userFolder->getFirstNodeById($this->fileId);
+ if (!$node) {
throw new NotFoundException('Node for share not found, fileid: ' . $this->fileId);
}
- $this->node = $nodes[0];
+ $this->node = $node;
}
return $this->node;
@@ -211,12 +211,16 @@ class Share implements IShare {
/**
* @inheritdoc
*/
- public function getNodeId() {
+ public function getNodeId(): int {
if ($this->fileId === null) {
$this->fileId = $this->getNode()->getId();
}
- return $this->fileId;
+ if ($this->fileId === null) {
+ throw new NotFoundException("Share source not found");
+ } else {
+ return $this->fileId;
+ }
}
/**
diff --git a/lib/private/SpeechToText/TranscriptionJob.php b/lib/private/SpeechToText/TranscriptionJob.php
index 8921d52ecd1..083cd129657 100644
--- a/lib/private/SpeechToText/TranscriptionJob.php
+++ b/lib/private/SpeechToText/TranscriptionJob.php
@@ -65,7 +65,7 @@ class TranscriptionJob extends QueuedJob {
try {
\OC_Util::setupFS($owner);
$userFolder = $this->rootFolder->getUserFolder($owner);
- $file = current($userFolder->getById($fileId));
+ $file = $userFolder->getFirstNodeById($fileId);
if (!($file instanceof File)) {
$this->logger->warning('Transcription of file ' . $fileId . ' failed. The file could not be found');
$this->eventDispatcher->dispatchTyped(