cmd/go/internal/modfetch: consolidate global vars

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 <matloob@golang.org>
Reviewed-by: Michael Matloob <matloob@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Ian Alexander 2025-11-11 13:50:51 -05:00
parent 028375323f
commit 099e0027bd
3 changed files with 47 additions and 42 deletions

View file

@ -35,13 +35,6 @@ import (
modzip "golang.org/x/mod/zip" 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") var ErrToolchain = errors.New("internal error: invalid operation on toolchain module")
// Download downloads the specific module version to the // 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. // 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) dir, err := download(ctx, mod)
if err != nil { if err != nil {
return "", err return "", err
@ -85,7 +78,7 @@ func Unzip(ctx context.Context, mod module.Version, zipfile string) (dir string,
base.Fatal(err) 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()) ctx, span := trace.StartSpan(ctx, "modfetch.Unzip "+mod.String())
defer span.Done() 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 // 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. // 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 { type modSum struct {
mod module.Version mod module.Version
sum string sum string
@ -471,11 +461,31 @@ type modSumStatus struct {
// State holds a snapshot of the global state of the modfetch package. // State holds a snapshot of the global state of the modfetch package.
type State struct { type State struct {
goSumFile string // path to go.sum; set by package modload
workspaceGoSumFiles []string GoSumFile string
lookupCache *par.Cache[lookupCacheKey, Repo] // path to module go.sums in workspace; set by package modload
downloadCache *par.ErrCache[module.Version, string] WorkspaceGoSumFiles []string
sumState sumState // 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 // 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() defer goSum.mu.Unlock()
oldState = State{ oldState = State{
goSumFile: GoSumFile, GoSumFile: ModuleFetchState.GoSumFile,
workspaceGoSumFiles: WorkspaceGoSumFiles, WorkspaceGoSumFiles: ModuleFetchState.WorkspaceGoSumFiles,
lookupCache: lookupCache, lookupCache: ModuleFetchState.lookupCache,
downloadCache: downloadCache, downloadCache: ModuleFetchState.downloadCache,
sumState: goSum.sumState, sumState: goSum.sumState,
} }
GoSumFile = newState.goSumFile ModuleFetchState.GoSumFile = newState.GoSumFile
WorkspaceGoSumFiles = newState.workspaceGoSumFiles ModuleFetchState.WorkspaceGoSumFiles = newState.WorkspaceGoSumFiles
// Uses of lookupCache and downloadCache both can call checkModSum, // Uses of lookupCache and downloadCache both can call checkModSum,
// which in turn sets the used bit on goSum.status for modules. // which in turn sets the used bit on goSum.status for modules.
// Set (or reset) them so used can be computed properly. // Set (or reset) them so used can be computed properly.
lookupCache = newState.lookupCache ModuleFetchState.lookupCache = newState.lookupCache
downloadCache = newState.downloadCache ModuleFetchState.downloadCache = newState.downloadCache
// Set, or reset all fields on goSum. If being reset to empty, it will be initialized later. // Set, or reset all fields on goSum. If being reset to empty, it will be initialized later.
goSum.sumState = newState.sumState goSum.sumState = newState.sumState
@ -525,7 +535,7 @@ func SetState(newState State) (oldState State) {
// use of go.sum is now enabled. // use of go.sum is now enabled.
// The goSum lock must be held. // The goSum lock must be held.
func initGoSum() (bool, error) { func initGoSum() (bool, error) {
if GoSumFile == "" { if ModuleFetchState.GoSumFile == "" {
return false, nil return false, nil
} }
if goSum.m != nil { if goSum.m != nil {
@ -536,7 +546,7 @@ func initGoSum() (bool, error) {
goSum.status = make(map[modSum]modSumStatus) goSum.status = make(map[modSum]modSumStatus)
goSum.w = make(map[string]map[module.Version][]string) 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) goSum.w[f] = make(map[module.Version][]string)
_, err := readGoSumFile(goSum.w[f], f) _, err := readGoSumFile(goSum.w[f], f)
if err != nil { 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 goSum.enabled = enabled
return enabled, err return enabled, err
} }
@ -790,7 +800,7 @@ func checkModSum(mod module.Version, h string) error {
// goSum.mu must be locked. // goSum.mu must be locked.
func haveModSumLocked(mod module.Version, h string) bool { func haveModSumLocked(mod module.Version, h string) bool {
sumFileName := "go.sum" sumFileName := "go.sum"
if strings.HasSuffix(GoSumFile, "go.work.sum") { if strings.HasSuffix(ModuleFetchState.GoSumFile, "go.work.sum") {
sumFileName = "go.work.sum" sumFileName = "go.work.sum"
} }
for _, vh := range goSum.m[mod] { for _, vh := range goSum.m[mod] {
@ -934,7 +944,7 @@ Outer:
if readonly { if readonly {
return ErrGoSumDirty 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") 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() 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) tidyGoSum := tidyGoSum(data, keep)
return tidyGoSum, nil return tidyGoSum, nil
}) })
@ -963,7 +973,7 @@ Outer:
func TidyGoSum(keep map[module.Version]bool) (before, after []byte) { func TidyGoSum(keep map[module.Version]bool) (before, after []byte) {
goSum.mu.Lock() goSum.mu.Lock()
defer goSum.mu.Unlock() defer goSum.mu.Unlock()
before, err := lockedfile.Read(GoSumFile) before, err := lockedfile.Read(ModuleFetchState.GoSumFile)
if err != nil && !errors.Is(err, fs.ErrNotExist) { if err != nil && !errors.Is(err, fs.ErrNotExist) {
base.Fatalf("reading go.sum: %v", err) 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 // truncated the file to remove erroneous hashes, and we shouldn't restore
// them without good reason. // them without good reason.
goSum.m = make(map[module.Version][]string, len(goSum.m)) 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 { for ms, st := range goSum.status {
if st.used && !sumInWorkspaceModulesLocked(ms.mod) { if st.used && !sumInWorkspaceModulesLocked(ms.mod) {
addModSumLocked(ms.mod, ms.sum) addModSumLocked(ms.mod, ms.sum)

View file

@ -184,11 +184,6 @@ type RevInfo struct {
// To avoid version control access except when absolutely necessary, // To avoid version control access except when absolutely necessary,
// Lookup does not attempt to connect to the repository itself. // 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 { type lookupCacheKey struct {
proxy, path string proxy, path string
} }
@ -210,7 +205,7 @@ func Lookup(ctx context.Context, proxy, path string) Repo {
defer logCall("Lookup(%q, %q)", proxy, path)() 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) { return newCachingRepo(ctx, path, func(ctx context.Context) (Repo, error) {
r, err := lookup(ctx, proxy, path) r, err := lookup(ctx, proxy, path)
if err == nil && traceRepo { if err == nil && traceRepo {

View file

@ -928,9 +928,9 @@ func loadModFile(loaderstate *State, ctx context.Context, opts *PackageOpts) (*R
} }
for _, modRoot := range loaderstate.modRoots { for _, modRoot := range loaderstate.modRoots {
sumFile := strings.TrimSuffix(modFilePath(modRoot), ".mod") + ".sum" 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 { } else if len(loaderstate.modRoots) == 0 {
// We're in module mode, but not inside a module. // 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. // See golang.org/issue/32027.
} else { } 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 { if len(loaderstate.modRoots) == 0 {
// TODO(#49228): Instead of creating a fake module with an empty modroot, // TODO(#49228): Instead of creating a fake module with an empty modroot,