mirror of
https://github.com/nextcloud/server.git
synced 2026-05-19 08:25:56 -04:00
Merge pull request #53773 from nextcloud/backport/53730/stable30
[stable30] perf(dav): Preload dav search with tags/favorites
This commit is contained in:
commit
33805b8d69
4 changed files with 53 additions and 14 deletions
|
|
@ -98,6 +98,7 @@ class TagsPlugin extends \Sabre\DAV\ServerPlugin {
|
|||
$this->server = $server;
|
||||
$this->server->on('propFind', [$this, 'handleGetProperties']);
|
||||
$this->server->on('propPatch', [$this, 'handleUpdateProperties']);
|
||||
$this->server->on('preloadProperties', [$this, 'handlePreloadProperties']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -153,6 +154,24 @@ class TagsPlugin extends \Sabre\DAV\ServerPlugin {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefetches tags for a list of file IDs and caches the results
|
||||
*
|
||||
* @param array $fileIds List of file IDs to prefetch tags for
|
||||
* @return void
|
||||
*/
|
||||
private function prefetchTagsForFileIds(array $fileIds) {
|
||||
$tags = $this->getTagger()->getTagsForObjects($fileIds);
|
||||
if ($tags === false) {
|
||||
// the tags API returns false on error...
|
||||
$tags = [];
|
||||
}
|
||||
|
||||
foreach ($fileIds as $fileId) {
|
||||
$this->cachedTags[$fileId] = $tags[$fileId] ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the tags of the given file id
|
||||
*
|
||||
|
|
@ -203,22 +222,11 @@ class TagsPlugin extends \Sabre\DAV\ServerPlugin {
|
|||
)) {
|
||||
// note: pre-fetching only supported for depth <= 1
|
||||
$folderContent = $node->getChildren();
|
||||
$fileIds[] = (int) $node->getId();
|
||||
$fileIds = [(int) $node->getId()];
|
||||
foreach ($folderContent as $info) {
|
||||
$fileIds[] = (int) $info->getId();
|
||||
}
|
||||
$tags = $this->getTagger()->getTagsForObjects($fileIds);
|
||||
if ($tags === false) {
|
||||
// the tags API returns false on error...
|
||||
$tags = [];
|
||||
}
|
||||
|
||||
$this->cachedTags = $this->cachedTags + $tags;
|
||||
$emptyFileIds = array_diff($fileIds, array_keys($tags));
|
||||
// also cache the ones that were not found
|
||||
foreach ($emptyFileIds as $fileId) {
|
||||
$this->cachedTags[$fileId] = [];
|
||||
}
|
||||
$this->prefetchTagsForFileIds($fileIds);
|
||||
}
|
||||
|
||||
$isFav = null;
|
||||
|
|
@ -274,4 +282,14 @@ class TagsPlugin extends \Sabre\DAV\ServerPlugin {
|
|||
return 200;
|
||||
});
|
||||
}
|
||||
|
||||
public function handlePreloadProperties(array $nodes, array $requestProperties): void {
|
||||
if (
|
||||
!in_array(self::FAVORITE_PROPERTYNAME, $requestProperties, true) &&
|
||||
!in_array(self::TAGS_PROPERTYNAME, $requestProperties, true)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
$this->prefetchTagsForFileIds(array_map(fn ($node) => $node->getId(), $nodes));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use OC\Files\View;
|
|||
use OCA\DAV\Connector\Sabre\CachingTree;
|
||||
use OCA\DAV\Connector\Sabre\Directory;
|
||||
use OCA\DAV\Connector\Sabre\FilesPlugin;
|
||||
use OCA\DAV\Connector\Sabre\Server;
|
||||
use OCA\DAV\Connector\Sabre\TagsPlugin;
|
||||
use OCP\Files\Cache\ICacheEntry;
|
||||
use OCP\Files\Folder;
|
||||
|
|
@ -44,6 +45,7 @@ class FileSearchBackend implements ISearchBackend {
|
|||
public const OPERATOR_LIMIT = 100;
|
||||
|
||||
public function __construct(
|
||||
private Server $server,
|
||||
private CachingTree $tree,
|
||||
private IUser $user,
|
||||
private IRootFolder $rootFolder,
|
||||
|
|
@ -133,6 +135,7 @@ class FileSearchBackend implements ISearchBackend {
|
|||
* @param string[] $requestProperties
|
||||
*/
|
||||
public function preloadPropertyFor(array $nodes, array $requestProperties): void {
|
||||
$this->server->emit('preloadProperties', [$nodes, $requestProperties]);
|
||||
}
|
||||
|
||||
private function getFolderForPath(?string $path = null): Folder {
|
||||
|
|
|
|||
|
|
@ -322,6 +322,7 @@ class Server {
|
|||
\OC::$server->getAppManager()
|
||||
));
|
||||
$lazySearchBackend->setBackend(new \OCA\DAV\Files\FileSearchBackend(
|
||||
$this->server,
|
||||
$this->server->tree,
|
||||
$user,
|
||||
\OC::$server->getRootFolder(),
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ use OCA\DAV\Connector\Sabre\Directory;
|
|||
use OCA\DAV\Connector\Sabre\File;
|
||||
use OCA\DAV\Connector\Sabre\FilesPlugin;
|
||||
use OCA\DAV\Connector\Sabre\ObjectTree;
|
||||
use OCA\DAV\Connector\Sabre\Server;
|
||||
use OCA\DAV\Files\FileSearchBackend;
|
||||
use OCP\Files\FileInfo;
|
||||
use OCP\Files\Folder;
|
||||
|
|
@ -33,6 +34,7 @@ use Test\TestCase;
|
|||
class FileSearchBackendTest extends TestCase {
|
||||
/** @var ObjectTree|\PHPUnit\Framework\MockObject\MockObject */
|
||||
private $tree;
|
||||
private Server&\PHPUnit\Framework\MockObject\MockObject $server;
|
||||
|
||||
/** @var IUser */
|
||||
private $user;
|
||||
|
|
@ -67,6 +69,8 @@ class FileSearchBackendTest extends TestCase {
|
|||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->server = $this->createMock(Server::class);
|
||||
|
||||
$this->view = $this->createMock(View::class);
|
||||
|
||||
$this->view->expects($this->any())
|
||||
|
|
@ -97,7 +101,7 @@ class FileSearchBackendTest extends TestCase {
|
|||
|
||||
$filesMetadataManager = $this->createMock(IFilesMetadataManager::class);
|
||||
|
||||
$this->search = new FileSearchBackend($this->tree, $this->user, $this->rootFolder, $this->shareManager, $this->view, $filesMetadataManager);
|
||||
$this->search = new FileSearchBackend($this->server, $this->tree, $this->user, $this->rootFolder, $this->shareManager, $this->view, $filesMetadataManager);
|
||||
}
|
||||
|
||||
public function testSearchFilename(): void {
|
||||
|
|
@ -421,4 +425,17 @@ class FileSearchBackendTest extends TestCase {
|
|||
$this->expectException(\InvalidArgumentException::class);
|
||||
$this->search->search($query);
|
||||
}
|
||||
|
||||
public function testPreloadPropertyFor(): void {
|
||||
$node1 = $this->createMock(File::class);
|
||||
$node2 = $this->createMock(Directory::class);
|
||||
$nodes = [$node1, $node2];
|
||||
$requestProperties = ['{DAV:}getcontenttype', '{DAV:}getlastmodified'];
|
||||
|
||||
$this->server->expects($this->once())
|
||||
->method('emit')
|
||||
->with('preloadProperties', [$nodes, $requestProperties]);
|
||||
|
||||
$this->search->preloadPropertyFor($nodes, $requestProperties);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue