github.com/graywolf-at-work-2/terraform-vendor@v1.4.5/internal/getproviders/memoize_source.go (about) 1 package getproviders 2 3 import ( 4 "context" 5 "sync" 6 7 "github.com/hashicorp/terraform/internal/addrs" 8 ) 9 10 // MemoizeSource is a Source that wraps another Source and remembers its 11 // results so that they can be returned more quickly on future calls to the 12 // same object. 13 // 14 // Each MemoizeSource maintains a cache of response it has seen as part of its 15 // body. All responses are retained for the remaining lifetime of the object. 16 // Errors from the underlying source are also cached, and so subsequent calls 17 // with the same arguments will always produce the same errors. 18 // 19 // A MemoizeSource can be called concurrently, with incoming requests processed 20 // sequentially. 21 type MemoizeSource struct { 22 underlying Source 23 availableVersions map[addrs.Provider]memoizeAvailableVersionsRet 24 packageMetas map[memoizePackageMetaCall]memoizePackageMetaRet 25 mu sync.Mutex 26 } 27 28 type memoizeAvailableVersionsRet struct { 29 VersionList VersionList 30 Warnings Warnings 31 Err error 32 } 33 34 type memoizePackageMetaCall struct { 35 Provider addrs.Provider 36 Version Version 37 Target Platform 38 } 39 40 type memoizePackageMetaRet struct { 41 PackageMeta PackageMeta 42 Err error 43 } 44 45 var _ Source = (*MemoizeSource)(nil) 46 47 // NewMemoizeSource constructs and returns a new MemoizeSource that wraps 48 // the given underlying source and memoizes its results. 49 func NewMemoizeSource(underlying Source) *MemoizeSource { 50 return &MemoizeSource{ 51 underlying: underlying, 52 availableVersions: make(map[addrs.Provider]memoizeAvailableVersionsRet), 53 packageMetas: make(map[memoizePackageMetaCall]memoizePackageMetaRet), 54 } 55 } 56 57 // AvailableVersions requests the available versions from the underlying source 58 // and caches them before returning them, or on subsequent calls returns the 59 // result directly from the cache. 60 func (s *MemoizeSource) AvailableVersions(ctx context.Context, provider addrs.Provider) (VersionList, Warnings, error) { 61 s.mu.Lock() 62 defer s.mu.Unlock() 63 64 if existing, exists := s.availableVersions[provider]; exists { 65 return existing.VersionList, nil, existing.Err 66 } 67 68 ret, warnings, err := s.underlying.AvailableVersions(ctx, provider) 69 s.availableVersions[provider] = memoizeAvailableVersionsRet{ 70 VersionList: ret, 71 Err: err, 72 Warnings: warnings, 73 } 74 return ret, warnings, err 75 } 76 77 // PackageMeta requests package metadata from the underlying source and caches 78 // the result before returning it, or on subsequent calls returns the result 79 // directly from the cache. 80 func (s *MemoizeSource) PackageMeta(ctx context.Context, provider addrs.Provider, version Version, target Platform) (PackageMeta, error) { 81 s.mu.Lock() 82 defer s.mu.Unlock() 83 84 key := memoizePackageMetaCall{ 85 Provider: provider, 86 Version: version, 87 Target: target, 88 } 89 if existing, exists := s.packageMetas[key]; exists { 90 return existing.PackageMeta, existing.Err 91 } 92 93 ret, err := s.underlying.PackageMeta(ctx, provider, version, target) 94 s.packageMetas[key] = memoizePackageMetaRet{ 95 PackageMeta: ret, 96 Err: err, 97 } 98 return ret, err 99 } 100 101 func (s *MemoizeSource) ForDisplay(provider addrs.Provider) string { 102 return s.underlying.ForDisplay(provider) 103 }