Research cross system storage dissection - kmosoti/FabricO11y GitHub Wiki

Historical report imported 2026-10-10 from docs/research/cross-system-storage-dissection.md. Original SHA-256: bbb33118087f176a4128b2fcbc892f5bc74af6077890b2260700ceb8078969be. Measurements and outcomes retain their stated revisions. Links and local environment labels are normalized; $FABRIC_DATA is the mounted experiment drive. See evidence policy.

Storage ownership, pressure relief and construction costs

Source dissection, 2026-10-08; research tier, not an adopted design. This extends the cross-system program using downloaded implementation files under the continuation protocol (local checkout reference docs/experiments/benchmarks/cross-system-continuation-protocol.md; not present at origin/main). The strongest additions are a distinction between retained and construction memory, a drain condition after cancellation, and a choice of maintenance work that addresses both resident pressure and the oldest unreclaimable journal. No upstream code, workload, build or validator was executed for this dissection.

Frozen coverage

The receipts below record immutable revisions, archive/member digests, requested and missing paths, selected-source readback, and cleanup. The inspected members are inside each receipt's sibling selected-source.tar.gz; complete regular-file inventories are sibling regular-members.jsonl.gz files. Inventory coverage is not implementation review coverage. The following table states the narrower inspection performed here; individual function bodies and nearby control flow were read, rather than every line of every selected file.

Project and exact revision Inspected paths Evidence
Comet 412468e2817207eff0c1907d1c4aac8c3f06680d native/core/src/alloc_accounting.rs; native/core/src/execution/memory_pools/{fair_pool,plan_pool,task_shared}.rs receipt (local evidence omitted from stage)
Feldera proposal ff12ddadd8dbfbcb8dedc276cc83382d4c2f3095 README.md, storage layers, buffer pool, checkpoint and reclamation sections; proposal only receipt (local evidence omitted from stage)
Feldera implementation 31b177027205a35e51b08c6209cd9ea90f5c881c crates/dbsp/src/trace/spine_async.rs; crates/dbsp/src/trace/spine_async/list_merger.rs receipt (local evidence omitted from stage)
Vortex 881b867d736e8955a0381655f80d6d2d630fc590 encodings/fsst/src/{kernel.rs,compute/filter.rs,compute/like.rs,dfa/mod.rs}; vortex-array/src/arrays/filter/execute/take.rs receipt (local evidence omitted from stage)
Lance b8886f554b773ceaa78aef9666af616217bd0199 rust/lance/src/io/exec/filtered_read.rs, stable-ID routing and intersection; rust/lance/src/index/scalar.rs, training projection/stream construction receipt (local evidence omitted from stage)
redb f403a514fd557f633bd4725248f0d19b434eedff src/transaction_tracker.rs, reader registration/durable-ancestor ownership; src/tree_store/page_store/page_manager.rs, deferred-free ranges and page allocation receipt (local evidence omitted from stage)
Fjall 17ae6720cbf1a44a1f1f0dcbcb1f4fd913b23c89 src/keyspace/mod.rs, insert/maintenance/backpressure; src/journal/manager.rs; src/journal/writer.rs, persistence/rotation receipt (local evidence omitted from stage)

All requested paths in these retrieval receipts were found. This does not cover the transitive implementations called by those files. In particular Lance's RowIdSequence::mask_to_offset_ranges, Vortex's VarBin filter implementation, Feldera's buffer-cache allocator, and Fjall's lsm_tree dependency are outside this inspection. The proposal archive contained no selected license file; its receipt records that absence, without a licensing conclusion.

1. A retention budget can hide construction and recomputation

Observed source. Lance's fragment_metadata_load loads the stable-ID sequence and constructs upper_ranges with mask_to_offset_ranges before calling retain_stable_index_ranges. The latter charges vector capacity times size_of::<Range<u64>>(), using a compare/exchange loop against the 16 MiB request-scoped retention allowance. On refusal it returns None and the constructed vector is dropped. intersect_index_ranges uses a retained vector when available; otherwise it calls mask_to_offset_ranges again. It consumes precomputed ranges fragment by fragment rather than retaining all of them beside the completed plan.

Deduction and counterexample. That allowance bounds this retained range storage, not the first vector's construction peak, the loaded ID sequence, or the final plan. A highly fragmented candidate mask can spend allocation and CPU on a vector that is discarded and later rebuilt. Multiple concurrent routing operations can amplify transient construction even if retained storage obeys its allowance. This is a structural counterexample to calling a cache budget a whole-query memory bound; its size and timing have not been measured here.

Fabric mapping and candidate. The bounded builder (local checkout reference crates/fabric-server/src/segment/bounded.rs; not present at origin/main) already counts string capacities and map overhead, while the sealer view explicitly permits an oversized row alone. Apply the same distinction to future query candidate sets and hot-tail structures: retained bytes, transient construction bytes and recomputation are three costs. First compare a streaming range intersection with retained/rebuilt ranges on identical clustered and alternating-ID masks. H1: streaming lowers construction peak on fragmented masks while preserving exact ordered results. H0: repeated traversal, locality loss or output storage erases the benefit. Dense/contiguous matches are the deliberate adverse case; candidate-set build CPU and final output ownership must remain in the measurement boundary.

2. Completion ownership needs a drain measurement

Observed source. Comet's PlanMemoryPool counts held bytes before invoking the inner grow/try_grow, rolls back refused growth, and subtracts only after inner shrink. wait_until_released waits on a condition variable until held bytes reach zero or a deadline, and returns any remaining bytes. The file explains why plan drop can leave reservations in merge tasks until those tasks yield. TaskSharedMemoryPool uses an Arc lifetime and weak registry entries; its drop logic distinguishes the old pool from a replacement. These are implementation observations; the accompanying upstream tests were read, not run.

The fair pool accounts sibling reservations under one consumer identity. Its try_grow checks both the consumer share and the whole pool because late registration does not revoke allocations already held by earlier consumers. Its infallible grow records already-existing allocation even beyond those limits. The allocator observer separately batches signed thread-local deltas at 64 KiB and clamps its shared reported balance at zero; it is an approximate observer, with drift dependent on live thread count, rather than admission.

Deduction and counterexample. A canceled request, a dropped high-level owner, a zero local request counter and returned worker memory are distinct events. Splitting reservations must not manufacture new shares. A new fairness denominator also cannot reclaim earlier holdings. Importing Comet's approximate observer without its drift qualification would make small short-lived allocation changes look more exact than they are.

Fabric mapping and candidate. Fabric already moves the query permit into the actual blocking closure in spawn_query_work; this is not a proposal to repeat that repair. Measure canceled-request-to-worker-completion, permit release and live requested bytes at the same cut. H1: at least one declared cancellation shape has a measurable memory drain interval after client completion that affects available admission. H0: work finishes promptly or the remaining memory belongs to shared state that cancellation cannot release. Shared-cache residency, uncanceled work and allocator retention are competing explanations. Do not use zero permits or reservations alone as a cleanup oracle, and do not change Fabric's precise probe counters merely to imitate Comet.

3. Relieving resident pressure can create a maintenance backlog

Observed source. Feldera's current Spine::try_start_merge checks the batch-count threshold before the memory-pressure branch. The stated reason is to prevent repeatedly merging only in-memory batches while total batch count keeps growing. Under high pressure and below that threshold it selects only memory-resident batches; stored batches need not be rewritten just to move resident state to disk. This is more specific than the older proposal's buffer-pool eviction discussion, whose policy and failure handling were TBD.

The inspected scheduler gives level-zero merges isize::MAX fuel; other levels receive fuel based on average level-zero merge work. ListMerger::copy_times can traverse time/weight entries before charging one emitted value, and a zero-weight result returns before that charge. Thus even the finite-fuel paths do not establish byte or wall-time bounds. This confirms the previous candidate screen and adds the level-zero and pressure-versus-batch-count scheduling qualifications.

Deduction and counterexample. Minimizing resident bytes alone can leave more immutable objects, discovery overhead and future merging behind. Conversely, forcing every pressure event to merge stored inputs can increase I/O when the resident subset was sufficient. Neither unconditional policy dominates.

Fabric mapping and candidate. D3's hot-tail-versus-sealing budget needs a second guard for accumulated maintenance work: journal age/bytes and source fanout, alongside live derived bytes. H1: memory relief with a backlog guard avoids growing future read/maintenance work better than resident-only relief. H0: the existing scheduler already controls the relevant backlog, or extra work increases ACK/query cost without useful drain. Use a stalled oldest journal, many small files and sparse repeated queries as separate discriminating shapes. Weighted consolidation and negative-weight cancellation are Feldera semantics and must not be transferred into exact Fabric Batch custody.

4. Choose work against the oldest obstruction, with the right lifetime

Observed source. Fjall's journal manager identifies the keyspaces whose persisted sequence numbers do not yet cover the oldest journal's recorded watermarks. Maintenance examines that oldest journal first and returns without deleting it if any required watermark is uncovered. It uses persisted table sequence numbers rather than newer memtable sequence numbers; its safety argument explicitly depends on FIFO flush queues. This identifies work that can make reclamation progress instead of treating all queued work as equivalent.

Fjall's insert writes the journal, inserts the value, publishes its sequence, drops the journal lock, then charges write-buffer size and calls maintenance. Local backpressure can wait for level-zero runs or sealed memtables after that insertion. This is a concrete counterexample to treating those thresholds as refusal before allocating. PersistMode::Buffer flushes the userspace buffer but does not provide the power-loss guarantee of SyncData/SyncAll; rotation explicitly invokes SyncAll. These settings cannot replace Fabric's durable ACK.

redb adds a separate lifetime qualification. register_read_transaction captures the committed snapshot and registers its reader under the tracker/header locks, so reclamation cannot miss the reader. Pending non-durable commits retain references to their nearest durable ancestor. In the page manager, data_freed_in_range explicitly handles reversed/equal bounds because the oldest unprocessed non-durable commit and oldest live reader are independently derived. Reader protection and durability protection are distinct owners; subtracting one from the other is not automatically a valid reclaim interval.

Fabric mapping and synthesized candidate. Combine oldest-obstruction work selection from Fjall with Feldera's resident-only relief under low fanout and Comet's completion-owned accounting. Proposed rule: prefer work that releases the oldest durable journal obstruction when backlog pressure dominates; under resident pressure and controlled backlog, relieve optional derived memory; retain each admission owner until its actual work drains. This is a new combination in this research program, not an originality claim or implemented controller. Fabric's existing ordered-prefix reclamation remains the safety boundary; later completion must never reclaim through a hole. redb's reader-pinned retention must not be imported: Fabric's expired page tokens return Gone and do not promise a file lease.

H1: compared with fixed oldest-first sealing and a resident-only policy, this choice reduces both journal byte-time and derived-memory byte-time on the declared skewed workload without worsening registered ACK/query guards. H0: shared commit/disk contention, inaccurate relief estimates or oldest-label cost makes either simpler policy equal or better. The inverse workload, where the oldest file is the largest and expensive to finish, is essential: completing small later files may release more memory while yielding no physical journal reclaim. Measure those objectives separately. Require isolated policy ablations before the combination, unchanged exact replay/query checks, and explicit progress reserve before any adaptive prototype is nominated.

Compressed execution remains a conditional alternative

Vortex's FSST kernel registration routes LIKE, filtering, byte length and other supported operations to encoding-specific implementations. The inspected LIKE path requires a constant pattern and declines case-insensitive evaluation. FsstMatcher::try_new rejects unsupported wildcard shapes and enforces byte limits: 253 for literal prefix and 254 for literal contains. Its parser borrows unescaped literals and materializes escaped literals. Filtering invokes the VarBin filter on compressed codes and filters uncompressed lengths while reusing the symbol table. Generic Filter/take code has contiguous-slice and sequential-rank paths, and otherwise builds translated indices.

These observations narrow D5 rather than proving a whole-path advantage. Fabric literal needles containing %, _ or backslash require correct LIKE escaping; Unicode limits must be tested in bytes, with empty, 254-byte and 255-byte needles and compressed escape-code cases. H1: on sufficiently reused compressible blocks, predicate execution before payload materialization saves more CPU than training, conversion, selection and output consume. H0: broad results, high entropy, unsupported needles or coexisting buffers erase that saving. Exact custody and required validation remain, and the uninspected VarBin implementation prevents a zero-copy or retained-backing bound claim from this review alone.

The next discriminating work is construction/rebuild attribution and memory drain timing, followed by pressure-versus-oldest-obstruction scheduling only if those costs matter. No source observation here changes a product contract, qualification status, default allocator, storage format or current scheduler.

⚠️ **GitHub.com Fallback** ⚠️