anthropics / anthropics/buffa

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

未關閉
#429 0 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視
主要語言
Rust
星號
883
分支
88
平均合併
3 天 19 小時
30 天內合併 PR
42

描述

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

貢獻指南

開啟貢獻指南

評估

這個 Issue 還沒有評估資料。

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。