perf(coderd): build the workspace build fan-out maps once per batch - #28074
Merged
Conversation
convertWorkspaceBuild rebuilt seven maps from the caller's global slices on every call and rescanned the provisioner daemon rows, so convertWorkspaceBuilds paid that cost once per build over the same rows. The maps move into a workspaceBuildIndex built once per batch, keyed as before and now including daemons by job ID. Agents are sorted while the index is built, so a resource read by several builds is sorted once rather than once per build; the comparison and the rows are unchanged, so the order is the same.
…ortFunc The aliasing note claimed the index maps aliased the input slices, but each bucket is a freshly allocated slice of copied rows. The agent sort comment described a resource shared by several builds, which cannot happen because resources are grouped by job ID and each build has its own job. Document that conversion reorders bucket contents in place, and replace sort.Slice with slices.SortFunc.
…nversion The batch conversion reads one index for every build, so cover the rows each build receives: resource count and job ID, build-scoped resource, agent and app names, metadata, scripts, log sources and per-app statuses. Add a build with no eligible daemon rows alongside builds that have them, and a case where agents share a display order so the name comparison runs.
Keep the two facts the field names do not carry: buckets are reordered in place during conversion, and the input slices are not modified or aliased.
Row counts and the resource job ID already pin the index keying, so drop the resource and agent name prefixes and the assertions on fixture field values, which cover conversion of individual rows rather than how rows are grouped.
jscottmiller
marked this pull request as ready for review
August 17, 2026 18:32
BobbyHo
approved these changes
Aug 18, 2026
BobbyHo
left a comment
Contributor
There was a problem hiding this comment.
Nice memory optimization. LGTM.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
convertWorkspaceBuildrebuilt seven maps from the caller's global slices on every call and rescanned the provisioner daemon rows to filter by job ID.convertWorkspaceBuildscalls it once per build with identical slices, so map construction costO(builds x rows)whereO(rows)suffices — quadratic in the number of workspaces onGET /api/v2/workspaces.The maps move into a
workspaceBuildIndexbuilt once per batch, keyed exactly as before and now including daemons by job ID.convertWorkspaceBuildtakes the index instead of eight slices. Its parent already hoistedworkspaceByID,jobByID, andtemplateVersionByIDout of the same loop; this makes the rest consistent.Agents are sorted while the index is built, so a resource read by several builds is sorted once rather than once per build. Same comparator over the same rows, so the order is unchanged;
TestConvertWorkspaceBuildsAgentOrdercovers it.BenchmarkConvertWorkspaceBuilds, 5 resources x 2 agents x 4 apps per build:Single-build conversion is a wash (one extra struct allocation); the quadratic term is gone.
Addresses the map-allocation half of PLAT-386 / #27205. Bounding the page size is separate (#28040) and does not remove this cost: at 100 workspaces per page it is still 100 passes over every resource, agent, app, script, log source, status, and daemon row in the page.
Created with Coder Agents on behalf of @jscottmiller.