mirror of
https://github.com/opentffoundation/opentf.git
synced 2026-03-20 22:01:25 -04:00
This is the first chunk of the work to construct an execution graph based on the intermediate representation in resourceInstanceObjects. For now this just constructs an independent subgraph for each resource instance object, without honoring any of the inter-object dependencies. A subsequent commit will add in all of those dependencies in an additional loop afterwards. Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
80 lines
3.0 KiB
Go
80 lines
3.0 KiB
Go
// Copyright (c) The OpenTofu Authors
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
// Copyright (c) 2023 HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package planning
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"github.com/opentofu/opentofu/internal/addrs"
|
|
"github.com/opentofu/opentofu/internal/engine/internal/execgraph"
|
|
)
|
|
|
|
// execGraphBuilder is a higher-level wrapper around [execgraph.Builder] that
|
|
// is tailored to the needs of the planning engine.
|
|
//
|
|
// Specifically:
|
|
// - Its exported methods that add to or modify the graph are all
|
|
// concurrency-safe, for convenient use during the concurrent planning work
|
|
// driven by the evaluator.
|
|
// - It keeps track of certain "singleton" collections of graph nodes that
|
|
// different parts of the planning engine all need to agree on for the
|
|
// execution graph to be correct, such as ensuring there's only one open
|
|
// and one close operation per distinct provider instance address.
|
|
// - Many of its methods can potentially add multiple operations to the graph
|
|
// at once, to let the planning engine work at a higher level of abstraction
|
|
// than just the individual raw operation types. The lower-level
|
|
// [execgraph.Builder] instead directly matches the abstraction level of
|
|
// [execgraph.Operations].
|
|
type execGraphBuilder struct {
|
|
// mu must be locked while accessing any of the other fields.
|
|
mu sync.Mutex
|
|
|
|
// lower is the lower-level graph builder that this utility is built in
|
|
// terms of.
|
|
lower *execgraph.Builder
|
|
|
|
// During construction we treat certain items as singletons so that
|
|
// we can do the associated work only once while providing it to
|
|
// multiple callers, and so these maps track those singletons but
|
|
// we throw these away after building is complete because the graph
|
|
// becomes immutable at that point.
|
|
resourceInstAddrRefs addrs.Map[addrs.AbsResourceInstance, execgraph.ResultRef[addrs.AbsResourceInstance]]
|
|
}
|
|
|
|
// NOTE: There are additional methods for [execGraphBuilder] declared in
|
|
// the other files named execgraph_*.go , grouped by what kinds of objects they
|
|
// primarily work with.
|
|
|
|
func newExecGraphBuilder() *execGraphBuilder {
|
|
return &execGraphBuilder{
|
|
lower: execgraph.NewBuilder(),
|
|
resourceInstAddrRefs: addrs.MakeMap[addrs.AbsResourceInstance, execgraph.ResultRef[addrs.AbsResourceInstance]](),
|
|
}
|
|
}
|
|
|
|
// Finish returns the graph that has been built, which is then immutable.
|
|
//
|
|
// After calling this function the execGraphBuilder is invalid and must not be
|
|
// used anymore.
|
|
func (b *execGraphBuilder) Finish() *execgraph.Graph {
|
|
b.mu.Lock()
|
|
defer b.mu.Unlock()
|
|
return b.lower.Finish()
|
|
}
|
|
|
|
// makeCloseBlocker is a helper used by [execGraphBuilder] methods that produce
|
|
// open/close node pairs.
|
|
//
|
|
// Callers MUST hold a lock on b.mu throughout any call to this method, AND
|
|
// when calling the returned callback.
|
|
func (b *execGraphBuilder) makeCloseBlocker() (execgraph.AnyResultRef, func(execgraph.AnyResultRef)) {
|
|
waiter, lowerRegister := b.lower.MutableWaiter()
|
|
registerFunc := func(ref execgraph.AnyResultRef) {
|
|
lowerRegister(ref)
|
|
}
|
|
return waiter, registerFunc
|
|
}
|