When requesting previews, which we don't find in oc_previews, search in IAppData first before creating them. Move the logic from MovepreviewJob to PreviewMigrationService and reuse that in the Preview Generator. At the same time rename MovePreviewJob to PreviewMigrationJob as it is a better name. Signed-off-by: Carl Schwan <carl.schwan@nextcloud.com>pull/55649/head
parent
bd90e7c122
commit
6149168129
@ -0,0 +1,107 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/* |
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH |
||||
* SPDX-FileContributor: Carl Schwan |
||||
* SPDX-License-Identifier: AGPL-3.0-or-later |
||||
*/ |
||||
|
||||
namespace OC\Core\BackgroundJobs; |
||||
|
||||
use OC\Preview\Db\Preview; |
||||
use OC\Preview\PreviewMigrationService; |
||||
use OCP\AppFramework\Utility\ITimeFactory; |
||||
use OCP\BackgroundJob\TimedJob; |
||||
use OCP\DB\IResult; |
||||
use OCP\Files\IRootFolder; |
||||
use OCP\IAppConfig; |
||||
use OCP\IConfig; |
||||
use OCP\IDBConnection; |
||||
use Override; |
||||
|
||||
class PreviewMigrationJob extends TimedJob { |
||||
private string $previewRootPath; |
||||
|
||||
public function __construct( |
||||
ITimeFactory $time, |
||||
private readonly IAppConfig $appConfig, |
||||
private readonly IConfig $config, |
||||
private readonly IDBConnection $connection, |
||||
private readonly IRootFolder $rootFolder, |
||||
private readonly PreviewMigrationService $migrationService, |
||||
) { |
||||
parent::__construct($time); |
||||
|
||||
$this->setTimeSensitivity(self::TIME_INSENSITIVE); |
||||
$this->setInterval(24 * 60 * 60); |
||||
$this->previewRootPath = 'appdata_' . $this->config->getSystemValueString('instanceid') . '/preview/'; |
||||
} |
||||
|
||||
#[Override] |
||||
protected function run(mixed $argument): void { |
||||
if ($this->appConfig->getValueBool('core', 'previewMovedDone')) { |
||||
return; |
||||
} |
||||
|
||||
$startTime = time(); |
||||
while (true) { |
||||
$qb = $this->connection->getQueryBuilder(); |
||||
$qb->select('path') |
||||
->from('filecache') |
||||
// Hierarchical preview folder structure |
||||
->where($qb->expr()->like('path', $qb->createNamedParameter($this->previewRootPath . '%/%/%/%/%/%/%/%/%'))) |
||||
// Legacy flat preview folder structure |
||||
->orWhere($qb->expr()->like('path', $qb->createNamedParameter($this->previewRootPath . '%/%.%'))) |
||||
->hintShardKey('storage', $this->rootFolder->getMountPoint()->getNumericStorageId()) |
||||
->setMaxResults(100); |
||||
|
||||
$result = $qb->executeQuery(); |
||||
$foundPreviews = $this->processQueryResult($result); |
||||
|
||||
if (!$foundPreviews) { |
||||
break; |
||||
} |
||||
|
||||
// Stop if execution time is more than one hour. |
||||
if (time() - $startTime > 3600) { |
||||
return; |
||||
} |
||||
} |
||||
|
||||
$this->appConfig->setValueBool('core', 'previewMovedDone', true); |
||||
} |
||||
|
||||
private function processQueryResult(IResult $result): bool { |
||||
$foundPreview = false; |
||||
$fileIds = []; |
||||
$flatFileIds = []; |
||||
while ($row = $result->fetch()) { |
||||
$pathSplit = explode('/', $row['path']); |
||||
assert(count($pathSplit) >= 2); |
||||
$fileId = (int)$pathSplit[count($pathSplit) - 2]; |
||||
if (count($pathSplit) === 11) { |
||||
// Hierarchical structure |
||||
if (!in_array($fileId, $fileIds)) { |
||||
$fileIds[] = $fileId; |
||||
} |
||||
} else { |
||||
// Flat structure |
||||
if (!in_array($fileId, $flatFileIds)) { |
||||
$flatFileIds[] = $fileId; |
||||
} |
||||
} |
||||
$foundPreview = true; |
||||
} |
||||
|
||||
foreach ($fileIds as $fileId) { |
||||
$this->migrationService->migrateFileId($fileId, flatPath: false); |
||||
} |
||||
|
||||
foreach ($flatFileIds as $fileId) { |
||||
$this->migrationService->migrateFileId($fileId, flatPath: true); |
||||
} |
||||
return $foundPreview; |
||||
} |
||||
} |
||||
Loading…
Reference in new issue