Read this node's placement from its node and module keys, or its placement.<node> before the holder converts it, so a write of the holder's is composed only once its node key lands (issue 774, research 072 row 37)

This commit is contained in:
2026-10-31 09:37:23 +01:00
parent bb8383b065
commit a4c0cee251
8 changed files with 176 additions and 42 deletions
+29 -12
View File
@@ -98,7 +98,10 @@ type Composer struct {
mu sync.Mutex
wants map[string]delivery.Want // by module, the node's own under agent.NodeModule
placements map[string]delivery.Placement
records map[string]delivery.NodeRecord
// placementKeys is the seat's state placement key by key in either form, each node's placement assembled from it
// (delivery.PlacementKeys; research 072 row 37): a write of the holder's under way is never composed half.
placementKeys *delivery.PlacementKeys
records map[string]delivery.NodeRecord
// inOwn is, by module, whether this node's have of it names no fingerprint of the new form (mesh-wireguard, a module
// at a build of the old form): the node runs it inside its own composition, and composes it there again (issue 1126).
inOwn map[string]bool
@@ -215,7 +218,7 @@ func New(env Env) *Composer {
if env.Say == nil {
env.Say = func(string) {}
}
return &Composer{env: env, wants: map[string]delivery.Want{}, placements: map[string]delivery.Placement{},
return &Composer{env: env, wants: map[string]delivery.Want{}, placements: map[string]delivery.Placement{}, placementKeys: delivery.NewPlacementKeys(),
records: map[string]delivery.NodeRecord{}, inOwn: map[string]bool{}, modules: map[string]delivery.Module{}, values: map[string]map[string]any{},
manifests: map[string][]byte{}, archives: map[string][]byte{}, handed: map[string]string{}, sealedOwn: map[string]ownSealed{},
asked: make(chan chan Pass, 8)}
@@ -499,7 +502,9 @@ func (c *Composer) entry(bucket, key string) (v any, has, known bool) {
w, ok := c.wants[module]
return w.FP, ok, true
case delivery.PlacementBucket:
node, err := delivery.ParsePlacementKey(key)
// Any key of a node, its node key, a module key or its legacy key, stands for the node's whole placement: a
// module key written before its node key names it changes nothing composed.
node, _, _, err := delivery.ParsePlacementKey(key)
if err != nil {
return nil, false, true
}
@@ -551,18 +556,25 @@ func (c *Composer) takeWant(u agent.Update) {
}
func (c *Composer) takePlacement(u agent.Update) {
node, err := delivery.ParsePlacementKey(u.Key)
if err != nil {
if u.Caught {
return
}
c.mu.Lock()
defer c.mu.Unlock()
p, err := delivery.DecodePlacement(u.Value)
if u.Deleted || err != nil || p.Node != node {
delete(c.placements, node)
return
if c.placementKeys == nil {
c.placementKeys = delivery.NewPlacementKeys()
}
node, err := c.placementKeys.Put(u.Key, u.Value, u.Revision, u.Deleted || len(u.Value) == 0)
if node != "" {
if p, _, ok := c.placementKeys.Of(node); ok {
c.placements[node] = p
} else {
delete(c.placements, node)
}
}
c.mu.Unlock()
if node != "" && err != nil && c.env.Say != nil {
c.env.Say("the seat's placement of " + node + ": " + err.Error())
}
c.placements[node] = p
}
func (c *Composer) takeRecord(u agent.Update) {
@@ -1370,13 +1382,18 @@ func (r reader) Credentials(ctx context.Context, node string, asConsumer, asProv
// watch endWhenPlaced keeps). A node that switched never goes back on a failed read, however long it lasts.
func Placed(ctx context.Context, get func(ctx context.Context, bucket, key string) ([]byte, error), node string,
wait func(try int) time.Duration, say func(string), switched bool) (bool, error) {
key, err := delivery.PlacementKey(node)
key, err := delivery.PlacementNodeKey(node)
if err != nil {
return false, err
}
legacy, _ := delivery.LegacyPlacementKey(node)
said := ""
for try := 1; ; try++ {
// Its node key, or, before the seat's holder converted it, its legacy key (research 072 row 37).
raw, err := get(ctx, delivery.PlacementBucket, key)
if err == nil && len(raw) == 0 {
raw, err = get(ctx, delivery.PlacementBucket, legacy)
}
if errors.Is(err, nats.ErrBucketNotFound) {
return false, nil // the seat has written no placement state yet: nothing places it, read and known
}