Skip to content

Commit

Permalink
Merge pull request #30058 from nextcloud/backport/29735/stable23
Browse files Browse the repository at this point in the history
  • Loading branch information
Pytal authored Dec 2, 2021
2 parents 62bff51 + cc57b2b commit 395e90c
Show file tree
Hide file tree
Showing 12 changed files with 64 additions and 64 deletions.
43 changes: 23 additions & 20 deletions apps/files/lib/BackgroundJob/ScanFiles.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

namespace OCA\Files\BackgroundJob;

use OC\Files\Utils\Scanner;
Expand All @@ -29,7 +30,6 @@
use OCP\IConfig;
use OCP\IDBConnection;
use OCP\ILogger;
use OCP\IUserManager;

/**
* Class ScanFiles is a background job used to run the file scanner over the user
Expand All @@ -40,8 +40,6 @@
class ScanFiles extends \OC\BackgroundJob\TimedJob {
/** @var IConfig */
private $config;
/** @var IUserManager */
private $userManager;
/** @var IEventDispatcher */
private $dispatcher;
/** @var ILogger */
Expand All @@ -53,14 +51,12 @@ class ScanFiles extends \OC\BackgroundJob\TimedJob {

/**
* @param IConfig $config
* @param IUserManager $userManager
* @param IEventDispatcher $dispatcher
* @param ILogger $logger
* @param IDBConnection $connection
*/
public function __construct(
IConfig $config,
IUserManager $userManager,
IEventDispatcher $dispatcher,
ILogger $logger,
IDBConnection $connection
Expand All @@ -69,7 +65,6 @@ public function __construct(
$this->setInterval(60 * 10);

$this->config = $config;
$this->userManager = $userManager;
$this->dispatcher = $dispatcher;
$this->logger = $logger;
$this->connection = $connection;
Expand All @@ -81,10 +76,10 @@ public function __construct(
protected function runScanner(string $user) {
try {
$scanner = new Scanner(
$user,
null,
$this->dispatcher,
$this->logger
$user,
null,
$this->dispatcher,
$this->logger
);
$scanner->backgroundScan('');
} catch (\Exception $e) {
Expand All @@ -94,20 +89,20 @@ protected function runScanner(string $user) {
}

/**
* Find all storages which have unindexed files and return a user for each
* Find a storage which have unindexed files and return a user with access to the storage
*
* @return string[]
* @return string|false
*/
private function getUsersToScan(): array {
private function getUserToScan() {
$query = $this->connection->getQueryBuilder();
$query->select($query->func()->max('user_id'))
$query->select('user_id')
->from('filecache', 'f')
->innerJoin('f', 'mounts', 'm', $query->expr()->eq('storage_id', 'storage'))
->where($query->expr()->lt('size', $query->createNamedParameter(0, IQueryBuilder::PARAM_INT)))
->groupBy('storage_id')
->setMaxResults(self::USERS_PER_SESSION);
->andWhere($query->expr()->gt('parent', $query->createNamedParameter(-1, IQueryBuilder::PARAM_INT)))
->setMaxResults(1);

return $query->execute()->fetchAll(\PDO::FETCH_COLUMN);
return $query->execute()->fetchOne();
}

/**
Expand All @@ -119,10 +114,18 @@ protected function run($argument) {
return;
}

$users = $this->getUsersToScan();

foreach ($users as $user) {
$usersScanned = 0;
$lastUser = '';
$user = $this->getUserToScan();
while ($user && $usersScanned < self::USERS_PER_SESSION && $lastUser !== $user) {
$this->runScanner($user);
$lastUser = $user;
$user = $this->getUserToScan();
$usersScanned += 1;
}

if ($lastUser === $user) {
$this->logger->warning("User $user still has unscanned files after running background scan, background scan might be stopped prematurely");
}
}
}
3 changes: 0 additions & 3 deletions apps/files/tests/BackgroundJob/ScanFilesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
use OCP\IConfig;
use OCP\ILogger;
use OCP\IUser;
use OCP\IUserManager;
use Test\TestCase;
use Test\Traits\MountProviderTrait;
use Test\Traits\UserTrait;
Expand All @@ -54,7 +53,6 @@ protected function setUp(): void {
parent::setUp();

$config = $this->createMock(IConfig::class);
$userManager = $this->createMock(IUserManager::class);
$dispatcher = $this->createMock(IEventDispatcher::class);
$logger = $this->createMock(ILogger::class);
$connection = \OC::$server->getDatabaseConnection();
Expand All @@ -63,7 +61,6 @@ protected function setUp(): void {
$this->scanFiles = $this->getMockBuilder('\OCA\Files\BackgroundJob\ScanFiles')
->setConstructorArgs([
$config,
$userManager,
$dispatcher,
$logger,
$connection,
Expand Down
4 changes: 3 additions & 1 deletion apps/files_sharing/lib/ISharedStorage.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,7 @@
*/
namespace OCA\Files_Sharing;

interface ISharedStorage {
use OCP\Files\Storage\IStorage;

interface ISharedStorage extends IStorage {
}
1 change: 1 addition & 0 deletions apps/files_sharing/lib/Scanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

namespace OCA\Files_Sharing;

use OC\Files\ObjectStore\NoopScanner;
Expand Down
4 changes: 2 additions & 2 deletions apps/workflowengine/lib/Check/FileSystemTags.php
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,8 @@ protected function getFileIds(ICache $cache, $path, $isExternalStorage) {
// TODO: Fix caching inside group folders
// Do not cache file ids inside group folders because multiple file ids might be mapped to
// the same combination of cache id + path.
$shouldCacheFileIds = !$this->storage
->instanceOfStorage(\OCA\GroupFolders\Mount\GroupFolderStorage::class);
/** @psalm-suppress InvalidArgument */
$shouldCacheFileIds = !$this->storage->instanceOfStorage(\OCA\GroupFolders\Mount\GroupFolderStorage::class);
$cacheId = $cache->getNumericStorageId();
if ($shouldCacheFileIds && isset($this->fileIds[$cacheId][$path])) {
return $this->fileIds[$cacheId][$path];
Expand Down
37 changes: 25 additions & 12 deletions lib/private/Files/Cache/Scanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

use Doctrine\DBAL\Exception;
use OC\Files\Filesystem;
use OC\Files\Storage\Wrapper\Jail;
use OC\Files\Storage\Wrapper\Encoding;
use OC\Hooks\BasicEmitter;
use OCP\Files\Cache\IScanner;
Expand Down Expand Up @@ -509,19 +510,31 @@ public static function isPartialFile($file) {
* walk over any folders that are not fully scanned yet and scan them
*/
public function backgroundScan() {
if (!$this->cache->inCache('')) {
$this->runBackgroundScanJob(function () {
$this->scan('', self::SCAN_RECURSIVE, self::REUSE_ETAG);
}, '');
if ($this->storage->instanceOfStorage(Jail::class)) {
// for jail storage wrappers (shares, groupfolders) we run the background scan on the source storage
// this is mainly done because the jail wrapper doesn't implement `getIncomplete` (because it would be inefficient).
//
// Running the scan on the source storage might scan more than "needed", but the unscanned files outside the jail will
// have to be scanned at some point anyway.
$unJailedScanner = $this->storage->getUnjailedStorage()->getScanner();
$unJailedScanner->backgroundScan();
} else {
$lastPath = null;
while (($path = $this->cache->getIncomplete()) !== false && $path !== $lastPath) {
$this->runBackgroundScanJob(function () use ($path) {
$this->scan($path, self::SCAN_RECURSIVE_INCOMPLETE, self::REUSE_ETAG | self::REUSE_SIZE);
}, $path);
// FIXME: this won't proceed with the next item, needs revamping of getIncomplete()
// to make this possible
$lastPath = $path;
if (!$this->cache->inCache('')) {
// if the storage isn't in the cache yet, just scan the root completely
$this->runBackgroundScanJob(function () {
$this->scan('', self::SCAN_RECURSIVE, self::REUSE_ETAG);
}, '');
} else {
$lastPath = null;
// find any path marked as unscanned and run the scanner until no more paths are unscanned (or we get stuck)
while (($path = $this->cache->getIncomplete()) !== false && $path !== $lastPath) {
$this->runBackgroundScanJob(function () use ($path) {
$this->scan($path, self::SCAN_RECURSIVE_INCOMPLETE, self::REUSE_ETAG | self::REUSE_SIZE);
}, $path);
// FIXME: this won't proceed with the next item, needs revamping of getIncomplete()
// to make this possible
$lastPath = $path;
}
}
}
}
Expand Down
4 changes: 0 additions & 4 deletions lib/private/Files/Utils/Scanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,6 @@ public function backgroundScan($dir) {
continue;
}

// don't scan received local shares, these can be scanned when scanning the owner's storage
if ($storage->instanceOfStorage(SharedStorage::class)) {
continue;
}
$scanner = $storage->getScanner();
$this->attachListener($mount);

Expand Down
4 changes: 3 additions & 1 deletion lib/public/Files/IHomeStorage.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@

namespace OCP\Files;

use OCP\Files\Storage\IStorage;

/**
* Interface IHomeStorage
*
* @since 7.0.0
*/
interface IHomeStorage {
interface IHomeStorage extends IStorage {
}
3 changes: 3 additions & 0 deletions lib/public/Files/Storage.php
Original file line number Diff line number Diff line change
Expand Up @@ -368,9 +368,12 @@ public function isLocal();
/**
* Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class
*
* @template T of IStorage
* @param string $class
* @psalm-param class-string<T> $class
* @return bool
* @since 7.0.0
* @psalm-assert-if-true T $this
*/
public function instanceOfStorage($class);

Expand Down
2 changes: 1 addition & 1 deletion lib/public/Files/Storage/IDisableEncryptionStorage.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@
*
* @since 16.0.0
*/
interface IDisableEncryptionStorage {
interface IDisableEncryptionStorage extends IStorage {
}
3 changes: 3 additions & 0 deletions lib/public/Files/Storage/IStorage.php
Original file line number Diff line number Diff line change
Expand Up @@ -356,9 +356,12 @@ public function isLocal();
/**
* Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class
*
* @template T of IStorage
* @param string $class
* @psalm-param class-string<T> $class
* @return bool
* @since 9.0.0
* @psalm-assert-if-true T $this
*/
public function instanceOfStorage($class);

Expand Down
20 changes: 0 additions & 20 deletions tests/lib/Files/Utils/ScannerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
use OC\Files\Filesystem;
use OC\Files\Mount\MountPoint;
use OC\Files\Storage\Temporary;
use OCA\Files_Sharing\SharedStorage;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\Config\IMountProvider;
use OCP\Files\Storage\IStorageFactory;
Expand Down Expand Up @@ -192,25 +191,6 @@ public function testPropagateEtag() {
$this->assertNotEquals($oldRoot->getEtag(), $newRoot->getEtag());
}

public function testSkipLocalShares() {
$sharedStorage = $this->createMock(SharedStorage::class);
$sharedMount = new MountPoint($sharedStorage, '/share');
Filesystem::getMountManager()->addMount($sharedMount);

$sharedStorage->method('instanceOfStorage')
->willReturnCallback(function (string $c) {
return $c === SharedStorage::class;
});
$sharedStorage->expects($this->never())
->method('getScanner');

$scanner = new TestScanner('', \OC::$server->getDatabaseConnection(), $this->createMock(IEventDispatcher::class), \OC::$server->getLogger());
$scanner->addMount($sharedMount);
$scanner->scan('');

$scanner->backgroundScan('');
}

public function testShallow() {
$storage = new Temporary([]);
$mount = new MountPoint($storage, '');
Expand Down

0 comments on commit 395e90c

Please sign in to comment.