Exhibit 01 · Concurrency
Wait, or apologize.
Two ways to stop concurrent writers from corrupting each other. Both are correct. They bill you in different currencies, and only one of the bills grows quadratically.
Two people open the same record at the same time. Both read a balance of 100. One subtracts 30, the other subtracts 50, and both write their answer back. The row now says 70 or it says 50, depending on who finished last, and either way one of the withdrawals has silently vanished. This is the lost update, and every database, filesystem, collaborative editor and blockchain has to have an answer for it.
There are broadly two, and the folk version of the difference is that pessimistic is safe and optimistic is fast. That is not right, and believing it leads to picking the wrong one. Both are correct. Neither one loses an update. What separates them is not safety at all — it is which resource they are willing to burn to get there.
Ask permission, or ask forgiveness
Pessimistic control assumes the collision is coming. Before touching the row you take a lock on it, and anybody else who wants that row stands still until you are finished. Nothing is ever computed twice, because nobody is ever allowed to compute on stale data in the first place. The cost is that taking and releasing the lock is itself work — a round trip you pay on every transaction, including the overwhelming majority where no one else ever showed up.
Optimistic control assumes the collision is not coming. You read the row along with its version number, go away and do your work, and on the way out you tell the database: write this, but only if the version is still the one I read. If it is, you commit. If it is not, somebody beat you to it, your write is rejected, and everything you just computed is garbage — so you re-read and do it all again.
Pessimistic control drives wasted work to exactly zero and pays for it in waiting. Optimistic control drives waiting to exactly zero and pays for it in wasted work.
That symmetry is the whole thing, and it is why a single “which is faster” number is the wrong question. Below, both strategies run the same workload on the same scale. Push the dials.
5 of 5 contend.
Pessimistic
Take a lock. Everyone else waits.
- W1
- W2
- W3
- W4
- W5
- Wall time
- 20
- Thrown away
- 0
- Spent waiting
- 40
Optimistic
Do the work. Check on the way out.
- W1
- W2
- W3
- W4
- W5
- Wall time
- 15
- Thrown away
- 30
- Spent waiting
- 0
What the dials just showed you
Set contention to zero and the two strategies almost converge — optimistic finishes slightly sooner, and the entire gap is the lock overhead that pessimistic paid on transactions where no conflict was ever possible. That is the real argument for optimism, and it is a good one: in most systems most of the time, contention is rare, and pessimism taxes the common case to insure against the rare one.
Now put contention at 100% and drag the writer count up. Watch the thrown away figure. It is not climbing in step with the writers — it is climbing much faster than they are, because the second writer wastes one attempt, the third wastes two, the fourth wastes three. That is the triangular number, so discarded work grows with roughly the square of the colliding writers while useful work grows linearly with them.
The diagram is being generous to optimism, too. It assumes a thrown-away attempt costs nothing except itself. Real systems do not get that deal: doomed work is still holding a connection, still burning CPU, still consuming the IO budget that the one surviving transaction needs. Which is why systems under optimistic control tend not to slow down gracefully as contention rises. They run beautifully, and then they fall over.
So which one
The honest rule is not about speed, it is about the shape of your traffic. If two writers colliding on the same row is genuinely unusual, be optimistic and keep the tax off the common path. If collisions are the normal state of affairs — a hot counter, a popular seat map, an inventory row on a sale day — then the retries are not an exception you are insuring against, they are your workload, and locking is the cheaper answer.
The question worth carrying out of here is not “which is better.” It is which currency can I afford to spend — because you are going to spend one of them.
The third answer
Both strategies above accept the same premise: two conflicting writes are a problem, and something has to lose. A conflict-free replicated data type refuses the premise. A CRDT is built so that concurrent edits always merge into the same result, whatever order they arrive in and however long a replica has been offline — so there is nothing to wait for and nothing to throw away.
It is not free, of course; nothing here is. You buy it by giving up the ability to express arbitrary constraints. A CRDT can guarantee that two people typing in a document converge, and it cannot guarantee that a balance never goes below zero, because “never below zero” is exactly the kind of global invariant that requires somebody, somewhere, to be the one who decides. This is the ground that Yjs and Automerge occupy, and it is the next exhibit.
And the exotic case
A blockchain faces the same question with the difficulty raised: it must order conflicting writes among participants who may be actively lying, not merely slow. Sui’s answer is to notice that the question is not always worth asking. A transaction touching only objects you alone own has no possible conflict, so it skips consensus entirely; only shared objects — the ones several people can touch — take the expensive path. Consensus as a conditional cost rather than a universal one, which is exhibit 03 — and the far end of the same road is exhibit 02, where the other writers may be lying to you rather than merely getting there first.