aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/go/internal/cache/cache.go41
1 files changed, 31 insertions, 10 deletions
diff --git a/src/cmd/go/internal/cache/cache.go b/src/cmd/go/internal/cache/cache.go
index 23cc531e69..67f8202c06 100644
--- a/src/cmd/go/internal/cache/cache.go
+++ b/src/cmd/go/internal/cache/cache.go
@@ -385,13 +385,42 @@ func (c *DiskCache) Trim() error {
// trim time is too far in the future, attempt the trim anyway. It's possible that
// the cache was full when the corruption happened. Attempting a trim on
// an empty cache is cheap, so there wouldn't be a big performance hit in that case.
- if data, err := lockedfile.Read(filepath.Join(c.dir, "trim.txt")); err == nil {
+ skipTrim := func(data []byte) bool {
if t, err := strconv.ParseInt(strings.TrimSpace(string(data)), 10, 64); err == nil {
lastTrim := time.Unix(t, 0)
if d := now.Sub(lastTrim); d < trimInterval && d > -mtimeInterval {
- return nil
+ return true
}
}
+ return false
+ }
+ // Check to see if we need a trim. Do this check separately from the lockedfile.Transform
+ // so that we can skip getting an exclusive lock in the common case.
+ if data, err := lockedfile.Read(filepath.Join(c.dir, "trim.txt")); err == nil {
+ if skipTrim(data) {
+ return nil
+ }
+ }
+
+ errFileChanged := errors.New("file changed")
+
+ // Write the new timestamp before we start trimming to reduce the chance that multiple invocations
+ // try to trim at the same time, causing contention in CI (#76314).
+ err := lockedfile.Transform(filepath.Join(c.dir, "trim.txt"), func(data []byte) ([]byte, error) {
+ if skipTrim(data) {
+ // The timestamp in the file no longer meets the criteria for us to
+ // do a trim. It must have been updated by another go command invocation
+ // since we last read it. Skip the trim.
+ return nil, errFileChanged
+ }
+ return fmt.Appendf(nil, "%d", now.Unix()), nil
+ })
+ if errors.Is(err, errors.ErrUnsupported) {
+ return err
+ }
+ if errors.Is(err, errFileChanged) {
+ // Skip the trim because we don't need it anymore.
+ return nil
}
// Trim each of the 256 subdirectories.
@@ -403,14 +432,6 @@ func (c *DiskCache) Trim() error {
c.trimSubdir(subdir, cutoff)
}
- // Ignore errors from here: if we don't write the complete timestamp, the
- // cache will appear older than it is, and we'll trim it again next time.
- var b bytes.Buffer
- fmt.Fprintf(&b, "%d", now.Unix())
- if err := lockedfile.Write(filepath.Join(c.dir, "trim.txt"), &b, 0o666); err != nil {
- return err
- }
-
return nil
}