Choose where a cache belongs

Choose which work a cache hit can avoid while preserving durable writes, and understand the limits of MySQL MEMORY tables.

Remembering a link's destination could save the next visitor a database lookup, but that visitor still needs a recorded request. The admission design left us with both obligations. Choosing where to keep a copy starts with separating the work that can disappear from the work a successful redirect still promises.

The answer being copied

In the wiki/rate-limiting-and-abuse-prevention-case-study rate-limiting design, a redirect first passes local admission controls. The application finds the immutable destination, records an accepted-request event durably, and only then returns its redirect. A repeated destination lookup seems wasteful because 00f4240 will still point to https://example.com/article/1000000 .

A saved answer to that lookup is a cache entry. Finding a usable entry is a hit; finding no usable entry is a miss. The database remains the authority, or source of truth: losing the copy should leave a place from which the application can recover the answer. Recoverability says nothing about how much recovery traffic the database can handle at once.

Keep the copied value narrow, but include the source row id needed for event recording. The following proposed shape uses link id 1 from the one-machine design's separate test schema, not from the million-row table. It is an interface example, not the output of a running cache service.

The chosen v1 labels the shape readers expect. A later shape can use a different namespace, meaning a distinct key prefix, so an older reader does not decode incompatible data. The code remains case-sensitive. Lowercasing the key would change which mapping the application asks for.

Copying the creation receipt or quota allowance would be a different proposal. Those records determine whether work already happened or may begin. Throwing them away can change behavior, whereas discarding this destination copy simply requires another authoritative lookup. Use the record's responsibility to decide whether it belongs in an evictable cache.

The work left on a hit

You have already met a lower cache layer in wiki/what-a-database-is the database lesson. A database can retain recently accessed pages in memory. A page hit avoids fetching that page from storage, while the application still submits its query and the database still executes it. MySQL documents this role for the InnoDB buffer pool.

A copied destination sits above query execution. On a hit, the application already has the value the mapping query would return. On a miss, it reads the database and saves the positive result for another request. The application explicitly manages that read-then-fill path, commonly called cache-aside.

Here, the cache stores only positive mapping answers. An unknown code still asks the database and produces the existing missing-code result. Keeping an earlier absence would complicate the first request after a new mapping commits; the expiration lesson will examine that race.

Follow the event arrow as well as the mapping arrow in this drawing. The cache may be inside the application or a separate process; the responsibilities are the same at this level. The drawing separates Links and Events to show their work, although both are tables in Postgres.

On a hit, a visitor gets the same 302 , Location and Cache-Control: no-store response after the event commits. On a miss, the application obtains the mapping first. Failure to retain an optional mapping copy need not undo that successful lookup; inability to commit the required event still prevents a successful redirect.

Copying the entire HTTP redirect would skip more work. If a browser or an intermediary reused that response, the new request could avoid the application and its event recording entirely. The wiki/url-shortener-system-design one-machine design counts requests reaching the application, so we keep whole redirect responses out of caches under its current contract. HTTP cache rules belong to the CDN lesson.

An application-local map avoids another network exchange. It is also tied to that process: a restart loses its contents, and another application instance learns its own set of answers. Choose this placement when a bounded private working set addresses an observed repeated lookup and duplicated copies are acceptable.

A separate cache process can share one copied answer across application instances. That helps when requests for the same codes move among those instances, but obtaining the copy now has connection, deadline and failure behavior. Shared ownership earns its place when that reuse outweighs the added boundary. wiki/distributed-cache-design Distributed cache design will make that interface concrete.