Commit 90e821f2 authored by Stefan Bürk's avatar Stefan Bürk
Browse files

[WIP][BUGFIX] Use independent cache entries per domain for redirect caching

Resolves: #?
Releases: main, 11.5
Change-Id: Id335017cf890dca7c57e892a2561c3555348a668
parent ba2cae54
Pipeline #22363 failed with stages
in 2 minutes and 7 seconds
......@@ -36,7 +36,9 @@ class DataHandlerCacheFlushingHook
public function rebuildRedirectCacheIfNecessary(array $parameters, DataHandler $dataHandler)
{
if (isset($dataHandler->datamap['sys_redirect']) || isset($dataHandler->cmdmap['sys_redirect'])) {
GeneralUtility::makeInstance(RedirectCacheService::class)->rebuild();
// @todo Can we determine which source_hosts to rebuild instead of adding a rebuildAll() method
// to the redirect cache service and rebuild all caches here, which may be not necessary ?
GeneralUtility::makeInstance(RedirectCacheService::class)->rebuildAll();
}
}
}
......@@ -45,11 +45,11 @@ class RedirectCacheService
/**
* Fetches all redirects available to the system, grouped by domain and regexp/nonregexp
*/
public function getRedirects(): array
public function getRedirects(string $sourceHost): array
{
$redirects = $this->cache->get('redirects');
$redirects = $this->cache->get('redirects_'.$sourceHost);
if (!is_array($redirects)) {
$redirects = $this->rebuild();
$redirects = $this->rebuild($sourceHost);
}
return $redirects;
}
......@@ -58,7 +58,7 @@ class RedirectCacheService
* Rebuilds the cache for all redirects, grouped by host as well as by regular expressions and respect_query_parameters.
* Does not include deleted redirects, but includes the ones with dynamic starttime/endtime.
*/
public function rebuild(): array
public function rebuild(string $sourceHost): array
{
$redirects = [];
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_redirect');
......@@ -68,6 +68,9 @@ class RedirectCacheService
$statement = $queryBuilder
->select('*')
->from('sys_redirect')
->where(
$queryBuilder->expr()->eq('source_host', $queryBuilder->createNamedParameter($sourceHost))
)
->executeQuery();
while ($row = $statement->fetchAssociative()) {
$host = $row['source_host'] ?: '*';
......@@ -79,7 +82,25 @@ class RedirectCacheService
$redirects[$host]['flat'][rtrim($row['source_path'], '/') . '/'][$row['uid']] = $row;
}
}
$this->cache->set('redirects', $redirects);
$this->cache->set('redirects_'.$sourceHost, $redirects);
return $redirects;
}
/**
* Rebuild redirect caches for all available source_hosts.
* @todo Check if this method may be removed, if DataHandlerCacheFlushing can rebuild explicitly for source_hosts.
* @internal For internal use only. May vanish at any time without prior deprecation or notice.
*/
public function rebuildAll(): void
{
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_redirect');
$resultSet = $queryBuilder
->select('source_host')
->distinct()
->from('sys_redirect')
->executeQuery();
foreach($resultSet as $row) {
$this->rebuild($row['source_host']);
}
}
}
......@@ -77,11 +77,11 @@ class RedirectService implements LoggerAwareInterface
*/
public function matchRedirect(string $domain, string $path, string $query = ''): ?array
{
$allRedirects = $this->fetchRedirects();
$path = rawurldecode($path);
// Check if the domain matches, or if there is a
// redirect fitting for any domain
foreach ([$domain, '*'] as $domainName) {
$allRedirects = $this->fetchRedirects($domainName);
if (empty($allRedirects[$domainName])) {
continue;
}
......@@ -165,12 +165,12 @@ class RedirectService implements LoggerAwareInterface
}
/**
* Fetches all redirects from the DB and caches them, grouped by the domain
* does NOT take starttime/endtime into account, as it is cached.
* Fetches all redirects from cache, with fallback to rebuild cache from the DB if caches was empty,
* grouped by the domain does NOT take starttime/endtime into account, as it is cached.
*/
protected function fetchRedirects(): array
protected function fetchRedirects(string $sourceHost): array
{
return $this->redirectCacheService->getRedirects();
return $this->redirectCacheService->getRedirects($sourceHost);
}
/**
......
......@@ -113,6 +113,7 @@ class SlugService implements LoggerAwareInterface
public function rebuildSlugsForSlugChange(int $pageId, string $currentSlug, string $newSlug, CorrelationId $correlationId): void
{
$sourceHosts = [];
$currentPageRecord = BackendUtility::getRecord('pages', $pageId);
if ($currentPageRecord === null) {
return;
......@@ -122,13 +123,17 @@ class SlugService implements LoggerAwareInterface
if ($this->autoUpdateSlugs || $this->autoCreateRedirects) {
$this->createCorrelationIds($pageId, $correlationId);
if ($this->autoCreateRedirects) {
$this->createRedirect($currentSlug, $defaultPageId, (int)$currentPageRecord['sys_language_uid'], (int)$pageId);
$this->createRedirect($currentSlug, $defaultPageId, (int)$currentPageRecord['sys_language_uid'], (int)$pageId, $sourceHosts);
}
if ($this->autoUpdateSlugs) {
$this->checkSubPages($currentPageRecord, $currentSlug, $newSlug);
$this->checkSubPages($currentPageRecord, $currentSlug, $newSlug, $sourceHosts);
}
$this->sendNotification();
GeneralUtility::makeInstance(RedirectCacheService::class)->rebuild();
// rebuild caches only for matched source hosts - instead of all
$redirectService = GeneralUtility::makeInstance(RedirectCacheService::class);
foreach($sourceHosts as $sourceHost) {
$redirectService->rebuild($sourceHost);
}
}
}
......@@ -156,7 +161,7 @@ class SlugService implements LoggerAwareInterface
$this->correlationIdSlugUpdate = $correlationId->withAspects(self::CORRELATION_ID_IDENTIFIER, 'slug');
}
protected function createRedirect(string $originalSlug, int $pageId, int $languageId, int $pid): void
protected function createRedirect(string $originalSlug, int $pageId, int $languageId, int $pid, array &$sourceHosts): void
{
$siteLanguage = $this->site->getLanguageById($languageId);
$basePath = rtrim($siteLanguage->getBase()->getPath(), '/');
......@@ -196,9 +201,12 @@ class SlugService implements LoggerAwareInterface
$id = (int)$connection->lastInsertId('sys_redirect');
$record['uid'] = $id;
$this->getRecordHistoryStore()->addRecord('sys_redirect', $id, $record, $this->correlationIdRedirectCreation);
if (!in_array($record['source_host'], $sourceHosts, true)) {
$sourceHosts[] = $record['source_host'];
}
}
protected function checkSubPages(array $currentPageRecord, string $oldSlugOfParentPage, string $newSlugOfParentPage): void
protected function checkSubPages(array $currentPageRecord, string $oldSlugOfParentPage, string $newSlugOfParentPage, array &$sourceHosts): void
{
$languageUid = (int)$currentPageRecord['sys_language_uid'];
// resolveSubPages needs the page id of the default language
......@@ -208,7 +216,7 @@ class SlugService implements LoggerAwareInterface
$newSlug = $this->updateSlug($subPageRecord, $oldSlugOfParentPage, $newSlugOfParentPage);
if ($newSlug !== null && $this->autoCreateRedirects) {
$subPageId = (int)$subPageRecord['sys_language_uid'] === 0 ? (int)$subPageRecord['uid'] : (int)$subPageRecord['l10n_parent'];
$this->createRedirect($subPageRecord['slug'], $subPageId, $languageUid, $pageId);
$this->createRedirect($subPageRecord['slug'], $subPageId, $languageUid, $pageId, $sourceHosts);
}
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment