anthropics / anthropics/buffa

`MessageFieldView` boxes every present nested message on decode, while owned `MessageField` defaults to inline storage

Offen
#429 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
Vorherrschende Sprache
Rust
Sterne
883
Forks
88
Ø Merge
3 T. 19 Std.
Gemergte PRs (30 T.)
42

Beschreibung

`MessageFieldView` stores a set field as `Option>`, so decoding a view of a message allocates once for every nested message field that is present, however small the nested view is. The owned side made the opposite default: `MessageField` is `Inline` with recursive fields boxed automatically and `box_type_in` as the opt-out, and the `ProtoBox` docs note in passing that "view types are unaffected". So the zero-copy decode path, which is the one chosen for allocation-sensitive servers, pays a per-nested-message allocation that the owned path was redesigned to avoid.

Measured in connect-rust's small-unary gRPC benchmark (`benches/rpc`, `BenchService/Unary` with the ~300-byte `small_request()` payload: a `BenchRequest` holding a `Payload` with 15 scalar/string fields, a nested `Metadata`, two small maps, a packed `repeated int32` and a `repeated string`), with a counting global allocator on the server: the request's `decode_view` makes 7 heap allocations, and 2 of them are `MessageFieldView::set` boxing the `PayloadView` (200 B) and the `MetadataView` (72 B). The other 5 are `Vec` growth in `MapView::push` (128 B then 256 B for a 4-entry `map`, 128 B for a 2-entry one), `RepeatedView<&str>::push` (64 B) and `extend_packed_int32` (20 B). For scale, the whole connect-rust request path around that decode (HTTP/2 framing, routing, response encoding) is about 20 allocations after connectrpc/connect-rust#296, so the view decode is a third of the framework-side total for this message shape.

The box exists to break the size recursion for self-referential messages, which is the same problem `MessageField` solves with a per-field storage parameter chosen by codegen (`Inline` by default, boxed where the codegen's cycle detection or a user option asks for it). Carrying that policy over, `MessageFieldView>` with codegen emitting the boxed storage on exactly the fields where it already boxes the owned type, would make the common case allocation-free without changing what recursive schemas generate. The `DefaultViewInstance` / `Deref` behaviour is independent of where the value is stored.

The `Vec`-backed `MapView` / `RepeatedView` growth is a separate and smaller question (a first-push capacity larger than 1, or a small inline buffer, would remove most of it for short maps and lists); mentioning it here only because it is the rest of the same measurement.

Beitragsleitfaden

Beitragsleitfaden öffnen

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.