- 已装运
- 2026年8月25日 15:20 UTC
- 作者
- Kamo
- 提交
- f33ef98
A resource write is not one row: it is the domain rows, the canonical JSON, up to eight kinds of search-index row, a reference link per reference, and a security label per sensitivity. They land in ONE transaction or the resource becomes findable before it is labelled, and that window is exactly as long as the gap between two writes. FhirProjection lets a per-resource mapper be a PURE FUNCTION — resource in, projection out, no database, no transaction, no ordering. That is what makes 35 mappers tractable to test, and it means the eventual StructureDefinition generator only has to emit something that builds one of these; it never has to understand persistence. The writer decides ORDER, the mapper decides CONTENT, and keeping that line is what stops the Yugabyte-specific rules being duplicated into every mapper. FhirResourceWriter is the order, and every step is there because doing it differently fails intermittently or silently: The version is claimed FIRST, with an UPDATE that returns the new value. Reading then writing is a read-after-write in one transaction, which Yugabyte aborts with 40001 under concurrency — it presents as a random deadlock and a retry loop appears to fix it while fixing nothing. Stale index rows are swept BEFORE new ones are written, and every index type is swept even when this write produces none of that type, because the PREVIOUS version may have had them. An update that only inserts leaves a resolved problem or a removed allergy still answering a search — a wrong clinical answer, not a slow one. The label sweep deliberately excludes manuallyAssigned rows: a clinician's explicit restriction must survive reprocessing, which is the whole reason SecurityLabelAssignment records who set it. Everything is batched. This platform lost weeks to a per-row audit transaction that made a 1,427-row grid take 23 seconds, and a resource write has the same shape at higher volume. Not @Transactional and not a stereotype, both deliberate. A resource write is frequently one entry in a transaction Bundle, so a nested boundary would either split the Bundle or silently mark the outer transaction rollback-only; the caller owns it. And a shared-lib @Component needing an unscanned repository has crash-looped services four times. Mutation-proven: moving the sweep after the writes and widening the label delete to include manual labels produced three failures across the two ordering tests and the label-scope test before the revert. 1666 tests green.