Chapter 07 · InnoDB in MariaDB: Storage, Buffering, Redo, Undo, and Recovery
Redo Logs, Undo, Doublewrite, Checkpoints, Crash Recovery, and Durability
Trace an InnoDB write through undo, redo, dirty pages, checkpoints, doublewrite and crash recovery, then make durability tradeoffs explicit with innodb_flush_log_at_trx_commit and sync_binlog.
Learning outcomes
A developer asks a deceptively simple question: “If COMMIT returned success, where is my row?” The answer is not “the final table page was already forced to disk.” InnoDB separates logical transaction durability from data-page flushing. Changes occur in buffer-pool pages, old row versions are represented through undo, and redo records describe modifications needed for crash recovery. A commit can become durable when the required log state is safely persisted even though many dirty data pages will be flushed later.
This lesson traces a write through write-ahead logging (WAL), undo, redo, checkpoints and the doublewrite mechanism. It also separates three artifacts that operators often confuse: the InnoDB redo log protects crash recovery of InnoDB pages; the MariaDB binary log records logical/row events used for replication and point-in-time recovery; a backup is a restorable copy/base from which recovery begins. None substitutes universally for the other two.
Trace one committed InnoDB update through undo creation, buffer-pool modification, redo generation, commit flushing and later data-page flushing.
Explain checkpoints and why redo capacity affects checkpoint pressure and recovery work.
Explain how the doublewrite buffer protects against partial page writes and when disabling it can be unsafe.
Distinguish redo log, binary log and backup by purpose, retention and recovery role.
Evaluate innodb_flush_log_at_trx_commit and sync_binlog as explicit durability/performance tradeoffs.
MariaDB 10.5 and later use one InnoDB redo file named
ib_logfile0. Do not teach old
innodb_log_files_in_group multiplication recipes
on 12.3. The redo log is circular and records are identified
by log sequence numbers (LSNs).
1. Establish a write-path lab and record durability settings
DROP DATABASE IF EXISTS servicehub_innodb_lab;CREATE DATABASE servicehub_innodb_lab CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;USE servicehub_innodb_lab;CREATE TABLE digits (n TINYINT NOT NULL PRIMARY KEY) ENGINE=InnoDB;INSERT INTO digits VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);CREATE TABLE work_orders ( work_order_id BIGINT NOT NULL AUTO_INCREMENT, customer_id BIGINT NOT NULL, status VARCHAR(20) NOT NULL, priority TINYINT NOT NULL, opened_at DATETIME(6) NOT NULL, summary VARCHAR(180) NOT NULL, notes LONGTEXT NULL, PRIMARY KEY (work_order_id), KEY ix_work_orders_status (status, priority, work_order_id), KEY ix_work_orders_customer (customer_id, opened_at)) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;INSERT INTO work_orders(customer_id,status,priority,opened_at,summary,notes)SELECT 1 + (x.n % 250), ELT(1 + (x.n % 4),'queued','open','closed','cancelled'), 1 + (x.n % 5), TIMESTAMP('2026-08-01 00:00:00') + INTERVAL x.n SECOND, CONCAT('ServiceHub order ', x.n), RPAD(CONCAT('diagnostic-note-',x.n,' '), 1200, 'x')FROM ( SELECT a.n + 10*b.n + 100*c.n + 1000*d.n AS n FROM digits a CROSS JOIN digits b CROSS JOIN digits c CROSS JOIN digits d) AS xWHERE x.n BETWEEN 1 AND 8000;
SHOW VARIABLES WHERE Variable_name IN ('datadir','innodb_log_group_home_dir','innodb_log_file_size', 'innodb_flush_log_at_trx_commit','innodb_doublewrite', 'log_bin','sync_binlog','binlog_format');SHOW GLOBAL STATUS WHERE Variable_name IN ('Innodb_lsn_current','Innodb_lsn_flushed','Innodb_lsn_last_checkpoint', 'Innodb_os_log_written','Innodb_dblwr_writes','Innodb_dblwr_pages_written');
Variable/status availability can evolve; if one LSN counter is
absent, use SHOW ENGINE INNODB STATUS and
INFORMATION_SCHEMA.INNODB_METRICS as documented
alternatives. The objective is to prove the current server’s
write/recovery state, not to make a monitoring query depend on
one historic variable name forever.
2. Follow one UPDATE from old version to commit
Before modifying an indexed record, InnoDB must preserve enough old information to support rollback and multi-version consistent reads. Undo records form the historical chain used by active snapshots. The current clustered/secondary index pages are changed in memory, producing dirty pages. Redo records describe changes so they can be replayed after a crash. Write-ahead ordering means the redo needed to reconstruct a page must be durable before that dirty page can safely be considered persisted.
SHOW GLOBAL STATUS LIKE 'Innodb_os_log_written';START TRANSACTION;UPDATE work_ordersSET summary=CONCAT(summary,' / inspected')WHERE work_order_id BETWEEN 100 AND 500;COMMIT;SHOW GLOBAL STATUS WHERE Variable_name IN ('Innodb_os_log_written','Innodb_buffer_pool_pages_dirty');SHOW ENGINE INNODB STATUS\G
Redo-byte growth and dirty-page counts will vary because internal logging and background flushing happen concurrently. You are verifying causal direction—not predicting an exact byte count per UPDATE. The data pages can remain dirty after COMMIT while the transaction is still durable according to the configured log-flush policy.
3. Checkpoints bound how far recovery must scan/replay
Because the redo log is circular, old log space eventually has to be reusable. A checkpoint advances the point before which dirty page state is sufficiently persisted that older redo can be overwritten. If dirty-page flushing cannot keep up with redo generation, the checkpoint age approaches available redo capacity and InnoDB must increase flushing pressure. More redo capacity can absorb longer write bursts, but it also changes recovery/space considerations; “bigger is always faster” is not a safe rule.
SHOW ENGINE INNODB STATUS\GSELECT NAME, SUBSYSTEM, COUNT, COMMENTFROM information_schema.INNODB_METRICSWHERE NAME IN ('log_lsn_current','log_lsn_last_checkpoint', 'log_lsn_checkpoint_age','log_lsn_buf_pool_oldest')ORDER BY NAME;
INNODB_METRICS requires PROCESS privilege and some
counters can be disabled or differ by version. For production
dashboards, verify which metrics are enabled and what reset
semantics apply before alerting on them.
4. Doublewrite protects a different failure mode than redo
Redo can reconstruct changes only if the data-page base it applies to is structurally usable. A torn/partial page write caused by power or OS failure can leave half of a page from the old version and half from the new version. InnoDB’s doublewrite mechanism first writes pages to a protected intermediate area and then to their final tablespace locations, giving recovery a valid page copy when a final write is torn.
On current MariaDB, innodb_doublewrite=ON is the
default. The setting also supports fast on newer
versions and can be disabled, but OFF assumes the underlying
storage/filesystem provides atomic writes at the InnoDB page
size. Disabling the doublewrite buffer simply because a
benchmark is a few percent faster can convert a power-loss event
into page corruption.
SHOW VARIABLES LIKE 'innodb_doublewrite';SHOW GLOBAL STATUS WHERE Variable_name IN ('Innodb_dblwr_writes','Innodb_dblwr_pages_written');
The course does not ask you to simulate torn writes by corrupting files or disable doublewrite on your primary lab. Destructive crash/corruption drills belong in disposable copies with verified backups and separate recovery runbooks.
5. Redo log, binary log and backup are not synonyms
| Artifact | Primary purpose | Typical retention/use |
|---|---|---|
| InnoDB redo log | Crash recovery of InnoDB changes/pages. | Circular engine-internal log sized for recovery/write behavior, not a long-term history archive. |
| Binary log | Replication stream and point-in-time recovery input; contains statement/row events depending on format. | Retained according to replication/PITR policy; operationally separate from redo. |
| Backup | Restorable base copy of database state. | Retained according to RPO/RTO/compliance policy; recovery can replay binary logs after the base. |
A server with healthy redo but no usable backup cannot recover from every operator error or lost storage device. A backup without binary-log retention cannot necessarily reach an arbitrary point after that backup. A binary log without a base backup is not an efficient full-dataset reconstruction mechanism. Later chapters build the complete backup/PITR chain.
6. Durability settings make risk explicit
innodb_flush_log_at_trx_commit=1 writes and flushes
the redo log at each transaction commit and is MariaDB’s default
full-ACID baseline. Value 0 defers both write/flush to a
periodic interval; value 2 writes on commit but flushes
periodically. Those alternatives can improve throughput on some
systems but allow recent committed transactions to be lost in
server/OS/power failure scenarios as documented. Value 3 exists
for historic group-commit behavior and is not a modern tuning
recommendation.
When the conventional binary log is enabled,
sync_binlog=1 is the safest setting for
synchronizing binlog writes, while the documented default is 0
(OS-managed flushing). For strongest ordinary InnoDB +
binary-log durability and replication consistency, MariaDB
documentation recommends combining
innodb_flush_log_at_trx_commit=1 with
sync_binlog=1. That can cost fsync latency, so
measure storage and group-commit behavior rather than silently
weakening durability.
SELECT @@global.innodb_flush_log_at_trx_commit AS innodb_commit_flush, @@global.sync_binlog AS sync_binlog, @@global.log_bin AS binary_log_enabled, @@global.binlog_format AS binlog_format;
7. Deliberately wrong approach: “turn off fsync-like safety until benchmarks pass”
A benchmark run that changes both
innodb_flush_log_at_trx_commit and
sync_binlog from durable to relaxed values can show
an attractive throughput gain while measuring a different
correctness contract. The repaired experiment records the
baseline, changes one setting only on a disposable instance,
measures throughput/latency, documents the exact crash-loss
window, restores the setting, and never promotes the result
without explicit business approval of the durability tradeoff.
Likewise, changing redo size and buffer-pool size together destroys causal attribution. Performance engineering is an experiment: hypothesis, one controlled change, workload, counters, latency distribution, rollback, conclusion. Chapter 18 will make that discipline systematic.
8. Lab checklist, knowledge check, and bridge
- Record redo file size/location variables, commit-flush setting, doublewrite, log_bin and sync_binlog.
- Commit a controlled UPDATE and compare redo/dirty-page evidence before and after.
- Inspect checkpoint/LSN information from SHOW ENGINE INNODB STATUS or INNODB_METRICS.
- Explain why a committed transaction can still have dirty data pages.
- Write a three-row table that distinguishes redo, binlog and backup.
- Document the failure mode protected by doublewrite.
Check your understanding
- Why can COMMIT be durable before the final table page is flushed?
- What does a checkpoint allow InnoDB to do with old redo space?
- Why does redo not make the doublewrite mechanism redundant?
- What is the safest ordinary innodb_flush_log_at_trx_commit value?
- Why is a binary log not a replacement for a backup?
Review the answers
Commit durability is based on the configured log-flush contract; dirty data pages can be flushed later because redo can replay changes after a crash. A checkpoint advances the durable page state so older circular redo can be reused. Doublewrite addresses torn final-page writes, a different failure mode from missing redo. The normal full-ACID baseline is innodb_flush_log_at_trx_commit=1. Binary logs are incremental change streams used with a restorable base; they are not themselves a complete backup strategy.
Durability knobs are business-risk controls, not generic performance knobs. Record the exact failure model you are accepting before relaxing them. Keep doublewrite ON unless atomic-write guarantees are proven for the real storage path, and treat redo sizing as a checkpoint/recovery engineering decision.
The next lesson follows the other half of MVCC: undo history. You will deliberately hold an old read view while another session updates rows, observe history-list growth, and see why long transactions can delay purge long after their own SQL appears idle.