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  }