Repository navigation
perf: save vehicle checkpoints in one transaction and stop idle switch updates - #80
Conversation
The 5-minute vehicle checkpoint committed every vehicle separately on the main thread, waiting for the disk once per vehicle, then copied the whole database as a backup. On Main that froze the server for 0.3-0.6 s every 5 minutes. Save all vehicles in one transaction instead, and fall back to one-by-one saves if that transaction fails so a rollback loses nothing. The backup copy now runs on the first checkpoint and then every 6th (30 minutes); the WAL checkpoint still runs every cycle. Track switches were animated by reading the tags of every rail display on every tick and re-teleporting each switch even when it was already in place. Keep the switch displays and their junctions in their own list, and skip the teleport when the yaw would not change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Summary
Merge Risk: ⚪ Minimal · up to
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
Summary
Two main-thread costs found in a spark profile of Main (2026-10-22, 20:28–21:28 UTC):
1. The 5-minute vehicle checkpoint froze the server for 0.3–0.6 s, up to about 1 s.
Every 5 minutes, "Checkpointing vehicles..." ran on the server thread. It saved each live vehicle as a separate SQLite commit, each waiting for the disk, then took a full
VACUUM INTObackup copy. The database is small (about 336 KB on Main), so the time is spent waiting on the disk, which is busy on the shared host. Players feel this as a lag/rubber-band blip every 5 minutes. Main's ticks peaked at 600 ms–3 s every 5 minutes.VehiclePersistence.saveLiveBatchsaves all live vehicles in one transaction, so a checkpoint waits for one commit instead of one per vehicle.VACUUM INTObackup now runs on every 6th checkpoint: at startup, then every 30 minutes. The WAL checkpoint still runs every cycle. Backup retention is unchanged (KEEP = 3), so it now covers about 1.5 h instead of 15 min.2. Rail-switch animation read the tags of every track display, every tick.
TrackDisplayManager.tickSwitcheslooped over every live rail display each tick and read its persistent data to find the few switch displays. It also re-teleported each switch every tick, even when it was already at its target yaw. At 21:13 on Main it took +1.5 s in one minute.liveon chunk load and unload, as before.Testing
mvn -B clean verifylocally: 1748 tests, 0 failures, 9 skipped. The skipped ones are POSIX-only tests that skip on Windows; the coverage gate reports 10 missed lines in those untouched classes only. The changed classes have 0 missed lines. Linux CI is the reference.~/grave-hopper-test/, character bot TestChar1):fixed_artilleryrows (3 reloaded from SQLite after a restart, 3 freshly spawned) all got the sameupdated_atfrom the 00:05:47 checkpoint, within 1 ms of each other. There were no "Failed to persist" or "checkpoint transaction failed" lines. The test then removed them with/vf kill.Part of the 2026-10-22 ping/lag investigation, together with RPCharacters and Games PRs.
🤖 Generated with Claude Code