Saving Safely -- Never Half a File
The simple way to save -- wipe the file, then write it out again -- has a nasty problem: if the computer crashes halfway through, you're left with half a file, and your data is gone.
So saving works like a careful student copying out their homework:
- Write the new version on a fresh sheet -- a temporary file right next to the real one.
- Make sure the ink is dry --
fsyncpushes the bytes out of the computer's memory and onto the disk. - Swap the fresh sheet in for the old one in a single instant step.
At every moment there's a complete file: the old one or the new one, never
half of each. Real databases like SQLite and PostgreSQL use the same trick.
The code lives in atomic.py.
When a Save File Is Damaged
Loading is careful too. If the file is missing, isn't valid JSON, or isn't
one of our save files at all, load_store raises a PersistenceError
that names the file. It never quietly hands back an empty database -- that
would be like a game starting a brand-new save and then overwriting your
old one the next time you pressed "save".