Fix concurrent map races in Statelet, collector, and session cache - #108
Conversation
97521a2 to
3574859
Compare
Statelet column names, collector parent indexes, predicate registry, and session cache JSON could fatal with concurrent map iteration or write.
3574859 to
bd33e37
Compare
Copying the embedded QuerySelector before columnNamesMu raced with Add on Fields and Columns; ViewMetaHandler also read valuePosition without the collector index lock.
Review feedbackHigh: Fix: do not assign Medium: ValidationNon-race tests pass on the refreshed PR branch: go test ./service/executor/expand ./service/session ./view ./view/extension ./view/state -count=1Race-focused tests fail: go test -race ./service/executor/expand ./service/session ./view ./view/extension ./view/state -run 'Concurrent|CloneForSummary|Registry|MarshalJSON|Types' -count=1The concrete failure is |
How the review feedback was addressedPushed in High —
The clone now:
That is the same lock Medium —
This path is on the collector’s own index (not the parent map), so it uses Re-validationNon-race: go test ./service/executor/expand ./service/session ./view ./view/extension ./view/state -count=1Race-focused (now passing, including go test -race ./service/executor/expand ./service/session ./view ./view/extension ./view/state -run 'Concurrent|CloneForSummary|Registry|MarshalJSON|Types' -count=1 |
Returning the live valuePosition maps after unlock left child relation matching reading while indexValueToPosition still wrote.
Review feedbackMedium: Safer shape: return copied positions for a specific key under lock, like the updated Resolved from prior review
ValidationLatest PR head before this follow-up: Tests passed on the refreshed PR worktree: go test ./service/executor/expand ./service/session ./view ./view/extension ./view/state -count=1
go test -race ./service/executor/expand ./service/session ./view ./view/extension ./view/state -run 'Concurrent|CloneForSummary|Registry|MarshalJSON|Types' -count=1I would not block on the old Statelet issue anymore. The remaining question is whether collector parent-index reads can truly overlap with parent-index writes in production execution. If yes, the returned-map pattern should be tightened before merge. |
How the review feedback was addressedPushed in Medium — unlocked reads of returned parent-index maps
Callers that needed positions for one key now go through:
Writers such as Re-validationgo test ./service/executor/expand ./service/session ./view ./view/extension ./view/state -count=1
go test -race ./service/executor/expand ./service/session ./view ./view/extension ./view/state -run 'Concurrent|CloneForSummary|Registry|MarshalJSON|Types' -count=1Both passed, including |
Summary
concurrent map iteration and map write(and the read/write variant) under parallel reads.Statelet._columnNamesis the production path:CloneForSummaryranged the map whileAddwrote it. Collector parent indexes,PredicateRegistry, session cache JSON, andTypes.Lookuphad the same shape.Fixes #107.
Test plan
go test -timeout 10s -count=1 -run TestStateletCloneForSummaryConcurrentColumnNames ./view/— crashed before the lock, passes after 3sgo test -timeout 10s -count=1 -run TestCollectorConcurrentParentValuePositions ./view/go test -timeout 10s -count=1 -run TestPredicateRegistryConcurrentLookupAndAdd ./view/extension/go test -timeout 10s -count=1 -run TestSessionMarshalJSONConcurrentCachePut ./service/session/go test -timeout 10s -count=1 -run TestDataUnitConcurrentSliceIndex ./service/executor/expand/go test -timeout 10s -count=1 -run TestTypesConcurrentLookupAndPut ./view/state/