diff --git a/docs/PERFORMANCE_BACKLOG.md b/docs/PERFORMANCE_BACKLOG.md index 070747c..a7e2e19 100644 --- a/docs/PERFORMANCE_BACKLOG.md +++ b/docs/PERFORMANCE_BACKLOG.md @@ -19,6 +19,7 @@ appview database. | `034ea59` | Hold reports blob size on read presigns; appview Stat no longer HEADs S3 for it. | | `f4343d7` | Blobs under 16MB go up as one presigned PUT; every upload is hashed and verified against its digest. | | `47a1070` | Process-wide budget on upload buffer memory; sweep for abandoned uploads; flush boundary pinned at exactly 16MB. | +| `2a94f92` | Per-request memo of blob presigns; a blob GET is one hold call, not three (Stat, ServeBlob and the notification listener's Stat shared it). | In flight as of 2026-09-09: the registry reads the sailor profile from the local users row instead of the owner's PDS on every request, and part uploads @@ -26,32 +27,6 @@ are pipelined so one part is in flight while the next fills. ## Remaining -### Presign memoization within a request - -**Problem.** Every blob GET costs three hold calls, each doing full token -validation, a captain record read and a presign. Distribution's blob handler -calls `Stat` then `ServeBlob`, and distribution's notifications listener -(`notifications.Listen` wraps every repository unconditionally, whether or not -any endpoint is configured) calls `Stat` a third time after `ServeBlob` to -build the pull event. Measured 2026-09-11 with `TestBenchRealImages`: a p90 -pull of 22 layers is 22 registry GETs and 66 hold calls, 44 of them HEAD -presigns whose URL is never used. - -**Where.** `ProxyBlobStore.Stat` and `ServeBlob` in -`pkg/appview/storage/proxy_blob_store.go`. - -**Fix.** The store is built per request, so a small memo keyed by digest and -method inside it is safe. Stat reads the request method from the context -(`storage.HTTPRequestMethod`, already set by the auth middleware), presigns -for that method when it is GET or HEAD, and remembers the URL and size. -ServeBlob reuses the URL when the digest and method match; the listener's -second Stat is answered from the memo. S3 signs the HTTP method, so a HEAD -URL cannot serve a GET; anything other than GET or HEAD must still presign -HEAD, since the hold refuses `method=PUT` on the read path. - -**Impact.** One hold call per blob fetch instead of three. On the p90 pull -that is 66 hold calls down to 22. - ### Stat from the appview's own layers table **Problem.** For a layer of an already indexed manifest, the appview's `layers`