Skip to content

Commit 47a8883

Browse files
juliusknorrbackportbot[bot]
authored andcommitted
perf(dav): Preload dav search with tags/favorites
Signed-off-by: Julius Knorr <[email protected]> [skip ci]
1 parent 213ff32 commit 47a8883

File tree

3 files changed

+51
-13
lines changed

3 files changed

+51
-13
lines changed

apps/dav/lib/Connector/Sabre/TagsPlugin.php

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ public function initialize(\Sabre\DAV\Server $server) {
9898
$this->server = $server;
9999
$this->server->on('propFind', [$this, 'handleGetProperties']);
100100
$this->server->on('propPatch', [$this, 'handleUpdateProperties']);
101+
$this->server->on('preloadProperties', [$this, 'handlePreloadProperties']);
101102
}
102103

103104
/**
@@ -153,6 +154,24 @@ private function getTags($fileId) {
153154
return null;
154155
}
155156

157+
/**
158+
* Prefetches tags for a list of file IDs and caches the results
159+
*
160+
* @param array $fileIds List of file IDs to prefetch tags for
161+
* @return void
162+
*/
163+
private function prefetchTagsForFileIds(array $fileIds) {
164+
$tags = $this->getTagger()->getTagsForObjects($fileIds);
165+
if ($tags === false) {
166+
// the tags API returns false on error...
167+
$tags = [];
168+
}
169+
170+
foreach ($fileIds as $fileId) {
171+
$this->cachedTags[$fileId] = $tags[$fileId] ?? [];
172+
}
173+
}
174+
156175
/**
157176
* Updates the tags of the given file id
158177
*
@@ -207,18 +226,7 @@ public function handleGetProperties(
207226
foreach ($folderContent as $info) {
208227
$fileIds[] = (int) $info->getId();
209228
}
210-
$tags = $this->getTagger()->getTagsForObjects($fileIds);
211-
if ($tags === false) {
212-
// the tags API returns false on error...
213-
$tags = [];
214-
}
215-
216-
$this->cachedTags = $this->cachedTags + $tags;
217-
$emptyFileIds = array_diff($fileIds, array_keys($tags));
218-
// also cache the ones that were not found
219-
foreach ($emptyFileIds as $fileId) {
220-
$this->cachedTags[$fileId] = [];
221-
}
229+
$this->prefetchTagsForFileIds($fileIds);
222230
}
223231

224232
$isFav = null;
@@ -274,4 +282,14 @@ public function handleUpdateProperties($path, PropPatch $propPatch) {
274282
return 200;
275283
});
276284
}
285+
286+
public function handlePreloadProperties(array $nodes, array $requestProperties): void {
287+
if (
288+
!in_array(self::FAVORITE_PROPERTYNAME, $requestProperties, true) &&
289+
!in_array(self::TAGS_PROPERTYNAME, $requestProperties, true)
290+
) {
291+
return;
292+
}
293+
$this->prefetchTagsForFileIds(array_map(fn ($node) => $node->getId(), $nodes));
294+
}
277295
}

apps/dav/lib/Files/FileSearchBackend.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use OCA\DAV\Connector\Sabre\CachingTree;
1616
use OCA\DAV\Connector\Sabre\Directory;
1717
use OCA\DAV\Connector\Sabre\FilesPlugin;
18+
use OCA\DAV\Connector\Sabre\Server;
1819
use OCA\DAV\Connector\Sabre\TagsPlugin;
1920
use OCP\Files\Cache\ICacheEntry;
2021
use OCP\Files\Folder;
@@ -44,6 +45,7 @@ class FileSearchBackend implements ISearchBackend {
4445
public const OPERATOR_LIMIT = 100;
4546

4647
public function __construct(
48+
private Server $server,
4749
private CachingTree $tree,
4850
private IUser $user,
4951
private IRootFolder $rootFolder,
@@ -133,6 +135,7 @@ private function getPropertyDefinitionsForMetadata(): array {
133135
* @param string[] $requestProperties
134136
*/
135137
public function preloadPropertyFor(array $nodes, array $requestProperties): void {
138+
$this->server->emit('preloadProperties', [$nodes, $requestProperties]);
136139
}
137140

138141
private function getFolderForPath(?string $path = null): Folder {

apps/dav/tests/unit/Files/FileSearchBackendTest.php

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use OCA\DAV\Connector\Sabre\File;
1515
use OCA\DAV\Connector\Sabre\FilesPlugin;
1616
use OCA\DAV\Connector\Sabre\ObjectTree;
17+
use OCA\DAV\Connector\Sabre\Server;
1718
use OCA\DAV\Files\FileSearchBackend;
1819
use OCP\Files\FileInfo;
1920
use OCP\Files\Folder;
@@ -33,6 +34,7 @@
3334
class FileSearchBackendTest extends TestCase {
3435
/** @var ObjectTree|\PHPUnit\Framework\MockObject\MockObject */
3536
private $tree;
37+
private Server&\PHPUnit\Framework\MockObject\MockObject $server;
3638

3739
/** @var IUser */
3840
private $user;
@@ -67,6 +69,8 @@ protected function setUp(): void {
6769
->disableOriginalConstructor()
6870
->getMock();
6971

72+
$this->server = $this->createMock(Server::class);
73+
7074
$this->view = $this->createMock(View::class);
7175

7276
$this->view->expects($this->any())
@@ -97,7 +101,7 @@ protected function setUp(): void {
97101

98102
$filesMetadataManager = $this->createMock(IFilesMetadataManager::class);
99103

100-
$this->search = new FileSearchBackend($this->tree, $this->user, $this->rootFolder, $this->shareManager, $this->view, $filesMetadataManager);
104+
$this->search = new FileSearchBackend($this->server, $this->tree, $this->user, $this->rootFolder, $this->shareManager, $this->view, $filesMetadataManager);
101105
}
102106

103107
public function testSearchFilename(): void {
@@ -421,4 +425,17 @@ public function testSearchOperatorLimit(): void {
421425
$this->expectException(\InvalidArgumentException::class);
422426
$this->search->search($query);
423427
}
428+
429+
public function testPreloadPropertyFor(): void {
430+
$node1 = $this->createMock(File::class);
431+
$node2 = $this->createMock(Directory::class);
432+
$nodes = [$node1, $node2];
433+
$requestProperties = ['{DAV:}getcontenttype', '{DAV:}getlastmodified'];
434+
435+
$this->server->expects($this->once())
436+
->method('emit')
437+
->with('preloadProperties', [$nodes, $requestProperties]);
438+
439+
$this->search->preloadPropertyFor($nodes, $requestProperties);
440+
}
424441
}

0 commit comments

Comments
 (0)