PostgreSQL's hidden recovery delay: recovery_init_sync_method explained
PostgreSQL's crash recovery includes a mandatory full-directory fsync pass that can take minutes on large clusters, with syncfs on Linux offering the only alternative since PostgreSQL 14.
Summary
Database consultant Christophe Pettus details how PostgreSQL's recovery_init_sync_method parameter controls a little-known crash recovery step: fsyncing every file in the data directory before WAL replay begins. This safety mechanism, added in 2014 after a data corruption bug, can consume minutes or hours on clusters with hundreds of thousands of files. The default fsync method walks the directory twice; Linux users since PostgreSQL 14 can switch to syncfs. The pass also triggers on pg_basebackup-created standbys, not just actual crashes.
What the sync pass does and costs
- Two-pass fsync walk: First pass calls sync_file_range() to start writeback, second pass fsync()s each file and its directory; follows pg_wal and tablespace symlinks only
- Per-file cost, not per-byte: A single table with primary key and text column creates 4 files (heap, index, TOAST heap, TOAST index) before holding any rows
- Benchmark: 601,112 files in 5.7 GB took 29-37 seconds on local VM storage; 700,000-file cluster reported at 7 minutes (quiet) to 90 minutes (busy server)
- syncfs alternative: Available only on Linux since PostgreSQL 14; uses single system call instead of per-file fsync
- Monitoring: log_startup_progress_interval (since PostgreSQL 15) exposes pass duration in logs
- Error handling: I/O errors during this pass are logged and ignored, unlike normal fsync failures which trigger PANIC
Why it matters
The parameter addresses a real operational pain point for large PostgreSQL deployments, particularly multi-tenant providers with file-per-database architectures. The syncfs option significantly reduces recovery time on Linux, though the underlying full-sync requirement remains unavoidable for data safety.
Original reference: postgr.es →