Skip to content

Immutable/volatile split of LeiosDB + garbage collection - #2223

Draft
geo2a wants to merge 3 commits into
leios-prototypefrom
geo2a/leios-969-leiosdb-gc
Draft

Immutable/volatile split of LeiosDB + garbage collection#2223
geo2a wants to merge 3 commits into
leios-prototypefrom
geo2a/leios-969-leiosdb-gc

Conversation

@geo2a

@geo2a geo2a commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Implements input-output-hk/ouroboros-leios#969

cardano-node PR: IntersectMBO/cardano-node#6656

This PR splits the contents of LeiosDB into volatile and immutable partitions, and periodically marking EBs as immutable once their referencing RB becomes immutable and garbage collection orphaned volatile EBs.

An EB is marked as immutable via the immutable flag column of the ebs table. All transactions (rows of the txs table) referenced by this EB via the ebTxs table become immutable as well, but there are no explicit marker in those tables.

The PR also adds observability of the volatile/immutable EB counts an the GC rates, which is wired into a Graphana dashboard which looks like this:

run-13-08-2026-k2160-v03-leiosdb-board

Benchmarking

The PR adds the leios-gc-bench benchmark, which works both synthetic data and with a real leios.db. I've generated some input data by running the devnet overnight to test the performance:

Totals over 50 cycles:
  marked as immutable ebs/ebTxs/txs = 83/203314/130147
  evicted ebs/ebTxs/txs = 0/0/0
  insert collisions     = 0
  mark as immutable : min=20 ns  avg=42 ms  max=884 ms
  gc                : min=383 μs  avg=241 ms  max=12.049219837 s

The duration of the first immutable marking and GC are an outlier, which Claude attributes to cold OS page cache. The outliers are clearly visible on the following scatter plot (x axis is log scale):

gc-bench-plot-k2160

When running the benchmark with synthetic data, the outliers don't show up, probably because the sqlite database is written into before the start of the measurement:

Totals over 50 cycles:
  marked as immutable ebs/ebTxs/txs = 750/150000/150000
  evicted ebs/ebTxs/txs = 750/150000/150000
  insert collisions     = 0
  mark as immutable : min=38 ms  avg=43 ms  max=52 ms
  gc                : min=18 ms  avg=26 ms  max=257 ms
gc-bench-plot-synth

Implementation details

One particular peculiarity that I had to iron out was the use of the unsafe FFI calls to the SQLite bindings. The immutalisation or GC operations need to run in a safe FFI call so that they are run on a separate GHC RTS capability and do not block the node from doing other things. This needs further investigation, together with auditing other FFI calls and making a weighted decision on which mechanism to better for every one of them.

@geo2a
geo2a force-pushed the geo2a/leios-969-leiosdb-gc branch 4 times, most recently from e3544e6 to dabc62d Compare August 20, 2026 06:41
geo2a added 3 commits August 20, 2026 15:25
- Add a column to the `ebs` SQLite table that distinguishes EBs as immutable.
- Mark EBs as immutable once their RB becomes immutable.
- Garbage Collect EBs and their transations if they are volatile and are older that
  the immutable tip.
- Add trace events for Prometheus gauges:
  * `TraceLeiosDbCopiedToImmutable` --- Rows moved into the immutable partition
    by 'LeiosDbHandle.leiosDbCopyToImmutable'
  * `TraceLeiosDbVolatileStats` --- volatile counts and file bytes, sampled on a
  timer over a fresh read-only connection per tick, kept clear of startup.
  * `TraceLeiosDbImmutableStats` --- the immutable counts maintained incrementally
     in a one-row `immutableStats` table.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant