.../Core/EventSubscriber/SmartCacheSubscriber.php | 10 +++---- .../Render/MainContent/SmartCacheHtmlRenderer.php | 34 +++++++++++++++------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/core/lib/Drupal/Core/EventSubscriber/SmartCacheSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/SmartCacheSubscriber.php index 0dc4fc0..93dc74e 100644 --- a/core/lib/Drupal/Core/EventSubscriber/SmartCacheSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/SmartCacheSubscriber.php @@ -12,7 +12,6 @@ use Drupal\Core\Routing\RouteMatchInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; -use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; use Symfony\Component\HttpKernel\KernelEvents; /** @@ -83,23 +82,22 @@ public function onRouteMatch(GetResponseEvent $event) { $this->routeMatch->getRouteName(); - // Smart cache caches per route. - $cid_part_route_match = $this->routeMatch->getRouteName() . serialize($this->routeMatch->getRawParameters()->all()); - // Get the contexts by which the current route's response must be varied. - $cache_contexts = $this->smartContextsCache->get('smartcache:contexts:' . $cid_part_route_match); + $cache_contexts = $this->smartContextsCache->get('smartcache:contexts:' . $this->cacheContexts->convertTokensToKeys(['route'])[0]); // If we already know the contexts by which the current route's response // must be varied, check if a response already is cached for the current // request's values for those contexts, and if so, return early. if ($cache_contexts !== FALSE) { - $cid = 'smartcache:html_render_array:' . $cid_part_route_match . implode(':', $this->cacheContexts->convertTokensToKeys($cache_contexts->data)); + $cid = 'smartcache:html_render_array:' . implode(':', $this->cacheContexts->convertTokensToKeys($cache_contexts->data)); $cached_html = $this->smartHtmlCache->get($cid); if ($cached_html !== FALSE) { $html = $cached_html->data; $event->getRequest() ->attributes ->set('_controller', function() use ($html) { + // Mark the render array, to skip as much in SmartCacheHtmlRenderer. + $html['#smartcache'] = TRUE; // Return the #type => html render array. Let Symfony's HttpKernel // handle the conversion to a Response object via its VIEW event. return $html; diff --git a/core/lib/Drupal/Core/Render/MainContent/SmartCacheHtmlRenderer.php b/core/lib/Drupal/Core/Render/MainContent/SmartCacheHtmlRenderer.php index aab13c6..133499d 100644 --- a/core/lib/Drupal/Core/Render/MainContent/SmartCacheHtmlRenderer.php +++ b/core/lib/Drupal/Core/Render/MainContent/SmartCacheHtmlRenderer.php @@ -89,13 +89,16 @@ public function __construct(TitleResolverInterface $title_resolver, PluginManage * {@inheritdoc} */ protected function finish(array $html) { - $cacheable_html = $html; + // If this is a #type => html render array that comes from SmartCache + // already, then there is no point in + if (isset($html['#smartcache'])) { + return parent::finish($html); + } - // Smart cache caches per route. - $cid_part_route_match = $this->routeMatch->getRouteName() . serialize($this->routeMatch->getRawParameters()->all()); + $cacheable_html = $html; // Get the contexts by which the current route's response must be varied. - $contexts_cid = 'smartcache:contexts:' . $cid_part_route_match; + $contexts_cid = 'smartcache:contexts:' . $this->cacheContexts->convertTokensToKeys(['route'])[0]; $stored_cache_contexts = $this->smartContextsCache->get($contexts_cid); if ($stored_cache_contexts !== FALSE) { $stored_cache_contexts = $stored_cache_contexts->data; @@ -112,16 +115,24 @@ protected function finish(array $html) { // time, collect the total set of cache contexts (to update the stored cache // contexts, if any), and the total set of cache tags (to associate with the // smart_cache_html cache item). - $cache_contexts = []; $html_cache_max_age = Cache::PERMANENT; + // SmartCache always caches per route, so always include that cache context. + $html_cache_contexts = ['route']; $html_cache_tags = []; foreach (Element::children($cacheable_html) as $child) { $cacheable_html[$child] = $this->renderer->getCacheableRenderArray($cacheable_html[$child]); - $cache_contexts = Cache::mergeContexts($cache_contexts, $cacheable_html[$child]['#cache']['contexts']); + $html_cache_contexts = Cache::mergeContexts($html_cache_contexts, $cacheable_html[$child]['#cache']['contexts']); $html_cache_tags = Cache::mergeTags($html_cache_tags, $cacheable_html[$child]['#cache']['tags']); $html_cache_max_age = Cache::mergeMaxAges($html_cache_max_age, $cacheable_html[$child]['#cache']['max-age']); } + // @todo DEBUG DEBUG DEBUG PROFILING PROFILING PROFILING — Until only the + // truly uncacheable things set max-age = 0 (such as the search block and + // the breadcrumbs block, which currently set max-age = 0, even though it + // is perfectly possible to cache them), to see the performance boost this + // will bring, uncomment this line. +// $html_cache_max_age = Cache::PERMANENT; + // @todo Remove this. Work-around to support the deep-render-array-scanning- // dependent logic bartik_preprocess_html() has: it needs to know about // the presence or absence of certain regions. That is similar (but less @@ -132,17 +143,18 @@ protected function finish(array $html) { // SmartCache only caches cacheable pages. if ($html_cache_max_age !== 0) { + $html_cache_contexts = $this->cacheContexts->optimizeTokens($html_cache_contexts); // If the set of cache contexts is different, store the union of the already // stored cache contexts and the contexts for this request. - if ($cache_contexts !== $stored_cache_contexts) { + if ($html_cache_contexts !== $stored_cache_contexts) { if (is_array($stored_cache_contexts)) { - $cache_contexts = Cache::mergeContexts($cache_contexts, $stored_cache_contexts); + $html_cache_contexts = $this->cacheContexts->optimizeTokens(Cache::mergeContexts($html_cache_contexts, $stored_cache_contexts)); } - $this->smartContextsCache->set($contexts_cid, $cache_contexts); + $this->smartContextsCache->set($contexts_cid, $html_cache_contexts); } - // Finally, cache the html render array according to those contexts. - $cid = 'smartcache:html_render_array:' . $cid_part_route_match . implode(':', $this->cacheContexts->convertTokensToKeys($cache_contexts)); + // Finally, cache the #type => html render array by those contexts. + $cid = 'smartcache:html_render_array:' . implode(':', $this->cacheContexts->convertTokensToKeys($html_cache_contexts)); $expire = ($html_cache_max_age === Cache::PERMANENT) ? Cache::PERMANENT : (int) $this->requestStack->getMasterRequest()->server->get('REQUEST_TIME') + $html_cache_max_age; $this->smartHtmlCache->set($cid, $cacheable_html, $expire, $html_cache_tags); }