don't store an entire Resource in each Instance

The AbstractResourceInstance type was storing the entire Resource from
the state, when it only needs the actual instance state. This would
cause resources to consume memory on the order of n^2, where n in the
number of instances of the resource.

Rather than attaching the entire resource state, which includes copying
each individual instance, only attach the ResourceInstance state, and
extract out the provider address from the Resource.
This commit is contained in:
James Bardin 2020-07-10 10:16:45 -04:00
parent 1c7a8c3e43
commit ee8cc627a0
3 changed files with 26 additions and 26 deletions

View File

@ -101,11 +101,14 @@ type NodeAbstractResourceInstance struct {
NodeAbstractResource
Addr addrs.AbsResourceInstance
// The fields below will be automatically set using the Attach
// interfaces if you're running those transforms, but also be explicitly
// set if you already have that information.
ResourceState *states.Resource
Dependencies []addrs.ConfigResource
// These are set via the AttachState method.
instanceState *states.ResourceInstance
// storedProviderConfig is the provider address retrieved from the
// state, but since it is only stored in the whole Resource rather than the
// ResourceInstance, we extract it out here.
storedProviderConfig addrs.AbsProviderConfig
Dependencies []addrs.ConfigResource
}
var (
@ -287,11 +290,9 @@ func dottedInstanceAddr(tr addrs.ResourceInstance) string {
// StateDependencies returns the dependencies saved in the state.
func (n *NodeAbstractResourceInstance) StateDependencies() []addrs.ConfigResource {
if rs := n.ResourceState; rs != nil {
if s := rs.Instance(n.Addr.Resource.Key); s != nil {
if s.Current != nil {
return s.Current.Dependencies
}
if s := n.instanceState; s != nil {
if s.Current != nil {
return s.Current.Dependencies
}
}
@ -339,12 +340,12 @@ func (n *NodeAbstractResourceInstance) ProvidedBy() (addrs.ProviderConfig, bool)
}, false
}
// If we have state, then we will use the provider from there
if n.ResourceState != nil {
// See if we have a valid provider config from the state.
if n.storedProviderConfig.Provider.Type != "" {
// An address from the state must match exactly, since we must ensure
// we refresh/destroy a resource with the same provider configuration
// that created it.
return n.ResourceState.ProviderConfig, true
return n.storedProviderConfig, true
}
// No provider configuration found; return a default address
@ -410,7 +411,12 @@ func (n *NodeAbstractResource) AttachResourceDependencies(deps []addrs.ConfigRes
// GraphNodeAttachResourceState
func (n *NodeAbstractResourceInstance) AttachResourceState(s *states.Resource) {
n.ResourceState = s
if s == nil {
log.Printf("[WARN] attaching nil state to %s", n.Addr)
return
}
n.instanceState = s.Instance(n.Addr.Resource.Key)
n.storedProviderConfig = s.ProviderConfig
}
// GraphNodeAttachResourceConfig

View File

@ -63,11 +63,9 @@ func (n *NodeDestroyResourceInstance) CreateBeforeDestroy() bool {
}
// Otherwise check the state for a stored destroy order
if rs := n.ResourceState; rs != nil {
if s := rs.Instance(n.Addr.Resource.Key); s != nil {
if s.Current != nil {
return s.Current.CreateBeforeDestroy
}
if s := n.instanceState; s != nil {
if s.Current != nil {
return s.Current.CreateBeforeDestroy
}
}
@ -134,11 +132,7 @@ func (n *NodeDestroyResourceInstance) EvalTree() EvalNode {
addr := n.ResourceInstanceAddr()
// Get our state
rs := n.ResourceState
var is *states.ResourceInstance
if rs != nil {
is = rs.Instance(n.Addr.Resource.Key)
}
is := n.instanceState
if is == nil {
log.Printf("[WARN] NodeDestroyResourceInstance for %s with no state", addr)
}

View File

@ -215,7 +215,7 @@ func (n *NodeRefreshableManagedResourceInstance) EvalTree() EvalNode {
// Eval info is different depending on what kind of resource this is
switch addr.Resource.Resource.Mode {
case addrs.ManagedResourceMode:
if n.ResourceState == nil {
if n.instanceState == nil {
log.Printf("[TRACE] NodeRefreshableManagedResourceInstance: %s has no existing state to refresh", addr)
return n.evalTreeManagedResourceNoState()
}
@ -253,7 +253,7 @@ func (n *NodeRefreshableManagedResourceInstance) evalTreeManagedResource() EvalN
// This happened during initial development. All known cases were
// fixed and tested but as a sanity check let's assert here.
if n.ResourceState == nil {
if n.instanceState == nil {
err := fmt.Errorf(
"No resource state attached for addr: %s\n\n"+
"This is a bug. Please report this to Terraform with your configuration\n"+