Unverified Commit a14ca0ca authored by Alex Pott's avatar Alex Pott
Browse files

fix: #3550724 Reduce usleep() calls in Renderer::executeInRenderContext()

By: @catch
By: @berdir
By: @godotislate
By: @alexpott
(cherry picked from commit ee1598d4)
parent c5d1b06c
Loading
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@

use Drupal\Core\Entity\Query\QueryInterface;
use Drupal\Core\Cache\MemoryCache\MemoryCacheInterface;
use Drupal\Core\Utility\FiberResumeType;

/**
 * A base entity storage class.
@@ -294,7 +295,7 @@ public function loadMultiple(?array $ids = NULL) {
        // of entities to load, so that another call can load everything at
        // once.
        $this->entityIdsToLoad = array_unique(array_merge($this->entityIdsToLoad, $ids));
        $fiber->suspend();
        $fiber->suspend(FiberResumeType::Immediate);

        // If all the IDs we need to return have already been loaded into the
        // static cache, ignore any additionally requested entities here since
+7 −5
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
use Drupal\Core\Security\DoTrustedCallbackTrait;
use Drupal\Core\Theme\ThemeManagerInterface;
use Drupal\Core\Utility\CallableResolver;
use Drupal\Core\Utility\FiberResumeType;
use Symfony\Component\HttpFoundation\RequestStack;

/**
@@ -632,6 +633,7 @@ public function executeInRenderContext(RenderContext $context, callable $callabl

    $fiber = new \Fiber(static fn () => $callable());
    $fiber->start();
    $resume_type = NULL;
    while (!$fiber->isTerminated()) {
      if ($fiber->isSuspended()) {
        // When ::executeInRenderContext() is executed within a Fiber, which is
@@ -644,12 +646,12 @@ public function executeInRenderContext(RenderContext $context, callable $callabl
          \Fiber::suspend();
          $this->setCurrentRenderContext($context);
        }
        $fiber->resume();
        $resume_type = $fiber->resume();
      }
      if (!$fiber->isTerminated()) {
        // If we've reached this point, then the fiber has already been started
        // and resumed at least once, so may be suspending repeatedly. Avoid
        // a spin-lock by waiting for 0.5ms prior to continuing the while loop.
      // If the fiber has been suspended and has not signaled that it can be
      // immediately resumed, assume that the fiber is waiting on an async
      // operation and wait a bit.
      if (!$fiber->isTerminated() && $resume_type !== FiberResumeType::Immediate) {
        usleep(500);
      }
    }
+31 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\Core\Utility;

/**
 * Enumeration for Fiber resume hints.
 *
 * This can be passed to \Fiber::suspend() to allow the loop that processes the
 * fiber to immediately retry or wait. The loop should only use this if there
 * are no other fibers to process.
 *
 * In a number of places, Drupal has adopted a pattern that uses fibers not
 * to wait for external async operations, but group multiple slow operations,
 * such as an entity load or path alias lookup together.
 *
 * This is currently only used by
 * \Drupal\Core\Render\Renderer::executeInRenderContext() and the default is
 * delayed.
 *
 * This may be deprecated and removed again in the future, once the Revolt event
 * loop is adopted in www.drupal.org/project/drupal/issues/3394423.
 *
 * @see \Drupal\Core\Entity\EntityStorageBase::loadMultiple()
 * @see \Drupal\path_alias\AliasManager::getAliasByPath()
 */
enum FiberResumeType {
  case Immediate;
  case Delayed;
}
+2 −1
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Utility\FiberResumeType;

/**
 * The default alias manager implementation.
@@ -137,7 +138,7 @@ public function getAliasByPath($path, $langcode = NULL) {
    // If we're inside a Fiber, suspend now, this allows other fibers to collect
    // more requested paths.
    if (\Fiber::getCurrent() !== NULL) {
      \Fiber::suspend();
      \Fiber::suspend(FiberResumeType::Immediate);
    }

    // If we reach here, then either there are no other Fibers, or none of them