aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichael Matloob <matloob@golang.org>2026-03-09 13:51:56 -0400
committerGopher Robot <gobot@golang.org>2026-03-09 14:20:29 -0700
commit2a5890cd46e5658b5ceab6cfd7a06b3bfe947fb9 (patch)
treeb0776a0cc5f7c044f2ac0ca26d0ffd272c326b9f /src
parente2ce40125fd03f8420a9cbbfe36d1e0f4bc93966 (diff)
downloadgo-2a5890cd46e5658b5ceab6cfd7a06b3bfe947fb9.tar.xz
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>
Diffstat (limited to 'src')
-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
}