ADR 0592 §5, §6, §9, §25 (the grants part's share by ADR 0593 §10): an object bucket and a stream that keeps its history are created create-only with their caps and no age limit, refusing new data when full; the owner alone writes its bucket and a module its grant names reads it; the part raises mesh-grants.history-full once any passes 75 percent. Each engine also reads the indexer's manifest verdicts by one key for compose-candidate. Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
96 lines
3.6 KiB
Go
96 lines
3.6 KiB
Go
package grants
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/asks"
|
|
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
)
|
|
|
|
// **A history stream or an object bucket past 75 percent of its cap is said, in one place for every module** (novox/hq
|
|
// ADR 0592 §6, §25; ADR 0593 §10 gives the controller's part to this part). Such a stream or bucket refuses a new message
|
|
// or object when full rather than dropping its oldest, so filling up is the one way it fails: the part reads every
|
|
// stream's size from the bus module's nats_streams at each pass (HeldStreams) and raises the warning FullCondition naming
|
|
// each one past catalogue.FullWarnPercent, cleared once none is.
|
|
|
|
// FullCondition is the key of the warning raised while a history stream or an object bucket is past its mark.
|
|
const FullCondition = "mesh-grants.history-full"
|
|
|
|
// Fill is how full one history stream or object bucket is: its module, its stream on the bus, its bytes and its cap.
|
|
type Fill struct {
|
|
Module string `json:"module"`
|
|
Stream string `json:"stream"`
|
|
Bytes int64 `json:"bytes"`
|
|
Cap int64 `json:"cap"`
|
|
}
|
|
|
|
// Percent is its bytes in percent of its cap, rounded down.
|
|
func (f Fill) Percent() int64 { return f.Bytes * 100 / f.Cap }
|
|
|
|
// Full is every history stream and object bucket of a placed module past catalogue.FullWarnPercent of its cap, by the
|
|
// sizes the bus holds (bytes, by stream name), in module and stream order. One the bus does not hold is not full. Pure.
|
|
func Full(in Inputs, bytes map[string]int64) []Fill {
|
|
var out []Fill
|
|
for _, module := range sortedKeys(in.Manifests) {
|
|
if !assigned(in, module) {
|
|
continue
|
|
}
|
|
m := in.Manifests[module]
|
|
var capped []Fill
|
|
for _, s := range m.Streams {
|
|
if s.KeepsHistory() {
|
|
capped = append(capped, Fill{Module: module, Stream: s.BusName(), Cap: int64(s.Cap()) << 20})
|
|
}
|
|
}
|
|
for _, o := range objectsOf(m) {
|
|
capped = append(capped, Fill{Module: module, Stream: "OBJ_" + o.Bucket(), Cap: int64(o.MaxMiB) << 20})
|
|
}
|
|
for _, f := range capped {
|
|
held, ok := bytes[f.Stream]
|
|
if !ok || f.Cap <= 0 {
|
|
continue
|
|
}
|
|
f.Bytes = held
|
|
if f.Bytes*100 >= catalogue.FullWarnPercent*f.Cap {
|
|
out = append(out, f)
|
|
}
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// sayFull raises FullCondition while a history stream or an object bucket is past its mark, and clears it once none is:
|
|
// said once per set of streams, again when that set changes, and at the first pass after a start.
|
|
func (p *Part) sayFull(full []Fill) {
|
|
if p.Say == nil {
|
|
return
|
|
}
|
|
var names, lines []string
|
|
for _, f := range full {
|
|
names = append(names, f.Stream)
|
|
lines = append(lines, fmt.Sprintf("%s of %s: %d of %d MiB (%d%%)", f.Stream, f.Module, f.Bytes>>20, f.Cap>>20, f.Percent()))
|
|
}
|
|
said := strings.Join(names, " ")
|
|
p.holdMu.Lock()
|
|
defer p.holdMu.Unlock()
|
|
if p.fullKnown && said == p.fullSaid {
|
|
return
|
|
}
|
|
c := asks.Condition{Key: FullCondition, Subject: asks.Scope{Scope: "module", ID: Module}}
|
|
if said == "" {
|
|
c.State = asks.StateCleared
|
|
} else {
|
|
c.Severity, c.State = asks.SeverityWarning, asks.StateRaised
|
|
c.Summary = fmt.Sprintf("%d history stream(s) or object bucket(s) past %d%% of their cap: %s", len(full),
|
|
catalogue.FullWarnPercent, strings.Join(lines, "; "))
|
|
c.Headline, c.Needs = "A stream that keeps its history is filling up", "a larger cap in the module's manifest, or data removed"
|
|
c.Explanation = asks.NeedsYou + "a decision before it is full: such a stream or bucket refuses new messages when full " +
|
|
"rather than dropping its oldest (novox/hq ADR 0592 §6). " + strings.Join(lines, "; ")
|
|
c.Resolved = "every history stream and object bucket is below its mark"
|
|
}
|
|
if p.Say(c) == nil {
|
|
p.fullSaid, p.fullKnown = said, true
|
|
}
|
|
}
|