diff --git a/docs/execution.md b/docs/execution.md index 9f0d27c..7897a9f 100644 --- a/docs/execution.md +++ b/docs/execution.md @@ -95,16 +95,18 @@ sequenceDiagram participant client as Client participant og as Omnigraph::mutate
(mutation.rs:511) participant cmp as omnigraph-compiler + participant runs as RunRegistry participant ts as table_store participant lance as Lance dataset participant mr as ManifestRepo
(manifest.rs:280) - participant manifest as __manifest/ client->>og: mutate(target, source, name, params) og->>cmp: parse + typecheck_query cmp-->>og: CheckedQuery (Mutation IR) - og->>og: resolve expression literals
literal_to_typed_array(lit, type, n) - loop for each mutation statement + og->>runs: begin_run(target, op_hash)
fork __run__ from target head + runs-->>og: RunRecord + loop for each mutation statement (on __run__) + og->>og: resolve expression literals
literal_to_typed_array(lit, type, n) alt insert og->>ts: append RecordBatches ts->>lance: WriteMode::Append → new fragment(s) @@ -116,22 +118,30 @@ sequenceDiagram ts->>lance: merge_insert(WhenMatched::Delete) end lance-->>ts: new dataset version - ts-->>og: SubTableUpdate (key, version, row_count) + og->>mr: commit_updates(SubTableUpdate)
per-statement commit on __run__ + mr-->>og: ack end - og->>mr: commit(updates) - mr->>manifest: append rows
(table_version per sub-table) - manifest-->>mr: new graph-manifest version - mr-->>og: graph version + og->>og: OCC: target head unchanged since begin_run? + og->>og: publish_run(run_id) + alt fast path (target hasn't moved) + og->>mr: commit_updates_on_branch(target, updates)
promote run snapshot + else merge path (target advanced) + og->>og: branch_merge_internal(__run__, target)
three-way merge + end + mr-->>og: new target snapshot + og->>runs: terminate_run(Published) og-->>client: MutationResult ``` **Code paths:** - Entry: `Omnigraph::mutate` at `crates/omnigraph/src/exec/mutation.rs:511` -- Actor-attributed variant: `Omnigraph::mutate_as` at `crates/omnigraph/src/exec/mutation.rs:522` -- Manifest commit: `ManifestRepo::commit` at `crates/omnigraph/src/db/manifest.rs:280` +- Per-mutation orchestration: `mutate_with_current_actor` at `crates/omnigraph/src/exec/mutation.rs:539` +- Per-statement commit on the run-branch: `commit_updates` (called from `execute_insert` / `execute_update` / `execute_delete` in `crates/omnigraph/src/exec/mutation.rs`) +- Run publish: `Omnigraph::publish_run` at `crates/omnigraph/src/db/omnigraph.rs:858` +- Manifest commit primitive: `ManifestRepo::commit` at `crates/omnigraph/src/db/manifest.rs:280` (called from both per-statement `commit_updates` and the publish path) -The whole mutation — every statement, every affected sub-table — publishes through one call to `ManifestRepo::commit`. That single append to `__manifest` is what gives multi-statement mutations their atomicity guarantee (per [`docs/invariants.md`](invariants.md) §VI.26). +Multi-statement mutations don't get atomicity from a single final `commit` — they get it from the **run-branch + publish_run** pattern. Every mutation runs on a fresh `__run__` branch (`begin_run`); each statement individually commits its sub-table updates to that run-branch. After all statements complete, an OCC pre-check verifies the target hasn't moved since the run started, then `publish_run` atomically promotes the run-branch into the target — either via the fast path (direct promotion if the target hasn't moved) or a three-way merge. That final publish is what gives multi-statement mutations their atomicity guarantee (per [`docs/invariants.md`](invariants.md) §VI.26). If anything fails mid-run, the run is failed and the run-branch is dropped without affecting the target. See [runs.md](runs.md) for the full run lifecycle. ## Bulk loader (`loader/mod.rs`)