Skip to content

Pull Match Resources During the Type Search Scan #3720

Description

@alexanderkiel

Problem

FHIR type search (blaze.interaction.search-type) builds a page in two strictly sequential steps: it first materializes a full page of resource handles (the single-threaded index scan), and only afterwards pulls the match resource contents via pull-many. On servers with slower (disk) I/O the scan and the parallel pull therefore run back to back, so per-page latency is roughly scan + pull.

Measurements on representative code queries show scan and pull times in the same ballpark (e.g. ~24 ms / ~23 ms on a slower server), so overlapping them removes a meaningful fraction of per-page latency — most relevant for bulk export, where pages are fetched sequentially.

Change

Pull each match's resource content as soon as its handle is produced during the scan, so the resource I/O overlaps the scan instead of starting after it. Per-page latency moves from scan + pull toward max(scan, pull).

Supporting changes in the db module:

  • d/pull-fn — a streaming, per-handle pull primitive. It processes the options once (:variant / :elements / :skip-cache-insertion?) and returns a function of a resource handle to a CompletableFuture, avoiding pull-many's batch overhead.
  • rc/get-skip-cache-insertion — single-key counterpart to the existing multi-get-skip-cache-insertion, needed when paging (skips cache insertion).

In search-type:

  • The scan reduction fires a pull for each match handle and collects the futures; they are awaited afterwards. The next-match handle (which only seeds the paging link) is not pulled. Includes still use pull-many.
  • Phase histograms fhir_interaction_search_type_search_duration_seconds with phase = compile-query / scan / pull-matches / pull-includes, to measure the overlap on real servers (compare scan vs pull-matches).

Notes

  • Deleted-resource handling and error propagation (including too-costly includes) are unchanged.
  • The too-costly inclusion message is now built at call time so its thousands separator follows the default locale (tests pin it via tu/set-default-locale-english!).

Metadata

Metadata

Assignees

No fields configured for Feature.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions