G findings: artifact-store-tools and mesh-config read what their held writer holds, so a restart neither drops nor rewrites their findings
Their in-memory open sets go. Builds: design 47 G A-32, A-29, A-38
This commit is contained in:
@@ -93,12 +93,10 @@ type Holder struct {
|
||||
Now func() time.Time
|
||||
Logf func(string, ...any)
|
||||
|
||||
sweep sync.Mutex // one sweep at a time
|
||||
mu sync.Mutex
|
||||
fmu sync.Mutex // the findings said and the sweep's refusal
|
||||
said map[string]meshconditions.Finding // S25's findings as last written, by key
|
||||
refused *meshconditions.Finding // the sweep's finding while a seat's refusal stands
|
||||
ended map[string]time.Time // a done key's end, read once from its history
|
||||
sweep sync.Mutex // one sweep at a time
|
||||
mu sync.Mutex
|
||||
fmu sync.Mutex // one pass of Observe at a time
|
||||
ended map[string]time.Time // a done key's end, read once from its history
|
||||
}
|
||||
|
||||
// Build is one done build of a module, as its key holds it, with when it ended.
|
||||
@@ -856,7 +854,8 @@ func inStoreAt(image, address string) string {
|
||||
}
|
||||
|
||||
// Observe says S25's findings (image-missing): each want whose build names an image the store does not hold, on the
|
||||
// want's machine, written once and cleared once it no longer holds. Nothing is said without a listing.
|
||||
// want's machine, written once and cleared once it no longer holds. Nothing is said without a listing. What stands is what
|
||||
// the held writer holds (design 47 G A-32, A-38), so a restart neither drops nor rewrites it.
|
||||
func (h *Holder) Observe(ctx context.Context) error {
|
||||
now, err := h.observed(ctx)
|
||||
if err != nil {
|
||||
@@ -867,52 +866,36 @@ func (h *Holder) Observe(ctx context.Context) error {
|
||||
}
|
||||
h.fmu.Lock()
|
||||
defer h.fmu.Unlock()
|
||||
if h.said == nil {
|
||||
h.said = map[string]meshconditions.Finding{}
|
||||
said := map[string]meshconditions.Finding{}
|
||||
for _, f := range h.Findings.Held() {
|
||||
if f.Kind == ImageMissing {
|
||||
said[views.FindingKey(f.Scope, f.ID, f.Kind)] = f
|
||||
}
|
||||
}
|
||||
for k, was := range h.said {
|
||||
for k, was := range said {
|
||||
if _, still := now[k]; !still {
|
||||
if err := h.Findings.Clear(ctx, was.Scope, was.ID, was.Kind, "the store holds the image again"); err != nil {
|
||||
return err
|
||||
}
|
||||
delete(h.said, k)
|
||||
}
|
||||
}
|
||||
for k, f := range now {
|
||||
if was, ok := h.said[k]; ok && was.Summary == f.Summary {
|
||||
if was, ok := said[k]; ok && was.Summary == f.Summary {
|
||||
continue // written only when what it says changes
|
||||
}
|
||||
if err := h.Findings.Write(ctx, f); err != nil {
|
||||
return err
|
||||
}
|
||||
h.said[k] = f
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Findings is the module's finding writer (views.Writer): the holder writes and clears through it (design 47 G §689).
|
||||
// Findings is the module's held finding writer (views.HeldWriter): the holder writes and clears through it and reads what it
|
||||
// holds (design 47 G §689, A-29, A-38).
|
||||
type Findings interface {
|
||||
Write(ctx context.Context, finding meshconditions.Finding) error
|
||||
Clear(ctx context.Context, scope, id, kind, why string) error
|
||||
}
|
||||
|
||||
// FindingsObserved answers the findings this module observes now, for its writer's statement (views.WriterConfig.Observe):
|
||||
// S25's findings and the sweep's, when a seat refused it and no clean sweep cleared it.
|
||||
func (h *Holder) FindingsObserved(ctx context.Context) (views.Observed[meshconditions.Finding], error) {
|
||||
now, err := h.observed(ctx)
|
||||
if err != nil {
|
||||
return views.Observed[meshconditions.Finding]{}, err
|
||||
}
|
||||
var out views.Observed[meshconditions.Finding]
|
||||
for _, f := range now {
|
||||
out.Findings = append(out.Findings, f)
|
||||
}
|
||||
h.fmu.Lock()
|
||||
defer h.fmu.Unlock()
|
||||
if h.refused != nil {
|
||||
out.Findings = append(out.Findings, *h.refused)
|
||||
}
|
||||
return out, nil
|
||||
Held() []meshconditions.Finding
|
||||
}
|
||||
|
||||
// observed is S25's findings now by key, nil without a listing.
|
||||
|
||||
@@ -418,6 +418,8 @@ func TestAWantedImageTheStoreLacksIsAFindingAndImagesNamesWantsAndHaves(t *testi
|
||||
t.Fatalf("the finding is %+v (%v, %v)", f, found, err)
|
||||
}
|
||||
view.L.Repos[repo].Revisions[digest] = true
|
||||
// A restart: a holder made afresh holds no finding of its own, and clears what the writer holds (design 47 G A-32, A-38).
|
||||
h = &Holder{Bus: h.Bus, Findings: h.Findings, Door: h.Door, Listed: h.Listed, Seats: h.Seats, Now: h.Now, Acts: h.Acts, Logf: h.Logf}
|
||||
if err := h.Observe(context.Background()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -459,6 +461,24 @@ func (f findingsThrough) Write(_ context.Context, finding meshconditions.Finding
|
||||
return f.bus.Put(FindingsState, views.FindingKey(finding.Scope, finding.ID, finding.Kind), finding)
|
||||
}
|
||||
|
||||
// Held is what the writer holds: the findings in the module's state.
|
||||
func (f findingsThrough) Held() []meshconditions.Finding {
|
||||
var out []meshconditions.Finding
|
||||
keys, _ := f.bus.(interface {
|
||||
Keys(string) ([]string, error)
|
||||
}).Keys(FindingsState)
|
||||
for _, k := range keys {
|
||||
raw, ok, _ := f.bus.(interface {
|
||||
Get(string, string) ([]byte, bool, error)
|
||||
}).Get(FindingsState, k)
|
||||
var m meshconditions.Finding
|
||||
if ok && json.Unmarshal(raw, &m) == nil {
|
||||
out = append(out, m)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (f findingsThrough) Clear(_ context.Context, scope, id, kind, _ string) error {
|
||||
return f.bus.Delete(FindingsState, views.FindingKey(scope, id, kind))
|
||||
}
|
||||
|
||||
@@ -30,9 +30,9 @@ func main() {
|
||||
h := &Holder{Bus: runtimeBus{views: v}, Door: DoorAt(os.Getenv("MESH_ARTIFACT_STORE_ADDRESS_FILE"), s), Listed: s.View,
|
||||
Seats: stdio.Ask, Now: time.Now, Logf: logf}
|
||||
h.Acts = meshhandactsclient.Recorder{Ask: stdio.Ask}
|
||||
// The module's one writer (design 47 G §689, A-16): the holder's findings and the reader's go through it.
|
||||
w, err := views.NewStdioWriter(views.WriterConfig[meshconditions.Finding, meshconditions.FindingCleared, meshconditions.FindingsStated, meshconditions.FindingsAskedEvent]{
|
||||
Asked: meshconditions.SubjectFindingsAsked, Module: Module, State: stdio.State("findings"), Kinds: []string{ImageMissing, SweepRefused}, Observe: h.FindingsObserved})
|
||||
// The module's one held writer (design 47 G §689, A-16, A-29, A-32): the holder's findings and the reader's go through it.
|
||||
w, err := views.NewStdioHeldWriter(views.WriterConfig[meshconditions.Finding, meshconditions.FindingCleared, meshconditions.FindingsStated, meshconditions.FindingsAskedEvent]{
|
||||
Asked: meshconditions.SubjectFindingsAsked, Module: Module, State: stdio.State("findings"), Kinds: []string{ImageMissing, SweepRefused}})
|
||||
if err != nil {
|
||||
logf("%v", err)
|
||||
os.Exit(1)
|
||||
|
||||
@@ -123,25 +123,20 @@ func (h *Holder) sweepFinding(what string, err error) {
|
||||
Needs: "read the seat holder's journal for the refusal; the next sweep asks again.",
|
||||
Evidence: []meshconditions.Evidence{{At: at.UTC(), Said: fmt.Sprintf("%s: %v", what, err)}},
|
||||
Source: "CAT-AS1", Observer: Module, At: at}
|
||||
h.fmu.Lock()
|
||||
h.refused = &f
|
||||
h.fmu.Unlock()
|
||||
if werr := h.Findings.Write(context.Background(), f); werr != nil {
|
||||
h.logf("the sweep's finding (%s: %v) could not be written: %v", what, err, werr)
|
||||
}
|
||||
}
|
||||
|
||||
// sweepClean clears the sweep's finding after a sweep no seat refused.
|
||||
// sweepClean clears the sweep's finding, when the held writer holds it, after a sweep no seat refused.
|
||||
func (h *Holder) sweepClean() {
|
||||
h.fmu.Lock()
|
||||
was := h.refused
|
||||
h.refused = nil
|
||||
h.fmu.Unlock()
|
||||
if was == nil {
|
||||
return
|
||||
}
|
||||
if err := h.Findings.Clear(context.Background(), was.Scope, was.ID, was.Kind, "a sweep ran through without a refusal"); err != nil {
|
||||
h.logf("the sweep's finding could not be cleared: %v", err)
|
||||
for _, was := range h.Findings.Held() {
|
||||
if was.Kind != SweepRefused {
|
||||
continue
|
||||
}
|
||||
if err := h.Findings.Clear(context.Background(), was.Scope, was.ID, was.Kind, "a sweep ran through without a refusal"); err != nil {
|
||||
h.logf("the sweep's finding could not be cleared: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user