A report says which declaration it is about
The mesh decided "has this machine caught up" by comparing its send time to the report's arrival, and lost the race it invited: an apply started under the previous declaration finishes after the next one is sent, its report lands newer than the send, and the machine reads as caught up with words it has not read yet. The lab hit exactly that — one test's closing push was still being applied when the next test's push recorded its send, and the next test then read files that were never going to be there yet. Clocks cannot answer "which". The report now carries the digest of the exact bytes it applied — the same bytes, hashed the same way, that the mesh recorded when it sent them — and which-declaration becomes an equality the mesh checks rather than an ordering it hopes.
This commit is contained in:
+11
-1
@@ -8,7 +8,9 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/sha256"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
@@ -734,7 +736,7 @@ func applyAndKeep(ctx context.Context, opts options, raw []byte, signed *store.D
|
|||||||
saveErr.Error()}
|
saveErr.Error()}
|
||||||
}
|
}
|
||||||
|
|
||||||
report := link.Report{Carried: carriedPorts(updated)}
|
report := link.Report{Carried: carriedPorts(updated), Declared: digestOf(raw)}
|
||||||
for _, change := range outcome.Outcomes {
|
for _, change := range outcome.Outcomes {
|
||||||
report.Applied = append(report.Applied, change.ID)
|
report.Applied = append(report.Applied, change.ID)
|
||||||
}
|
}
|
||||||
@@ -809,6 +811,14 @@ func sealOpener(statePath string) apply.Unseal {
|
|||||||
//
|
//
|
||||||
// Only what was carried. What the mesh itself put here it already knows about, and reporting it
|
// Only what was carried. What the mesh itself put here it already knows about, and reporting it
|
||||||
// back would make the machine an authority on the mesh's own bookkeeping.
|
// back would make the machine an authority on the mesh's own bookkeeping.
|
||||||
|
// digestOf names a declaration by its bytes, exactly as the mesh names what it sends. The two
|
||||||
|
// sides never exchange the digest of different things: this hashes the same raw bytes the mesh
|
||||||
|
// hashed when it recorded the send.
|
||||||
|
func digestOf(body []byte) string {
|
||||||
|
sum := sha256.Sum256(body)
|
||||||
|
return hex.EncodeToString(sum[:])
|
||||||
|
}
|
||||||
|
|
||||||
func carriedPorts(state store.State) []int {
|
func carriedPorts(state store.State) []int {
|
||||||
seen := map[int]bool{}
|
seen := map[int]bool{}
|
||||||
var out []int
|
var out []int
|
||||||
|
|||||||
@@ -67,4 +67,14 @@ type Report struct {
|
|||||||
// A node *states* and the mesh writes, which is the whole shape of this message: this is the
|
// A node *states* and the mesh writes, which is the whole shape of this message: this is the
|
||||||
// machine saying what is true of it, not asking for anything.
|
// machine saying what is true of it, not asking for anything.
|
||||||
Carried []int `json:"carried,omitempty"`
|
Carried []int `json:"carried,omitempty"`
|
||||||
|
|
||||||
|
// Declared is the digest of the declaration this report is about — sha256 of the exact bytes
|
||||||
|
// the mesh sent, which the mesh recorded when it sent them.
|
||||||
|
//
|
||||||
|
// **Which declaration, not when.** The mesh compared its send time to this report's arrival
|
||||||
|
// to decide whether a machine had caught up, and lost the race it invited: an apply started
|
||||||
|
// under the previous declaration finishes after the next one is sent, its report lands newer
|
||||||
|
// than the send, and the machine reads as caught up with words it has not read yet. Clocks
|
||||||
|
// cannot answer "which"; the digest is the answer itself.
|
||||||
|
Declared string `json:"declared,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user