anthropics / anthropics/buffa

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

Ouverte
#429 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub
Langage dominant
Rust
Étoiles
883
Forks
88
Merge moyen
3 j 19 h
PR mergées (30 j)
42

Description

`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.

Guide de contribution

Ouvrir le guide de contribution

Évaluation

Cette issue n'a pas encore été évaluée.

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.