Skip to content
About
Main content

Every entry is a claim about the past

In which currencies can the gap between a cache and the truth be closed, and why is verification underused?

The constraint that creates all the cost was stated in The second copy. Now we have to pay it:

People often list the tools for this problem as if they were five settings of one dial: , versioned keys, , and . They are not one dial. They are two independent dimensions, and mixing them up is a real design error. (An error of the same kind: treating two independent dimensions as one spectrum because their common cases happen to go together.) When you separate the dimensions, the empty cells of the resulting table turn out to be the most informative part.

There is also a third instrument that is missing from the usual list, and it is the one most worth knowing.

The three currencies of freshness

The gap between a cache and the truth can be closed in exactly three currencies. There is no fourth.

CurrencyMechanismCost scales withWho pays
Coordinationwrite-through, invalidation broadcast, a coherence protocolwrite rate × number of cachesthe writer
StalenessTTL, asynchronous invalidation, serve-stalenothing: it is freethe reader, silently
Verification, ETag or version , conditional GETread rate, but at the price of a round trip, not a payloadthe reader, cheaply

Here is how to read the table with a little background from transaction processing. A database that lets many users change data at once needs concurrency control, a rule for who may touch what. There are two classic styles. Pessimistic control takes locks first, so conflicts cannot happen: that is coordination. Optimistic control lets everyone proceed and checks for conflicts at the end: that is verification. The third option, proceeding and never checking, is unsound in a transaction system, because it loses updates. But a cache is allowed to be wrong. So:

Verification is the instrument practitioners use too little, because it changes the unit of the cost. A revalidation that answers "unchanged" costs one round trip and carries no payload. Where an entry is large compared with a round trip, verification gives near-coherence at a small part of the price of coordination. Three familiar mechanisms are all this one move:

  • HTTP's ETag header: the client sends "I have version abc123", and the server replies 304 Not Modified with no body if it is still current (a conditional GET).
  • AFS-style callbacks: a distributed file system in which the server promises to tell the client when a cached file changes.
  • A database buffer pool's LSN check: each page carries a log sequence number (the position in the write-ahead log of the last change to it), and a reader compares it with the expected one.