diff --git a/modules/mesh-grants/grants_test.go b/modules/mesh-grants/grants_test.go index ef3fad7c..74f7bacb 100644 --- a/modules/mesh-grants/grants_test.go +++ b/modules/mesh-grants/grants_test.go @@ -3165,8 +3165,11 @@ func TestGrants(t *testing.T) { want: map[string]string{}, status: [3]int{0, 0, 1}, said: map[string]string{}}, // §9 (1966/AC203-3..): an answer no entry of which carries a binding. {name: "§9 a key-value entry the bus holds is composed from the answer's fields, and said once per answer", answer: []any{oldBusModule}, - want: map[string]string{"late": "mod-x_late"}, status: [3]int{1, 0, 1}, composed: 1, noted: 2, again: []any{oldBusModule}, + want: map[string]string{"late": "mod-x_late"}, status: [3]int{1, 0, 1}, composed: 0, noted: 2, again: []any{oldBusModule}, wantAgn: map[string]string{"late": "mod-x_late"}}, + {name: "§9 an entry an event named since the ask is not written, so it is not counted composed", answer: []any{oldBusModule}, + during: func(st *setup) { hear(st, "created", "late", "mod-x_event") }, want: map[string]string{"late": "mod-x_event"}, + status: [3]int{0, 0, 1}, noted: 1}, {name: "§9 an object-store entry is composed with its object store", answer: []any{noBinding("media", "object-store", "OBJ_", true)}, want: map[string]string{"media": "mod-x_media"}, status: [3]int{1, 0, 1}, composed: 1, noted: 1}, {name: "§9 a stream and a ledger are left unbound and logged", answer: []any{noBinding("s", "stream", "", true), noBinding("l", "ledger", "", true)}, diff --git a/modules/mesh-grants/internal/grants/bindingsview.go b/modules/mesh-grants/internal/grants/bindingsview.go index e75eacf0..7b26c4aa 100644 --- a/modules/mesh-grants/internal/grants/bindingsview.go +++ b/modules/mesh-grants/internal/grants/bindingsview.go @@ -43,7 +43,7 @@ type BindingsStatus struct { Listed int `json:"listed"` Written int `json:"written"` Rewritten int `json:"rewritten"` - // Composed is how many entries of the last answer had their binding composed from the answer's own fields, and Unbound + // Composed is how many of the bindings the last answer wrote or rewrote were composed from its own fields, and Unbound // the entries it left unbound, `/ ()`: both only for an answer no entry of which // carries `binding` (§9). Composed int `json:"composed"` @@ -329,7 +329,7 @@ func (v *BindingsView) apply(p *Part, raw json.RawMessage) error { } entries, composed, unbound := v.compose(answer.Entries) p.bindMu.Lock() - written, rewritten, err := v.take(p, entries, composed) + written, rewritten, fromFields, err := v.take(p, entries, composed) p.bindMu.Unlock() if err != nil { return err @@ -340,7 +340,7 @@ func (v *BindingsView) apply(p *Part, raw json.RawMessage) error { v.st.Answered = v.now() v.st.Listed = len(answer.Entries) v.st.Written, v.st.Rewritten = written, rewritten - v.st.Composed, v.st.Unbound = len(composed), unbound + v.st.Composed, v.st.Unbound = fromFields, unbound status := v.statusLocked() v.mu.Unlock() if wasRaised { @@ -401,7 +401,7 @@ func composeBinding(e meshbroker.Held) (*meshbroker.Binding, bool) { // take writes the bindings of the entries an event did not name since the ask was sent, keeps every binding the answer does // not list and raises its unlisted condition, and answers how many bindings it wrote and rewrote; composed names the // entries whose binding compose gave them. The caller holds the part's bindMu. -func (v *BindingsView) take(p *Part, entries []meshbroker.Held, composed map[string]bool) (written, rewritten int, err error) { +func (v *BindingsView) take(p *Part, entries []meshbroker.Held, composed map[string]bool) (written, rewritten, fromFields int, err error) { v.mu.Lock() touched := copyOf(v.touched) v.mu.Unlock() @@ -425,7 +425,7 @@ func (v *BindingsView) take(p *Part, entries []meshbroker.Held, composed map[str } b, berr := p.bound(module) if berr != nil { - return written, rewritten, berr + return written, rewritten, fromFields, berr } changed := false for _, e := range byModule[module] { @@ -447,6 +447,9 @@ func (v *BindingsView) take(p *Part, entries []meshbroker.Held, composed map[str } b.Bindings[e.LocalName] = bind changed = true + if composed[localKey(module, e.LocalName)] { + fromFields++ + } if had { rewritten++ v.logf("the binding of %s %s was rewritten, the cause %s", module, e.LocalName, cause) @@ -458,11 +461,11 @@ func (v *BindingsView) take(p *Part, entries []meshbroker.Held, composed map[str if changed { raw, _ := json.Marshal(b) if _, perr := p.Store.Put(StateMemberships, BoundKey(module), raw); perr != nil { - return written, rewritten, fmt.Errorf("its own %s %s cannot be written: %w", StateMemberships, BoundKey(module), perr) + return written, rewritten, fromFields, fmt.Errorf("its own %s %s cannot be written: %w", StateMemberships, BoundKey(module), perr) } } } - return written, rewritten, v.unlisted(p, listed, touched) + return written, rewritten, fromFields, v.unlisted(p, listed, touched) } // unlisted keeps every binding the answer does not list and raises its condition, one per binding; a binding it lists again diff --git a/sdk/parts/receive.go b/sdk/parts/receive.go index 9fac2795..0eef245e 100644 --- a/sdk/parts/receive.go +++ b/sdk/parts/receive.go @@ -239,8 +239,8 @@ func (r *Receiver[M]) arm(id string) error { } // Take takes one chunk of a part from the transfer's opener: chunks of a part arrive in sequence from 0, the last -// marked, and a chunk 0 again starts the part afresh (its earlier chunks are dropped); the whole part must hash to its digest, else its chunks are dropped and the part is lacked again. Belongs, -// when given, refuses a transfer the caller's own shape says is not this call's (another seat's, say). When the last +// marked, and a chunk 0 again starts the part afresh (its earlier chunks are dropped); the whole part must hash to its +// digest, else its chunks are dropped and the part is lacked again. Belongs, when given, refuses a transfer the caller's own shape says is not this call's (another seat's, say). When the last // lacked part arrives the transfer ends: the caller's check, then its store. func (r *Receiver[M]) Take(id, opener, digest string, sequence int, last bool, data []byte, belongs func(Transfer[M]) error) (Received, error) { t, found, err := r.Transfers.Get(id)