Skip to main content
RunBook Academy

PostgreSQLVI · Storage, Pages and TOASTStorage

The durability chain from COMMIT to platter

Advanced⏱ ~25 minpsql

What you'll learn

  • Trace the path from COMMIT to durable storage and name each layer
  • State what fsync, synchronous_commit and full_page_writes each protect against
  • Identify which layers can acknowledge a write before it is durable
  • Reason about a storage platform's durability claims without accepting them

Prerequisites

Verified against PostgreSQL 18.x · PostgreSQL (comparison targets) 17.11, 16.15 · PostgreSQL (support calendar) 18, 17, 16, 15, 14 supported · pgBackRest 2.59.1 · PgBouncer 1.25.2 · Patroni 4.1.5 · Ubuntu (host baseline) 26.04 LTS · 2026-08-27

Not yet marked complete on this device.

When COMMIT returns without an error, PostgreSQL has promised that the transaction survives a crash. Understanding exactly what it did to earn that promise — and what it is relying on others to have done — is the foundation of every durability decision in this course.

The chain

flowchart TD
    A["COMMIT issued"] --> B["WAL record written\ninto the WAL buffers"]
    B --> C["write() to the WAL file\nnow in the OS page cache"]
    C --> D["fsync / fdatasync\nOS asked to make it durable"]
    D --> E["Device receives the flush"]
    E --> F["Data is on stable media"]
    F --> G["COMMIT returns to the client"]
    H["The dirty data PAGE\nis still only in shared_buffers"] -.-> I["Written later by the\ncheckpointer"]

The critical structural fact is on the right-hand branch. COMMIT does not write the data page. It makes the log record durable. The page is written later, and if the server crashes before that happens, recovery replays the log to reconstruct it. Part XII covers the replay; this lesson is about the flush.

The three parameters that govern it

Read-only / Safethe durability settings and their contexts
$ psql -U postgres -c "SELECT name, setting, context FROM pg_settings WHERE name IN ('fsync','synchronous_commit','full_page_writes','wal_sync_method') ORDER BY name"
        name        |  setting  | context
--------------------+-----------+---------
fsync              | on        | sighup
full_page_writes   | on        | sighup
synchronous_commit | on        | user
wal_sync_method    | fdatasync | sighup
(4 rows)

fsync decides whether PostgreSQL asks the operating system to make writes durable at all. With it off, PostgreSQL never issues a flush, and a crash of the host — not the database — can lose or corrupt arbitrary data.

synchronous_commit decides whether COMMIT waits for that flush. With it off, PostgreSQL still flushes, but the client is told the transaction committed before the flush completes.

full_page_writes decides whether the first modification of a page after a checkpoint writes the whole page into WAL, protecting against torn pages.

The difference between the first two matters enormously and is routinely conflated.

fsync = offsynchronous_commit = off
Flush issued?NoYes, just later
Lose recent commits on OS crash?YesYes, a bounded window
Database left corrupt after OS crash?Yes, possiblyNo
Reasonable in production?NeverSometimes, deliberately

What each layer can lie about

PostgreSQL issues fsync() and trusts the answer. Every layer below can return success before the data is on stable media.

LayerHow it can acknowledge earlyDetectable by PostgreSQL?
OS page cacheOnly if fsync is off, or the call is ignoredNo
FilesystemJournal modes, barrier settingsNo
Volume manager / RAIDWrite-back cache without a batteryNo
VirtualisationHost cache mode set to writeback/unsafeNo
Network storageAcknowledging before the remote commitNo
The disk itselfVolatile write cache, no power-loss protectionNo

Every row in that “detectable” column says no, and that is the whole problem. PostgreSQL’s durability is exactly as good as the weakest honest layer beneath it, and it has no way to measure that.

Verifying what you can from inside

Some of the chain is visible from the host, and it is worth checking the parts that are.

# What PostgreSQL believes it is doing
psql -U postgres -c \
  "SELECT name, setting FROM pg_settings
    WHERE name IN ('fsync','synchronous_commit','full_page_writes','wal_sync_method')"

# Which flush method is actually available and chosen
psql -U postgres -c 'SHOW wal_sync_method'

# Filesystem mount options: barriers, journal mode
findmnt -no SOURCE,TARGET,FSTYPE,OPTIONS "$(psql -U postgres -tAc 'SHOW data_directory')"

# Device write cache, where the device exposes it
lsblk -o NAME,ROTA,SCHED,MODEL 2>/dev/null || true

wal_sync_method is worth a look. PostgreSQL selects a default appropriate to the platform — fdatasync on Linux — and the alternatives differ in how many system calls they make and whether they flush metadata as well as data. Changing it is a measurement exercise rather than a default worth adjusting.

Production discipline

  1. Never set fsync = off on anything whose data matters. It is not a performance setting; it removes the guarantee that makes recovery possible.
  2. Use synchronous_commit = off when you want that trade, and record the bounded loss window it accepts.
  3. Leave full_page_writes on unless the platform documents atomic 8 KiB writes, and budget its WAL cost.
  4. Ask the storage questions explicitly and record the answers. PostgreSQL cannot detect a layer that acknowledges early.
  5. Re-ask after any infrastructure change. A hypervisor migration, a SAN firmware update or a move to different instance storage changes the answers.
  6. Treat a controller battery as a durability dependency, and check that its health is monitored.

Cross-course references

  • Linux for Production Sysadmins — Part XIII (Disks), Part XV (Fstab) and Part XLI (Disk performance) cover mount options, write barriers and device caches directly.
  • Ceph & Distributed Storage — Part II (Storage performance) and Part XII (BlueStore) cover what a distributed storage layer does with a flush, which is the same question asked of a different platform.
  • Proxmox — Part V (Storage fundamentals) covers hypervisor disk cache modes, which is where the guest’s flush is most often acknowledged early.

Quiz

Knowledge check · 6 questions

  1. Q1. What is the essential difference between fsync = off and synchronous_commit = off after an operating-system crash?

  2. Q2. Why does full_page_writes exist?

  3. Q3. Which layers can acknowledge a write before it is on stable media, without PostgreSQL being able to detect it? Select all that apply.

  4. Q4. COMMIT returns only after the modified data pages have been written to disk.

  5. Q5. Name three questions to ask a storage or virtualisation team to establish whether a COMMIT is a genuine durability promise.

  6. Q6. Assess the change and state what must be established before it proceeds.

    A team reports that a nightly bulk load takes four hours and proposes setting fsync = off for the duration of the load, then setting it back and reloading afterwards. The database is the production order-management system, 900 GB, with a documented RPO of five minutes. They note that the load runs on a replica-free single instance during a maintenance window when no users are connected, and that they will take a backup beforehand.

Passing score: 75%. Answers are checked in this browser.