Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rework search api to allow searching on multiple caches at once #26874

Merged
merged 7 commits into from
Jun 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 16 additions & 11 deletions apps/files_sharing/lib/Cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,13 @@

use OC\Files\Cache\FailedCache;
use OC\Files\Cache\Wrapper\CacheJail;
use OC\Files\Search\SearchBinaryOperator;
use OC\Files\Search\SearchComparison;
use OC\Files\Storage\Wrapper\Jail;
use OCP\Files\Cache\ICacheEntry;
use OCP\Files\Search\ISearchBinaryOperator;
use OCP\Files\Search\ISearchComparison;
use OCP\Files\Search\ISearchOperator;
use OCP\Files\StorageNotAvailableException;

/**
Expand Down Expand Up @@ -181,19 +186,19 @@ public function clear() {
// Not a valid action for Shared Cache
}

public function search($pattern) {
// Do the normal search on the whole storage for non files
public function getQueryFilterForStorage(): ISearchOperator {
// Do the normal jail behavior for non files
if ($this->storage->getItemType() !== 'file') {
return parent::search($pattern);
return parent::getQueryFilterForStorage();
}

$regex = '/' . str_replace('%', '.*', $pattern) . '/i';

$data = $this->get('');
if (preg_match($regex, $data->getName()) === 1) {
return [$data];
}

return [];
// for single file shares we don't need to do the LIKE
return new SearchBinaryOperator(
ISearchBinaryOperator::OPERATOR_AND,
[
\OC\Files\Cache\Cache::getQueryFilterForStorage(),
new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'path', $this->getGetUnjailedRoot()),
]
);
}
}
5 changes: 2 additions & 3 deletions apps/files_trashbin/lib/Trashbin.php
Original file line number Diff line number Diff line change
Expand Up @@ -988,8 +988,7 @@ private static function getVersionsFromTrash($filename, $timestamp, $user) {
$query = new CacheQueryBuilder(
\OC::$server->getDatabaseConnection(),
\OC::$server->getSystemConfig(),
\OC::$server->getLogger(),
$cache
\OC::$server->getLogger()
);
$normalizedParentPath = ltrim(Filesystem::normalizePath(dirname('files_trashbin/versions/'. $filename)), '/');
$parentId = $cache->getId($normalizedParentPath);
Expand All @@ -998,7 +997,7 @@ private static function getVersionsFromTrash($filename, $timestamp, $user) {
}

$query->selectFileCache()
->whereStorageId()
->whereStorageId($cache->getNumericStorageId())
->andWhere($query->expr()->eq('parent', $query->createNamedParameter($parentId)))
->andWhere($query->expr()->iLike('name', $query->createNamedParameter($pattern)));

Expand Down
1 change: 1 addition & 0 deletions lib/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -1061,6 +1061,7 @@
'OC\\Files\\Cache\\Propagator' => $baseDir . '/lib/private/Files/Cache/Propagator.php',
'OC\\Files\\Cache\\QuerySearchHelper' => $baseDir . '/lib/private/Files/Cache/QuerySearchHelper.php',
'OC\\Files\\Cache\\Scanner' => $baseDir . '/lib/private/Files/Cache/Scanner.php',
'OC\\Files\\Cache\\SearchBuilder' => $baseDir . '/lib/private/Files/Cache/SearchBuilder.php',
'OC\\Files\\Cache\\Storage' => $baseDir . '/lib/private/Files/Cache/Storage.php',
'OC\\Files\\Cache\\StorageGlobal' => $baseDir . '/lib/private/Files/Cache/StorageGlobal.php',
'OC\\Files\\Cache\\Updater' => $baseDir . '/lib/private/Files/Cache/Updater.php',
Expand Down
1 change: 1 addition & 0 deletions lib/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -1090,6 +1090,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Files\\Cache\\Propagator' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/Propagator.php',
'OC\\Files\\Cache\\QuerySearchHelper' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/QuerySearchHelper.php',
'OC\\Files\\Cache\\Scanner' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/Scanner.php',
'OC\\Files\\Cache\\SearchBuilder' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/SearchBuilder.php',
'OC\\Files\\Cache\\Storage' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/Storage.php',
'OC\\Files\\Cache\\StorageGlobal' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/StorageGlobal.php',
'OC\\Files\\Cache\\Updater' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/Updater.php',
Expand Down
136 changes: 33 additions & 103 deletions lib/private/Files/Cache/Cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
namespace OC\Files\Cache;

use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use OCP\DB\IResult;
use OC\Files\Search\SearchComparison;
use OC\Files\Search\SearchQuery;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\Cache\CacheEntryInsertedEvent;
Expand All @@ -52,6 +53,8 @@
use OCP\Files\Cache\ICacheEntry;
use OCP\Files\FileInfo;
use OCP\Files\IMimeTypeLoader;
use OCP\Files\Search\ISearchComparison;
use OCP\Files\Search\ISearchOperator;
use OCP\Files\Search\ISearchQuery;
use OCP\Files\Storage\IStorage;
use OCP\IDBConnection;
Expand Down Expand Up @@ -118,15 +121,14 @@ public function __construct(IStorage $storage) {
$this->mimetypeLoader = \OC::$server->getMimeTypeLoader();
$this->connection = \OC::$server->getDatabaseConnection();
$this->eventDispatcher = \OC::$server->get(IEventDispatcher::class);
$this->querySearchHelper = new QuerySearchHelper($this->mimetypeLoader);
$this->querySearchHelper = \OC::$server->query(QuerySearchHelper::class);
}

protected function getQueryBuilder() {
return new CacheQueryBuilder(
$this->connection,
\OC::$server->getSystemConfig(),
\OC::$server->getLogger(),
$this
\OC::$server->getLogger()
);
}

Expand All @@ -153,7 +155,7 @@ public function get($file) {
// normalize file
$file = $this->normalize($file);

$query->whereStorageId()
$query->whereStorageId($this->getNumericStorageId())
->wherePath($file);
} else { //file id
$query->whereFileId($file);
Expand Down Expand Up @@ -482,7 +484,7 @@ public function getId($file) {
$query = $this->getQueryBuilder();
$query->select('fileid')
->from('filecache')
->whereStorageId()
->whereStorageId($this->getNumericStorageId())
->wherePath($file);

$result = $query->execute();
Expand Down Expand Up @@ -718,7 +720,7 @@ public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) {
public function clear() {
$query = $this->getQueryBuilder();
$query->delete('filecache')
->whereStorageId();
->whereStorageId($this->getNumericStorageId());
$query->execute();

$query = $this->connection->getQueryBuilder();
Expand Down Expand Up @@ -746,7 +748,7 @@ public function getStatus($file) {
$query = $this->getQueryBuilder();
$query->select('size')
->from('filecache')
->whereStorageId()
->whereStorageId($this->getNumericStorageId())
->wherePath($file);

$result = $query->execute();
Expand Down Expand Up @@ -775,37 +777,8 @@ public function getStatus($file) {
* @return ICacheEntry[] an array of cache entries where the name matches the search pattern
*/
public function search($pattern) {
// normalize pattern
$pattern = $this->normalize($pattern);

if ($pattern === '%%') {
return [];
}

$query = $this->getQueryBuilder();
$query->selectFileCache()
->whereStorageId()
->andWhere($query->expr()->iLike('name', $query->createNamedParameter($pattern)));

$result = $query->execute();
$files = $result->fetchAll();
$result->closeCursor();

return array_map(function (array $data) {
return self::cacheEntryFromData($data, $this->mimetypeLoader);
}, $files);
}

/**
* @param IResult $result
* @return CacheEntry[]
*/
private function searchResultToCacheEntries(IResult $result): array {
$files = $result->fetchAll();

return array_map(function (array $data) {
return self::cacheEntryFromData($data, $this->mimetypeLoader);
}, $files);
$operator = new SearchComparison(ISearchComparison::COMPARE_LIKE, 'name', $pattern);
return $this->searchQuery(new SearchQuery($operator, 0, 0, [], null));
}

/**
Expand All @@ -816,71 +789,16 @@ private function searchResultToCacheEntries(IResult $result): array {
* @return ICacheEntry[] an array of cache entries where the mimetype matches the search
*/
public function searchByMime($mimetype) {
$mimeId = $this->mimetypeLoader->getId($mimetype);

$query = $this->getQueryBuilder();
$query->selectFileCache()
->whereStorageId();

if (strpos($mimetype, '/')) {
$query->andWhere($query->expr()->eq('mimetype', $query->createNamedParameter($mimeId, IQueryBuilder::PARAM_INT)));
if (strpos($mimetype, '/') === false) {
$operator = new SearchComparison(ISearchComparison::COMPARE_LIKE, 'mimetype', $mimetype . '/%');
} else {
$query->andWhere($query->expr()->eq('mimepart', $query->createNamedParameter($mimeId, IQueryBuilder::PARAM_INT)));
$operator = new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'mimetype', $mimetype);
}

$result = $query->execute();
$files = $result->fetchAll();
$result->closeCursor();

return array_map(function (array $data) {
return self::cacheEntryFromData($data, $this->mimetypeLoader);
}, $files);
return $this->searchQuery(new SearchQuery($operator, 0, 0, [], null));
}

public function searchQuery(ISearchQuery $searchQuery) {
$builder = $this->getQueryBuilder();

$query = $builder->selectFileCache('file');

$query->whereStorageId();

if ($this->querySearchHelper->shouldJoinTags($searchQuery->getSearchOperation())) {
$user = $searchQuery->getUser();
if ($user === null) {
throw new \InvalidArgumentException("Searching by tag requires the user to be set in the query");
}
$query
->innerJoin('file', 'vcategory_to_object', 'tagmap', $builder->expr()->eq('file.fileid', 'tagmap.objid'))
->innerJoin('tagmap', 'vcategory', 'tag', $builder->expr()->andX(
$builder->expr()->eq('tagmap.type', 'tag.type'),
$builder->expr()->eq('tagmap.categoryid', 'tag.id')
))
->andWhere($builder->expr()->eq('tag.type', $builder->createNamedParameter('files')))
->andWhere($builder->expr()->eq('tag.uid', $builder->createNamedParameter($user->getUID())));
}

$searchExpr = $this->querySearchHelper->searchOperatorToDBExpr($builder, $searchQuery->getSearchOperation());
if ($searchExpr) {
$query->andWhere($searchExpr);
}

if ($searchQuery->limitToHome() && ($this instanceof HomeCache)) {
$query->andWhere($builder->expr()->like('path', $query->expr()->literal('files/%')));
}

$this->querySearchHelper->addSearchOrdersToQuery($query, $searchQuery->getOrder());

if ($searchQuery->getLimit()) {
$query->setMaxResults($searchQuery->getLimit());
}
if ($searchQuery->getOffset()) {
$query->setFirstResult($searchQuery->getOffset());
}

$result = $query->execute();
$cacheEntries = $this->searchResultToCacheEntries($result);
$result->closeCursor();
return $cacheEntries;
return current($this->querySearchHelper->searchInCaches($searchQuery, [$this]));
}

/**
Expand Down Expand Up @@ -949,7 +867,7 @@ public function calculateFolderSize($path, $entry = null) {
$query->selectAlias($query->func()->sum('size'), 'f1')
->selectAlias($query->func()->min('size'), 'f2')
->from('filecache')
->whereStorageId()
->whereStorageId($this->getNumericStorageId())
->whereParent($id);

$result = $query->execute();
Expand Down Expand Up @@ -982,7 +900,7 @@ public function getAll() {
$query = $this->getQueryBuilder();
$query->select('fileid')
->from('filecache')
->whereStorageId();
->whereStorageId($this->getNumericStorageId());

$result = $query->execute();
$files = $result->fetchAll(\PDO::FETCH_COLUMN);
Expand All @@ -1006,7 +924,7 @@ public function getIncomplete() {
$query = $this->getQueryBuilder();
$query->select('path')
->from('filecache')
->whereStorageId()
->whereStorageId($this->getNumericStorageId())
->andWhere($query->expr()->lt('size', $query->createNamedParameter(0, IQueryBuilder::PARAM_INT)))
->orderBy('fileid', 'DESC')
->setMaxResults(1);
Expand All @@ -1028,7 +946,7 @@ public function getPathById($id) {
$query = $this->getQueryBuilder();
$query->select('path')
->from('filecache')
->whereStorageId()
->whereStorageId($this->getNumericStorageId())
->whereFileId($id);

$result = $query->execute();
Expand Down Expand Up @@ -1127,4 +1045,16 @@ private function cacheEntryToArray(ICacheEntry $entry): array {
'metadata_etag' => $entry->getMetadataEtag(),
];
}

public function getQueryFilterForStorage(): ISearchOperator {
return new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'storage', $this->getNumericStorageId());
}

public function getCacheEntryFromSearchResult(ICacheEntry $rawEntry): ?ICacheEntry {
if ($rawEntry->getStorageId() === $this->getNumericStorageId()) {
return $rawEntry;
} else {
return null;
}
}
}
4 changes: 4 additions & 0 deletions lib/private/Files/Cache/CacheEntry.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,8 @@ public function getUploadTime(): ?int {
public function getData() {
return $this->data;
}

public function __clone() {
$this->data = array_merge([], $this->data);
}
}
9 changes: 3 additions & 6 deletions lib/private/Files/Cache/CacheQueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,10 @@
* Query builder with commonly used helpers for filecache queries
*/
class CacheQueryBuilder extends QueryBuilder {
private $cache;
private $alias = null;

public function __construct(IDBConnection $connection, SystemConfig $systemConfig, ILogger $logger, Cache $cache) {
public function __construct(IDBConnection $connection, SystemConfig $systemConfig, ILogger $logger) {
parent::__construct($connection, $systemConfig, $logger);

$this->cache = $cache;
}

public function selectFileCache(string $alias = null) {
Expand All @@ -56,8 +53,8 @@ public function selectFileCache(string $alias = null) {
return $this;
}

public function whereStorageId() {
$this->andWhere($this->expr()->eq('storage', $this->createNamedParameter($this->cache->getNumericStorageId(), IQueryBuilder::PARAM_INT)));
public function whereStorageId(int $storageId) {
$this->andWhere($this->expr()->eq('storage', $this->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));

return $this;
}
Expand Down
11 changes: 11 additions & 0 deletions lib/private/Files/Cache/FailedCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@
*/
namespace OC\Files\Cache;

use OC\Files\Search\SearchComparison;
use OCP\Constants;
use OCP\Files\Cache\ICache;
use OCP\Files\Cache\ICacheEntry;
use OCP\Files\Search\ISearchComparison;
use OCP\Files\Search\ISearchOperator;
use OCP\Files\Search\ISearchQuery;

/**
Expand Down Expand Up @@ -138,4 +141,12 @@ public function normalize($path) {
public function copyFromCache(ICache $sourceCache, ICacheEntry $sourceEntry, string $targetPath): int {
throw new \Exception("Invalid cache");
}

public function getQueryFilterForStorage(): ISearchOperator {
return new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'storage', -1);
}

public function getCacheEntryFromSearchResult(ICacheEntry $rawEntry): ?ICacheEntry {
return null;
}
}
Loading