Skip to content
Snippets Groups Projects
Commit a70d348b authored by Alan Donovan's avatar Alan Donovan Committed by Gopher Robot
Browse files

gopls/internal/util/persistent: add concurrency test

It didn't find any problems.

Updates golang/go#72931

Change-Id: Idb65548480af1fd6777dffdcc0e6c6e89b5a06f5
Reviewed-on: https://go-review.googlesource.com/c/tools/+/659015


Auto-Submit: Alan Donovan <adonovan@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: default avatarRobert Findley <rfindley@google.com>
parent 7042bab9
No related branches found
No related tags found
No related merge requests found
......@@ -203,6 +203,8 @@ func (pm *Map[K, V]) SetAll(other *Map[K, V]) {
// Set updates the value associated with the specified key.
// If release is non-nil, it will be called with entry's key and value once the
// key is no longer contained in the map or any clone.
//
// TODO(adonovan): fix release, which has the wrong type.
func (pm *Map[K, V]) Set(key K, value V, release func(key, value any)) {
first := pm.root
second := newNodeWithRef(key, value, release)
......
// Copyright 2025 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build race
package persistent
import (
"context"
"maps"
"testing"
"time"
"golang.org/x/sync/errgroup"
)
// TestConcurrency exercises concurrent map access.
// It doesn't assert anything, but it runs under the race detector.
func TestConcurrency(t *testing.T) {
ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second)
defer cancel()
var orig Map[int, int] // maps subset of [0-10] to itself (values aren't interesting)
for i := range 10 {
orig.Set(i, i, func(k, v any) { /* just for good measure*/ })
}
g, ctx := errgroup.WithContext(ctx)
const N = 10 // concurrency level
g.SetLimit(N)
for range N {
g.Go(func() error {
// Each thread has its own clone of the original,
// sharing internal structures. Each map is accessed
// only by a single thread; the shared data is immutable.
m := orig.Clone()
// Run until the timeout.
for ctx.Err() == nil {
for i := range 1000 {
key := i % 10
switch {
case i%2 == 0:
_, _ = m.Get(key)
case i%11 == 0:
m.Set(key, key, func(key, value any) {})
case i%13 == 0:
_ = maps.Collect(m.All())
case i%17 == 0:
_ = m.Delete(key)
case i%19 == 0:
_ = m.Keys()
case i%31 == 0:
_ = m.String()
case i%23 == 0:
_ = m.Clone()
}
// Don't call m.Clear(), as it would
// disentangle the various maps from each other.
}
}
return nil
})
}
g.Wait() // no errors
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment