Skip to content

Media: Port Children/Descendants traversal optimisations to media (#22742 follow-up) - #23356

Merged
Zeegaan merged 6 commits into
v17/devfrom
v17/improvement/22646-port-document-traversal-improvements-to-media
Jul 14, 2026
Merged

Media: Port Children/Descendants traversal optimisations to media (#22742 follow-up)#23356
Zeegaan merged 6 commits into
v17/devfrom
v17/improvement/22646-port-document-traversal-improvements-to-media

Conversation

@AndyButland

@AndyButland AndyButland commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Background

#22742 (closing #22646, shipped in 17.5) improved Children()/Descendants() traversal performance. After release, a user reported the problem persisted for media.

Reviewing the original PR against the media path showed two of its wins were applied to documents but not media. This PR ports them across.

Changes

1. The sync fast path is now reachable for media.
#22742 added a sync L0 fast path to MediaCache.GetById(bool preview, Guid contentId), with a comment stating it's "hit per-key by the FilterAvailable lazy chain." It never was: PublishedMediaStatusFilteringService calls candidateKeys.Select(_publishedMediaCache.GetById), and that method group binds to the single-argument GetById(Guid) overload — not the two-argument one that received the fast path. So every media item spun up an async state machine even on a warm cache, while documents (which call GetById(preview, key) explicitly) took the fast path.

The single-argument GetById(Guid) now runs the TryGetCached fast path, and GetById(bool, Guid) delegates to it (media has no draft/preview dimension).

2. Removed a vestigial id/key-map lookup per media item.
MediaCacheService.GetByKeyAsync performed _idKeyMap.GetIdForKey(key, Media) on every call — a reader-writer lock plus a database hit when the map is cold. Documents never did this. It used to be load-bearing (the DB fetch was once by int id), but #17727 refactored the fetch to resolve by key via GetNodeAsync, leaving the resolved id unused. The lookup only survived as an "is this a media node?" guard, which is redundant because GetMediaSourceAsync(key) already filters by the media object type and returns null for a non-media/unknown key. GetByKeyAsync is now just => await GetNodeAsync(key), matching DocumentCacheService.

Notes

These address the warm-cache and moderate-size case (and the "applied to docs, not media" gap). What looks to be reported is a cold-cache scenario — a large, flat media library exceeding MediaBreadthFirstSeedCount — dominated by per-item DB round trips on the materialisation path (no batched fetch), which affects both trees and is not addressed here; that may be something further to look at.

Testing

Added MediaCacheSyncFastPathTests (verified failing without the fast-path fix); solution builds and CI checks should pass.

Copilot AI review requested due to automatic review settings July 10, 2026 10:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Ports the v17.5 Children()/Descendants() traversal performance optimizations from documents to media by making the media sync cache fast-path reachable and removing per-item unnecessary id/key map work.

Changes:

  • Make MediaCache.GetById(Guid) consult IMediaCacheService.TryGetCached before falling back to the async path (and route the (bool preview, Guid) overload through it).
  • Remove the redundant id/key map lookup from MediaCacheService.GetByKeyAsync(Guid) so media key fetch mirrors the document path.
  • Add unit tests validating the media sync fast-path behavior and ensuring the async fallback is skipped on L0 hits.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
tests/Umbraco.Tests.UnitTests/Umbraco.PublishedCache.HybridCache/MediaCacheSyncFastPathTests.cs Adds regression tests proving the Guid overload hits TryGetCached and avoids the async fallback on warm cache.
src/Umbraco.PublishedCache.HybridCache/Services/MediaCacheService.cs Simplifies media fetch by key by removing the vestigial id/key map lookup before resolving via GetNodeAsync.
src/Umbraco.PublishedCache.HybridCache/MediaCache.cs Routes media Guid sync lookups through a TryGetCached fast-path to avoid per-item async state machine setup.

Comment thread src/Umbraco.PublishedCache.HybridCache/Services/MediaCacheService.cs Outdated
AndyButland and others added 4 commits July 10, 2026 12:12
There is no work before or after the await, so the async/await only added
an async state machine allocation on the traversal hot path this PR optimizes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Local test scaffolding that should not be part of this change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@Zeegaan Zeegaan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick win, love it 🙌

@Zeegaan
Zeegaan merged commit 54bd53f into v17/dev Jul 14, 2026
31 checks passed
@Zeegaan
Zeegaan deleted the v17/improvement/22646-port-document-traversal-improvements-to-media branch July 14, 2026 00:26
@Zeegaan Zeegaan added category/performance Fixes for performance (generally cpu or memory) fixes release/18.1.0 release/17.6.0 labels Jul 14, 2026
@gelucostea

Copy link
Copy Markdown

Hello again, The latest version 17.6.0 still have same performance issue for Children()/Descendants() of a media node. Getting 366 files needs 34 seconds. Can you check please ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

category/performance Fixes for performance (generally cpu or memory) fixes release/17.6.0 release/18.1.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants