Solid Cache: database internals
This course reads the source of the solid_cache gem and the SQL it sends to Postgres. It follows reads through key_hash and the unique index, and writes through a single upsert that computes byte_size and leaves created_at untouched. It tests unless_exist and increment with ten concurrent threads and explains how the cache size is estimated from two indexes. It shows how expiry deletes rows in id order. It also covers failsafe error handling, Maglev sharding, the background thread, and a comparison with Redis.
What you'll learn
- ✓How reads hash the key into a signed 64-bit key_hash served by a unique index
- ✓How a write becomes one upsert, with compression and a computed byte_size
- ✓Where FOR UPDATE leaves unless_exist and increment non-atomic on missing keys
- ✓How the cache size is estimated from the byte_size and composite indexes
- ✓How write-driven expiry deletes the oldest rows by id
- ✓How failsafe, Maglev sharding and the background thread behave
One query per read: key_hash and the unique index
The junior course "Solid Cache: database caching" ended at the table: SolidCache::Entry, one row per cached fragment, with a real byte_size column you could sum. This course opens the gem and reads the code that puts those rows there. Every claim below was run against this application's development…
Read the full lesson free →Curriculum
7 lessonsOne query per read: key_hash and the unique index
Reads hash the key with SHA-256 into a signed 64-bit key_hash and look it up through a unique index.
The write path: upsert, compression and byte_size
A write is one INSERT ON CONFLICT upsert that compresses the value, computes byte_size and never updates created_at.
FOR UPDATE locks rows, not absences
Ten-thread tests show unless_exist and increment are exact on existing rows and racy on missing keys.
Estimating the cache size from two indexes
The cache size is estimated from the largest rows and a random key_hash range, using two indexes.
Expiry: FIFO by id, not LRU
Writes trigger expiry batches that delete the lowest ids first, while expires_in is checked only on read.
Failsafe, shards and the background thread
Transient database errors become cache misses, expiry runs on one background thread, and Maglev hashing routes keys across shards.
Putting it together: one fetch, end to end
One fetch traced through every layer, with the trade-offs of each design choice and a comparison with Redis.