Skip to content

Conversation

@7layermagik
Copy link

@7layermagik 7layermagik commented Dec 29, 2025

Summary

Adds disk persistence to the existing in-memory program cache.

Before: Compiled SBPF programs are cached in memory during replay, but when you stop mithril (Ctrl+C) and run it again, the cache starts empty and all programs must be recompiled as they're encountered.

After: When mithril exits, it saves the compiled programs to program_cache.gob. On the next mithril run, it loads them back, skipping recompilation and speeding up warmup.

Key Changes

  • New file: pkg/accountsdb/program_cache.go - gob serialization/deserialization of compiled programs
  • Config option: tuning.persist_program_cache (default: true)
  • Snapshot validation: Cache is discarded if built from a different snapshot slot
  • Cleanup: program_cache.gob properly removed when rebuilding AccountsDB
  • otter v2: Upgraded cache library for improved API

Configuration

[tuning]
# Persist compiled program cache across mithril restarts
# Speeds up replay warmup by avoiding program recompilation
persist_program_cache = true

Cache Defaults

  • Program cache: 3000 entries (reduced from 5000)
  • Vote account cache: 2000 entries
  • Common accounts cache: 10000 entries

Test plan

  • Run mithril and replay some slots
  • Stop mithril (Ctrl+C) and verify program_cache.gob is created in accountsdb dir
  • Run mithril again and check logs for "loaded N programs from cache"
  • Verify cache is invalidated when using a different snapshot

🤖 Generated with Claude Code

7layermagik and others added 7 commits December 28, 2025 21:58
Add a new config option `persist_program_cache` under [tuning] that:
- Saves compiled SBPF programs to disk on shutdown
- Reloads them on startup to speed up replay warmup

Since program compilation is expensive and the same programs are used
repeatedly, persisting the cache can significantly reduce warmup time
after restarts.

Also reduces vote account cache size from 5000 to 2000 entries since
there are only ~600 validators on mainnet.

Config: tuning.persist_program_cache = true/false (default: false)
- Upgrade otter cache library from v1 to v2
- Remove Cost() anti-pattern per otter docs (use count-based eviction)
- Add configurable cache sizes to [tuning] config section
- Enable persist_program_cache by default for faster restarts
- Use otter v2 API: GetIfPresent(), Invalidate(), All() iterator

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Ensures the persistent program cache file is removed during fresh
snapshot builds to prevent loading stale cache from a previous run.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Show whether program cache persistence is enabled in the "initializing
caches" log message for both verify-range and verify-live commands.
Store the snapshot slot in the program cache file and validate it on
load. If the cache was built from a different snapshot, discard it to
prevent potential state mismatch issues.

This protects against edge cases where the AccountsDB is replaced or
modified but the cache file remains, which could cause incorrect
program bytecode to be used during replay.
Update fmtDuration to show minutes and seconds for longer durations
instead of raw seconds like "1082.342s".

Examples:
- < 1s: "123.456ms"
- < 1m: "45.2s"
- < 1h: "18m2s"
- >= 1h: "1h30m45s"
The 3000 entry limit is sufficient since there aren't that many
programs on Solana that are frequently used in practice.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@7layermagik 7layermagik changed the base branch from main to dev December 29, 2025 14:27
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.

2 participants