Skip to content

[SharovBot] db/state: fix DATA RACE between Aggregator.Close and MergeLoop goroutine - #22227

Closed
erigon-copilot[bot] wants to merge 1 commit into
mainfrom
agent-fix/aggregator-mergeloop-race-wg
Closed

erigon-copilot[bot] wants to merge 1 commit into
mainfrom
agent-fix/aggregator-mergeloop-race-wg

Conversation

@erigon-copilot

@erigon-copilot erigon-copilot Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

[SharovBot]

Problem

The CI job race-tests / tests-linux (ubuntu-latest, other, parallel) on commit bc4670467 failed with:

WARNING: DATA RACE
Write at 0x00c0653acb90 by goroutine 321:
  github.com/erigontech/erigon/db/state.(*Aggregator).Close()
      db/state/aggregator.go:630 +0x15c

Previous read at 0x00c0653acb90 by goroutine 373:
  github.com/erigontech/erigon/db/state.(*Aggregator).MergeLoop()
      db/state/aggregator.go:1228 +0x64

FAIL: TestImportClosesChaindataOnInitError

Root cause: The background merge goroutine spawned in backend.go called a.wg.Add(1) inside MergeLoop(), after the goroutine was scheduled. A concurrent Close() could observe a zero WaitGroup counter, return from wg.Wait() immediately, and then write to struct fields (e.g. ctxCancel = nil) concurrently with the goroutine's wg.Add(1) / mergeLoop startup — a classic wg.Add/wg.Wait race.

Fix

Added StartMergeLoopBackground(ctx, onErr) to Aggregator (and the TemporalDebugDB interface) which calls wg.Add(1) synchronously before spawning the goroutine. This guarantees the counter is non-zero before any Close()/wg.Wait() can execute.

backend.go now uses StartMergeLoopBackground instead of a manual goroutine wrapping MergeLoop.

Verification

go test -race -count=3 -run TestImportClosesChaindataOnInitError ./cmd/utils/app/...
ok  github.com/erigontech/erigon/cmd/utils/app  5.463s

No DATA RACE warnings. 3/3 passes.

Fixes: https://github.com/erigontech/erigon/actions/runs/28674562917/job/85045122311

…eLoop goroutine

The background MergeLoop goroutine called a.wg.Add(1) inside MergeLoop
itself, but the spawning goroutine in backend.go could race with Close()
calling a.wg.Wait(): if Close() observed the WaitGroup counter at zero
before the goroutine executed wg.Add(1), Wait() returned early and Close
proceeded to write fields (ctxCancel = nil) concurrently with MergeLoop
starting up.

The race detector reported:
  WARNING: DATA RACE
  Write at ... (*Aggregator).Close() aggregator.go:630
  Previous read at ... (*Aggregator).MergeLoop() aggregator.go:1228

Fix: add StartMergeLoopBackground to Aggregator (and the TemporalDebugDB
interface) which calls wg.Add(1) synchronously before launching the goroutine.
This guarantees the counter is non-zero before Close/wg.Wait can be called,
eliminating the race.

Verified: go test -race -count=3 -run TestImportClosesChaindataOnInitError
./cmd/utils/app/... passes cleanly.

Co-authored-by: Giulio Rebuffo <giulio.rebuffo@gmail.com>
@AskAlexSharov

Copy link
Copy Markdown
Collaborator

fixed by #22203

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