aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorRobin Appelman <robin@icewind.nl>2024-02-16 12:34:07 +0100
committerRobin Appelman <robin@icewind.nl>2024-03-04 13:57:31 +0100
commita9ee278ec6059d164ed2f45b0eb304e940ffd588 (patch)
tree5182ea3e384f7c9f91976570e5eb48fe18fcbef4 /lib
parente7a7b4a40184dc3da2c83e858c820625f660e48e (diff)
downloadnextcloud-server-a9ee278ec6059d164ed2f45b0eb304e940ffd588.tar.gz
nextcloud-server-a9ee278ec6059d164ed2f45b0eb304e940ffd588.zip
perf: cache path by id to speedup getting nodes by id
Signed-off-by: Robin Appelman <robin@icewind.nl>
Diffstat (limited to 'lib')
-rw-r--r--lib/private/Files/Node/Root.php30
-rw-r--r--lib/private/Server.php5
2 files changed, 32 insertions, 3 deletions
diff --git a/lib/private/Files/Node/Root.php b/lib/private/Files/Node/Root.php
index bc76640966e..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');
}
/**
@@ -406,7 +411,28 @@ class Root extends Folder implements IRootFolder {
}
public function getFirstNodeByIdInPath(int $id, string $path): ?INode {
- return current($this->getByIdInPath($id, $path));
+ // 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;
}
/**
diff --git a/lib/private/Server.php b/lib/private/Server.php
index 1aedd7d06ac..c956da4fdd8 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -448,14 +448,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(