diff --git a/apps/settings/lib/Controller/CheckSetupController.php b/apps/settings/lib/Controller/CheckSetupController.php index 89dfc7b617..407834cf9d 100644 --- a/apps/settings/lib/Controller/CheckSetupController.php +++ b/apps/settings/lib/Controller/CheckSetupController.php @@ -110,6 +110,8 @@ class CheckSetupController extends Controller { private $iniGetWrapper; /** @var IDBConnection */ private $connection; + /** @var OC\AppFramework\Maintenance\OptionalIndexManager */ + private $indexManager; public function __construct($AppName, IRequest $request, @@ -126,7 +128,8 @@ class CheckSetupController extends Controller { MemoryInfo $memoryInfo, ISecureRandom $secureRandom, IniGetWrapper $iniGetWrapper, - IDBConnection $connection) { + IDBConnection $connection, + OC\AppFramework\Maintenance\OptionalIndexManager $indexManager) { parent::__construct($AppName, $request); $this->config = $config; $this->clientService = $clientService; @@ -142,6 +145,7 @@ class CheckSetupController extends Controller { $this->secureRandom = $secureRandom; $this->iniGetWrapper = $iniGetWrapper; $this->connection = $connection; + $this->indexManager = $indexManager; } /** @@ -466,6 +470,11 @@ Raw output $event = new GenericEvent($indexInfo); $this->dispatcher->dispatch(IDBConnection::CHECK_MISSING_INDEXES_EVENT, $event); + $indexes = $this->indexManager->getPending(); + foreach ($indexes as $index) { + $indexInfo->addHintForMissingSubject($index->getTable(), $index->getName()); + } + return $indexInfo->getListOfMissingIndexes(); } diff --git a/core/Command/Db/AddMissingIndices.php b/core/Command/Db/AddMissingIndices.php index 1acff55fa4..11155afb4f 100644 --- a/core/Command/Db/AddMissingIndices.php +++ b/core/Command/Db/AddMissingIndices.php @@ -33,6 +33,7 @@ declare(strict_types=1); namespace OC\Core\Command\Db; +use OC\AppFramework\Maintenance\OptionalIndexManager; use OC\DB\Connection; use OC\DB\SchemaWrapper; use OCP\IDBConnection; @@ -58,11 +59,17 @@ class AddMissingIndices extends Command { /** @var EventDispatcherInterface */ private $dispatcher; - public function __construct(Connection $connection, EventDispatcherInterface $dispatcher) { + /** @var OptionalIndexManager */ + private $indexManager; + + public function __construct(Connection $connection, + EventDispatcherInterface $dispatcher, + OptionalIndexManager $indexManager) { parent::__construct(); $this->connection = $connection; $this->dispatcher = $dispatcher; + $this->indexManager = $indexManager; } protected function configure() { @@ -77,9 +84,21 @@ class AddMissingIndices extends Command { // Dispatch event so apps can also update indexes if needed $event = new GenericEvent($output); $this->dispatcher->dispatch(IDBConnection::ADD_MISSING_INDEXES_EVENT, $event); + + $this->addOptionalIndexed($output); + return 0; } + private function addOptionalIndexed(OutputInterface $output): void { + $indexes = $this->indexManager->getPending(); + + foreach ($indexes as $index) { + $output->writeln('Adding additional ' . $index->getName() . ' index to the ' . $index->getTable() . ' this can take some time …'); + $index->add(); + } + } + /** * add missing indices to the share table * diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index f63d74b560..bc951a4009 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -66,6 +66,7 @@ return array( 'OCP\\AppFramework\\Http\\TooManyRequestsResponse' => $baseDir . '/lib/public/AppFramework/Http/TooManyRequestsResponse.php', 'OCP\\AppFramework\\Http\\ZipResponse' => $baseDir . '/lib/public/AppFramework/Http/ZipResponse.php', 'OCP\\AppFramework\\IAppContainer' => $baseDir . '/lib/public/AppFramework/IAppContainer.php', + 'OCP\\AppFramework\\Maintenance\\IOptionalIndex' => $baseDir . '/lib/public/AppFramework/Maintenance/IOptionalIndex.php', 'OCP\\AppFramework\\Middleware' => $baseDir . '/lib/public/AppFramework/Middleware.php', 'OCP\\AppFramework\\OCSController' => $baseDir . '/lib/public/AppFramework/OCSController.php', 'OCP\\AppFramework\\OCS\\OCSBadRequestException' => $baseDir . '/lib/public/AppFramework/OCS/OCSBadRequestException.php', @@ -605,6 +606,7 @@ return array( 'OC\\AppFramework\\Http\\Output' => $baseDir . '/lib/private/AppFramework/Http/Output.php', 'OC\\AppFramework\\Http\\Request' => $baseDir . '/lib/private/AppFramework/Http/Request.php', 'OC\\AppFramework\\Logger' => $baseDir . '/lib/private/AppFramework/Logger.php', + 'OC\\AppFramework\\Maintenance\\OptionalIndexManager' => $baseDir . '/lib/private/AppFramework/Maintenance/OptionalIndexManager.php', 'OC\\AppFramework\\Middleware\\AdditionalScriptsMiddleware' => $baseDir . '/lib/private/AppFramework/Middleware/AdditionalScriptsMiddleware.php', 'OC\\AppFramework\\Middleware\\CompressionMiddleware' => $baseDir . '/lib/private/AppFramework/Middleware/CompressionMiddleware.php', 'OC\\AppFramework\\Middleware\\MiddlewareDispatcher' => $baseDir . '/lib/private/AppFramework/Middleware/MiddlewareDispatcher.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 9c861fd327..2a8ccde579 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -95,6 +95,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OCP\\AppFramework\\Http\\TooManyRequestsResponse' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/TooManyRequestsResponse.php', 'OCP\\AppFramework\\Http\\ZipResponse' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/ZipResponse.php', 'OCP\\AppFramework\\IAppContainer' => __DIR__ . '/../../..' . '/lib/public/AppFramework/IAppContainer.php', + 'OCP\\AppFramework\\Maintenance\\IOptionalIndex' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Maintenance/IOptionalIndex.php', 'OCP\\AppFramework\\Middleware' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Middleware.php', 'OCP\\AppFramework\\OCSController' => __DIR__ . '/../../..' . '/lib/public/AppFramework/OCSController.php', 'OCP\\AppFramework\\OCS\\OCSBadRequestException' => __DIR__ . '/../../..' . '/lib/public/AppFramework/OCS/OCSBadRequestException.php', @@ -634,6 +635,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\AppFramework\\Http\\Output' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Http/Output.php', 'OC\\AppFramework\\Http\\Request' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Http/Request.php', 'OC\\AppFramework\\Logger' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Logger.php', + 'OC\\AppFramework\\Maintenance\\OptionalIndexManager' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Maintenance/OptionalIndexManager.php', 'OC\\AppFramework\\Middleware\\AdditionalScriptsMiddleware' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Middleware/AdditionalScriptsMiddleware.php', 'OC\\AppFramework\\Middleware\\CompressionMiddleware' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Middleware/CompressionMiddleware.php', 'OC\\AppFramework\\Middleware\\MiddlewareDispatcher' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Middleware/MiddlewareDispatcher.php', diff --git a/lib/private/AppFramework/Bootstrap/RegistrationContext.php b/lib/private/AppFramework/Bootstrap/RegistrationContext.php index 0859e606b7..82cb884db1 100644 --- a/lib/private/AppFramework/Bootstrap/RegistrationContext.php +++ b/lib/private/AppFramework/Bootstrap/RegistrationContext.php @@ -34,6 +34,7 @@ use Closure; use OC\Support\CrashReport\Registry; use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IRegistrationContext; +use OCP\AppFramework\Maintenance\IOptionalIndex; use OCP\AppFramework\Middleware; use OCP\AppFramework\Services\InitialStateProvider; use OCP\Authentication\IAlternativeLogin; @@ -94,6 +95,9 @@ class RegistrationContext { /** @var ServiceRegistration[] */ private $notifierServices = []; + /** @var ServiceRegistration */ + private $optionalIndexes = []; + /** @var ServiceRegistration<\OCP\Authentication\TwoFactorAuth\IProvider>[] */ private $twoFactorProviders = []; @@ -221,6 +225,13 @@ class RegistrationContext { ); } + public function registerOptionalIndex(string $class): void { + $this->context->registerOptionalIndex( + $this->appId, + $class + ); + } + public function registerTwoFactorProvider(string $twoFactorProviderClass): void { $this->context->registerTwoFactorProvider( $this->appId, @@ -298,6 +309,10 @@ class RegistrationContext { $this->notifierServices[] = new ServiceRegistration($appId, $class); } + public function registerOptionalIndex(string $appId, string $class): void { + $this->optionalIndexes[] = new ServiceRegistration($appId, $class); + } + public function registerTwoFactorProvider(string $appId, string $class): void { $this->twoFactorProviders[] = new ServiceRegistration($appId, $class); } @@ -315,6 +330,7 @@ class RegistrationContext { $appId = $registration->getAppId(); $this->logger->error("Error during capability registration of $appId: " . $e->getMessage(), [ 'exception' => $e, + ]); } } @@ -331,6 +347,7 @@ class RegistrationContext { $appId = $registration->getAppId(); $this->logger->error("Error during crash reporter registration of $appId: " . $e->getMessage(), [ 'exception' => $e, + ]); } } @@ -347,6 +364,7 @@ class RegistrationContext { $appId = $panel->getAppId(); $this->logger->error("Error during dashboard registration of $appId: " . $e->getMessage(), [ 'exception' => $e, + ]); } } @@ -364,6 +382,7 @@ class RegistrationContext { $appId = $registration->getAppId(); $this->logger->error("Error during event listener registration of $appId: " . $e->getMessage(), [ 'exception' => $e, + ]); } } @@ -389,6 +408,7 @@ class RegistrationContext { $appId = $registration->getAppId(); $this->logger->error("Error during service registration of $appId: " . $e->getMessage(), [ 'exception' => $e, + ]); } } @@ -405,6 +425,7 @@ class RegistrationContext { $appId = $registration->getAppId(); $this->logger->error("Error during service alias registration of $appId: " . $e->getMessage(), [ 'exception' => $e, + ]); } } @@ -421,6 +442,7 @@ class RegistrationContext { $appId = $registration->getAppId(); $this->logger->error("Error during service alias registration of $appId: " . $e->getMessage(), [ 'exception' => $e, + ]); } } @@ -439,6 +461,7 @@ class RegistrationContext { $appId = $middleware->getAppId(); $this->logger->error("Error during capability registration of $appId: " . $e->getMessage(), [ 'exception' => $e, + ]); } } @@ -486,6 +509,13 @@ class RegistrationContext { return $this->notifierServices; } + /** + * @return ServiceRegistration[] + */ + public function getOptionalIndexes(): array { + return $this->optionalIndexes; + } + /** * @return ServiceRegistration<\OCP\Authentication\TwoFactorAuth\IProvider>[] */ diff --git a/lib/private/AppFramework/Maintenance/OptionalIndexManager.php b/lib/private/AppFramework/Maintenance/OptionalIndexManager.php new file mode 100644 index 0000000000..82570046f0 --- /dev/null +++ b/lib/private/AppFramework/Maintenance/OptionalIndexManager.php @@ -0,0 +1,92 @@ + + * + * @author Roeland Jago Douma + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OC\AppFramework\Maintenance; + +use OC\AppFramework\Bootstrap\Coordinator; +use OCP\AppFramework\Maintenance\IOptionalIndex; +use OCP\AppFramework\QueryException; +use OCP\IServerContainer; +use Psr\Log\LoggerInterface; + +class OptionalIndexManager { + + /** @var IServerContainer */ + private $serverContainer; + + /** @var Coordinator */ + private $coordinator; + + /** @var LoggerInterface */ + private $logger; + + /** @var IOptionalIndex[] */ + private $optionalIndexes; + + public function __construct( + IServerContainer $serverContainer, + Coordinator $coordinator, + LoggerInterface $logger + ) { + $this->coordinator = $coordinator; + $this->serverContainer = $serverContainer; + $this->logger = $logger; + } + + /** + * @return IOptionalIndex[] + */ + public function getPending(): array { + if ($this->optionalIndexes !== null) { + return $this->optionalIndexes; + } + + $context = $this->coordinator->getRegistrationContext(); + + foreach ($context->getOptionalIndexes() as $optionalIndex) { + try { + $class = $this->serverContainer->query($optionalIndex->getService()); + } catch (QueryException $e) { + $this->logger->info('Could not initialize ' . $optionalIndex->getService() . ' for ' . $optionalIndex->getAppId()); + continue; + } + + if (!($class instanceof IOptionalIndex)) { + $this->logger->info($optionalIndex->getService() . ' is not an instance of ' . IOptionalIndex::class); + continue; + } + + if ($class->exists()) { + $this->logger->debug($optionalIndex->getService() . ' is already added'); + continue; + } + + $this->optionalIndexes[] = $class; + } + + return $this->optionalIndexes; + } +} diff --git a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php index 4819d4e211..c247040a29 100644 --- a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php +++ b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php @@ -32,6 +32,7 @@ namespace OCP\AppFramework\Bootstrap; use OCP\AppFramework\IAppContainer; use OCP\Authentication\TwoFactorAuth\IProvider; use OCP\Capabilities\ICapability; +use OCP\AppFramework\Maintenance\IOptionalIndex; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Template\ICustomTemplateProvider; use OCP\IContainer; @@ -221,6 +222,15 @@ interface IRegistrationContext { */ public function registerNotifierService(string $notifierClass): void; + /** + * Register an optional index that is able to display and add indexes to the system + * + * @param string $class + * @psalm-param class-string $class + * @since 22.0.0 + */ + public function registerOptionalIndex(string $class): void; + /** * Register a two-factor provider * diff --git a/lib/public/AppFramework/Maintenance/IOptionalIndex.php b/lib/public/AppFramework/Maintenance/IOptionalIndex.php new file mode 100644 index 0000000000..6e3d0a8609 --- /dev/null +++ b/lib/public/AppFramework/Maintenance/IOptionalIndex.php @@ -0,0 +1,72 @@ + + * + * @author Roeland Jago Douma + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCP\AppFramework\Maintenance; + +/** + * @since 22.0.0 + */ +interface IOptionalIndex { + /** + * Get the name of the optional index to display + * + * @since 22.0.0 + * @return string + */ + public function getName(): string; + + /** + * Get the name of the table this operates on + * + * @since 22.0.0 + * @return string + */ + public function getTable(): string; + + /** + * Does the optional index already exist + * + * @since 22.0.0 + * @return bool + */ + public function exists(): bool; + + /** + * Adds the index + * + * @since 22.0.0 + */ + public function add(): void; + + /** + * Get the SQL for the index creation so we can display this for admins + * to run the queries directly on their DB + * + * @since 22.0.0 + * @return string + */ + public function getSQL(): string; +}