The runtime answers a bulk read of kept state: the values after a key in one request (issue 1966)

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
2026-11-09 08:51:19 +01:00
parent 27710ccabd
commit 1a9190774d
4 changed files with 86 additions and 3 deletions
+37
View File
@@ -139,6 +139,43 @@ func (c *Conn) StateGet(module, name, key string) (*StateEntry, error) {
return &StateEntry{Key: e.Key(), Value: valueOf(e.Value()), Revision: e.Revision(), At: e.Created().UTC()}, nil
}
// StatePage is the current values after a key, in key order, and the key to ask after for the rest.
type StatePage struct {
Entries []StateEntry `json:"entries"`
Next string `json:"next,omitempty"`
}
// StatePage reads the values in key order after `after` in one pass, as many as fit maxBytes (each key and value) and
// at least one, so a bundle asks one request for many values, where StateGet is one request each. It is a read like
// StateGet: served to the owner and to every reader, and writes nothing. Next is the last key given when more follow.
func (c *Conn) StatePage(module, name, after string, maxBytes int) (StatePage, error) {
keys, err := c.StateKeys(module, name)
if err != nil {
return StatePage{}, err
}
page := StatePage{Entries: []StateEntry{}}
size := 0
for _, k := range keys {
if after != "" && k <= after {
continue
}
e, err := c.StateGet(module, name, k)
if err != nil {
return StatePage{}, err
}
if e == nil {
continue
}
if size > 0 && size+len(k)+len(e.Value) > maxBytes {
page.Next = page.Entries[len(page.Entries)-1].Key
break
}
page.Entries = append(page.Entries, *e)
size += len(k) + len(e.Value)
}
return page, nil
}
// StateKept is one value a bucket still keeps for a key: a put, or a delete (a purge reads as one).
type StateKept struct {
Key string `json:"key"`