Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/nornir

docs/v2/mimir/tables.md

Mímir v2 — tables and columns

Every column below is taken from crates/mimir-schema/src/lib.rs (the four payload tables), crates/mimir-schema/src/code_mir.rs (the three lossless tables of schema 8) and crates/mimir-ingest/src/schema.rs (the lake's event prefix and table names). utf8 is an Arrow string; "null" means nullable.

1. The driver's payload tables

code_nodes (*.nodes.arrow)

column type meaning
id utf8 the moniker
kind utf8 node kind (list below)
level utf8 workspace · repo · crate · module · item · part
name utf8 the item's name
parent utf8 null the containing node's id
repo utf8 null from MIMIR_REPO
crate utf8 crate name
version utf8 crate version
file utf8 null path relative to the workspace root (members) or the manifest dir (dependencies); OUT_DIR files mapped
start_line, end_line u32 null the item's span
cfg utf8 null the cfg predicate
origin utf8 local · library · lang
provenance utf8 source_only · binary_only · both
valid_from_sha, valid_to_sha utf8 null from MIMIR_SHA; valid_to_sha is null in a dump
ty utf8 null printed type for params, fields, consts, statics, aliases (short paths: OnceLock<Option<Arc<T>>>; null on a reference stub); the MIR payload for mir_body
is_test bool a test fn
defined_here bool false = a reference stub of another crate's item
visibility utf8 null pub · pub(crate) · private
effective_visibility utf8 null direct · reexported · reachable · reachable_impl_trait · internal
doc utf8 null the first line of the doc comment
has_doc bool null the item carries a doc comment
ignored bool null #[ignore] on a test fn
doc_hidden bool null the item itself is #[doc(hidden)]
link_name utf8 null the symbol a foreign fn or static is linked as

Node kinds (mimir_schema::kind):

crate mod fn method struct enum union trait trait_alias impl const static type macro
ffi foreign_type field variant param ret local generic assoc_type assoc_const
mono_instance ffi_import feature

plus the MIR part mir_body (one per fn), at level part. Its payload (the block fingerprints, terminator kinds and successors) is derived from the fn's code_mir rows. Since schema 8 the driver writes no mir_block node: a reader derives the blocks from the same rows (section 1.1).

code_edges (*.edges.arrow)

column type meaning
from, to utf8 monikers
kind utf8 edge kind (list below)
count u32 distinct sites that carry the edge
provenance utf8 source_only · binary_only · both
valid_from_sha, valid_to_sha utf8 null commit range
negated bool null GATED_BY only: the feature sits under an odd number of not(…)
partial bool null GATED_BY only: the feature gates something inside the item
access utf8 null TOUCHES_TABLE only: read · write · both

Edge kinds (mimir_schema::EdgeKind):

CONTAINS DEPENDS_ON CALLS IMPLEMENTS FOR_TYPE USES_TYPE READS_FIELD EXPANDS GATED_BY
TESTS TOUCHES_TABLE COMPATIBLE INSTANCE_OF ENABLES ENABLES_WEAK BUILT_FROM SYSCALLS CFG_SUCC
WRITES_FIELD

The order is EdgeKind::ALL: a new kind is appended (mimir-room keys its kind masks on the position), so WRITES_FIELD (schema 6) is index 18. CFG_SUCC keeps its position, but since schema 8 the driver writes no CFG_SUCC edge: the successors of a block are derived from a code_mir row (section 1.1).

The two field kinds, for a body owner b and a field f (a struct, union or enum-variant field):

READS_FIELD(b, f)   ⇔ b has an expression `e.f` (struct / union): a MENTION, read or written
WRITES_FIELD(b, f)  ⇔ f ∈ written(p) for a place p of b with  p = v | p op= v | &mut p | &raw mut p
                      | p auto-borrowed &mut (a `&mut self` method on p)
                    ∨ b has a literal `S { f: v, .. }` / `E::V { f: v, .. }`  (not the fields `..base` fills)
written(p)          = { g : `.g` on the path of p, outside in, up to the first deref }
count               = |{ (file, line) of the field expression }|      (as for every kind)

A read-only use is READS_FIELD(b, f) ∧ ¬WRITES_FIELD(b, f); a literal names a field without a field expression, so it is a WRITES_FIELD only. a.b.c = v writes c and b, and a too unless a is reached through a pointer; r.f = v with r: &mut S writes only f.

code_spans (*.spans.arrow)

column type meaning
target utf8 node or edge
key utf8 the node id, or from ␞ to ␞ KIND for an edge site (U+001E separators)
file utf8 path, as in code_nodes.file
start_line, end_line u32 the span; an edge site has start_line = end_line

code_symbols (*.symbols.arrow)

column type meaning
id utf8 moniker
symbol utf8 the linked symbol
demangled utf8 null its demangled form
role utf8 the symbol's role (for example import)
crate, version utf8 owner crate
binary utf8 null artifact file name; null on a driver row
section utf8 null ELF section
addr, size u64 null address and size in the artifact
provenance utf8 as above
valid_from_sha, valid_to_sha utf8 null commit range

1.1 The lossless tables (schema 8)

Three more files per unit hold the MIR facts in ONE lossless form (crates/mimir-schema/src/code_mir.rs; the plan is exec-graph-plan.md). A unit may lack any of them (MIMIR_MIR=off, a dump of an older driver). A program's --exec unit has only these files and <stem>.exec.json.

file table one row per identity
<stem>.mir.arrow code_mir body (fn, method, closure, coroutine, compiler shim) def
<stem>.inst.arrow code_instances instance (a body with concrete generic arguments) inst
<stem>.data.arrow code_data a static the unit defines, or an unnamed allocation a constant or a static points at (the instance pass: the statics of every crate the program names) id

The files are Arrow IPC with zstd buffers, at most 2,048 rows per record batch. A row holds its lists as Arrow List columns (a struct of arrays). A string column inside a row holds indices into the row's own pool strs (0xFFFF_FFFF = none). Every table ends with content.

code_mir, columns in schema order:

column type meaning
def utf8 the body's def key (std::fs::File::open, app[bin=app]@0.1.0::main::{closure#0}; a shim: its instance key): the same string in every compiler session, the key code_instances.body joins on
owner utf8 moniker of the nearest item with a node (the fn, the method, the static a closure sits in)
sub utf8 def path from the owner to the body: empty for the owner's own body, {closure#0}, {closure#0}::{closure#1}; a shim: {shim:…}
kind utf8 fn, closure, coroutine, shim
legacy utf8 null the block-name prefix of the schema-7 view (empty, c1., c2. …); null = that view never held this body
arg_count u32 the first arg_count locals after _0 are the parameters
legacy_cap u32 the schema-7 view keeps at most this many (non-cleanup) blocks (0xFFFF_FFFF = all: the default)
base_line u32 the owner's first line when the unit was dumped; the positions of the sites are relative to it; not part of content
local_flags list<u8> per local: bit 0 mutable, bit 1 user variable, bit 2 parameter
blk_flags list<u8> per block: bit 0 cleanup (unwind) block
st_kind list<u8> per site: its kind (code_mir::site)
st_flags list<u8> per site: bit 0 from a macro expansion, bit 1 the site has a position
op_kind list<u8> per operand: code_mir::opk (copy, move, constant, place)
pj_kind list<u8> per projection step: code_mir::pjk
k_kind list<u8> per constant: code_mir::kk
tg_role list<u8> per target: code_mir::role
st_file list<u16> per site: its source file (index into files; 0 = the owner's file)
files list<u32> source files of the positions (strs); entry 0 is the owner's file
local_ty list<u32> per local: its type, rustc's full print (strs)
dbg_name, dbg_place list<u32> every source name (strs) and the place it names (0xFFFF_FFFF = a constant)
blk_end list<u32> block b holds the sites [blk_end[b-1], blk_end[b]); its last site is the terminator
st_word list<u32> per site: the operation word (strs): Add, cast.IntToInt, adt~2, assert.bounds, use …
st_dest list<u32> per site: the written place, 0xFFFF_FFFF = none
st_ty list<u32> per site: a type (strs): a cast's target, the dropped type, an aggregate's type
st_callee list<u32> per site: the callee as the body's own text names it, a stable moniker (strs)
st_op_end list<u32> per site: its operands are [st_op_end[i-1], st_op_end[i])
st_tg_end list<u32> per site: its targets are [st_tg_end[i-1], st_tg_end[i])
st_dline list<u32> per site with a position: its line, zigzag-coded: relative to base_line in the owner's file, the absolute line in another file
st_col list<u32> per site: its column (1-based)
op_ref list<u32> per operand: index of its place or constant
pl_local, pl_pj_end list<u32> per place: its local, and its projection run [pl_pj_end[i-1], pl_pj_end[i])
pj_a, pj_b list<u32> per projection step: its two arguments (code_mir::pjk)
k_ty list<u32> per constant: its type (strs)
k_def, k_args list<u32> per constant: see code_mir::kk (strs)
k_bytes list<u32> per constant: its bytes (index into bytes)
tg_block list<u32> per target: the block (0xFFFF_FFFF = no block: see tg_role)
drop_key list<u32> one per drop site, in site order: the dropped type's key (strs), written over the body's own generic parameters
st_aux list<u64> per site: variant index; an assert's expected value; a drop's state; a storage marker's local; asm flags; a call's flags (bit 0: the callee is a compiler intrinsic)
k_lo, k_hi list<u64> per constant: the value's low and high 64 bits
tg_lo, tg_hi list<u64> per target: the switch value
strs list<utf8> the row's string pool
bytes list<binary> the row's byte pool (k_bytes)
content u64 a hash of every other column but base_line (the lake's delta key)

code_instances, columns in schema order:

column type meaning
inst utf8 the instance key
body utf8 the code_mir row this instance runs (code_mir.def)
args utf8 the generic arguments as type keys (⟨a,b⟩, empty = none)
symbol utf8 null rustc's symbol name of the instance (v0 mangling)
root u32 0 no; 1 main; 2 an exported fn; 3 a constructor (.init_array); 4 the process start (std::rt::lang_start)
flags u32 bit 0: the body is a compiler shim or an instance body the program's pass wrote; bit 1: rustc holds no MIR for it
res_kind list<u8> per resolved term: code_mir::res (instance, virtual, intrinsic, foreign item, fn pointer, nothing to do, not resolved)
res_def, res_args list<u32> a generic term of the body: the fn item (k_def, k_args of the code_mir row), or the dropped type (res_def = drop, res_args = the type's key)
res_inst list<u32> what it is in this instance: an instance key, a trait method + slot, a link name
res_line, res_col list<u32> where the term's site is in the source (line 1-based, 0 = none; column 1-based)
kv_def, kv_args list<u32> a generic constant of the body (k_def, k_args)
vt_dyn, vt_ty list<u32> every vtable this instance builds: the trait object type's key, the concrete type's key
vt_end, vt_m list<u32> its methods are vt_m[vt_end[i-1] .. vt_end[i]]: instance keys
fp_sig, fp_inst list<u32> every fn pointer this instance makes: the signature's key and the instance
spawn list<u32> thread / task marks: this instance starts the named instance as a new entry
kv_lo, kv_hi list<u64> the value of each generic constant in this instance
strs list<utf8> the row's string pool
content u64 a hash of every other column

code_data, columns in schema order:

column type meaning
id utf8 a static: its def key; an unnamed allocation: alloc:<16 hex digits> (code_mir::alloc_id, a hash of size, alignment, mutability, bytes and pointers)
ty utf8 a static: its type's key; an unnamed allocation: empty
link_section utf8 null the link section (.init_array makes a constructor)
flags u32 bit 0 mutable (a static mut, or the allocation is mutable), bit 1 thread local, bit 2 bytes is cut at 64 KiB, bit 3 the #[global_allocator] (not set yet), bit 4 #[used]; bits 8 to 13 log2 of the alignment
size u64 its size
bytes list<u8> its bytes (at most 64 KiB); an uninitialised byte and the bytes of a pointer are 0
ptr_to list<u32> every pointer in the allocation, in offset order, never cut: its target (strs): fn:<instance key>, a static's def key, alloc:<hash>, `{vtable}
ptr_sig list<u32> for a fn pointer: the signature's key (strs), else 0xFFFF_FFFF
ptr_off list<u64> the pointer's offset in the allocation
strs list<utf8> the row's string pool
content u64 a hash of every other column

The schema-7 view is derived, never stored. For a code_mir row with legacy not null, mimir_schema::code_mir::legacy gives:

view(row)         the non-cleanup blocks: name, fingerprint, terminator word, successors
body_payload      the `mir_body` node's `ty` (the driver writes it as the derived column it is)
block_nodes(row)  per block: id `<fn>bb<name>:`, the schema-7 `mir_block` payload, the CFG_SUCC successor ids

Every batch carries schema metadata mimir.schema = "8" and mimir.table = <table name>.

Versions (mimir_schema::SCHEMA_VERSION): 1 the four tables; 2 the visibility / doc columns, negated, partial, the feature kinds; 3 ignored, doc_hidden; 4 access, link_name; 5 stable identities; 6 WRITES_FIELD and every MIR block of a body written (no 1,024 cap); 7 REFERS_FN; 8 the three lossless tables, no mir_block node and no CFG_SUCC edge. Migration: a version that only adds nullable columns is evolved in place; a lake stamped before the re-read epoch (8, mimir-ingest REREAD_SCHEMA) is wiped by EventLog::open_lake and the consumer re-reads every repo from its tip, because the facts of every unit changed and a dependency already in the ring is never re-dumped. The wipe keeps no backup: the lake is derived data.

2. The lake (skade namespace mimir_v2)

An event table is a payload table with eight prefix columns in front:

column meaning
repo the member, or @universe for the dependency ring
seq the repo's sequence number (its commit ordinal in the log)
sha the commit
op + or -
krate the crate the row came from
payload_hash hash of the payload columns; for a lossless table the row's content (its 8 bytes, little endian, then zeros)
key_dup non-null only when one key was dumped with different payloads
rev binary stream only: the binary release ordinal per repo

Tables:

table payload written by
code_node_events code_nodes the consumer (source stream)
code_edge_events code_edges the consumer
code_span_events code_spans the consumer
code_mir_events code_mir the consumer (source stream), key def
code_instance_events code_instances the consumer, key inst
code_data_events code_data the consumer, key id
universe_node_events code_nodes the consumer, repo = @universe, once the lake is split (mimir.ring = split)
universe_edge_events code_edges same
universe_span_events code_spans same
universe_mir_events, universe_instance_events, universe_data_events code_mir, code_instances, code_data same: every dependency and toolchain crate carries its bodies, once per crate@version
universe_manifest the ring's manifest (the dependency and toolchain crates dumped into it) the consumer
code_symbol_events code_symbols mimir-binary (binary stream)
bin_node_events, bin_edge_events binary-layer nodes and edges mimir-binary
bin_ingest_runs one row per (artifact, binary release) mimir-binary
bin_offsets per artifact: the release and commit last written mimir-binary
consumer_offsets per repo: the seq and commit the lake is at the consumer
ingest_runs the ledger of consumer runs the consumer
consumer_feed_runs one row per (repo, sha, feed) for the non-graph feeds that ride the offsets the consumer
backfill_runs requested / done rows of a history backfill the consumer

Table properties: mimir.schema (the mimir-schema version the columns are at) and the comma-joined list of columns added in place by an evolution.

The lossless tables in the lake (crates/mimir-ingest/src/lossless.rs):

Storage: Parquet, zstd level 3, 256 k-row row groups (log.rs write_props); every write of a release goes through one commit lock and one skade atomic commit.