Skip to content

Commit

Permalink
[FIXED] JetStream: stream assignment data race (#4589)
Browse files Browse the repository at this point in the history
Two go routines could possibly execute the stream assignment at the same
time. A WaitGroup was used to prevent that, but an issue caused the data
race and possible concurrent execution.

Signed-off-by: Ivan Kozlovic <ivan@synadia.com>
  • Loading branch information
derekcollison committed Sep 26, 2023
2 parents 83cc80a + ca2a961 commit 3056af0
Showing 1 changed file with 11 additions and 2 deletions.
13 changes: 11 additions & 2 deletions server/stream.go
Expand Up @@ -404,12 +404,21 @@ func (a *Account) addStreamWithAssignment(config *StreamConfig, fsConfig *FileSt
}

// Make sure we are ok when these are done in parallel.
v, loaded := jsa.inflight.LoadOrStore(cfg.Name, &sync.WaitGroup{})
// We used to call Add(1) in the "else" clause of the "if loaded"
// statement. This caused a data race because it was possible
// that one go routine stores (with count==0) and another routine
// gets "loaded==true" and calls wg.Wait() while the other routine
// then calls wg.Add(1). It also could mean that two routines execute
// the rest of the code concurrently.
swg := &sync.WaitGroup{}
swg.Add(1)
v, loaded := jsa.inflight.LoadOrStore(cfg.Name, swg)
wg := v.(*sync.WaitGroup)
if loaded {
wg.Wait()
// This waitgroup is "thrown away" (since there was an existing one).
swg.Done()
} else {
wg.Add(1)
defer func() {
jsa.inflight.Delete(cfg.Name)
wg.Done()
Expand Down

0 comments on commit 3056af0

Please sign in to comment.