it looks like it could use one, saves some useless cache lookups.

also, let's not look up a system path when we already have one.

CommentFileSizeAuthor
#6 2248897-6.patch2.71 KBwim leers
#4 2248897-5.patch2.6 KBAnonymous (not verified)
#2 2248897-2.patch2.6 KBAnonymous (not verified)
url-aliasessese.patch1.77 KBAnonymous (not verified)

Comments

Anonymous’s picture

Issue tags: +Performance
Anonymous’s picture

Title: AliasManagerCacheDecorator static cache » cleanup some useless queries to AliasManager
Issue summary: View changes
StatusFileSize
new2.6 KB

here's the initial patch plus something catch put together to stop us looking up a system path when we already have a system path.

here's the diff:

diff --git a/core/includes/common.inc b/core/includes/common.inc
index a60ff1c..2f3357f 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -1058,7 +1058,8 @@ function l($text, $path, array $options = array()) {
     // Add a "data-drupal-link-system-path" attribute to let the
     // drupal.active-link library know the path in a standardized manner.
     if (!isset($variables['options']['attributes']['data-drupal-link-system-path'])) {
-      $variables['options']['attributes']['data-drupal-link-system-path'] = \Drupal::service('path.alias_manager.cached')->getSystemPath($path);
+      $sytem_path = empty($variables['options']['alias']) ? $path : \Drupal::service('path.alias_manager.cached')->getSystemPath($path);
+      $variables['options']['attributes']['data-drupal-link-system-path'] = $system_path;
     }
   }
Anonymous’s picture

Issue summary: View changes
Anonymous’s picture

StatusFileSize
new2.6 KB

doh, fixed $sytem_path typo.

The last submitted patch, 2: 2248897-2.patch, failed testing.

wim leers’s picture

Title: cleanup some useless queries to AliasManager » Fix AliasManager and AliasManagerCacheDecorator
Component: cache system » path.module
Priority: Normal » Major
Issue tags: +Needs tests
StatusFileSize
new2.71 KB

I wanted to review the patch, but I ended up trying to understand how AliasManager and AliasManagerCacheDecorator work. I talked to beejeebus, because from reading the patch, it seems that the DB cache will no longer be hit. Turns out he was very confused by the existing code also. So I went on a mission to understand what was going on. The conclusion of that mission:

  1. they're nigh impossible to understand,
  2. they lack test coverage (there's zero test coverage!)
  3. AliasManagerCacheDecorator abuses implementation details of AliasManager to achieve a hacky, partial and undocumented performance win
  4. AliasManagerCacheDecorator is probably fundamentally broken (it uses the wrong cache key to retrieve data from cache)
  5. The cache key is literally the request's system path, instead of prefixing that with something, like everything else (unless it has its own cache bin, then it'd be fine — maybe that was the case before)

AliasManagerCacheDecorator wants to preload SYSTEM PATHS (i.e. alias -> source), but AliasManager wants to preload ALIASES (i.e. source -> alias)… yet AliasManagerCacheDecorator uses AliasManager's preload functionality, but then of course doesn't yield the desired result, since it's doing the opposite!
AliasManager::lookupPathAlias does:

    // During the first call to this method per language, load the expected
    // system paths for the page from cache.
    if (!empty($this->firstLookup)) {
      $this->firstLookup = FALSE;
      $this->lookupMap[$langcode] = array();
      // Load system paths from cache.
      if (!empty($this->preloadedPathLookups)) {
        // Now fetch the aliases corresponding to these system paths.
        $this->lookupMap[$langcode] = $this->storage->preloadPathAlias($this->preloadedPathLookups, $langcode);
        // Keep a record of paths with no alias to avoid querying twice.
        $this->noAliases[$langcode] = array_flip(array_diff_key($this->preloadedPathLookups, array_keys($this->lookupMap[$langcode])));
      }
    }

But AliasManager::lookupPathSource() (the inverse) also uses $this->lookupMap:

      // Look for the value $path within the cached $map
      $source = isset($this->lookupMap[$langcode]) ? array_search($path, $this->lookupMap[$langcode]) : FALSE;
      if (!$source) {
        if ($source = $this->storage->lookupPathSource($path, $langcode)) {
          $this->lookupMap[$langcode][$source] = $path;
        }

and this is how it "kind of" works, except that it then doesn't catch the case of "this already is a system path, you should be smart enough to not do a DB query for these". So I guess it's doing the best it can… but the end result is wildly confusing!


Hopefully it's sufficiently clear that these two classes need a lot of love.

Attached is an initial patch to make it work again and document the most confusing part. beejeebus and I think these classes should pretty much be ripped apart and rewritten, if there's any hope of making this maintainable.

I apologize if I didn't explain it well or too fiercely — my head is still spinning from confusion.

(The previous patches could be applied to this also, but I think it might be better to unbreak things first?)

Status: Needs review » Needs work

The last submitted patch, 6: 2248897-6.patch, failed testing.

dawehner’s picture

  1. +++ b/core/lib/Drupal/Core/CacheDecorator/AliasManagerCacheDecorator.php
    @@ -88,14 +88,38 @@ public function writeCache() {
    +    static $preloaded;
    +
    +    if (!isset($preloaded)) {
    

    Do we really have a usecase for a static variable here or could we just use a plain old member variable on the object?

  2. +++ b/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php
    @@ -53,7 +53,7 @@ public function onKernelRequestConvertPath(GetResponseEvent $event) {
         // Set the cache key on the alias manager cache decorator.
         if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) {
    ...
    +      $this->aliasManager->setCacheKey('aliases:' . $path);
         }
    

    Just in general I don't understand why we can't just pull that information manually from a request stack passed as dependency into the cached alias manager.

Anonymous’s picture

Anonymous’s picture

this issue may not fit with the existing work in #2002126: [meta] Refactor the alias subsystem (classes in \Drupal\Core\Path), so might be best to close it.

berdir’s picture

Not exactly sure what's left of this after #2233623: Merge AliasManagerCacheDecorator into AliasManager is in, but we probably still want to improve the getPathFromAlias() case there as that will still not be cached by the other issue.

jhedstrom’s picture

If there is work remaining here, the issue summary needs updating.

Crell’s picture

Status: Needs work » Closed (won't fix)

The code base has drifted enough that this issue is no longer relevant. If there's other cleanup to do in AliasManager now start a new issue.