From 099e0027bd7d282c400b1f5930d19a4652a265eb Mon Sep 17 00:00:00 2001 From: Ian Alexander Date: Tue, 11 Nov 2025 13:50:51 -0500 Subject: [PATCH] cmd/go/internal/modfetch: consolidate global vars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit conslidates global variables represeting the current modfetch state into a single variable in preparation for injection via the rsc.io/rf tool. This commit is part of the larger effort to eliminate global module loader state. [git-generate] cd src/cmd/go/internal/modfetch rf ' add State func NewState() *State {\ s := new(State)\ s.lookupCache = new(par.Cache[lookupCacheKey, Repo])\ s.downloadCache = new(par.ErrCache[module.Version, string])\ return s\ } add State var ModuleFetchState *State = NewState() mv State.goSumFile State.GoSumFile add State:/^[[:space:]]*GoSumFile /-0 // path to go.sum; set by package modload ex { GoSumFile -> ModuleFetchState.GoSumFile } mv State.workspaceGoSumFiles State.WorkspaceGoSumFiles add State:/^[[:space:]]*WorkspaceGoSumFiles /-0 // path to module go.sums in workspace; set by package modload ex { WorkspaceGoSumFiles -> ModuleFetchState.WorkspaceGoSumFiles } add State:/^[[:space:]]*lookupCache /-0 // The Lookup cache is used cache the work done by Lookup.\ // It is important that the global functions of this package that access it do not\ // do so after they return. add State:/^[[:space:]]*downloadCache /-0 // The downloadCache is used to cache the operation of downloading a module to disk\ // (if it'\\\''s not already downloaded) and getting the directory it was downloaded to.\ // It is important that downloadCache must not be accessed by any of the exported\ // functions of this package after they return, because it can be modified by the\ // non-thread-safe SetState function. add State:/^[[:space:]]*downloadCache.*$/ // version → directory; ex { lookupCache -> ModuleFetchState.lookupCache downloadCache -> ModuleFetchState.downloadCache } rm 'lookupCache' rm 'downloadCache' ' for dir in modload ; do cd ../${dir} rf ' ex { import "cmd/go/internal/modfetch" modfetch.GoSumFile -> modfetch.ModuleFetchState.GoSumFile modfetch.WorkspaceGoSumFiles -> modfetch.ModuleFetchState.WorkspaceGoSumFiles } ' done cd ../modfetch rf ' rm GoSumFile rm WorkspaceGoSumFiles ' Change-Id: Iaa0f8a40192127457a539120eb94337940cb8d4a Reviewed-on: https://go-review.googlesource.com/c/go/+/719700 Reviewed-by: Michael Matloob Reviewed-by: Michael Matloob LUCI-TryBot-Result: Go LUCI --- src/cmd/go/internal/modfetch/fetch.go | 76 +++++++++++++++------------ src/cmd/go/internal/modfetch/repo.go | 7 +-- src/cmd/go/internal/modload/init.go | 6 +-- 3 files changed, 47 insertions(+), 42 deletions(-) diff --git a/src/cmd/go/internal/modfetch/fetch.go b/src/cmd/go/internal/modfetch/fetch.go index 9e8d3639a9e..0a84aecd426 100644 --- a/src/cmd/go/internal/modfetch/fetch.go +++ b/src/cmd/go/internal/modfetch/fetch.go @@ -35,13 +35,6 @@ import ( modzip "golang.org/x/mod/zip" ) -// The downloadCache is used to cache the operation of downloading a module to disk -// (if it's not already downloaded) and getting the directory it was downloaded to. -// It is important that downloadCache must not be accessed by any of the exported -// functions of this package after they return, because it can be modified by the -// non-thread-safe SetState function -var downloadCache = new(par.ErrCache[module.Version, string]) // version → directory; - var ErrToolchain = errors.New("internal error: invalid operation on toolchain module") // Download downloads the specific module version to the @@ -56,7 +49,7 @@ func Download(ctx context.Context, mod module.Version) (dir string, err error) { } // The par.Cache here avoids duplicate work. - return downloadCache.Do(mod, func() (string, error) { + return ModuleFetchState.downloadCache.Do(mod, func() (string, error) { dir, err := download(ctx, mod) if err != nil { return "", err @@ -85,7 +78,7 @@ func Unzip(ctx context.Context, mod module.Version, zipfile string) (dir string, base.Fatal(err) } - return downloadCache.Do(mod, func() (string, error) { + return ModuleFetchState.downloadCache.Do(mod, func() (string, error) { ctx, span := trace.StartSpan(ctx, "modfetch.Unzip "+mod.String()) defer span.Done() @@ -444,9 +437,6 @@ func RemoveAll(dir string) error { // accessed by any of the exported functions of this package after they return, because // they can be modified by the non-thread-safe SetState function. -var GoSumFile string // path to go.sum; set by package modload -var WorkspaceGoSumFiles []string // path to module go.sums in workspace; set by package modload - type modSum struct { mod module.Version sum string @@ -471,11 +461,31 @@ type modSumStatus struct { // State holds a snapshot of the global state of the modfetch package. type State struct { - goSumFile string - workspaceGoSumFiles []string - lookupCache *par.Cache[lookupCacheKey, Repo] - downloadCache *par.ErrCache[module.Version, string] - sumState sumState + // path to go.sum; set by package modload + GoSumFile string + // path to module go.sums in workspace; set by package modload + WorkspaceGoSumFiles []string + // The Lookup cache is used cache the work done by Lookup. + // It is important that the global functions of this package that access it do not + // do so after they return. + lookupCache *par.Cache[lookupCacheKey, Repo] + // The downloadCache is used to cache the operation of downloading a module to disk + // (if it's not already downloaded) and getting the directory it was downloaded to. + // It is important that downloadCache must not be accessed by any of the exported + // functions of this package after they return, because it can be modified by the + // non-thread-safe SetState function. + downloadCache *par.ErrCache[module.Version, string] // version → directory; + + sumState sumState +} + +var ModuleFetchState *State = NewState() + +func NewState() *State { + s := new(State) + s.lookupCache = new(par.Cache[lookupCacheKey, Repo]) + s.downloadCache = new(par.ErrCache[module.Version, string]) + return s } // Reset resets globals in the modfetch package, so previous loads don't affect @@ -500,20 +510,20 @@ func SetState(newState State) (oldState State) { defer goSum.mu.Unlock() oldState = State{ - goSumFile: GoSumFile, - workspaceGoSumFiles: WorkspaceGoSumFiles, - lookupCache: lookupCache, - downloadCache: downloadCache, + GoSumFile: ModuleFetchState.GoSumFile, + WorkspaceGoSumFiles: ModuleFetchState.WorkspaceGoSumFiles, + lookupCache: ModuleFetchState.lookupCache, + downloadCache: ModuleFetchState.downloadCache, sumState: goSum.sumState, } - GoSumFile = newState.goSumFile - WorkspaceGoSumFiles = newState.workspaceGoSumFiles + ModuleFetchState.GoSumFile = newState.GoSumFile + ModuleFetchState.WorkspaceGoSumFiles = newState.WorkspaceGoSumFiles // Uses of lookupCache and downloadCache both can call checkModSum, // which in turn sets the used bit on goSum.status for modules. // Set (or reset) them so used can be computed properly. - lookupCache = newState.lookupCache - downloadCache = newState.downloadCache + ModuleFetchState.lookupCache = newState.lookupCache + ModuleFetchState.downloadCache = newState.downloadCache // Set, or reset all fields on goSum. If being reset to empty, it will be initialized later. goSum.sumState = newState.sumState @@ -525,7 +535,7 @@ func SetState(newState State) (oldState State) { // use of go.sum is now enabled. // The goSum lock must be held. func initGoSum() (bool, error) { - if GoSumFile == "" { + if ModuleFetchState.GoSumFile == "" { return false, nil } if goSum.m != nil { @@ -536,7 +546,7 @@ func initGoSum() (bool, error) { goSum.status = make(map[modSum]modSumStatus) goSum.w = make(map[string]map[module.Version][]string) - for _, f := range WorkspaceGoSumFiles { + for _, f := range ModuleFetchState.WorkspaceGoSumFiles { goSum.w[f] = make(map[module.Version][]string) _, err := readGoSumFile(goSum.w[f], f) if err != nil { @@ -544,7 +554,7 @@ func initGoSum() (bool, error) { } } - enabled, err := readGoSumFile(goSum.m, GoSumFile) + enabled, err := readGoSumFile(goSum.m, ModuleFetchState.GoSumFile) goSum.enabled = enabled return enabled, err } @@ -790,7 +800,7 @@ func checkModSum(mod module.Version, h string) error { // goSum.mu must be locked. func haveModSumLocked(mod module.Version, h string) bool { sumFileName := "go.sum" - if strings.HasSuffix(GoSumFile, "go.work.sum") { + if strings.HasSuffix(ModuleFetchState.GoSumFile, "go.work.sum") { sumFileName = "go.work.sum" } for _, vh := range goSum.m[mod] { @@ -934,7 +944,7 @@ Outer: if readonly { return ErrGoSumDirty } - if fsys.Replaced(GoSumFile) { + if fsys.Replaced(ModuleFetchState.GoSumFile) { base.Fatalf("go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay") } @@ -944,7 +954,7 @@ Outer: defer unlock() } - err := lockedfile.Transform(GoSumFile, func(data []byte) ([]byte, error) { + err := lockedfile.Transform(ModuleFetchState.GoSumFile, func(data []byte) ([]byte, error) { tidyGoSum := tidyGoSum(data, keep) return tidyGoSum, nil }) @@ -963,7 +973,7 @@ Outer: func TidyGoSum(keep map[module.Version]bool) (before, after []byte) { goSum.mu.Lock() defer goSum.mu.Unlock() - before, err := lockedfile.Read(GoSumFile) + before, err := lockedfile.Read(ModuleFetchState.GoSumFile) if err != nil && !errors.Is(err, fs.ErrNotExist) { base.Fatalf("reading go.sum: %v", err) } @@ -980,7 +990,7 @@ func tidyGoSum(data []byte, keep map[module.Version]bool) []byte { // truncated the file to remove erroneous hashes, and we shouldn't restore // them without good reason. goSum.m = make(map[module.Version][]string, len(goSum.m)) - readGoSum(goSum.m, GoSumFile, data) + readGoSum(goSum.m, ModuleFetchState.GoSumFile, data) for ms, st := range goSum.status { if st.used && !sumInWorkspaceModulesLocked(ms.mod) { addModSumLocked(ms.mod, ms.sum) diff --git a/src/cmd/go/internal/modfetch/repo.go b/src/cmd/go/internal/modfetch/repo.go index 5d4d679e832..bb5dfc4655d 100644 --- a/src/cmd/go/internal/modfetch/repo.go +++ b/src/cmd/go/internal/modfetch/repo.go @@ -184,11 +184,6 @@ type RevInfo struct { // To avoid version control access except when absolutely necessary, // Lookup does not attempt to connect to the repository itself. -// The Lookup cache is used cache the work done by Lookup. -// It is important that the global functions of this package that access it do not -// do so after they return. -var lookupCache = new(par.Cache[lookupCacheKey, Repo]) - type lookupCacheKey struct { proxy, path string } @@ -210,7 +205,7 @@ func Lookup(ctx context.Context, proxy, path string) Repo { defer logCall("Lookup(%q, %q)", proxy, path)() } - return lookupCache.Do(lookupCacheKey{proxy, path}, func() Repo { + return ModuleFetchState.lookupCache.Do(lookupCacheKey{proxy, path}, func() Repo { return newCachingRepo(ctx, path, func(ctx context.Context) (Repo, error) { r, err := lookup(ctx, proxy, path) if err == nil && traceRepo { diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go index 3d6f9a4a65a..bbdd0e95b5c 100644 --- a/src/cmd/go/internal/modload/init.go +++ b/src/cmd/go/internal/modload/init.go @@ -928,9 +928,9 @@ func loadModFile(loaderstate *State, ctx context.Context, opts *PackageOpts) (*R } for _, modRoot := range loaderstate.modRoots { sumFile := strings.TrimSuffix(modFilePath(modRoot), ".mod") + ".sum" - modfetch.WorkspaceGoSumFiles = append(modfetch.WorkspaceGoSumFiles, sumFile) + modfetch.ModuleFetchState.WorkspaceGoSumFiles = append(modfetch.ModuleFetchState.WorkspaceGoSumFiles, sumFile) } - modfetch.GoSumFile = loaderstate.workFilePath + ".sum" + modfetch.ModuleFetchState.GoSumFile = loaderstate.workFilePath + ".sum" } else if len(loaderstate.modRoots) == 0 { // We're in module mode, but not inside a module. // @@ -950,7 +950,7 @@ func loadModFile(loaderstate *State, ctx context.Context, opts *PackageOpts) (*R // // See golang.org/issue/32027. } else { - modfetch.GoSumFile = strings.TrimSuffix(modFilePath(loaderstate.modRoots[0]), ".mod") + ".sum" + modfetch.ModuleFetchState.GoSumFile = strings.TrimSuffix(modFilePath(loaderstate.modRoots[0]), ".mod") + ".sum" } if len(loaderstate.modRoots) == 0 { // TODO(#49228): Instead of creating a fake module with an empty modroot,