Databases & Storage

PostgreSQL's hidden recovery delay: recovery_init_sync_method explained

Key Takeaway

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 →