From b342a239e71302e007fa333ebc0a5cc5b8f7e5fb Mon Sep 17 00:00:00 2001 From: Roeland Jago Douma Date: Wed, 3 Feb 2021 22:33:07 +0100 Subject: [PATCH] Add optional index This will allow apps to register a handler to provide information about optional indexes. Signed-off-by: Roeland Jago Douma --- .../lib/Controller/CheckSetupController.php | 11 ++- core/Command/Db/AddMissingIndices.php | 21 ++++- lib/composer/composer/autoload_classmap.php | 2 + lib/composer/composer/autoload_static.php | 2 + .../Bootstrap/RegistrationContext.php | 32 +++++++ .../Maintenance/OptionalIndexManager.php | 92 +++++++++++++++++++ .../Bootstrap/IRegistrationContext.php | 11 +++ .../Maintenance/IOptionalIndex.php | 72 +++++++++++++++ 8 files changed, 241 insertions(+), 2 deletions(-) create mode 100644 lib/private/AppFramework/Maintenance/OptionalIndexManager.php create mode 100644 lib/public/AppFramework/Maintenance/IOptionalIndex.php 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..f41e923fea 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 additonal ' . $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..625866ff7a 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, @@ -284,6 +295,7 @@ class RegistrationContext { public function registerInitialState(string $appId, string $class): void { $this->initialStates[] = new ServiceRegistration($appId, $class); + } public function registerWellKnown(string $appId, string $class): void { @@ -298,6 +310,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 +331,7 @@ class RegistrationContext { $appId = $registration->getAppId(); $this->logger->error("Error during capability registration of $appId: " . $e->getMessage(), [ 'exception' => $e, + ]); } } @@ -331,6 +348,7 @@ class RegistrationContext { $appId = $registration->getAppId(); $this->logger->error("Error during crash reporter registration of $appId: " . $e->getMessage(), [ 'exception' => $e, + ]); } } @@ -347,6 +365,7 @@ class RegistrationContext { $appId = $panel->getAppId(); $this->logger->error("Error during dashboard registration of $appId: " . $e->getMessage(), [ 'exception' => $e, + ]); } } @@ -364,6 +383,7 @@ class RegistrationContext { $appId = $registration->getAppId(); $this->logger->error("Error during event listener registration of $appId: " . $e->getMessage(), [ 'exception' => $e, + ]); } } @@ -389,6 +409,7 @@ class RegistrationContext { $appId = $registration->getAppId(); $this->logger->error("Error during service registration of $appId: " . $e->getMessage(), [ 'exception' => $e, + ]); } } @@ -405,6 +426,7 @@ class RegistrationContext { $appId = $registration->getAppId(); $this->logger->error("Error during service alias registration of $appId: " . $e->getMessage(), [ 'exception' => $e, + ]); } } @@ -421,6 +443,7 @@ class RegistrationContext { $appId = $registration->getAppId(); $this->logger->error("Error during service alias registration of $appId: " . $e->getMessage(), [ 'exception' => $e, + ]); } } @@ -439,6 +462,7 @@ class RegistrationContext { $appId = $middleware->getAppId(); $this->logger->error("Error during capability registration of $appId: " . $e->getMessage(), [ 'exception' => $e, + ]); } } @@ -486,6 +510,13 @@ class RegistrationContext { return $this->notifierServices; } + /** + * @return ServiceRegistration[] + */ + public function getOptionalIndexes(): array { + return $this->optionalIndexes; + } + /** * @return ServiceRegistration<\OCP\Authentication\TwoFactorAuth\IProvider>[] */ @@ -493,3 +524,4 @@ class RegistrationContext { return $this->twoFactorProviders; } } + 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..6c9d551348 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 * @@ -230,3 +240,4 @@ interface IRegistrationContext { */ public function registerTwoFactorProvider(string $twoFactorProviderClass): void; } + 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; +}