Module columnar_index

Module columnar_index 

Source
Expand description

Columnar entity index — a compact, binary-searched alternative to the EntityIndex FxHashMap<u32, (usize, usize)>.

§Why

The streaming pre-pass hands every wasm worker (N geometry workers plus the prepass and parser workers) the same pre-scanned entity index as three parallel u32 columns via setEntityIndex. Each worker used to materialize a private FxHashMap<u32, (usize, usize)> from those columns. hashbrown rounds the bucket count up to the next power of two, so for a 19.1 M-entity model it allocates 2^25 buckets × ~13 B ≈ 436 MB per worker, rebuilt in every realm. Three sorted Vec<u32> columns for the same model are 3 × 19.1 M × 4 B ≈ 229 MB — no power-of-two rounding, no per-bucket control byte, no (usize, usize) widening. The lookup becomes a binary_search (≈24 probes at 19 M rows) instead of an O(1) hash probe; see the PR for the measured wall-time delta on the full geometry pipeline.

§u32 offsets

starts/lengths are u32, which is only sound while the source file is < 4 GiB. WASM ingestion (setEntityIndex and cached_entity_index) already lives in that linear address space and delivers &[u32] columns. The native processor also uses this representation for large sources with sparse ids, after checking their byte length fits u32; dense ids may use crate::DenseEntityIndex. Wider native sources keep the usize-carrying EntityIndex hashmap.

§Duplicate express ids

crate::build_entity_index inserts scanned spans into an FxHashMap in file order, so a repeated express id resolves to its last occurrence in the file (HashMap::insert overwrites). Express ids are unique per the STEP spec and duplicates essentially never occur, but this type replicates the last-in-file-order-wins behaviour deliberately (see from_unsorted and the duplicate_id_last_wins test) so a malformed file cannot diverge between the hashmap and columnar paths.

Structs§

ColumnLengthMismatch
The three columns handed to ColumnarEntityIndex::from_columns or ColumnarEntityIndex::from_owned_columns were not all the same length. A caller-facing error, not an empty index: an empty index is also what an empty file produces, so folding the two together hid a malformed payload.
ColumnarEntityIndex
Compact, sorted, binary-searched entity index. Columns are kept sorted by ids (strictly ascending, unique) so Self::lookup can binary_search.