Delta#start(): avoid a race across maps by using a mutex

Imagine an Icinga restart w/o any config changes and a full dump already being done.
One goroutine reads Redis, the other the database.
Both get the same object at the same time and check it in the map of the other goroutine - not present.
So they store it in their own map.
I.e. the same object hasn't been changed, but has to be deleted and inserted.
If the insert comes first, that causes a duplicate key error.
This commit is contained in:
Alexander A. Klimov 2021-04-08 16:28:42 +02:00
parent d1b1693d14
commit d36928afd3

View file

@ -46,6 +46,7 @@ func (delta *Delta) start(ctx context.Context, actualCh, desiredCh <-chan contra
}
actual := sync.Map{}
desired := sync.Map{}
var mtx sync.Mutex
g, ctx := errgroup.WithContext(ctx)
g.Go(func() error {
@ -61,14 +62,18 @@ func (delta *Delta) start(ctx context.Context, actualCh, desiredCh <-chan contra
}
id := a.ID().String()
mtx.Lock()
if d, ok := desired.Load(id); ok {
desired.Delete(id)
mtx.Unlock()
if delta.WithChecksum && !a.(contracts.Checksumer).Checksum().Equal(d.(contracts.Checksumer).Checksum()) {
update.Store(id, d)
}
} else {
actual.Store(id, a)
mtx.Unlock()
}
cnt.Inc()
@ -91,14 +96,18 @@ func (delta *Delta) start(ctx context.Context, actualCh, desiredCh <-chan contra
}
id := d.ID().String()
mtx.Lock()
if a, ok := actual.Load(id); ok {
actual.Delete(id)
mtx.Unlock()
if delta.WithChecksum && !a.(contracts.Checksumer).Checksum().Equal(d.(contracts.Checksumer).Checksum()) {
update.Store(id, d)
}
} else {
desired.Store(id, d)
mtx.Unlock()
}
cnt.Inc()