Merge pull request 'The assigner puts only changed values and keeps a placed node's record ask while it waits (issue 774)' (#121) from fix/assigner-puts-only-changes into main
This commit was merged in pull request #121.
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
@@ -566,6 +567,11 @@ func (p *passer) put(ctx context.Context, bucket, key string, encode func() ([]b
|
|||||||
p.logf("%s %s is not written: %v", bucket, key, err)
|
p.logf("%s %s is not written: %v", bucket, key, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// A value the bucket already holds is not put again: every put is a change its watchers hear, and a want put unchanged
|
||||||
|
// made its node compose again (issue 774, 2026-10-31: novox composed every 8 s, two asks of the vault each time).
|
||||||
|
if held := p.w.value(bucket, key); held != nil && bytes.Equal(held, value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if _, err := p.kvs[bucket].Put(ctx, key, value); err != nil && !errors.Is(err, context.Canceled) {
|
if _, err := p.kvs[bucket].Put(ctx, key, value); err != nil && !errors.Is(err, context.Canceled) {
|
||||||
p.logf("%s %s could not be written: %v", bucket, key, err)
|
p.logf("%s %s could not be written: %v", bucket, key, err)
|
||||||
return
|
return
|
||||||
@@ -645,6 +651,14 @@ func (p *passer) staleAsk(key string, trunk map[string]delivery.Module) bool {
|
|||||||
if !on {
|
if !on {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
// A node that composes its own asks about its own composition, which its have names as the one it waits on (yeses): that
|
||||||
|
// ask stands while the have waits on it, whatever the controller composes (issue 774, 2026-10-31: novox's asks of
|
||||||
|
// postgres, keycloak and mongodb were taken away and made again under a new id every pass, so no answer could count).
|
||||||
|
if hkey, err := delivery.HaveKey(k.Node, k.Module); err == nil {
|
||||||
|
if h, err := delivery.DecodeHave(p.w.value(delivery.HaveBucket, hkey)); err == nil && h.Phase == delivery.PhaseWaitingYes && h.Waits == k.Composed {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
// The assigner asks about a composition at more than the trunk fingerprint: a node held back by the rules is asked about the
|
// The assigner asks about a composition at more than the trunk fingerprint: a node held back by the rules is asked about the
|
||||||
// revised composition of the fingerprint it runs (ADR 0545), and a node's first want at the older fingerprint it runs. So a
|
// revised composition of the fingerprint it runs (ADR 0545), and a node's first want at the older fingerprint it runs. So a
|
||||||
// record ask is stale only when its digest is the composition of none of the fingerprints the node can still want (the
|
// record ask is stale only when its digest is the composition of none of the fingerprints the node can still want (the
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
@@ -26,10 +27,12 @@ import (
|
|||||||
type memKV struct {
|
type memKV struct {
|
||||||
jetstream.KeyValue
|
jetstream.KeyValue
|
||||||
values map[string][]byte
|
values map[string][]byte
|
||||||
|
puts int // how many puts reached the bucket
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *memKV) Put(_ context.Context, key string, value []byte) (uint64, error) {
|
func (m *memKV) Put(_ context.Context, key string, value []byte) (uint64, error) {
|
||||||
m.values[key] = value
|
m.values[key] = value
|
||||||
|
m.puts++
|
||||||
return uint64(len(m.values)), nil
|
return uint64(len(m.values)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -952,6 +955,30 @@ func aPlacedNodesWantsNameTheBuildAloneAndItsYesComesFromItsHave(t *testing.T) {
|
|||||||
if _, there := asksKV.values[akey]; !there {
|
if _, there := asksKV.values[akey]; !there {
|
||||||
t.Fatal("a have waiting for a yes raised no record ask")
|
t.Fatal("a have waiting for a yes raised no record ask")
|
||||||
}
|
}
|
||||||
|
// Issue 774, 2026-10-31: while the controller still composes the placed node's module (its lease not handed away), its
|
||||||
|
// digests are not the one the node's have waits on; the ask stays, and a pass that changes nothing puts nothing: on novox
|
||||||
|
// the asks of postgres, keycloak and mongodb were taken away and made again every 8 s, and a want put unchanged each
|
||||||
|
// pass made the node compose again each time.
|
||||||
|
for _, fp := range []string{fpTest, fpOld} {
|
||||||
|
ck, _ := delivery.ComposedKey("g14", "web", fp)
|
||||||
|
cv, _ := delivery.EncodeComposedDigest(delivery.ComposedDigest{Digest: "sha256:" + strings.Repeat("c", 64), Judgement: delivery.JudgedUnchanged})
|
||||||
|
put(delivery.ControllerComposedBucket, ck, cv)
|
||||||
|
}
|
||||||
|
asked := asksKV.values[akey]
|
||||||
|
p.wants(context.Background())
|
||||||
|
if !bytes.Equal(asksKV.values[akey], asked) {
|
||||||
|
t.Fatalf("the record ask the node's have waits on was taken away or made again: %q", asksKV.values[akey])
|
||||||
|
}
|
||||||
|
wantPuts, askPuts := wantsKV.puts, asksKV.puts
|
||||||
|
p.wants(context.Background())
|
||||||
|
if wantsKV.puts != wantPuts || asksKV.puts != askPuts {
|
||||||
|
t.Fatalf("a pass that changed nothing put %d wants and %d asks", wantsKV.puts-wantPuts, asksKV.puts-askPuts)
|
||||||
|
}
|
||||||
|
// Whichever rule asks it, a want put with the value the bucket holds reaches no bucket: each put is a change its node hears.
|
||||||
|
p.put(context.Background(), delivery.AssignerWantsBucket, wkey, func() ([]byte, error) { return wantsKV.values[wkey], nil })
|
||||||
|
if wantsKV.puts != wantPuts {
|
||||||
|
t.Fatalf("a want put unchanged reached the bucket")
|
||||||
|
}
|
||||||
a, err := delivery.DecodeAssignerAsk(akey, asksKV.values[akey])
|
a, err := delivery.DecodeAssignerAsk(akey, asksKV.values[akey])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|||||||
Reference in New Issue
Block a user