Files
mesh-delivery/modules/mesh-delivery-indexer/internal/index/oldsections.go
T
jschoubben d662c63db5 DLV-J1, DLV-J2, DLV-J3: the foundation is the nine parts, and indexer_old_sections counts the reads left on the owners' state
The judge's foundation holds exactly the nine parts of ADR 0619 §1 and §3,
left out of the old sections' count, and refuses a foundation manifest
asking bus state in the new form. The indexer also counts, across the
accepted manifests, the reads entries still declared on the indexer's and
the assigner's state, by owner and by entry; indexer_old_sections answers
both, so design 25 § 12.7's live row (0 on each owner) has its tool.

Issue 1966.

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
2026-11-04 12:22:26 +01:00

80 lines
3.1 KiB
Go

package index
import (
"context"
"encoding/json"
"fmt"
"maps"
"git.novox.be/novox/mesh-sdk/go/delivery"
"mesh-delivery-indexer/judge"
)
// How many accepted modules use each old section (issue 1966 D4; novox/hq ADR 0595 §11): the indexer counts them, the
// foundation left out, as it judges, keeps the count in its state oldsections under one key, and the tool
// indexer_old_sections reads it. The judge refuses a manifest of another module that uses a section whose count is 0.
const (
// OldSectionsTool is the tool that reads the count.
OldSectionsTool = "indexer_old_sections"
// OldSectionsState is the indexer's state of the count: the bucket mesh-delivery-indexer_oldsections.
OldSectionsState = "oldsections"
OldSectionsBucket = delivery.IndexerModule + "_" + OldSectionsState
// OldSectionsKey is the one key it holds.
OldSectionsKey = "counts"
)
// OldSectionsCount is the value of the oldsections state: per old section, the accepted modules outside the foundation using it.
type OldSectionsCount struct {
V int `json:"v"`
Counts map[string]int `json:"counts"`
// Reads are the `reads` entries left on the indexer's and the assigner's state, by owner and by entry, across the
// accepted manifests (judge.CountOwnerReads; ADR 0615 §1): 0 for each owner once every reader moved.
Reads map[string]int `json:"reads,omitempty"`
}
// DecodeOldSections reads the oldsections value.
func DecodeOldSections(value []byte) (OldSectionsCount, error) {
var c OldSectionsCount
if err := json.Unmarshal(value, &c); err != nil {
return c, fmt.Errorf("the count of the old sections cannot be read: %w", err)
}
if c.V != 1 {
return c, fmt.Errorf("a count of the old sections of version %d, not 1", c.V)
}
return c, nil
}
// heldOldSections is the count the last pass wrote (the accepted set it held): a module that keeps using a section was
// accepted with it, so it is counted, and a fresh manifest changes nothing in it. Nil when none is held yet or it cannot be
// read; a failed read is said, never taken as 0 (issue 1966 D4).
func (ix *Indexer) heldOldSections(ctx context.Context) judge.OldSectionCounts {
value, _, found, err := ix.OldSections.Get(ctx, OldSectionsKey)
if err == nil && found {
var c OldSectionsCount
if c, err = DecodeOldSections(value); err == nil {
return c.Counts
}
}
if err != nil {
ix.logf("judge: the count of the old sections cannot be read (%v), so the zero rule is not applied in this pass", err)
}
return nil
}
// keepOldSections writes the counts under OldSectionsKey when they differ from the ones held.
func (ix *Indexer) keepOldSections(ctx context.Context, counts judge.OldSectionCounts, reads map[string]int) error {
if ix.OldSections == nil {
return nil
}
return write(ctx, ix.OldSections, OldSectionsKey, func(value []byte, found bool) ([]byte, bool, error) {
if found {
if cur, err := DecodeOldSections(value); err == nil && maps.Equal(cur.Counts, counts) && maps.Equal(cur.Reads, reads) {
return nil, false, nil
}
}
next, err := json.Marshal(OldSectionsCount{V: 1, Counts: counts, Reads: reads})
return next, false, err
})
}