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

serde: Require (serde_fields) XOR (explicit read and/or write) #23239

Merged
merged 3 commits into from
Sep 13, 2024

Conversation

oleiman
Copy link
Member

@oleiman oleiman commented Sep 9, 2024

If a serde envelope implements either serde_read or serde_write, that envelope may not implement serde_fields.

PR also updates a couple of existing structs to account for this requirement.

Backports Required

  • none - not a bug fix
  • none - this is a backport
  • none - issue does not exist in previous branches
  • none - papercut/not impactful enough to backport
  • v24.2.x
  • v24.1.x
  • v23.3.x

Release Notes

  • none

@oleiman oleiman self-assigned this Sep 9, 2024
@oleiman oleiman marked this pull request as ready for review September 9, 2024 06:37
@oleiman oleiman requested a review from dotnwat September 9, 2024 14:20
Copy link
Member

@dotnwat dotnwat left a comment

Choose a reason for hiding this comment

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

yeh pretty much lgtm just a question or two

src/v/cluster/topic_configuration.cc Outdated Show resolved Hide resolved
Comment on lines 203 to 204
offset_options = read_nested<decltype(offset_options)>(
in, h._bytes_left_limit);
Copy link
Member

Choose a reason for hiding this comment

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

cc @rockwotj i think i'm still a bit confused about how exactly std::variant serde works, but on the surface this looks like a correct transformation from serde_fields to serde_read.

Copy link
Member Author

Choose a reason for hiding this comment

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

tangential, but I wonder whether we need the bytes_left checks in here...

I was using topic_configuration::serde_read as an example, but column_store::serde_read is much more involved.

Copy link
Member

Choose a reason for hiding this comment

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

i don't think you need this part

   if (in.bytes_left() > h._bytes_left_limit) {
        in.skip(in.bytes_left() - h._bytes_left_limit);
    }

because it's done automatically in tag_invoke(read_tag) after serde_read is called. did you have a specific reason for adding it?

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

done automatically inn tag_invoke

Ah, I misread that as embedded in the !has_serde_read branch.

specific reason for adding it

Nope. Saw it written that way somewhere and it stuck for whatever reason.

environment = read_nested<decltype(environment)>(in, h._bytes_left_limit);
uuid = read_nested<decltype(uuid)>(in, h._bytes_left_limit);
source_ptr = read_nested<decltype(source_ptr)>(in, h._bytes_left_limit);
offset_options = read_nested<decltype(offset_options)>(
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't we need a version check here? Only read this if version > 0, same for the version 2 fields only.

Or do these noop if there are no bytes left?

Copy link
Contributor

@felixguendling felixguendling Sep 10, 2024

Choose a reason for hiding this comment

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

If called, read functions expect that there are bytes left to read. E.g. here:

if (unlikely(in.bytes_left() - bytes_left_limit < sizeof(Type))) {
throw serde_exception(fmt_with_ctx(
ssx::sformat,
"reading type {} of size {}: {} bytes left",
type_str<Type>(),
sizeof(Type),
in.bytes_left()));
}

That's why the default version for reading an envelope is okay if the bytes_left were depleted and skips reading the following fields (compat_version vs serialized version comparison made sure this is okay):

envelope_for_each_field(t, [&](auto& f) {
using FieldType = std::decay_t<decltype(f)>;
if (h._bytes_left_limit == in.bytes_left()) {
return false;
}

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, I completely misread this comment. Thanks @rockwotj

@dotnwat
Copy link
Member

dotnwat commented Sep 12, 2024

no rush on this, just wondering if i should be waiting on any more pushes?

@oleiman
Copy link
Member Author

oleiman commented Sep 12, 2024

force push little cleanup

@dotnwat - I think the conclusion from these threads is that functionally we're good to go

dotnwat
dotnwat previously approved these changes Sep 12, 2024
@rockwotj
Copy link
Contributor

No, transform options will fail to read old versions now, we need to fix that

Copy link
Contributor

@rockwotj rockwotj left a comment

Choose a reason for hiding this comment

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

Github is horrible at showing threads, but we need to resolve this: #23239 (comment)

See Felix's comment, old versions dont have all the fields so we need to explicitly check for the version before trying to read more fields

@dotnwat
Copy link
Member

dotnwat commented Sep 12, 2024

Github is horrible at showing threads, but we need to resolve this: #23239 (comment)

See Felix's comment, old versions dont have all the fields so we need to explicitly check for the version before trying to read more fields

Thanks for seeing the issue and blocking @rockwotj.

I'm a little bit unclear about what the concern is. My understanding is that @oleiman is replacing serde_fields for the read path, which as I understand it, wasn't doing any verison checks (because it was using the serde_fields interface). so in the replaced, explicit version of reads, those checks also aren't there.

i think either i'm misunderstanding how serde_fields is operating internally, how the replacement read calls work, or there was a bug in the original version?

@rockwotj
Copy link
Contributor

wasn't doing any verison checks (because it was using the serde_fields interface). so in the replaced, explicit version of reads

serde_fields internally stops when there are no more bytes left, meaning you can not populate some fields (due to reading an old version that didn't write them).

We need that stopping early behavior either by checking if there are more bytes when reading fields for v1 or v2, or by explicitly doing version checks.

@oleiman

This comment was marked as off-topic.

@oleiman

This comment was marked as off-topic.

@oleiman
Copy link
Member Author

oleiman commented Sep 12, 2024

Ah, forget all that. @rockwotj - You're talking about the versioning on transform_metadata, not the variant struct. Yeah, sorry for the confusion.

More precisely, if a serde envelope implements either serde_read
or serde_write, that envelope may not implement serde_fields.
@oleiman
Copy link
Member Author

oleiman commented Sep 12, 2024

force push version checks for model::transform_metadata

@oleiman
Copy link
Member Author

oleiman commented Sep 12, 2024

@vbotbuildovich
Copy link
Collaborator

new failures in https://buildkite.com/redpanda/redpanda/builds/54427#0191e7d4-c1fe-4d66-8085-2ea2ad4ee7ad:

"rptest.tests.nodes_decommissioning_test.NodesDecommissioningTest.test_recycle_all_nodes.auto_assign_node_id=False"

@vbotbuildovich
Copy link
Collaborator

vbotbuildovich commented Sep 12, 2024

@oleiman oleiman merged commit 755310b into redpanda-data:dev Sep 13, 2024
17 checks passed
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants