[gold] web.go: Fix data race (and Infra-PerCommit-Race).
Go's data race detector reported a race due to potentially simultaneous read and write accesses on lines 813 and 838-841. Using an RWMutex fixes this.
Bug: skia:10246
Change-Id: Ic7ed7549c9a8009bd58f1340ffd561f7c71844cb
Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/404208
Reviewed-by: Kevin Lubick <kjlubick@google.com>
Commit-Queue: Kevin Lubick <kjlubick@google.com>
Commit-Queue: Leandro Lovisolo <lovisolo@google.com>
Auto-Submit: Leandro Lovisolo <lovisolo@google.com>
diff --git a/golden/go/web/web.go b/golden/go/web/web.go
index 65022e9..71b4fb5 100644
--- a/golden/go/web/web.go
+++ b/golden/go/web/web.go
@@ -788,7 +788,7 @@
// This mutex protects the passed in rules array and allows the final step of each
// of the goroutines below to be done safely in parallel to add each shard's results
// to the total.
- var mutex sync.Mutex
+ var mutex sync.RWMutex
err = util.ChunkIterParallel(ctx, len(traces), chunkSize, func(ctx context.Context, start, stop int) error {
type counts struct {
Count int
@@ -796,42 +796,53 @@
ExclusiveCount int
ExclusiveUntriagedCount int
}
- ruleCounts := make([]counts, len(rules))
- for _, tp := range traces[start:stop] {
- if err := ctx.Err(); err != nil {
- return skerr.Wrap(err)
- }
- id, tr := tp.ID, tp.Trace
- if _, ok := nonIgnoredTraces[id]; ok {
- // This wasn't ignored, so we can skip having to count it
- continue
- }
- idxMatched := -1
- untIdxMatched := -1
- numMatched := 0
- untMatched := 0
- for i, r := range rules {
- if tr.Matches(r.ParsedQuery) {
- numMatched++
- ruleCounts[i].Count++
- idxMatched = i
- // Check to see if the digest is untriaged at head
- if d := tr.AtHead(); d != tiling.MissingDigest && exp.Classification(tr.TestName(), d) == expectations.Untriaged {
- ruleCounts[i].UntriagedCount++
- untMatched++
- untIdxMatched = i
+ ruleCounts, err := func() ([]counts, error) {
+ mutex.RLock()
+ defer mutex.RUnlock()
+
+ ruleCounts := make([]counts, len(rules))
+ for _, tp := range traces[start:stop] {
+ if err := ctx.Err(); err != nil {
+ return nil, skerr.Wrap(err)
+ }
+ id, tr := tp.ID, tp.Trace
+ if _, ok := nonIgnoredTraces[id]; ok {
+ // This wasn't ignored, so we can skip having to count it
+ continue
+ }
+ idxMatched := -1
+ untIdxMatched := -1
+ numMatched := 0
+ untMatched := 0
+ for i, r := range rules {
+ if tr.Matches(r.ParsedQuery) {
+ numMatched++
+ ruleCounts[i].Count++
+ idxMatched = i
+
+ // Check to see if the digest is untriaged at head
+ if d := tr.AtHead(); d != tiling.MissingDigest && exp.Classification(tr.TestName(), d) == expectations.Untriaged {
+ ruleCounts[i].UntriagedCount++
+ untMatched++
+ untIdxMatched = i
+ }
}
}
+ // Check for any exclusive matches
+ if numMatched == 1 {
+ ruleCounts[idxMatched].ExclusiveCount++
+ }
+ if untMatched == 1 {
+ ruleCounts[untIdxMatched].ExclusiveUntriagedCount++
+ }
}
- // Check for any exclusive matches
- if numMatched == 1 {
- ruleCounts[idxMatched].ExclusiveCount++
- }
- if untMatched == 1 {
- ruleCounts[untIdxMatched].ExclusiveUntriagedCount++
- }
+ return ruleCounts, nil
+ }()
+ if err != nil {
+ return skerr.Wrap(err)
}
+
mutex.Lock()
defer mutex.Unlock()
for i := range rules {