Count an unasked report as said only once the broker has taken it (hq ADR 0100)
This commit is contained in:
+26
-8
@@ -638,11 +638,11 @@ func runLink(ctx context.Context, opts options) error {
|
||||
// (novox/hq ADR 0004).
|
||||
// Reports a reconcile has to make unasked — what an adopted node holds changed, or its
|
||||
// firewall did — go out over the link when it is up (novox/hq ADR 0100).
|
||||
outbox := make(chan link.Report, 1)
|
||||
outbox := make(chan link.Unasked, 1)
|
||||
watch := &adoptionWatch{}
|
||||
applier = watch.noting(applier)
|
||||
go holdTheMachine(ctx, opts, mine, say, sched, func(r link.Report) {
|
||||
if !watch.changed(r) {
|
||||
if !watch.differs(r) {
|
||||
return
|
||||
}
|
||||
select {
|
||||
@@ -650,7 +650,13 @@ func runLink(ctx context.Context, opts options) error {
|
||||
// An older one nobody has published yet; this one says everything it did.
|
||||
default:
|
||||
}
|
||||
outbox <- r
|
||||
// Counted as said only once the broker has taken it: queued and lost — the link down, the
|
||||
// publish refused — the change would never be said again (novox/hq ADR 0100).
|
||||
outbox <- link.Unasked{Report: r, Done: func(published bool) {
|
||||
if published {
|
||||
watch.said(r)
|
||||
}
|
||||
}}
|
||||
})
|
||||
|
||||
return link.HoldRoused(ctx, link.Membership{
|
||||
@@ -686,15 +692,27 @@ func adoptionFingerprint(r link.Report) string {
|
||||
return strings.Join(parts, "\n")
|
||||
}
|
||||
|
||||
// changed records a report and says whether it differs from the last one that went out.
|
||||
func (w *adoptionWatch) changed(r link.Report) bool {
|
||||
// differs says whether a report says anything the last one that went out did not. It records
|
||||
// nothing: what was said is what reached the mesh, not what was written down to send.
|
||||
func (w *adoptionWatch) differs(r link.Report) bool {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
now := adoptionFingerprint(r)
|
||||
if now == w.last {
|
||||
return adoptionFingerprint(r) != w.last
|
||||
}
|
||||
|
||||
// said records a report the mesh has actually been told.
|
||||
func (w *adoptionWatch) said(r link.Report) {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
w.last = adoptionFingerprint(r)
|
||||
}
|
||||
|
||||
// changed is differs and said together, for a report published as it is made.
|
||||
func (w *adoptionWatch) changed(r link.Report) bool {
|
||||
if !w.differs(r) {
|
||||
return false
|
||||
}
|
||||
w.last = now
|
||||
w.said(r)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -244,3 +244,21 @@ func TestOnlyOneApplyRunsAtATime(t *testing.T) {
|
||||
t.Errorf("the apply recorded %d resource(s): %v", len(known.Resources), loadErr)
|
||||
}
|
||||
}
|
||||
|
||||
// Defends novox/hq ADR 0100: a change is counted as said only once the mesh has been told. Queued
|
||||
// and lost — the link down when the reconcile spoke — it must be said again.
|
||||
func TestAChangeThatNeverReachedTheMeshIsSaidAgain(t *testing.T) {
|
||||
w := &adoptionWatch{}
|
||||
held := link.Report{Firewall: "ufw", Held: []link.Held{{ID: "hello-web.page", Changed: "rewritten"}}}
|
||||
if !w.differs(held) {
|
||||
t.Fatal("the first report of a change was not new")
|
||||
}
|
||||
// The link was down: nothing published it, so nothing says it was said.
|
||||
if !w.differs(held) {
|
||||
t.Error("a change that never reached the mesh was counted as said")
|
||||
}
|
||||
w.said(held)
|
||||
if w.differs(held) {
|
||||
t.Error("a change the mesh was told was said again")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user