mirror of
https://github.com/ModernRelay/omnigraph.git
synced 2026-06-12 01:45:14 +02:00
* MR-854: convert engine call sites to &dyn TableStorage; demote legacy methods
Phase 1b: every db.table_store.X(...) call site converts to
db.storage().X(...), reaching the storage layer through the sealed
TableStorage trait (returns &dyn TableStorage). Opaque SnapshotHandle
and StagedHandle replace bare lance::Dataset and Transaction in the
threaded values.
Phase 9: the inherent inline-commit methods on TableStore
(append_batch, merge_insert_batch{,es}, overwrite_batch,
create_btree_index, create_inverted_index) demote from pub to
pub(crate). Their only remaining direct users are table_store.rs
itself and the bulk loader's LoadMode::{Append, Overwrite, Merge}
concurrent fast-paths in loader::write_batch_to_dataset (no
two-phase shape in Lance 4.0.0 — closes after lance#6658 and #6666).
Docs:
- invariants.md \u00a7VI.23: drop "at the writer-trait surface"
qualifier; staged primitives are now the only engine surface.
- runs.md: residual matrix shrinks to delete_where and
create_vector_index (the two upstream-blocked residuals).
- forbidden_apis.rs: replace transitional language with the
current allow-list shape (table_store.rs + loader concurrent
fast-path only).
Files touched:
- changes/mod.rs, db/omnigraph.rs (+export/optimize/schema_apply/
table_ops.rs), exec/{merge,mod,mutation,staging}.rs,
loader/mod.rs, storage_layer.rs, table_store.rs,
tests/forbidden_apis.rs, docs/{invariants,runs}.md.
Co-Authored-By: Ragnor Comerford <ragnor.comerford@gmail.com>
* MR-854: replace test-only inline-commit append callers with local Lance helpers
After demoting TableStore::append_batch from pub to pub(crate), the
integration tests in tests/recovery.rs and tests/staged_writes.rs
that previously called store.append_batch(...) directly to simulate
HEAD-ahead-of-manifest drift can no longer access the inherent
method. Replace those calls with small in-test helpers that do a raw
Dataset::append (the same body the inherent method runs).
- tests/helpers/mod.rs gains lance_append_inline (shared helper).
- tests/staged_writes.rs gets a file-local lance_append_inline_local
(staged_writes.rs does not import helpers::).
- tests/recovery.rs drops the unused TableStore import in the one
function whose store binding became unused after the conversion.
Co-Authored-By: Ragnor Comerford <ragnor.comerford@gmail.com>
* MR-854: retrigger CI for flaky Test Workspace job
Co-Authored-By: Ragnor Comerford <ragnor.comerford@gmail.com>
* MR-854: convert remaining table_store call sites in export.rs / read_blob
Two leftover `self.table_store.X` / `db.table_store.X` call sites were
missed in the initial sweep — flagged by Devin Review on PR #86. Both
now go through the trait surface:
- `entity_from_snapshot` (db/omnigraph/export.rs): switch from
`db.table_store.open_snapshot_table` + `db.table_store.scan` to
`db.storage().open_snapshot_at_table` + `db.storage().scan`.
- `read_blob` (db/omnigraph.rs): replace
`snapshot.open(table_key)` + `self.table_store.first_row_id_for_filter`
with `self.storage().open_snapshot_at_table` +
`self.storage().first_row_id_for_filter`. The follow-up
`take_blobs` call still needs an `Arc<Dataset>` (it's a Lance blob
accessor not surfaced through the trait), so we hand off via
`SnapshotHandle::into_arc()` with a comment.
After this commit, no engine code outside `table_store.rs` reaches the
inherent `TableStore` API — the docs/runs.md and docs/invariants.md
claim is now uniformly true.
Co-Authored-By: Ragnor Comerford <ragnor.comerford@gmail.com>
* MR-854: post-rebase doc fixes (Lance 6.0.1, MR-A framing, into_dataset note)
Reviewer feedback on the rebased PR:
* docs/dev/writes.md residuals matrix: drop demoted methods from the trait-surface table (now `pub(crate)`); keep only the two genuine trait-surface residuals (`delete_where`, `create_vector_index`); reframe under MR-A (Lance v7.x bump) per docs/dev/lance.md.
* tests/forbidden_apis.rs: update transitional allow-list header to (a) drop the truncate_table mislabel (truncate_table is a Lance Dataset method, not a TableStore method — overwrite_batch's internal call), (b) reframe trait-surface residuals under MR-A / Lance #6666.
* crates/omnigraph/src/storage_layer.rs::SnapshotHandle::{into_arc, into_dataset}: add single-ref invariant doc — both consume Arc via try_unwrap-or-clone; sibling SnapshotHandle clones across an await point force a deep Dataset clone.
* Replace lance-4.0.0 version refs with lance-6.0.1 in active source/test/dev-doc comments (storage_layer.rs, table_store.rs, table_ops.rs, schema_apply.rs, merge.rs, recovery.rs, staged_writes.rs, consistency.rs, docs/dev/execution.md, docs/user/query-language.md). Historical refs in docs/releases/v0.4.1.md and the canonical "Lance 4.0.0 → 6.0.1 migration" line in docs/dev/lance.md left intact.
No engine code changes.
* MR-854: update docs/dev/invariants.md Storage trait row + gap entry
Reviewer feedback: the docs reorg landed; the invariant row now lives in
docs/dev/invariants.md with stable headings (no more numbered §VI.23).
Update two pieces to reflect MR-854 completion:
* Status table 'Storage trait' row: was 'full call-site migration ... incomplete';
now 'engine call sites all route through db.storage() (MR-854); inline-commit
inherent methods are pub(crate)-demoted; capability/stat surfaces are roadmap'.
* 'Known Gaps' 'Storage abstraction' entry: was 'older inherent TableStore call
sites and inline residuals remain'; now names the closed scope (MR-854 — call
sites migrated, methods demoted, loader fast-paths) and the remaining
trait-surface residuals under MR-A (Lance v7.x bump) and Lance #6666.
Cross-links to docs/dev/lance.md and docs/dev/writes.md so the framing stays
co-located with the canonical Lance surface tracking.
* MR-854: remove dead inline-commit methods from the storage surface
The loader concurrent fast-path (write_batch_to_dataset) is only reached
for LoadMode::Overwrite — Append/Merge route through MutationStaging — so
its Append/Merge arms were unreachable. Collapse it to overwrite-only and
drop the now-unused mode params, which removes the only callers of:
- TableStorage::append_batch + TableStorage::merge_insert_batches (trait)
- TableStore::merge_insert_batch + merge_insert_batches (inherent)
create_btree_index / create_inverted_index had zero callers anywhere
(scalar index builds use the stage_* primitives). Remove both from the
trait and the inherent impl.
Inherent append_batch stays pub(crate): overwrite_batch and recovery
tests use it. Migrate the one trait-append_batch test caller
(seed_person_row) to stage_append + commit_staged. The merge_insert
FirstSeen-workaround rationale moves from the deleted merge_insert_batch
into stage_merge_insert (now the sole merge path). No behavior change.
Also corrects the inaccurate loader residual comment (the prior text
blamed Lance #6658/#6666, which are the delete and vector-index issues,
for keeping overwrite inline; a stage_overwrite primitive already exists
and schema_apply uses it).
* MR-854: seal db.storage() to staged-only; move residuals to InlineCommitResidual
Split the three remaining inline-commit writes (overwrite_batch,
delete_where, create_vector_index) off the TableStorage trait onto a new
sealed InlineCommitResidual trait, reachable only via the explicit
Omnigraph::storage_inline_residual() accessor. db.storage() now exposes
only staged primitives + reads, so engine code cannot couple a write
with a Lance HEAD advance through the default surface — MR-793 acceptance
§1 ("no public method commits as a side effect of writing") now holds by
construction, not by review + naming.
Call sites moved to storage_inline_residual(): loader overwrite
fast-path, the three mutation delete_where paths, the branch-merge
delete, and the vector-index build. Impl bodies are unchanged (same
delegation to the pub(crate) inherent methods); this is a pure surface
reshape with no behavior change.
The residual trait holds two genuinely upstream-blocked methods
(delete_where -> Lance #6658/v7.x, create_vector_index -> Lance #6666)
plus overwrite_batch, kept for the loader's cross-table bulk-overwrite
concurrency until its staged migration lands (tracked follow-up).
* MR-854 docs: describe the staged-only seal; fix stale Lance index URLs
- writes.md / invariants.md / AGENTS.md: the inline-commit residuals now
live on InlineCommitResidual behind db.storage_inline_residual(), so
acceptance §1 holds by construction rather than 'option (b)' per-method
enumeration. Drop the inaccurate 'until Lance exposes
Operation::Overwrite { fragments }' claim (that op exists; stage_overwrite
already builds it) and reframe overwrite_batch as a removable legacy
residual gated on the loader's bulk-overwrite concurrency.
- forbidden_apis.rs: rewrite the allow-list doc for the split surface.
- lance.md: the index spec pages moved from /format/table/index/ to
/format/index/ in Lance 6.x (the old paths 404). Fix all 13 URLs.
* MR-854: fix stale lance-4.0.0 comment refs flagged in review
Addresses greptile (exec/merge.rs) and aaltshuler's stale-version blocker:
update lance-4.0.0 -> 6.0.1 in the comment/doc refs within this PR's
footprint (exec/merge.rs, exec/mutation.rs, docs/dev/writes.md). Also
corrects exec/merge.rs to cite lance#6666 (not #6658) for
build_index_metadata_from_segments — that is the vector-index segment-commit
API; #6658 is the two-phase delete. (Pre-existing 4.0.0 refs in untouched
files like architecture.md/storage.md are main's incomplete migration
cleanup, left out of scope.)
* fix(storage): stage loader overwrites
* fix(storage): stage empty schema rewrites
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Ragnor Comerford <ragnor.comerford@gmail.com>
Co-authored-by: Ragnor Comerford <hello@ragnor.co>
313 lines
13 KiB
Markdown
313 lines
13 KiB
Markdown
# Architecture
|
||
|
||
OmniGraph is a typed property-graph engine built as a coordination layer over many Lance datasets, with Git-style branches and commits across the whole graph, multi-modal querying (vector + FTS + BM25 + RRF + graph traversal) in one runtime, an HTTP server with Cedar policy, and a CLI driven by a single `omnigraph.yaml`.
|
||
|
||
## Reading guide
|
||
|
||
Three views, increasing zoom:
|
||
|
||
1. **System context** — what OmniGraph is and what it touches.
|
||
2. **Layer view** — the eight-layer stack inside one OmniGraph process.
|
||
3. **Component zoom-ins** — what's inside each layer.
|
||
|
||
For runtime flows (read query, mutation), see [`docs/dev/execution.md`](execution.md). For the on-disk layout of a graph, see [`docs/user/storage.md`](../user/storage.md).
|
||
|
||
L1 (orange in the diagrams) is what we inherit from Lance; L2 (blue) is what OmniGraph adds. The L1/L2 framing is also called out in prose at the bottom of this doc.
|
||
|
||
## System context
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
classDef external fill:#fef3e8,stroke:#c46900,color:#000
|
||
classDef omnigraph fill:#e8f4fd,stroke:#1e6aa8,color:#000
|
||
classDef store fill:#f0f0f0,stroke:#555,color:#000
|
||
|
||
cli[CLI users]:::external
|
||
http[HTTP clients<br/>and SDKs]:::external
|
||
agents[Agents]:::external
|
||
embed[Embedding providers<br/>OpenAI / Gemini]:::external
|
||
|
||
og[OmniGraph<br/>kernel]:::omnigraph
|
||
|
||
cedar[Cedar policy<br/>engine]:::external
|
||
s3[Object store<br/>local FS / S3 / RustFS]:::store
|
||
|
||
cli --> og
|
||
http --> og
|
||
agents --> og
|
||
og --> embed
|
||
og --> cedar
|
||
og --> s3
|
||
```
|
||
|
||
OmniGraph runs as a single process (one binary, multiple crates). External dependencies are the embedding APIs (called during ingest and at query-time normalization), Cedar (called for every privileged action), and an object store (everything OmniGraph persists lands here).
|
||
|
||
## Layer view
|
||
|
||
Inside the OmniGraph process, work flows through these layers:
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
classDef l2 fill:#e8f4fd,stroke:#1e6aa8,color:#000
|
||
classDef l1 fill:#fef3e8,stroke:#c46900,color:#000
|
||
|
||
subgraph CLIs[CLI and HTTP server]
|
||
cli[omnigraph CLI]:::l2
|
||
srv[omnigraph-server<br/>Axum + Cedar]:::l2
|
||
end
|
||
|
||
subgraph compiler[omnigraph-compiler]
|
||
front[parse → AST → typecheck → catalog → IR]:::l2
|
||
end
|
||
|
||
subgraph engine[omnigraph engine]
|
||
plan[exec query and mutation]:::l2
|
||
gi[graph index CSR/CSC<br/>RuntimeCache LRU 8]:::l2
|
||
coord[coordinator<br/>ManifestCoordinator · CommitGraph]:::l2
|
||
end
|
||
|
||
subgraph storage[storage trait — wraps Lance]
|
||
ts[table_store · storage.rs<br/>direct lance::Dataset today]:::l2
|
||
end
|
||
|
||
subgraph lance_layer[Lance 4.x — substrate]
|
||
lance[per-dataset versions, fragments<br/>BTREE · Inverted FTS · IVF/HNSW vector<br/>merge_insert · compact_files · cleanup_old_versions]:::l1
|
||
end
|
||
|
||
subgraph object_store[Object store]
|
||
os[local FS · S3 · RustFS · MinIO]:::l1
|
||
end
|
||
|
||
CLIs -- "string + params" --> compiler
|
||
compiler -- IROp --> engine
|
||
engine -- "scan / write request" --> storage
|
||
storage -- "Stream of RecordBatch" --> engine
|
||
storage -- "Lance API calls" --> lance_layer
|
||
lance_layer -- bytes --> object_store
|
||
```
|
||
|
||
The storage seam is partly aspirational. `TableStorage` exists as the sealed staged-write trait, but capability/stat surfaces and full call-site migration are still roadmap. The diagram shows the intended boundary.
|
||
|
||
## Component zoom-ins
|
||
|
||
### Compiler — `omnigraph-compiler`
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
classDef l2 fill:#e8f4fd,stroke:#1e6aa8,color:#000
|
||
|
||
src[".gq source"]:::l2
|
||
p[parser Pest<br/>query.pest · schema.pest]:::l2
|
||
ast[AST<br/>QueryDecl · Mutation · Schema]:::l2
|
||
cat[catalog<br/>NodeType · EdgeType · Interface]:::l2
|
||
tc[typecheck<br/>typecheck_query]:::l2
|
||
low[lower<br/>lower_query]:::l2
|
||
ir[IROp pipeline<br/>NodeScan · Expand · Filter · AntiJoin]:::l2
|
||
|
||
src --> p --> ast --> tc
|
||
cat --> tc
|
||
tc --> low --> ir
|
||
```
|
||
|
||
The compiler crate has zero Lance dependency. It owns the schema language, the query language, and the AST → IR lowering.
|
||
|
||
Code paths:
|
||
|
||
- Parser: `crates/omnigraph-compiler/src/query/parser.rs`, `crates/omnigraph-compiler/src/query/query.pest`
|
||
- Typecheck: `crates/omnigraph-compiler/src/query/typecheck.rs:83` (`typecheck_query`)
|
||
- Lower: `crates/omnigraph-compiler/src/ir/lower.rs:11` (`lower_query`)
|
||
- Catalog: `crates/omnigraph-compiler/src/catalog/`
|
||
|
||
### Engine — `omnigraph` crate
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
classDef l2 fill:#e8f4fd,stroke:#1e6aa8,color:#000
|
||
|
||
subgraph exec[exec module]
|
||
eq[query · execute_query<br/>query.rs:347]:::l2
|
||
em[mutation · mutate<br/>mutation.rs:511]:::l2
|
||
ld[loader · ingest<br/>loader/mod.rs:74]:::l2
|
||
end
|
||
|
||
subgraph state[graph state]
|
||
coord[GraphCoordinator]:::l2
|
||
mr[ManifestCoordinator<br/>db/manifest.rs]:::l2
|
||
cg[CommitGraph<br/>_graph_commits.lance]:::l2
|
||
stg[MutationStaging<br/>per-query in-memory accumulator<br/>exec/staging.rs]:::l2
|
||
end
|
||
|
||
subgraph idx[graph index]
|
||
gi[GraphIndex<br/>CSR/CSC built per query]:::l2
|
||
rc[RuntimeCache LRU=8]:::l2
|
||
end
|
||
|
||
subgraph io[Lance I/O]
|
||
ts[table_store]:::l2
|
||
st[storage adapter<br/>storage.rs]:::l2
|
||
end
|
||
|
||
eq --> gi
|
||
eq --> ts
|
||
em --> stg
|
||
em --> ts
|
||
ld --> stg
|
||
ld --> ts
|
||
eq --> mr
|
||
em --> mr
|
||
coord --> mr
|
||
coord --> cg
|
||
ts --> st
|
||
```
|
||
|
||
The engine binds the compiler IR to Lance. It owns multi-dataset coordination, the graph topology index, the per-query staging accumulator, and the snapshot/manifest read path.
|
||
|
||
Code paths:
|
||
|
||
- Read entry: `Omnigraph::query` at `crates/omnigraph/src/exec/query.rs:7`
|
||
- Mutation entry: `Omnigraph::mutate` at `crates/omnigraph/src/exec/mutation.rs:511`
|
||
- Manifest commit: `ManifestCoordinator::commit` at `crates/omnigraph/src/db/manifest.rs:280`
|
||
- Graph index: `crates/omnigraph/src/graph_index/`
|
||
- Loader: `Omnigraph::ingest` at `crates/omnigraph/src/loader/mod.rs:74`
|
||
|
||
### Mutation atomicity — in-memory accumulator (MR-794)
|
||
|
||
Inserts and updates inside `mutate_as` and the bulk loader's
|
||
Append/Merge modes go through `MutationStaging`
|
||
([`crates/omnigraph/src/exec/staging.rs`](../../crates/omnigraph/src/exec/staging.rs)),
|
||
a per-query in-memory accumulator. No Lance HEAD advance happens during
|
||
op execution; one `stage_*` + `commit_staged` per touched table runs
|
||
at end-of-query, then the publisher commits the manifest atomically.
|
||
|
||
```
|
||
op-1 (insert/update) → push RecordBatch → MutationStaging.pending[table]
|
||
op-2 (insert/update) → read committed via Lance + pending via DataFusion
|
||
MemTable (read-your-writes) → push batch
|
||
op-N → push batch
|
||
─── end of query ───────────────────────────────────────
|
||
finalize: per pending table:
|
||
concat batches → stage_append OR stage_merge_insert OR stage_overwrite
|
||
→ commit_staged
|
||
publisher: ManifestBatchPublisher::publish (one cross-table CAS)
|
||
```
|
||
|
||
A failed op leaves Lance HEAD untouched on the staged tables: the next
|
||
mutation proceeds normally with no drift to reconcile. Concrete
|
||
contracts:
|
||
|
||
- `D₂` parse-time rule: a query is either insert/update-only or
|
||
delete-only. Mixed → reject. Deletes still inline-commit (Lance
|
||
4.0.0 has no public two-phase delete); D₂ keeps the inline path safe.
|
||
- `LoadMode::Overwrite` uses Lance `Operation::Overwrite` through the
|
||
same staged path. Loader validation runs against the replacement
|
||
in-memory batches before any `commit_staged`, and the publish window is
|
||
covered by `SidecarKind::Load` recovery.
|
||
- Read sites consume `TableStore::scan_with_pending`, which Lance-scans
|
||
the committed snapshot at the captured `expected_version` and unions
|
||
with a DataFusion `MemTable` over the pending batches.
|
||
|
||
This pattern realizes read-your-writes within a multi-statement mutation
|
||
and keeps failure scope bounded for inserts/updates by construction at
|
||
the writer layer. See [docs/dev/invariants.md](invariants.md) and
|
||
[docs/dev/writes.md](writes.md) for the publisher CAS contract this builds on.
|
||
|
||
### Storage trait — today vs. roadmap
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
classDef now fill:#e8f4fd,stroke:#1e6aa8,color:#000
|
||
classDef future fill:#fff,stroke:#888,stroke-dasharray:5 5,color:#444
|
||
|
||
subgraph today[Today]
|
||
d1[table_store<br/>opens lance::Dataset directly]:::now
|
||
d2[storage.rs<br/>S3 / file URI plumbing]:::now
|
||
end
|
||
|
||
subgraph roadmap[Roadmap - storage capabilities]
|
||
t[trait Dataset<br/>schema · stats · placement<br/>capabilities · scan · write]:::future
|
||
impl1[LanceStorage]:::future
|
||
impl2[future test impl]:::future
|
||
end
|
||
|
||
today -.-> roadmap
|
||
t --> impl1
|
||
t --> impl2
|
||
```
|
||
|
||
The staged-write trait exists today as `TableStorage`, implemented by `TableStore`. Full engine migration plus capability and statistics surfaces remain roadmap, so the planner cannot yet reason about all pushdown opportunities through a documented trait surface.
|
||
|
||
### Index lifecycle — today vs. roadmap
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
classDef now fill:#e8f4fd,stroke:#1e6aa8,color:#000
|
||
classDef future fill:#fff,stroke:#888,stroke-dasharray:5 5,color:#444
|
||
|
||
subgraph today[Today]
|
||
ei[ensure_indices<br/>omnigraph.rs:445]:::now
|
||
manual[called manually<br/>or from optimize]:::now
|
||
end
|
||
|
||
subgraph roadmap[Roadmap - manifest reconciler]
|
||
rec[Reconciler<br/>observes manifest]:::future
|
||
diff[coverage diff<br/>fragments − fragment_bitmap]:::future
|
||
wp[worker pool<br/>builds index segments]:::future
|
||
end
|
||
|
||
manual --> ei
|
||
today -.-> roadmap
|
||
rec --> diff --> wp
|
||
```
|
||
|
||
Today, indexes are built explicitly via `ensure_indices`. Reads degrade gracefully when index coverage is partial — Lance's scanner unions indexed and scan paths automatically. The roadmap reconciler observes manifest state and converges coverage in the background.
|
||
|
||
### Server / CLI
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
classDef l2 fill:#e8f4fd,stroke:#1e6aa8,color:#000
|
||
|
||
cli[omnigraph CLI<br/>command families]:::l2
|
||
srv_in[Axum HTTP<br/>REST + OpenAPI]:::l2
|
||
auth[Bearer auth<br/>SHA-256 hashed tokens]:::l2
|
||
pol[Cedar policy gate<br/>per request]:::l2
|
||
wl[WorkloadController<br/>per-actor admission]:::l2
|
||
eng[engine API<br/>Arc<Omnigraph>]:::l2
|
||
wq[WriteQueueManager<br/>per-(table, branch)]:::l2
|
||
|
||
cli -.-> eng
|
||
srv_in --> auth --> pol --> wl --> eng
|
||
eng --> wq
|
||
```
|
||
|
||
The server applies Cedar policy at the HTTP boundary today. The roadmap, called out in [docs/dev/invariants.md](invariants.md) as a known gap, is to push policy into the planner as predicates. After Cedar, mutating handlers go through `WorkloadController` (per-actor admission cap + byte budget; PR 2 / MR-686) before reaching the engine. The engine itself holds an `Arc<WriteQueueManager>` so concurrent mutations on the same `(table, branch)` serialize at the queue, while disjoint keys run in parallel — see [docs/user/server.md](../user/server.md) "Per-actor admission control" and [docs/dev/writes.md](writes.md). The CLI bypasses the HTTP layer (and admission) and calls the engine API directly.
|
||
|
||
Code paths:
|
||
|
||
- Server entry: `crates/omnigraph-server/src/lib.rs`
|
||
- Auth: `crates/omnigraph-server/src/auth.rs`
|
||
- Policy: `crates/omnigraph-server/src/policy.rs`
|
||
- CLI: `crates/omnigraph-cli/src/main.rs`
|
||
|
||
## L1 / L2 framing
|
||
|
||
Throughout the docs, capabilities are split into:
|
||
|
||
- **L1 — Inherited from Lance**: what OmniGraph gets "for free" by sitting on top of the Lance dataset format (columnar Arrow storage, per-dataset versions and branches, index types, `merge_insert`, `compact_files` / `cleanup_old_versions`).
|
||
- **L2 — Added by OmniGraph**: typing (schema language), graph semantics, multi-dataset coordination via `__manifest`, graph-level branches and commits, the `.gq` query language and IR, the topology index, the HTTP server, Cedar policy, the CLI.
|
||
|
||
## Concurrency model
|
||
|
||
- **MVCC**: every Lance write bumps a per-dataset version; the OmniGraph manifest version coordinates which sub-table versions are visible together.
|
||
- **Snapshot isolation**: a query holds one `Snapshot` for its lifetime; concurrent writes don't leak in.
|
||
- **Cross-branch isolation**: copy-on-write means readers and writers on different branches don't block each other.
|
||
- **Per-query staging**: `mutate_as` and `load` (Append/Merge) accumulate insert/update batches in an in-memory `MutationStaging`; one `stage_*` + `commit_staged` per touched table runs at end-of-query, then the publisher commits the manifest atomically. A mid-query failure leaves Lance HEAD untouched on staged tables. (MR-794; pre-v0.4.0 used a `__run__<id>` staging branch + Run state machine, removed in MR-771.)
|
||
- **Schema-apply lock**: `__schema_apply_lock__` system branch serializes schema migrations.
|
||
- **Fail-points** (`failpoints` cargo feature): `failpoints::maybe_fail("operation.step")?` in `branch_create`, publish, etc., for deterministic failure injection in tests.
|
||
|
||
## Workspace crates
|
||
|
||
- `omnigraph-compiler` — schema and query grammars, catalog, IR, lowering, type checker, lint, migration planner, OpenAI-style embedding client.
|
||
- `omnigraph` (engine, published as `omnigraph-engine` on crates.io since v0.2.2) — the Lance-backed runtime: manifest, commit graph, snapshot, exec (incl. per-query `MutationStaging` accumulator), merge, loader, Gemini embedding client.
|
||
- `omnigraph-cli` — the `omnigraph` binary.
|
||
- `omnigraph-server` — the `omnigraph-server` binary (Axum HTTP server).
|