Commit 8c896aa4 authored by Bryan C. Mills's avatar Bryan C. Mills

cmd/go/internal/lockedfile: add a sync.Mutex to lockedfile.Mutex

The compiler (and race detector) don't interpret locking a file as a
synchronization operation, so we add an explicit (and redundant)
sync.Mutex to make that property clear.

The additional synchronization makes it safe to parallelize the tests
in cmd/go/internal/modfetch/coderepo_test.go, which cuts the wall time
of that test by around 50%.

Updates #30550

Change-Id: Ief3479020ebf9e0fee524a4aae5568697727c683
Reviewed-on: https://go-review.googlesource.com/c/go/+/170597
Run-TryBot: Bryan C. Mills <bcmills@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarDaniel Martí <mvdan@mvdan.cc>
Reviewed-by: default avatarJay Conrod <jayconrod@google.com>
parent b0bcd7ae
......@@ -7,6 +7,7 @@ package lockedfile
import (
"fmt"
"os"
"sync"
)
// A Mutex provides mutual exclusion within and across processes by locking a
......@@ -22,6 +23,7 @@ import (
// use and must not be change thereafter.
type Mutex struct {
Path string // The path to the well-known lock file. Must be non-empty.
mu sync.Mutex // A redundant mutex. The race detector doesn't know about file locking, so in tests we may need to lock something that it understands.
}
// MutexAt returns a new Mutex with Path set to the given non-empty path.
......@@ -56,5 +58,10 @@ func (mu *Mutex) Lock() (unlock func(), err error) {
if err != nil {
return nil, err
}
return func() { f.Close() }, nil
mu.mu.Lock()
return func() {
mu.mu.Unlock()
f.Close()
}, nil
}
......@@ -45,7 +45,7 @@ var altVgotests = []string{
vgotest1hg,
}
var codeRepoTests = []struct {
type codeRepoTest struct {
path string
lookerr string
mpath string
......@@ -59,7 +59,9 @@ var codeRepoTests = []struct {
gomoderr string
zip []string
ziperr string
}{
}
var codeRepoTests = []codeRepoTest{
{
path: "github.com/rsc/vgotest1",
rev: "v0.0.0",
......@@ -339,13 +341,18 @@ var codeRepoTests = []struct {
func TestCodeRepo(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
tmpdir, err := ioutil.TempDir("", "vgo-modfetch-test-")
tmpdir, err := ioutil.TempDir("", "modfetch-test-")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
t.Run("parallel", func(t *testing.T) {
for _, tt := range codeRepoTests {
f := func(t *testing.T) {
f := func(tt codeRepoTest) func(t *testing.T) {
return func(t *testing.T) {
t.Parallel()
repo, err := Lookup(tt.path)
if tt.lookerr != "" {
if err != nil && err.Error() == tt.lookerr {
......@@ -440,7 +447,8 @@ func TestCodeRepo(t *testing.T) {
}
}
}
t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f)
}
t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f(tt))
if strings.HasPrefix(tt.path, vgotest1git) {
for _, alt := range altVgotests {
// Note: Communicating with f through tt; should be cleaned up.
......@@ -459,11 +467,12 @@ func TestCodeRepo(t *testing.T) {
tt.rev = remap(tt.rev, m)
tt.gomoderr = remap(tt.gomoderr, m)
tt.ziperr = remap(tt.ziperr, m)
t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f)
t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f(tt))
tt = old
}
}
}
})
}
var hgmap = map[string]string{
......@@ -538,8 +547,13 @@ func TestCodeRepoVersions(t *testing.T) {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
t.Run("parallel", func(t *testing.T) {
for _, tt := range codeRepoVersionsTests {
t.Run(strings.ReplaceAll(tt.path, "/", "_"), func(t *testing.T) {
tt := tt
t.Parallel()
repo, err := Lookup(tt.path)
if err != nil {
t.Fatalf("Lookup(%q): %v", tt.path, err)
......@@ -553,6 +567,7 @@ func TestCodeRepoVersions(t *testing.T) {
}
})
}
})
}
var latestTests = []struct {
......@@ -586,9 +601,14 @@ func TestLatest(t *testing.T) {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
t.Run("parallel", func(t *testing.T) {
for _, tt := range latestTests {
name := strings.ReplaceAll(tt.path, "/", "_")
t.Run(name, func(t *testing.T) {
tt := tt
t.Parallel()
repo, err := Lookup(tt.path)
if err != nil {
t.Fatalf("Lookup(%q): %v", tt.path, err)
......@@ -611,6 +631,7 @@ func TestLatest(t *testing.T) {
}
})
}
})
}
// fixedTagsRepo is a fake codehost.Repo that returns a fixed list of tags
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment