Skip to content

feat: implement snapshot-based persistence (closes #39)#69

Open
ithustle wants to merge 1 commit intoAlexJuca:mainfrom
ithustle:feat/snapshot-persistence
Open

feat: implement snapshot-based persistence (closes #39)#69
ithustle wants to merge 1 commit intoAlexJuca:mainfrom
ithustle:feat/snapshot-persistence

Conversation

@ithustle
Copy link

@ithustle ithustle commented Mar 3, 2026

Summary

  • Add snapshot persistence that serializes the store and expires hashtables
    to a binary RDB file with CRC32 integrity checking
  • Atomic writes via tmp file + fsync + rename to prevent corruption on crash
  • Graceful shutdown saves snapshot before exit (SIGINT sets flag, event loop
    calls shutdown_server)
  • Periodic save triggered from the 100ms timer in each event dispatcher when
    dirty >= threshold and enough ticks have elapsed
  • Snapshot loaded on startup, expired keys discarded during load
  • Enabled by default: save-interval 300 1 (5 min, 1 change minimum)
  • Configurable via save-interval, snapshot-path in server.conf;
    disable with save-interval 0 0

Files added (5)

  • src/persistence/crc32.h — CRC32 lookup table and update function
  • src/persistence/persistence.h — save/load API
  • src/persistence/persistence.c — serialization, atomic write, CRC verification
  • src/fkvs_time.h — standalone fkvs_now_ms() to decouple persistence from utils.h
  • tests/test_persistence.c — 8 test cases (round-trip, encoding, TTL, corruption)

Files modified (8)

  • src/server.h — new fields: save_interval, dirty, shutdown_requested, snapshot_path
  • src/config.c — defaults and parsing for save-interval, snapshot-path
  • src/server.c — shutdown_server(), load on startup, simplified SIGINT handler
  • src/networking/networking.c — dirty counter for write commands
  • src/io/event_dispatcher_{kqueue,epoll,io_uring}.c — shutdown check + periodic save
  • src/utils.h — delegates fkvs_now_ms() to fkvs_time.h
  • CMakeLists.txt — persistence.c in server targets, test_persistence target
  • server.conf — documented save-interval and snapshot-path options

RDB format

HEADER: [4B magic "FKVS"] [1B version] [8B timestamp BE]
STORE: [1B marker 0x01] [8B count BE] [entries: key_len|key|val_len|val|encoding]
EXPIRES: [1B marker 0x02] [8B count BE] [entries: key_len|key|deadline_ms BE]
FOOTER: [4B CRC32 BE] [1B EOF 0xFF]

Test plan

  • test_persistence — 8 unit tests covering round-trip, encoding, TTL,
    expired discard, empty DB, missing file, corrupted header, corrupted CRC
  • Manual: start server with default config, SET keys, wait >5min or
    Ctrl+C, verify fkvs-dump.rdb created, restart and GET keys back
  • Manual: set save-interval 0 0, verify no snapshot created

Issue reference: #39

  Serialize the hashtable to disk periodically and on shutdown using an
  atomic write strategy (tmp + fsync + rename + fsync dir). On startup
  the snapshot is loaded back, discarding any expired keys.

  Enabled by default (every 5 min if >= 1 change). Configurable via
  save-interval and snapshot-path in server.conf, or disabled with
  save-interval 0 0.
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