From 61d9750b9fc15c6587ed939d37695dae4147451e Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Wed, 3 Jan 2024 13:57:22 +0100 Subject: [PATCH] fix(TreeMapper#getChildren): Add more aggressive per-layer caching Signed-off-by: Marcel Klehr --- lib/Db/TreeMapper.php | 37 +++++++++++++++++++------------- lib/Service/TreeCacheManager.php | 11 +++++++--- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/lib/Db/TreeMapper.php b/lib/Db/TreeMapper.php index 8deef4ef9f..f1d4d584fb 100644 --- a/lib/Db/TreeMapper.php +++ b/lib/Db/TreeMapper.php @@ -805,24 +805,31 @@ public function getChildren(int $folderId, int $layers = 0): array { if ($children !== null) { return $children; } - $qb = $this->getChildrenQuery[self::TYPE_BOOKMARK]; - $this->selectFromType(self::TYPE_BOOKMARK, ['t.index', 't.type'], $qb); - $qb->setParameter('parent_folder', $folderId); - $childBookmarks = $qb->execute()->fetchAll(); - $qb = $this->getChildrenQuery[self::TYPE_FOLDER]; - $this->selectFromType(self::TYPE_FOLDER, ['t.index', 't.type'], $qb); - $qb->setParameter('parent_folder', $folderId); - $childFolders = $qb->execute()->fetchAll(); + $children = $this->treeCache->get(TreeCacheManager::CATEGORY_CHILDREN_LAYER, TreeMapper::TYPE_FOLDER, $folderId); - $qb = $this->getChildrenQuery[self::TYPE_SHARE]; - $this->selectFromType(self::TYPE_SHARE, ['t.index', 't.type'], $qb); - $qb->setParameter('parent_folder', $folderId); - $childShares = $qb->execute()->fetchAll(); + if ($children === null) { + $qb = $this->getChildrenQuery[self::TYPE_BOOKMARK]; + $this->selectFromType(self::TYPE_BOOKMARK, ['t.index', 't.type'], $qb); + $qb->setParameter('parent_folder', $folderId); + $childBookmarks = $qb->execute()->fetchAll(); - $children = array_merge($childBookmarks, $childFolders, $childShares); - $indices = array_column($children, 'index'); - array_multisort($indices, $children); + $qb = $this->getChildrenQuery[self::TYPE_FOLDER]; + $this->selectFromType(self::TYPE_FOLDER, ['t.index', 't.type'], $qb); + $qb->setParameter('parent_folder', $folderId); + $childFolders = $qb->execute()->fetchAll(); + + $qb = $this->getChildrenQuery[self::TYPE_SHARE]; + $this->selectFromType(self::TYPE_SHARE, ['t.index', 't.type'], $qb); + $qb->setParameter('parent_folder', $folderId); + $childShares = $qb->execute()->fetchAll(); + + $children = array_merge($childBookmarks, $childFolders, $childShares); + $indices = array_column($children, 'index'); + array_multisort($indices, $children); + + $this->treeCache->set(TreeCacheManager::CATEGORY_CHILDREN_LAYER, TreeMapper::TYPE_FOLDER, $folderId, $children); + } $children = array_map(function ($child) use ($layers) { $item = ['type' => $child['type'], 'id' => (int)$child['id'], 'title' => $child['title'], 'userId' => $child['user_id']]; diff --git a/lib/Service/TreeCacheManager.php b/lib/Service/TreeCacheManager.php index dfef68af6b..b18989f9bb 100644 --- a/lib/Service/TreeCacheManager.php +++ b/lib/Service/TreeCacheManager.php @@ -30,6 +30,7 @@ class TreeCacheManager implements IEventListener { public const CATEGORY_SUBFOLDERS = 'subFolders'; public const CATEGORY_FOLDERCOUNT = 'folderCount'; public const CATEGORY_CHILDREN = 'children'; + public const CATEGORY_CHILDREN_LAYER = 'children_layer'; public const CATEGORY_CHILDORDER = 'childOrder'; /** @@ -87,6 +88,7 @@ public function __construct(FolderMapper $folderMapper, BookmarkMapper $bookmark $this->caches[self::CATEGORY_SUBFOLDERS] = $cacheFactory->createLocal('bookmarks:'.self::CATEGORY_SUBFOLDERS); $this->caches[self::CATEGORY_FOLDERCOUNT] = $cacheFactory->createLocal('bookmarks:'.self::CATEGORY_FOLDERCOUNT); $this->caches[self::CATEGORY_CHILDREN] = $cacheFactory->createLocal('bookmarks:'.self::CATEGORY_CHILDREN); + $this->caches[self::CATEGORY_CHILDREN_LAYER] = $cacheFactory->createLocal('bookmarks:'.self::CATEGORY_CHILDREN_LAYER); $this->caches[self::CATEGORY_CHILDORDER] = $cacheFactory->createLocal('bookmarks:'.self::CATEGORY_CHILDORDER); $this->appContainer = $appContainer; $this->tagMapper = $tagMapper; @@ -133,9 +135,12 @@ public function set(string $category, string $type, int $id, $data) { * @param string $type * @param int $id */ - public function remove(string $type, int $id): void { + public function remove(string $type, int $id, array $previousFolders): void { $key = $this->getCacheKey($type, $id); - foreach ($this->caches as $cache) { + foreach ($this->caches as $type => $cache) { + if (count($previousFolders) !== 0 && ($type === self::CATEGORY_CHILDORDER || $type === self::CATEGORY_CHILDREN_LAYER)) { + continue; + } $cache->remove($key); } } @@ -149,7 +154,7 @@ public function invalidateFolder(int $folderId, array $previousFolders = []): vo // In case we have run into a folder loop return; } - $this->remove(TreeMapper::TYPE_FOLDER, $folderId); + $this->remove(TreeMapper::TYPE_FOLDER, $folderId, $previousFolders); $previousFolders[] = $folderId; // Invalidate parent