cmd/go/internal/cache: update trim timestamp before trimming

This reduces the chance that multiple go commands running in CI will
try to trim at the same time, causing contention and slowing things
down.

Fixes #76314

Change-Id: I3edf818fc9583795f3f51b715fdbe75b6a6a6964
Reviewed-on: https://go-review.googlesource.com/c/go/+/753240
Reviewed-by: Michael Matloob <matloob@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Michael Matloob <matloob@google.com>
Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
Michael Matloob
2026-03-09 13:51:56 -04:00
committed by Gopher Robot
parent e2ce40125f
commit 2a5890cd46

View File

@@ -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
}