Every method of builds, build requests, rollouts, merges and assignments reads and writes the chain alone: the else branches that read the tables, the movers and MoveChain with their tests, chain_moved reads, ChainReads and the flags that switched a kind, the store's assignments mirror (KeepAssignmentPlans needs none of it: it uses only the AssignmentMirrored type, mirrors.go, and AssignmentValues, provisioning.go) and its tick, the move code of the controller's start, and ForTest's chain_moved row. The listed store tests of the move go with their functions; the tests of the readers, requests, assignments and plans that lived beside them stay in chain_store_test.go. Tests that replayed old data migrations over the build, assignment and pin tables are removed with the tables. The static test that no plan is written but through SavePlansMoving now reads the plan's chain path.
80 lines
2.6 KiB
Go
80 lines
2.6 KiB
Go
package inventory
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/novox/mesh-controller/internal/chain"
|
|
)
|
|
|
|
// **The chain lives on the bus** (novox/hq ADR 0408, design 47 milestone 5): builds, rollouts and assignments are keys of the
|
|
// bus's key-value store, the controller's store keeps none of them, and every method of a kind reads and writes the chain this
|
|
// inventory is given (theChain).
|
|
|
|
// testChains are the chains in memory a test made for its store, by the store's address: every inventory opened on that
|
|
// store is given the same chain, as every process of a mesh is on the same bus. Empty outside a test.
|
|
var testChains sync.Map
|
|
|
|
// ErrNoChain is a read or write of the chain by an inventory that has none attached: a process that did not open the bus.
|
|
// Refused loudly.
|
|
var ErrNoChain = errors.New("this kind of record lives on the bus, and this process has not opened the bus")
|
|
|
|
// chainState is what an inventory keeps of the chain it is given.
|
|
type chainState struct {
|
|
mu sync.Mutex
|
|
open ChainOpener
|
|
// view is the rollouts bucket kept in memory by one watch (issue 1092); pending are the merges added to a plan that
|
|
// is not saved yet.
|
|
view *rolloutView
|
|
pending map[string]pendingMerge
|
|
}
|
|
|
|
// ChainOpener opens the chain on the bus when a process first needs it: a command that reads and never moved anything has
|
|
// no bus connection until a kind it reads turns out to be moved.
|
|
type ChainOpener func(ctx context.Context) (*chain.Chain, error)
|
|
|
|
// UseChainOpener gives the inventory the means to open the chain when it needs it and none is attached.
|
|
func (i *Inventory) UseChainOpener(open ChainOpener) {
|
|
i.state.mu.Lock()
|
|
i.state.open = open
|
|
i.state.mu.Unlock()
|
|
}
|
|
|
|
// UseChain attaches the chain the moved kinds are read and written through. The serving controller attaches the bus's,
|
|
// holding the lease for its writes; a test attaches one in memory.
|
|
func (i *Inventory) UseChain(c *chain.Chain) {
|
|
i.state.mu.Lock()
|
|
defer i.state.mu.Unlock()
|
|
i.chain = c
|
|
if i.state.view != nil {
|
|
i.state.view.stop()
|
|
i.state.view = nil
|
|
}
|
|
}
|
|
|
|
// attached is the chain this inventory has, nil when none.
|
|
func (i *Inventory) attached() *chain.Chain {
|
|
i.state.mu.Lock()
|
|
defer i.state.mu.Unlock()
|
|
return i.chain
|
|
}
|
|
|
|
// theChain is the chain this inventory writes and reads, opened if a command has not yet.
|
|
func (i *Inventory) theChain(ctx context.Context) (*chain.Chain, error) {
|
|
i.state.mu.Lock()
|
|
defer i.state.mu.Unlock()
|
|
if i.chain == nil && i.state.open != nil {
|
|
c, err := i.state.open(ctx)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%w: %v", ErrNoChain, err)
|
|
}
|
|
i.chain = c
|
|
}
|
|
if i.chain == nil {
|
|
return nil, ErrNoChain
|
|
}
|
|
return i.chain, nil
|
|
}
|