Skip to content

Add opt-in incremental builds that reuse unchanged imports - #1657

Closed
vadi2 wants to merge 2 commits into
FHIR:masterfrom
vadi2:incremental-2-import-cache
Closed

vadi2 wants to merge 2 commits into
FHIR:masterfrom
vadi2:incremental-2-import-cache

Conversation

@vadi2

@vadi2 vadi2 commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Description:

Part 2 of 3 of a stack for #544, on top of #1656. Every SUSHI run parses and imports every FSH file again, even when only one changed. This adds --incremental, which reuses the import of each unchanged file. On its own the gain is modest, as export takes most of a build: in a large R5 IG (511 FSH files), a build goes from 16.8 s to about 14.1 s. Part 3 reuses exports, which is where most of the time goes.

Until #1656 merges, this PR's diff includes it. The new work is the last commit: 6817cf2

Cause

As noted in #544, FSH has no imports and any definition can live in any file, so a file's import can depend on aliases, parameterized RuleSets and entity names from other files. SUSHI keeps nothing between runs, so it can't tell what is safe to reuse.

Fix

  • Opt-in: --incremental, or SUSHI_INCREMENTAL=1 for callers such as the IG Publisher. The cache lives in <project>/.sushi-cache (with its own .gitignore), or in SUSHI_CACHE_DIR. Without the option, nothing changes.
  • Import: each file's parse and visit results are cached by content hash, with the log messages they wrote and everything they used from other files: alias lookups, parameterized RuleSets (by hash) and duplicate-name checks. A cached file is reused only while all of those still give the same answers; its messages are written again, so the output and error/warning counts match a normal build.
  • Safety: the cache is keyed on the SUSHI build (its files, version and Node version). Every write goes to a temporary file that is renamed into place, and every read is checked against its hash. A missing, corrupt or unwritable cache falls back to a normal import, and the summary says so as info lines. Unused payloads are collected, keeping any used in the last hour by a concurrent build.
  • Limits: a file whose import runs out of stack space (such as a RuleSet that inserts itself) is never cached. How many errors that reports already varies between normal builds, and an incremental build can report one more. With --preprocessed, the cache is not used, and an info line says so.
  • Docs: the README describes the option, SUSHI_INCREMENTAL, SUSHI_CACHE_DIR and the cache folder.
  • Export: unchanged in this part.

Testing Instructions:

Run sushi . --incremental twice; the second run reports Incremental build: reused N of N files. Edit a file and run again: only that file (and files that depend on what it changed) is imported again.

Related Issue:

#544

vadi2 added 2 commits October 29, 2026 19:14
Preprocessing now extracts each document's aliases and parameterized
RuleSets before applying them, entity name checks share one helper, and
Package lists its fish candidates in one place. No behaviour change.
With --incremental or SUSHI_INCREMENTAL=1, each file's import is cached
by content hash with the aliases, RuleSets and duplicate names it used,
and reused while those are unchanged. Export runs as before.
@vadi2

vadi2 commented Oct 30, 2026

Copy link
Copy Markdown
Contributor Author

Closing for now. We'll reopen this as a proper stack of smaller, more bite-sized PRs once stacked PRs are enabled in this repo.

@vadi2 vadi2 closed this Oct 30, 2026
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