ContentsThe library

What a Transaction Promises

The Power Can Fail Between Your Two Statements

Taking money out of one account and putting it into another is two writes, and a crash between them is a real event. Here is the mechanism that makes it one.

This course is about what happens when two transactions run at the same time,

which is the hard and interesting problem. This first lesson is about the part

everybody already half knows, done properly, because the mechanism underneath

it is the one the rest of the course keeps using.

What the boundary is

A transaction is a boundary you draw around a group of changes. Inside the

boundary you make as many changes as you like. At the end you either commit,

and every change becomes visible at the same instant, or you roll back, and

none of them ever existed as far as anyone else is concerned.

That is the whole promise when nothing else is running. Not speed, not locking,

not consistency of your business rules. Simply that there is no observable

middle.

The canonical example earns its place. Moving fifty pounds between two accounts

is two writes: subtract from one, add to the other. There is a moment between

them when the money is nowhere. If nothing can observe that moment and nothing

can make it permanent, the pair of writes is a transfer. If either of those

fails, it is a way of losing money.

FIG 1A transfer, with a power failure between the two writes
stepmomentaccount Aaccount Bwhat exists on diskwhat happened
1before500200both rows as shownThe starting state, and the only invariant that matters is that the two balances sum to 700.
2after the first write450200a log record saying A goes to 450The sum is now 650. This state is wrong, and it is wrong for a few microseconds under normal operation, which is fine as long as it cannot be seen or kept.
3power fails here450200the same log record, nothing elseThe machine is off. Nothing in the two numbers indicates a problem: 450 and 200 are perfectly valid balances and no later inspection of the data can tell that fifty pounds is missing.
4after restart500200log replayed, no commit record foundRecovery reads the log, finds a started transaction with no commit record, and undoes it. The state is the one from before the transfer began.
5after a successful rerun450250both writes and a commit recordThe sum is 700 again. Either outcome is acceptable; the one in the middle row is not.
5 steps
Follow the last column rather than the balances. The balances on their own never reveal the problem, which is the essential difficulty: a partially applied transaction leaves data that is structurally valid and semantically wrong. Only a separate record of intention can tell the two apart, and producing that record is what the rest of this lesson is about.

The crash in the middle

It is worth being specific about what can interrupt the pair of writes, because

people often picture only one of these.

The process can be killed. The machine can lose power. The disk can accept a

write into its own cache and lose it. The network can disappear between the

application and the database after the first statement. The application can

throw an exception on the line between them. The container can be evicted.

All of these produce the same situation: some of the changes reached storage

and some did not, and nothing in the stored data distinguishes that from a

legitimate state.

Writing it down first

The mechanism is a log and a single rule.

Before any change is written to the page where the data lives, a record

describing that change is appended to a sequential log, and that log record is

made durable. This is the write-ahead rule, and the ordering is the whole of

it: log first, data afterwards.

FIG 2The order of operations at commit
Two properties of the log make this work. It is sequential, so appending to it is the fastest thing a storage device does, far faster than the scattered writes to the real data pages. And it holds intentions rather than outcomes, so a crash at any point in the flow leaves enough information to decide between finishing and undoing. Notice where the caller is told the commit succeeded: after the log is safe and long before the data is in place.

Recovery then has a simple job. Read the log from the last checkpoint. Any

transaction with a commit record gets its changes reapplied, because they may

not have reached the data pages. Any transaction without one gets its changes

undone, because the caller was never told it succeeded. The presence or absence

of one small record decides which.

FIG 3Where the crash happened, and what recovery does
changes exist in memorylog records on diskcommit record on diskdata pages written
before the log was flush1000
after the log, before th1100
after the commit record,1110
after everything1111
Only the marked row requires any work at restart, and it is the row where the caller was told the commit succeeded. There, recovery replays the log records onto the data pages and the promise is kept. The first two rows are undone, and in both the caller either received an error or received nothing, so nothing was promised. The fourth needs nothing. Four possible crash points, one of which does work, none of which can produce a half-applied transfer.

What the promise costs

There is one physical cost in the whole mechanism, and it is at the flush.

A commit cannot be reported to the caller until the log is actually on the

device. Not in the operating system's cache, not in the drive's own cache, but

on durable media. That operation is a disk sync, and it is slow in a way that

is unrelated to the amount of data: a few hundred microseconds on good flash,

several milliseconds on a spinning disk.

FIG 4What limits the commit rate
the time for one physical sync, which depends on the hardware and not on how much is being written
the number of transactions whose commit records ride along in a single sync
commits per second, which with n equal to one is simply the inverse of the sync time
With one sync per commit and a sync costing one millisecond, the ceiling is a thousand commits per second no matter how small the transactions are or how many cores the machine has. That is the number that surprises people: the limit is not the writing, it is the waiting. Group commit raises it by holding arriving commits for a fraction of a millisecond and syncing their log records together, so n becomes fifty or two hundred and the ceiling moves with it.

Two practical consequences follow from that figure, and both show up in real

systems.

Many small transactions are far more expensive than one larger one covering the

same work, because each pays its own sync. A loop that commits once per row is

the most common cause of a load that takes hours instead of minutes, and the

fix is to commit once per few thousand rows.

And every database offers a setting that relaxes the sync, reporting a commit

once the log record is in the operating system's cache rather than on the

device. It is genuinely faster and it genuinely gives up durability: a power

failure loses the last fraction of a second of committed transactions. That is

an acceptable trade for some workloads and a catastrophe for others, and the

thing to avoid is having made the trade without knowing it.

The next lesson drops the assumption that nothing else is running, which is

where the subject actually begins.

Recap

  • A transaction is a boundary you draw around several changes, and the only promise it makes alone is that the outside world sees all of them or none of them.
  • The mechanism is writing the intention to a log before touching the data, so that a crash leaves a record from which the work can be finished or undone.
  • Durability costs one physical disk sync per commit, which is why commit rate rather than write rate is often what limits a busy system.

This is the reading half

Starting the course gives you your own copy of it. Every idea on every page has problems standing under it, marked with a reason rather than a tick, and any sentence you do not believe can be opened and argued with. None of that can happen on a page nobody owns.

The contents

NextTwo of Them at Once →

The rest of this course

  1. 01The Power Can Fail Between Your Two Statementsyou are here
  2. 02Both of Them Read 10 and Both of Them Wrote 11opening only
  3. 03Reading Something That Was Never True, and Three Relativesopening only
  4. 04Your Database Is Not Using the Level You Think It Isopening only
  5. 05Take Them All Before You Give Any Backopening only
  6. 06Keep the Old Row and Nobody Has to Waitopening only
  7. 07Both Doctors Checked That Someone Else Was on Callopening only
  8. 08Name the Rule First, Then Pick the Weakest Level That Holds Itopening only

Read alongside