F-catalog-B: distribution counts incoming against its binding's cap and drops an idle transfer by its expiring key
The holder counted against 20 GiB while the bus caps incoming at 8 GiB, so the bus refused writes before the holder said refused naming the cap, and the 80 % finding came too late (running review F2). The cap is read from incoming's binding (the object store's fill); IncomingCap, 8 GiB, is said only where none is read, and the manifest's row holds it equal to max-mib. An abandoned transfer was dropped only on the next publish, and the transfers state's own lifetime dropped its key while its parts stayed: transfers keeps for good, and each open transfer has a key in the new state idle with its own time to live, whose end drops it (re-armed for the rest when it took a part since). registry_incoming reports the bound cap. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
@@ -15,10 +15,12 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
reg "git.novox.be/novox/mesh-contracts/go/seats/containerimageregistry"
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
"git.novox.be/novox/mesh-sdk/go/busstate"
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
"git.novox.be/novox/mesh-sdk/go/parts"
|
||||
@@ -164,6 +166,53 @@ func learnInto(state casState, module, fp string, attempts int) (bool, error) {
|
||||
return false, fmt.Errorf("%s was written by another writer first %d times: %w", holder.PublishingKey, attempts, stdio.ErrChanged)
|
||||
}
|
||||
|
||||
// incomingCap reads incoming's cap from its binding (the bus's bound of the object store, design 51 *Publishing*), once
|
||||
// it answers one: the binding's cap does not change while the bundle runs.
|
||||
func incomingCap() func() (uint64, error) {
|
||||
var known atomic.Uint64
|
||||
return func() (uint64, error) {
|
||||
if c := known.Load(); c > 0 {
|
||||
return c, nil
|
||||
}
|
||||
f, err := busstate.ObjectsOf(holder.IncomingObjects).Fill()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("incoming's cap cannot be read from its binding: %w", err)
|
||||
}
|
||||
if f.MaxBytes == 0 {
|
||||
return 0, errors.New("incoming's binding carries no cap")
|
||||
}
|
||||
known.Store(f.MaxBytes)
|
||||
return f.MaxBytes, nil
|
||||
}
|
||||
}
|
||||
|
||||
// armIdle writes a transfer's idle key with its own time to live; one already there is the same bound, kept.
|
||||
func armIdle(id string, ttl time.Duration) error {
|
||||
if _, err := stdio.State(holder.IdleState).CreateTTL(id, map[string]any{"transfer": id}, ttl); err != nil && !errors.Is(err, stdio.ErrChanged) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// followIdle drops a transfer when its idle key ends (holder.Expired): the bus's marker is the event, no timer runs.
|
||||
func followIdle(h *holder.Holder) {
|
||||
<-stdio.Served()
|
||||
stdio.State(holder.IdleState).Follow("", func(ch stdio.StateChange) error {
|
||||
if ch.Op != stdio.OpExpire {
|
||||
return nil
|
||||
}
|
||||
dropped, err := h.Expired(ch.Key)
|
||||
if err != nil {
|
||||
logf("%v", err)
|
||||
return err
|
||||
}
|
||||
if dropped {
|
||||
logf("transfer %s had no part for %s: dropped with its parts", ch.Key, holder.TransferIdle)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// mirrors is the state mirrors: an ask is created once; one already kept is the same copy, taken on already.
|
||||
type mirrors struct{}
|
||||
|
||||
@@ -245,7 +294,6 @@ func tools(v *holder.Verbs, windows kept[holder.Window], callers func() (holder.
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, _ = v.DropIdle()
|
||||
a, err := v.Publish(seat, stdio.CallerOf(args), publishOf(in))
|
||||
if err == nil {
|
||||
learnPublishing(windows, stdio.CallerOf(args))
|
||||
@@ -397,7 +445,7 @@ func tools(v *holder.Verbs, windows kept[holder.Window], callers func() (holder.
|
||||
}
|
||||
all, err := v.Transfers.List()
|
||||
used, _ := v.Objects.Used()
|
||||
return map[string]any{"transfers": all, "used": used, "cap": holder.IncomingCap, "dropped_idle": idle}, err
|
||||
return map[string]any{"transfers": all, "used": used, "cap": v.CapNow(), "dropped_idle": idle}, err
|
||||
}},
|
||||
stdio.Tool{Name: "registry_holds", Description: "What is held, since when and for whom; with release, lets one go through the seat's release as the operator's session (a hand act).",
|
||||
Input: obj(map[string]any{"seat": s("the seat"), "release": s("the name to release"), "digest": s("its digest"), "why": s("why")}),
|
||||
@@ -451,9 +499,10 @@ func main() {
|
||||
base, _ := url.Parse("http://127.0.0.1:5001")
|
||||
store := &holder.OCI{Base: base, Upstream: &holder.Upstream{}}
|
||||
h := &holder.Holder{Objects: parts.BusObjects(holder.IncomingObjects), Builder: delivery.BuilderVersions{Ask: stdio.Ask}, Store: store, Say: say, Finding: finding,
|
||||
Transfers: parts.BusTransfers[holder.Opening](holder.TransfersState)}
|
||||
Transfers: parts.BusTransfers[holder.Opening](holder.TransfersState), Cap: incomingCap(), Idle: armIdle}
|
||||
v := &holder.Verbs{Holder: h, Catalog: store, Holds: kept[holder.Hold]{state: "holds", key: holder.Hold.Key}, Mirrors: mirrors{}}
|
||||
go followMirrors(v)
|
||||
go followIdle(h)
|
||||
windows := kept[holder.Window]{state: "windows", key: func(w holder.Window) string { return w.Name }}
|
||||
if err := stdio.Serve("", tools(v, windows, holder.ConfiguredCallers)); err != nil {
|
||||
logf("%v", err)
|
||||
|
||||
Reference in New Issue
Block a user