From e576d0da68a4a3b00ad8992823fdf37fb39e673d Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 5 May 2021 19:36:41 +0200 Subject: [PATCH] perform file search in a single query Signed-off-by: Robin Appelman --- lib/private/Files/Cache/Cache.php | 2 +- lib/private/Files/Cache/QuerySearchHelper.php | 16 +++-- .../Files/Cache/Wrapper/CacheWrapper.php | 2 +- lib/private/Files/Node/Folder.php | 71 ++++++------------- 4 files changed, 31 insertions(+), 60 deletions(-) diff --git a/lib/private/Files/Cache/Cache.php b/lib/private/Files/Cache/Cache.php index 5bbc66cb81..c2816efbcb 100644 --- a/lib/private/Files/Cache/Cache.php +++ b/lib/private/Files/Cache/Cache.php @@ -803,7 +803,7 @@ class Cache implements ICache { } public function searchQuery(ISearchQuery $searchQuery) { - return $this->querySearchHelper->searchInCaches($searchQuery, [$this]); + return current($this->querySearchHelper->searchInCaches($searchQuery, [$this])); } /** diff --git a/lib/private/Files/Cache/QuerySearchHelper.php b/lib/private/Files/Cache/QuerySearchHelper.php index a4d96d9698..1b2958b905 100644 --- a/lib/private/Files/Cache/QuerySearchHelper.php +++ b/lib/private/Files/Cache/QuerySearchHelper.php @@ -30,6 +30,7 @@ use OC\Files\Search\SearchBinaryOperator; use OC\SystemConfig; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\Files\Cache\ICache; +use OCP\Files\Cache\ICacheEntry; use OCP\Files\IMimeTypeLoader; use OCP\Files\Search\ISearchBinaryOperator; use OCP\Files\Search\ISearchComparison; @@ -255,9 +256,10 @@ class QuerySearchHelper { } /** + * @template T of array-key * @param ISearchQuery $searchQuery - * @param ICache[] $caches - * @return CacheEntry[] + * @param array $caches + * @return array */ public function searchInCaches(ISearchQuery $searchQuery, array $caches): array { // search in multiple caches at once by creating one query in the following format @@ -298,9 +300,9 @@ class QuerySearchHelper { $query->andWhere($searchExpr); } - $storageFilters = array_map(function (ICache $cache) { + $storageFilters = array_values(array_map(function (ICache $cache) { return $cache->getQueryFilterForStorage(); - }, $caches); + }, $caches)); $query->andWhere($this->searchOperatorToDBExpr($builder, new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_OR, $storageFilters))); if ($searchQuery->limitToHome() && ($this instanceof HomeCache)) { @@ -326,12 +328,12 @@ class QuerySearchHelper { $result->closeCursor(); // loop trough all caches for each result to see if the result matches that storage - $results = []; + $results = array_fill_keys(array_keys($caches), []); foreach ($rawEntries as $rawEntry) { - foreach ($caches as $cache) { + foreach ($caches as $cacheKey => $cache) { $entry = $cache->getCacheEntryFromSearchResult($rawEntry); if ($entry) { - $results[] = $entry; + $results[$cacheKey][] = $entry; } } } diff --git a/lib/private/Files/Cache/Wrapper/CacheWrapper.php b/lib/private/Files/Cache/Wrapper/CacheWrapper.php index bc6ca1d751..6da2062cde 100644 --- a/lib/private/Files/Cache/Wrapper/CacheWrapper.php +++ b/lib/private/Files/Cache/Wrapper/CacheWrapper.php @@ -227,7 +227,7 @@ class CacheWrapper extends Cache { } public function searchQuery(ISearchQuery $searchQuery) { - return $this->querySearchHelper->searchInCaches($searchQuery, [$this]); + return current($this->querySearchHelper->searchInCaches($searchQuery, [$this])); } /** diff --git a/lib/private/Files/Node/Folder.php b/lib/private/Files/Node/Folder.php index f77c90b65a..cb32eddac3 100644 --- a/lib/private/Files/Node/Folder.php +++ b/lib/private/Files/Node/Folder.php @@ -31,6 +31,10 @@ namespace OC\Files\Node; +use OC\DB\QueryBuilder\Literal; +use OC\Files\Cache\QuerySearchHelper; +use OC\Files\Search\SearchBinaryOperator; +use OC\Files\Cache\Wrapper\CacheJail; use OC\Files\Search\SearchBinaryOperator; use OC\Files\Search\SearchComparison; use OC\Files\Search\SearchOrder; @@ -253,69 +257,34 @@ class Folder extends Node implements \OCP\Files\Folder { $mount = $this->root->getMount($this->path); $storage = $mount->getStorage(); $internalPath = $mount->getInternalPath($this->path); - $internalPath = rtrim($internalPath, '/'); - if ($internalPath !== '') { - $internalPath = $internalPath . '/'; - } - $subQueryLimit = $query->getLimit() > 0 ? $query->getLimit() + $query->getOffset() : 0; - $rootQuery = new SearchQuery( - new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_AND, [ - new SearchComparison(ISearchComparison::COMPARE_LIKE, 'path', $internalPath . '%'), - $query->getSearchOperation(), - ]), - $subQueryLimit, - 0, - $query->getOrder(), - $query->getUser() - ); - - $files = []; - - $cache = $storage->getCache(''); - - $results = $cache->searchQuery($rootQuery); - foreach ($results as $result) { - $files[] = $this->cacheEntryToFileInfo($mount, '', $internalPath, $result); - } + $caches = ['' => new CacheJail($storage->getCache(''), $internalPath)]; + /** @var array{IMountPoint, string}[] $infoParams */ + $infoParams = [ + '' => [$mount, ''] + ]; if (!$limitToHome) { $mounts = $this->root->getMountsIn($this->path); foreach ($mounts as $mount) { - $subQuery = new SearchQuery( - $query->getSearchOperation(), - $subQueryLimit, - 0, - $query->getOrder(), - $query->getUser() - ); - $storage = $mount->getStorage(); if ($storage) { - $cache = $storage->getCache(''); - $relativeMountPoint = ltrim(substr($mount->getMountPoint(), $rootLength), '/'); - $results = $cache->searchQuery($subQuery); - foreach ($results as $result) { - $files[] = $this->cacheEntryToFileInfo($mount, $relativeMountPoint, '', $result); - } + $caches[$relativeMountPoint] = $storage->getCache(''); + $infoParams[$relativeMountPoint] = [$mount, '']; } } } - $order = $query->getOrder(); - if ($order) { - usort($files, function (FileInfo $a, FileInfo $b) use ($order) { - foreach ($order as $orderField) { - $cmp = $orderField->sortFileInfo($a, $b); - if ($cmp !== 0) { - return $cmp; - } - } - return 0; - }); - } - $files = array_values(array_slice($files, $query->getOffset(), $query->getLimit() > 0 ? $query->getLimit() : null)); + /** @var QuerySearchHelper $searchHelper */ + $searchHelper = \OC::$server->get(QuerySearchHelper::class); + $resultsPerCache = $searchHelper->searchInCaches($query, $caches); + $files = array_merge(...array_map(function(array $results, $relativeMountPoint) use ($infoParams) { + $params = $infoParams[$relativeMountPoint]; + return array_map(function(ICacheEntry $result) use ($relativeMountPoint, $params) { + return $this->cacheEntryToFileInfo($params[0], $relativeMountPoint, $params[1], $result); + }, $results); + }, array_values($resultsPerCache), array_keys($resultsPerCache))); return array_map(function (FileInfo $file) { return $this->createNode($file->getPath(), $file);