Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Arc, Box wrapper of message fields. #705

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

ldm0
Copy link
Contributor

@ldm0 ldm0 commented Aug 13, 2022

Closes #429
Marked as draft since tests haven't been added.(Go to bed now :-P)

@ldm0 ldm0 changed the title Implement Arc, Rc, Box wrapper of message fields. Implement Arc, Box wrapper of message fields. Oct 17, 2022
@ldm0 ldm0 force-pushed the ldm_arc branch 4 times, most recently from 255b101 to 154c338 Compare October 18, 2022 06:27
@ldm0
Copy link
Contributor Author

ldm0 commented Oct 18, 2022

Mostly done, add more tests later.

@LucioFranco
Copy link
Member

Nice! Just want to let you know I see this but I have a bunch of high priority things on my plate atm so may take me a bit to get to a review of this.

@80ROkWOC4j
Copy link

How is this working out? It's sad that I have to call many Vec::clone() to send a message with repeated fields to thousands of clients 😥. I'm hoping this PR will solve my problem.

@PSeitz
Copy link

PSeitz commented Apr 18, 2024

I just want to second this. Having Arc would be sweet, as memory consumption on some structs is reaching relative high levels in quickwit

@Remediem
Copy link

Any updates on this?

@caspermeijn
Copy link
Collaborator

Any updates on this?

Yes, this PR needs a reviewer and someone to bring it to the finish line. @Remediem Are you willing to do some of that work?

@caspermeijn
Copy link
Collaborator

@juanAngel When I said, “this PR needs a reviewer”, I didn't mean someone who hits the Approve button. I meant someone who provides useful comments about the large code changes.

Maybe you are willing to split this PR is multiple smaller PRs that are easier to review?

@ldm0
Copy link
Contributor Author

ldm0 commented Sep 11, 2024

This PR is ready for review at 2022. The Box wrapper introduced in #1019 conflicts with this PR.

I can't split it into smaller PRs as it's quite self-contained, and most of the new code is from the tests.

@caspermeijn @LucioFranco Could you review the test code in this PR and let me know if it's acceptable? If you are still interested in the Arc wrapper for message fields, I can rebase this onto the master branch.

@juanAngel
Copy link

@caspermeijn

Don't think I didn't read the code before hitting the button
I can think of improvements to the code itself, but they are more optimizations than anything else. Like for example box and arc don't make much sense for most primitive types like u32

And I was implementing those improvements on my own.

As for the rest I don't know what kind of comments are needed if the code/tests seem to be correct

@caspermeijn
Copy link
Collaborator

Don't think I didn't read the code before hitting the button I can think of improvements to the code itself, but they are more optimizations than anything else. Like for example box and arc don't make much sense for most primitive types like u32

@juanAngel I'm sorry I reacted that way. There have been some low effort comments lately and I confused your approval with that. Thank you for explaining what you have reviewed, and thank you for the review.

Copy link
Collaborator

@caspermeijn caspermeijn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arc is a much requested feature. Thank you for implementing it.

I like the concept of a wrapper type. I like that it is mutual exclusive, as that reduces the possible combinations. I like that it only contains allocating wrappers.

The diff will be smaller after merging this code path with the existing boxed code.

Please add user-facing documentation.

@@ -421,6 +444,35 @@ impl Config {
self
}

fn field_wrapper<I, S>(&mut self, paths: I, wrapper: Wrapper)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking out loud: Is it beneficial to make field_wrapper public instead of arc and box? That way, it is clear that they are mutual exclusive.

let field_wrapper = self
.config
.field_wrappers
.get_first_field(fq_message_name, oneof.name())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to error out if there are conflicting field wrappers defined for a single field?

let boxed = !repeated
&& field_wrapper != Some(Wrapper::Box)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The message graph boxed detection is for solving recursive types. If a recursive type is detected, then it is automatically placed in a Box to make sure the struct size is known at compile time. Arc will have the same function.

I don't think message graph will take the explicit boxed into account. Maybe it should with more field wrappers?

pub(crate) struct PathMap<T> {
// insertion order might actually matter (to avoid warning about legacy-derive-helpers)
// see: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#legacy-derive-helpers
pub(crate) matchers: Vec<(String, T)>,
}

// Remove this after <https://github.com/rust-lang/rust/issues/26925> is fixed.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting that this trigger without changing the struct. I would like to see a comment to explain why this is needed (without reading the GitHub issue).

@@ -25,6 +29,8 @@ impl Field {
set_bool(&mut group, "duplicate group attributes")?;
} else if word_attr("boxed", attr) {
set_bool(&mut boxed, "duplicate boxed attributes")?;
} else if let Some(w) = wrapper_attr(attr) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the boxed code path should be merged into the wrapper code path.

match wrapper {
Some(Wrapper::Arc) => {
quote!(::prost::alloc::sync::Arc::get_mut(&mut self.#ident).ok_or_else(|| {
::prost::DecodeError::new("Cannot get mutable reference to a Arc field")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When can this happen? During decoding, there will never be another Arc to the same allocation, right? Is make_mut useful here?

pub(super) fn tag_attr(attr: &Meta) -> Result<Option<u32>, Error> {
// TODO pub(crate)?
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Wrapper {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the Wrapper type and helper functions be in a separate module to reduce file size?

/// Get reference of a field.
fn field_ref(wrapper: &Option<Wrapper>, ident: TokenStream) -> TokenStream {
if wrapper.is_some() {
quote!(&*#ident)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like the * could make a copy of the contents. Maybe as_ref() can help here. Would it be possible to replace field_ref by as_ref?

Comment on lines +367 to +372
let pushed = wrapper.wrap_type(quote!(pushed));
quote! {
let mut pushed = (*#field).clone();
pushed.push(value as i32);
self.#ident = #pushed;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why this is needed?

@@ -0,0 +1,10 @@
[package]
name = "field-wrappers"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like the tests to be part of crate tests as that crate is run for every edition and with no-std.

}

self.buf.push_str("::core::option::Option<");
self.buf.push_str(&name);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be better if arc was inside the option?

Normally you will try to clone the content of the option, not the whole option. And cloning a some or none I don't think will be a big cost.

self.buf.push_str("=\"");
self.buf.push_str(&key_tag);
self.buf.push_str(", ");
self.buf.push_str(&value_tag);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here it might be interesting to add an extra arc/box just for the value
That way you can share the individual elements

For the key, from my point of view it is less necessary since they are usually easily copied elements and are mostly only used for searches or insertions

.config
.field_wrappers
.get_first_field(fq_message_name, field.name())
.copied();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion it is interesting to add a filter here.
Since you will never want an enum wrapped in arc, or an integer
Since they are much cheaper to clone than arc itself, in addition to implementing automatic copying

@nothing2sayi
Copy link

Is there any progress on this issue? When is it expected to be merged? thanks.

@ldm0
Copy link
Contributor Author

ldm0 commented Oct 17, 2024

Is there any progress on this issue? When is it expected to be merged? thanks.

@nothing2sayi Yeah, I am working on this. I have successfully rebased this MR locally. But there are several bugs in the current implementation of boxed(in the master branch), which need to be solved before this MR could be merged. It may take several weeks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support for std::sync::Arc as indirection
8 participants