Skip to content

[DRAFT] perf(2892): preload notification objects, cache assignments - #6

Draft
tuannx wants to merge 1 commit into
poc/quickperf-database-queriesfrom
poc/repro-2892-notifications-n1
Draft

tuannx wants to merge 1 commit into
poc/quickperf-database-queriesfrom
poc/repro-2892-notifications-n1

Conversation

@tuannx

@tuannx tuannx commented Sep 26, 2026

Copy link
Copy Markdown
Owner

Problem (upstream IQSS#2892, private repro)

Rendering a notifications page resolves each row's objectId with service find() calls (up to 3 sequential finds for role notifications), plus getEffectiveRoleAssignments per row and requestor loads per row. Measured on a 12-notification/9-object fixture: 71 SELECTs for the legacy per-row pattern.

Fix

  • InAppNotificationsJsonPrinter.preload(): partitions notification ids by target kind (from the type switch) and loads everything with a fixed set of IN queries - dv objects, files with full to-one closure, versions, dataset display graphs (versions+fields), file metadatas - plus a per-page cache of effective role assignments keyed by (user, object).
  • New batch service methods: DvObjectServiceBean.findDvObjectsByIds, DataFileServiceBean.findFilesByIds, DatasetVersionServiceBean.findVersionsByIds, DatasetServiceBean.preloadDisplayGraphs, DataFileServiceBean.preloadFileMetadatas. To-one fetch closures only: no cartesian products. Inverse-side collections are set, never join-fetched (verified zero writes).
  • JsonPrinter.json loop preloads once per page; new 4-arg addFieldsByType resolves from the preload with identical JSON branches (old 3-arg delegates for single use).
  • UserNotificationServiceBean.findByUser fetch-joins requestors (11 -> 7 on the fixture; delta is exactly the 4 requestor loads).

Verification

  • New NotificationRenderBudgetIT (real services wired with the test EM, incl. the permission/group chain): legacy-vs-preloaded 71 -> 50, repeated notifications add ~zero queries (51 vs 50, 1 query of documented L1-order tolerance), JSON content asserts per type, zero writes.
  • No new checkstyle violations in touched files.

Notes / follow-ups

  • Residual per-object costs (EAGER hydration of thumbnail/quota/theme back-references, per-distinct-object assignment lookups, per-render assignee lookups) are pre-existing and unchanged; the win scales with notification count (repeats are free).
  • Measured finding: @BatchFetch does NOT reroute EAGER-at-build loading with weaving disabled (24 queries before and after annotating), so to-one EAGER residuals need fetch joins, not batch annotations. Relevant when reviewing upstream Faster file and dataset pages for datasets with many files IQSS/dataverse#12740's to-one annotations.
  • True bulk assignment resolution (one query per page instead of per distinct object) would need permission-system surgery and is left as a follow-up.
  • Stays on the private fork until reviewed; upstream proposal to follow.

…questors (+ repro IT)

Rendering notifications resolved objectId with service finds per row
(up to 3 for role types) plus role assignments per row and requestors
per row. Measured on a 12-notification/9-object fixture: legacy 71
SELECTs.

- InAppNotificationsJsonPrinter: preload() partitions ids by target
  kind and loads everything with fixed IN queries (dv objects, files
  with to-one closure, versions, display graphs); per-page cache for
  effective role assignments; 4-arg addFieldsByType resolves from the
  preload (same JSON branches as before).
- New batch service methods: DvObjectServiceBean.findDvObjectsByIds,
  DataFileServiceBean.findFilesByIds, DatasetVersionServiceBean
  .findVersionsByIds, DatasetServiceBean.preloadDisplayGraphs,
  DataFileServiceBean.preloadFileMetadatas. To-one fetch closures
  only (no cartesian products, no 6169 exposure: batch annotations
  are deliberately NOT used - measured @BatchFetch does not reroute
  EAGER-at-build loading with weaving disabled).
- JsonPrinter.json loop preloads once per page.
- UserNotificationServiceBean.findByUser fetches requestors (11->7).
- NotificationRenderBudgetIT: legacy-vs-preloaded (71->50), repeat
  notifications add ~zero queries, JSON content asserts, zero writes.

Draft: for private perf review; not yet proposed upstream.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant