Skip to content

fix(http-cache): a late single-flight leader re-reads the entry before fetching - #646

Merged
transfix merged 1 commit into
masterfrom
fix/http-cache-single-flight-recheck
Oct 17, 2026
Merged

transfix merged 1 commit into
masterfrom
fix/http-cache-single-flight-recheck

Conversation

@transfix

Copy link
Copy Markdown
Owner

Why

HttpCacheTest.SingleFlightCoalescesConcurrentResolves failed on #645's ubuntu Debug run (fake->calls was 2, expected 1). The cache had a real race, not a slow runner:

  1. A resolve reads the cache entry: a miss.
  2. The leader for that key finishes, stores the entry and erases its in-flight marker.
  3. The first resolve reaches fetch_and_cache, finds no marker and becomes a second leader. Its snapshot from step 1 predates the store, so it fetches again.

The result is a duplicate transfer of a URL that is already cached and fresh. That's wasted bandwidth, and it's the bug single-flight exists to prevent.

Change

  • fetch_and_cache re-reads the entry after it registers as leader. The previous leader stored before it erased its marker under the flight lock, and the new leader registers under that same lock, so this read sees the store. A fresh entry is served with no transfer.
  • Otherwise the re-read snapshot drives the fetch, never the caller's older one. Newer validators go into the conditional GET, and an entry evicted in between (no-store, or an invalidating store) gets an unconditional GET instead of a conditional GET against a body that's gone.
  • fetch_and_cache no longer takes the caller's snapshot.

Test

LateArrivalAfterTheLeaderLeftIsServedFromTheCache: 1000 rounds; each round starts 8 threads together on one key against an instant transport, which makes the late-arrival window common. Each round must be exactly one transfer.

Measured locally (Windows, MSVC Release):

  • Without the fix, the new test failed 13 of 20 runs, each with one or more extra transfers.
  • With the fix, it and SingleFlightCoalescesConcurrentResolves passed 30 of 30 runs.
  • All 13 tests in uri_http_cache_test pass in 1.9 s.

…e fetching

A resolve that missed the cache before the leader stored, then reached
single-flight after the leader left, became a second leader and fetched a
URL that was already cached and fresh. The new leader now re-reads the
entry under its own flight registration (ordered after the previous
leader's store) and serves it when fresh; otherwise that newer snapshot,
not the caller's, drives the fetch.

Adds LateArrivalAfterTheLeaderLeftIsServedFromTheCache, which failed 13
of 20 runs without the fix and passes 30 of 30 with it.
@transfix
transfix merged commit cf1b49d into master Oct 17, 2026
15 checks passed
@transfix
transfix deleted the fix/http-cache-single-flight-recheck branch October 17, 2026 14:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant