Skip to content

Commit f7b4fef

Browse files
authored
reduce the time Dispatch.Group holds the mutex (#4670)
* reduce the time Dispatch.Group holds the mutex Signed-off-by: Ethan Hunter <ehunter@hudson-trading.com> * add comment explaining behavior Signed-off-by: Ethan Hunter <ehunter@hudson-trading.com> * switch from manual map clone to maps.Clone Signed-off-by: Ethan Hunter <ehunter@hudson-trading.com> --------- Signed-off-by: Ethan Hunter <ehunter@hudson-trading.com>
1 parent e2b746b commit f7b4fef

File tree

1 file changed

+17
-2
lines changed

1 file changed

+17
-2
lines changed

dispatch/dispatch.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"errors"
1919
"fmt"
2020
"log/slog"
21+
"maps"
2122
"sort"
2223
"sync"
2324
"sync/atomic"
@@ -283,16 +284,30 @@ func (d *Dispatcher) Groups(ctx context.Context, routeFilter func(*Route) bool,
283284
d.WaitForLoading()
284285
groups := AlertGroups{}
285286

287+
// Make a snapshot of the aggrGroupsPerRoute map to use for this function.
288+
// This ensures that we hold the Dispatcher.mtx for as little time as
289+
// possible.
290+
// It also prevents us from holding the any locks in alertFilter or routeFilter
291+
// while we hold the dispatcher lock
286292
d.mtx.RLock()
287-
defer d.mtx.RUnlock()
293+
aggrGroupsPerRoute := map[*Route]map[model.Fingerprint]*aggrGroup{}
294+
for route, ags := range d.aggrGroupsPerRoute {
295+
// Since other goroutines could modify d.aggrGroupsPerRoute, we need to
296+
// copy it. We DON'T need to copy the aggrGroup objects because they each
297+
// have a mutex protecting their internal state.
298+
// The aggrGroup methods use the internal lock. It is important to avoid
299+
// accessing internal fields on the aggrGroup objects.
300+
aggrGroupsPerRoute[route] = maps.Clone(ags)
301+
}
302+
d.mtx.RUnlock()
288303

289304
// Keep a list of receivers for an alert to prevent checking each alert
290305
// again against all routes. The alert has already matched against this
291306
// route on ingestion.
292307
receivers := map[model.Fingerprint][]string{}
293308

294309
now := time.Now()
295-
for route, ags := range d.aggrGroupsPerRoute {
310+
for route, ags := range aggrGroupsPerRoute {
296311
if !routeFilter(route) {
297312
continue
298313
}

0 commit comments

Comments
 (0)