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/test: serde_fields for various structs #23123

Merged
merged 4 commits into from
Sep 5, 2024

Conversation

oleiman
Copy link
Member

@oleiman oleiman commented Aug 29, 2024

In #22782, we aim to require explicit serde_fields for serde structs that would otherwise use aggregate field order. This is one in a series of pull requests that add serde_fields to existing structs, to be followed by a PR to remove the aggregate order fallback from serde itself.

The primary acceptance criterion for this PR should be "field order unchanged". Any functional change is a bug.

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

Signed-off-by: Oren Leiman <oren.leiman@redpanda.com>
@oleiman oleiman self-assigned this Aug 29, 2024
@oleiman oleiman marked this pull request as ready for review August 29, 2024 00:34
@vbotbuildovich
Copy link
Collaborator

vbotbuildovich commented Aug 29, 2024

@vbotbuildovich
Copy link
Collaborator

new failures in https://buildkite.com/redpanda/redpanda/builds/53730#01919beb-e7d1-4580-978d-6fded9606fcb:

"rptest.tests.cluster_config_test.ClusterConfigTest.test_valid_settings"

src/v/serde/test/serde_test.cc Show resolved Hide resolved
@@ -657,6 +678,7 @@ struct new_cs
bool operator==(const new_cs&) const = default;

std::vector<test_msg1_new_manual> data_;
auto serde_fields() { return std::tie(data_); }
Copy link
Member

Choose a reason for hiding this comment

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

so this is the case where writes go to serde_fields, but reads go through read_nested?

Copy link
Member Author

Choose a reason for hiding this comment

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

yeah, there may be others in this file. i've seen it in actual live code as well, but an example hasn't sprung to mind.

Copy link
Member

Choose a reason for hiding this comment

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

cool. i think then a follow up to the final PR we might want to consider either serde_fields or writing both read/write methods explicitly. can discuss separately this tho.

Copy link
Member Author

Choose a reason for hiding this comment

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

you mean like xor, right? as in disallow cases like this one?

Copy link
Member

Choose a reason for hiding this comment

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

yeh, xor. i guess we talked about that before. nm

Copy link
Member Author

Choose a reason for hiding this comment

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

all good. i agree - will need another round of updates & reviews, so no harm in punting to follow up.

@@ -693,6 +715,7 @@ struct old_cs
bool operator==(const old_cs&) const = default;

std::vector<test_msg1_new_manual> data_;
auto serde_fields() { return std::tie(data_); }
Copy link
Member

Choose a reason for hiding this comment

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

the template name old_cs and old_no_cs in CRTP look wrong (unless its on purpose for the test)

Copy link
Member Author

Choose a reason for hiding this comment

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

sigh. these are all over the tests. no clue how to guess whether it's intentional.

Copy link
Member

Choose a reason for hiding this comment

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

we can ask @felixguendling and see if he has a memory

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is a copy & paste mistake I made. Back then, the type was not used by the envelope class at all, so maybe this is why it was overlooked.

Copy link
Member Author

Choose a reason for hiding this comment

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

Cool, thanks @felixguendling. I've made this mistake a handful of times, and I only catch it by visual inspection. Not sure whether it's testable in a general way in practice. Maybe as a clang-tidy check or something.

Copy link
Contributor

Choose a reason for hiding this comment

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

I tried something, but due to the cyclic nature, it didn't really work:

#include <type_traits>

template <typename T>
struct p {
    using value_t = T;

    // does not compile
    // definition of 'p<c>' is not complete until the closing '}'
    // static_assert(std::is_assignable_v<p<T>, T>);
};

struct c : p<c> {};
static_assert(std::is_assignable_v<p<c>, c>);  // correct, no problem

struct w : p<c> {};
static_assert(std::is_assignable_v<p<w>, w>);  // assertion fails

https://gcc.godbolt.org/z/baTocTqG9

So, yes - probably only a clang-tidy check or something similar would help.

Copy link
Contributor

Choose a reason for hiding this comment

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

With some manual overhead, you can check every envelope type after it's defined:

#include <type_traits>

template <typename T>
struct p {
    using value_t = T;
};

template <typename T>
concept Good = std::is_assignable_v<T, typename T::value_t>;

struct c : p<c> {};
static_assert(Good<c>);

struct w : p<c> {};
static_assert(Good<w>);  // fails

Copy link
Member Author

Choose a reason for hiding this comment

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

cyclic nature

Yeah, exactly. Manual check lgtm; I could envision adding a debug build step where we scrape headers for envelopes then generate and collect static asserts in a separate compilation unit, but that's probably rather expensive to compile. Besides which it wouldn't cover this case, where the envelope is isolated in a .cc file.

@@ -703,6 +726,8 @@ struct new_no_cs

serde::checksum_t unchecked_dummy_checksum_{0U};
std::vector<test_msg1_new_manual> data_;

auto serde_fields() { return std::tie(unchecked_dummy_checksum_, data_); }
Copy link
Member

Choose a reason for hiding this comment

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

this one has them flipped the other way, so maybe its intentional

Copy link
Member Author

Choose a reason for hiding this comment

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

oh i see. yeah, those value types have something to do with operator overloading, but the need (or lack of need, as the case may be) for those operators is mysterious to me.

@oleiman
Copy link
Member Author

oleiman commented Aug 29, 2024

CI Failures:

  • cluster_cloud_metadata_rpfixture - known/unrelated build
  • ClusterConfigTest.test_valid_settings - seen this elsewhere but needs a ticket build

@oleiman
Copy link
Member Author

oleiman commented Aug 30, 2024

/ci-repeat 1

@oleiman
Copy link
Member Author

oleiman commented Sep 3, 2024

force push to correct a few CRTP typos in serde_test.cc

@oleiman oleiman requested a review from dotnwat September 3, 2024 23:49
@dotnwat dotnwat merged commit a596496 into redpanda-data:dev Sep 5, 2024
18 checks passed
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.

4 participants