Demystifying Write-Ahead Logging: Ensuring Database Reliability and High Performance

Arpit Bhayani

Arpit Bhayani

Mar 21, 2022 • 8 min read

Play

Demystifying Write-Ahead Logging: Ensuring Database Reliability and High Performance

Every persistent database system (such as MySQL, PostgreSQL, or DynamoDB) must guarantee reliability and durability. When a client executes an update and the database signals that a transaction is committed, those changes must survive unexpected failures—including application crashes, operating system panics, and sudden power outages.

However, writing every committed transaction directly to table storage on non-volatile media introduces severe performance bottlenecks. To solve this, database architectures rely on Write-Ahead Logging (WAL). WAL allows systems to maintain strict persistence guarantees without paying the cost of immediate, random disk writes on every commit.


The Anatomy of a Transaction Commit

In relational databases, data is organized in structured disk formats like B+ Trees. A single modification can ripple across multiple structures:

+-------------------------------------------------------------------------+
| Client: UPDATE users SET name = 'Alice' WHERE id = 1;                  |
+-------------------------------------------------------------------------+
                                     |
                                     v
+-------------------------------------------------------------------------+
| Engine updates:                                                         |
|  - Target Data Block (Row data in B+ Tree leaf page)                    |
|  - Index Block (Secondary index leaves/branches)                        |
|  - Internal Tree Nodes (Splits/routing updates if sizes change)         |
+-------------------------------------------------------------------------+

Directly persisting this transaction requires multiple distinct disk blocks to be modified across different sectors of the storage device. Flushing these random blocks synchronously on every commit introduces high disk latency, turning storage I/O into a massive bottleneck.

The Multi-Stage Disk Write Path

A simple file write operation passes through several caching layers before reaching physical non-volatile storage:

  1. In-Memory Flush Buffer (Application RAM): The database process buffers dirty blocks in its memory pool (e.g., InnoDB Buffer Pool, PostgreSQL Shared Buffers).
  2. Operating System Page Cache (Kernel Space): The kernel caches file system writes in its page/buffer cache before scheduling writes to the hardware.
  3. Disk Controller Cache (Drive RAM): The physical SSD or HDD hardware controller has internal volatile cache to optimize write scheduling.
  4. Non-Volatile Storage (Flash NAND / Magnetic Platters): The physical medium where data remains safe across power cycles.
+-------------+     +---------------+     +---------------+     +--------------+
|  DB Memory  | --> | OS Page Cache | --> |  Disk Cache   | --> | Non-Volatile |
|   Buffer    |     | (Kernel RAM)  |     | (Controller)  |     |   Storage    |
+-------------+     +---------------+     +---------------+     +--------------+

To ensure durability, the database cannot rely on standard asynchronous writes because data held in volatile caches is lost during a power crash. Instead, it must issue an fsync call or open files with the O_SYNC flag, forcing an immediate flush to non-volatile storage.


How Write-Ahead Logging (WAL) Works

The fundamental invariant of Write-Ahead Logging is straightforward:

The WAL Invariant: No data block or index block can be written to non-volatile storage until the log record describing the change has been flushed to non-volatile storage.

Instead of updating table files and index trees synchronously on disk at commit time, the database writes a minimal append-only log record describing the transaction into a dedicated WAL file opened in sync mode (fsync).

Client Transaction Commit
         |
         v
[1. Write Log Record to WAL] ===== (Synchronous, Sequential Disk I/O)
         |
         v
[2. Update In-Memory Page Buffer] == (Fast RAM Mutation)
         |
         v
[3. Acknowledge Success to Client]
         |
         ~ (Asynchronous / Background Flusher)
         v
[4. Write Dirty Pages to Table Files] == (Deferred Random I/O)

Because appending to a sequential log is orders of magnitude faster than performing multiple scattered, random writes across B+ tree nodes, WAL makes transaction commits lightweight and fast.


Key Architectural Advantages

1. Deferred and Batch Disk Writes

Because the log record guarantees that changes can be reconstructed, data pages can remain in memory as “dirty pages.” The database does not need to flush these pages immediately on every commit. Instead, a background process lazily flushes dirty pages in batches, turning multiple random writes into coordinated background operations.

2. Fast Crash Recovery

If the server crashes due to an OS failure or power outage, data in RAM is lost. Upon reboot, the database enters recovery mode:

  • It inspects the WAL starting from the last known persistent checkpoint.
  • It reads all committed log entries that were not yet flushed to data files and replays them.
  • Any uncommitted transactions present in the log are rolled back.

This guarantees that no committed transaction is lost, restoring memory buffers and data blocks to a consistent state.

3. Drastic Reduction of Disk I/O Bottlenecks

Without WAL, updating a million rows would require writing millions of altered blocks across tables and indices before confirming the commit. With WAL, the database records the operation in the append-only log, updates the memory buffers, and acknowledges the write, reducing latency and avoiding I/O starvation.

4. Point-In-Time Recovery (PITR) and Time Travel

Because the WAL is an ordered, chronological stream of all state transitions, it enables point-in-time recovery. If a database is corrupted or an erroneous query is executed:

  1. Restore a cold physical backup taken at timestamp T0T_0.
  2. Replay the WAL records chronologically up to target timestamp TsafeT_{safe} (just before the error occurred).
  3. Stop replay at TsafeT_{safe}, yielding a consistent snapshot of the system at that specific point in time.

This mechanism is widely used for disaster recovery, historical audits, and automated integration testing.


WAL File Structure and Internals

A WAL is not simply an infinite flat file. Storage engines structure WAL records into structured hierarchies to ensure manageability, integrity, and fast offset traversal.

WAL Directory
  ├── Segment 000000010000000000000001 (16 MB)
  │     ├── Page 0 (8 KB)
  │     │     ├── Entry 1 [LSN: 0x0000] [CRC] [Payload]
  │     │     ├── Entry 2 [LSN: 0x00A0] [CRC] [Payload]
  │     ├── Page 1 (8 KB)
  │     └── ...
  └── Segment 000000010000000000000002 (16 MB)

Segments and Pages

  • Segments: The log stream is partitioned into fixed-size files called segments (commonly 16 MB in engines like PostgreSQL). Dividing the log into fixed segments prevents file unbounded growth and allows the engine to archive or delete old segments once checkpoints pass them.
  • Pages: Within each segment, data is organized into fixed-size pages (typically 8 KB), matching the OS and filesystem block boundaries to optimize disk controller operations.

Log Sequence Number (LSN)

Every log entry receives a unique identifier known as the Log Sequence Number (LSN).

Rather than using a simple auto-incrementing integer (e.g., 1,2,31, 2, 3\dots), engines design the LSN as the direct byte offset within the WAL stream.

Using byte offsets as LSNs provides substantial performance optimizations:

  • Direct Addressing: The storage engine can seek directly to the offset in the file corresponding to the LSN without needing an auxiliary index.
  • Progress Tracking: Data pages record the LSN of the latest update applied to them (page_lsn). During crash recovery, the recovery engine compares the page_lsn with the WAL entry’s LSN. If the page’s LSN is greater than or equal to the log entry’s LSN, the engine skips that entry, avoiding redundant writes during replay.

Data Integrity via Cyclic Redundancy Checks (CRC)

A crash can occur while the storage engine is midway through writing a 512-byte block or page. This results in a torn write (corrupted record).

To detect torn writes and storage corruption:

  1. The engine calculates a CRC checksum for the log record payload.
  2. The CRC is written to the record header ahead of the payload data.
  3. During recovery replay, the engine recomputes the checksum of the record. If the computed checksum does not match the header’s CRC, the engine detects corruption and halts replay, preventing the database from applying partially written or corrupted operations.

Trade-offs and Tuning

While WAL unlocks low-latency durability, it introduces operational trade-offs:

Configuration / MechanismBenefitTrade-off
Synchronous WAL Flushing (fsync on commit)Complete durability; zero data loss on crash.Commit latency is bound by disk flush speed.
Asynchronous Flushing (e.g., 1-second flush interval)Extremely high write throughput.Risk of losing up to 1 second of committed transactions during a sudden crash.
Frequent CheckpointsShorter crash recovery time; less disk space consumed by old segments.Higher continuous background write I/O.
Infrequent CheckpointsMinimal I/O overhead during normal operations.Extended crash recovery replay time on startup.

Summary

Write-Ahead Logging converts unpredictable, scattered random disk mutations across complex indexes into fast, deterministic, sequential appends. By ensuring that log records reach non-volatile storage before corresponding data pages are touched on disk, databases achieve resilience against crashes, high transaction throughput, and point-in-time recovery.

Arpit Bhayani

Principal Engineer II at Razorpay - building Agent Studio, Ex-staff engg at GCP Memorystore & Dataproc, Creator of DiceDB, ex-Amazon Fast Data, ex-Director of Engg. SRE and Data Engineering at Unacademy. I spark engineering curiosity through my no-fluff engineering videos on YouTube and my courses