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

cluster: add tombstone_retention_ms/delete.retention.ms #23662

Merged
merged 7 commits into from
Nov 5, 2024

Conversation

WillemKauf
Copy link
Contributor

@WillemKauf WillemKauf commented Oct 7, 2024

As a follow up to #23231 and #23380, this PR adds both the cluster-level configuration property tombstone_retention_ms and the topic-level property delete.retention.ms.

The cluster level property tombstone_retention_ms controls the default value for delete.retention.ms, which is equivalent to the Kafka topic property.

There is a tight coupling between the tiered storage properties (both at a topic and a cluster level) and these configurations. Namely,

  • tombstone_retention_ms cannot be enabled at the same time as any of cloud_storage_enabled, cloud_storage_enable_remote_read, cloud_storage_enable_remote_write.
  • delete.retention.ms cannot be enabled at the same time as any of redpanda.remote.read, redpanda.remote.write.

These restrictions are in place to ensure the deletion of tombstone records does not occur for topics with tiered storage enabled, a current restriction for compacted topics in redpanda.

Docs issue: https://github.com/redpanda-data/documentation-private/issues/2759

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

Features

  • Adds the topic property delete.retention.ms, as well as the cluster property tombstone_retention_ms. Configuring these allow for the removal of tombstone records in compacted topics with tiered storage disabled in redpanda.

@WillemKauf WillemKauf requested a review from a team as a code owner October 7, 2024 22:24
src/v/storage/ntp_config.h Outdated Show resolved Hide resolved
@@ -100,7 +100,7 @@ consteval describe_configs_type property_config_type() {
std::is_same_v<T, model::cleanup_policy_bitflags> ||
std::is_same_v<T, model::timestamp_type> ||
std::is_same_v<T, config::data_directory_path> ||
std::is_same_v<T, pandaproxy::schema_registry::subject_name_strategy> ||
std::is_same_v<T, pandaproxy::schema_registry::subject_name_strategy> ||
Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed trailing whitespace

@vbotbuildovich
Copy link
Collaborator

vbotbuildovich commented Oct 8, 2024

new failures in https://buildkite.com/redpanda/redpanda/builds/55964#019269fb-8611-4e0e-ac13-76b3f62a8749:

"rptest.tests.cluster_config_test.ClusterConfigTest.test_valid_settings"

new failures in https://buildkite.com/redpanda/redpanda/builds/55964#01926a00-34a4-458b-b616-878bdc7f3326:

"rptest.tests.cluster_config_test.ClusterConfigTest.test_valid_settings"

non flaky failures in https://buildkite.com/redpanda/redpanda/builds/56007#01926cde-1430-41c7-90d6-85501446db06:

"rptest.tests.license_enforcement_test.LicenseEnforcementTest.test_license_enforcement.clean_node_before_recovery=False.clean_node_after_recovery=True"

non flaky failures in https://buildkite.com/redpanda/redpanda/builds/56054#01926f61-8440-4115-98e5-c50e6578e0e9:

"rptest.tests.topic_recovery_test.TopicRecoveryTest.test_no_data.cloud_storage_type=CloudStorageType.S3"

non flaky failures in https://buildkite.com/redpanda/redpanda/builds/56163#019272e8-8bbe-4c4d-a17e-60d80d5d2f06:

"rptest.tests.topic_recovery_test.TopicRecoveryTest.test_no_data.cloud_storage_type=CloudStorageType.S3"

non flaky failures in https://buildkite.com/redpanda/redpanda/builds/56275#0192775c-3fce-4633-99a9-335b127ef068:

"rptest.tests.describe_topics_test.DescribeTopicsTest.test_describe_topics_with_documentation_and_types"

non flaky failures in https://buildkite.com/redpanda/redpanda/builds/57341#0192dba4-607d-4b39-ab20-96b0efab9dfd:

"rptest.tests.topic_recovery_test.TopicRecoveryTest.test_fast3.cloud_storage_type=CloudStorageType.S3"

non flaky failures in https://buildkite.com/redpanda/redpanda/builds/57557#0192f9c1-b707-4035-acb6-613149a54e6d:

"rptest.tests.describe_topics_test.DescribeTopicsTest.test_describe_topics_with_documentation_and_types"

non flaky failures in https://buildkite.com/redpanda/redpanda/builds/57557#0192f9e1-6036-46a5-891a-36d5dbb760d4:

"rptest.tests.topic_delete_test.TopicDeleteCloudStorageTest.topic_delete_unavailable_test.cloud_storage_type=CloudStorageType.ABS"

non flaky failures in https://buildkite.com/redpanda/redpanda/builds/57557#0192f9e1-6038-4fd8-b0c3-81d499a9bcfe:

"rptest.tests.describe_topics_test.DescribeTopicsTest.test_describe_topics_with_documentation_and_types"

@vbotbuildovich
Copy link
Collaborator

Retry command for Build#56007

please wait until all jobs are finished before running the slash command

/ci-repeat 1
tests/rptest/tests/license_enforcement_test.py::LicenseEnforcementTest.test_license_enforcement@{"clean_node_after_recovery":true,"clean_node_before_recovery":false}

@WillemKauf
Copy link
Contributor Author

Force push to:

  • Rebase to upstream dev to fix merge conflicts.

@vbotbuildovich
Copy link
Collaborator

vbotbuildovich commented Oct 9, 2024

the below tests from https://buildkite.com/redpanda/redpanda/builds/56054#01926f22-44e0-45a5-a2b1-6b2c6e7963da have failed and will be retried

kafka_server_rpfixture

the below tests from https://buildkite.com/redpanda/redpanda/builds/56054#01926f22-44dd-4ba4-ba1d-d24b156fea17 have failed and will be retried

kafka_server_rpfixture

the below tests from https://buildkite.com/redpanda/redpanda/builds/56275#01927707-5d1c-482c-a4a6-aa6b306a0a0f have failed and will be retried

kafka_server_rpfixture

the below tests from https://buildkite.com/redpanda/redpanda/builds/56275#01927707-5d1e-4522-b2e8-e8425117c06c have failed and will be retried

kafka_server_rpfixture

the below tests from https://buildkite.com/redpanda/redpanda/builds/56670#01929738-f679-4160-9f94-8a2c28bf866f have failed and will be retried

gtest_raft_rpunit

the below tests from https://buildkite.com/redpanda/redpanda/builds/57571#0192fa77-5464-4556-bb08-177b54038aa8 have failed and will be retried

partition_balancer_planner_test_rpunit
datalake_cloud_rpunit

@vbotbuildovich
Copy link
Collaborator

Retry command for Build#56054

please wait until all jobs are finished before running the slash command

/ci-repeat 1
tests/rptest/tests/topic_recovery_test.py::TopicRecoveryTest.test_no_data@{"cloud_storage_type":1}

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.

it looks like there is a bisection issue building this commit:

Author: Willem Kaufmann <willem.kaufmann@redpanda.com>
Date:   Wed Sep 4 13:09:21 2024 -0400

    `cluster`: add `topic_multi_property_validation()`

notes:

src/v/cluster/topic_configuration.cc:59:14: error: field designator 'tombstone_retention_ms' does not refer to any field in type 'storage::ntp_config::default_overrides'
   59 |             .tombstone_retention_ms = properties.delete_retention_ms});
      |             ~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

@WillemKauf
Copy link
Contributor Author

it looks like there is a bisection issue building this commit

Nice catch, corrected by moving changes to src/v/cluster/topic_configuration.cc to its proper commit (storage: add tombstone_retention_ms to ntp_config)

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.

is bisect still an issue on that same commit

git fetch upstream
git checkout 7b2b010eedf5c56f5887985f943c7ea9ddab39bd
git rebase 9e810f72f373ad3df8ff86fbef9a3d75b14aaa15
bazel build //...
src/v/cluster/topic_properties.cc:152:9: error: no member named 'tombstone_retention_ms' in 'storage::ntp_config::default_overrides'
  152 |     ret.tombstone_retention_ms = delete_retention_ms;
      |     ~~~ ^

@WillemKauf
Copy link
Contributor Author

WillemKauf commented Oct 9, 2024

is bisect still an issue on that same commit

Yup, missed another line, my bad.

Corrected by moving changes in src/v/cluster/topic_properties.cc to its proper commit (storage: add tombstone_retention_ms to ntp_config)

@vbotbuildovich
Copy link
Collaborator

Retry command for Build#56163

please wait until all jobs are finished before running the slash command

/ci-repeat 1
tests/rptest/tests/topic_recovery_test.py::TopicRecoveryTest.test_no_data@{"cloud_storage_type":1}

Feediver1
Feediver1 previously approved these changes Oct 10, 2024
Copy link

@Feediver1 Feediver1 left a comment

Choose a reason for hiding this comment

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

lgtm

@WillemKauf
Copy link
Contributor Author

Force push to:

  • Rebase to upstream dev to fix merge conflicts
  • Apply requested docs changes to config/configuration.cc.

@vbotbuildovich
Copy link
Collaborator

Retry command for Build#56370

please wait until all jobs are finished before running the slash command

/ci-repeat 1
tests/rptest/tests/cloud_storage_timing_stress_test.py::CloudStorageTimingStressTest.test_cloud_storage@{"cleanup_policy":"delete"}

@WillemKauf
Copy link
Contributor Author

/ci-repeat 1
tests/rptest/tests/cloud_storage_timing_stress_test.py::CloudStorageTimingStressTest.test_cloud_storage@{"cleanup_policy":"delete"}

@WillemKauf
Copy link
Contributor Author

/ci-repeat 1
release

@WillemKauf
Copy link
Contributor Author

/ci-repeat 1
release
tests/rptest/tests/describe_topics_test.py::DescribeTopicsTest.test_describe_topics

@WillemKauf
Copy link
Contributor Author

WillemKauf commented Oct 25, 2024

Force push to:

  • Rebase to upstream dev to fix merge conflicts

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.

looks pretty solid to me. just a few questions/comments

src/v/cluster/topic_table.cc Show resolved Hide resolved
src/v/storage/ntp_config.h Show resolved Hide resolved
tristate<T> override_if_not_default(
const tristate<T>& overrides, const std::optional<T>& def) {
// Overrides is {disabled}, cluster default is {value}
if (overrides.is_disabled() && def.has_value()) {
Copy link
Member

Choose a reason for hiding this comment

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

why does it matter if def.has_value here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For the two cases you have commented on (// Overrides is {disabled}, cluster default is {value}, // Overrides is {std::nullopt}, cluster default is {value}), note that the following case in which (overrides.is_empty() || overrides.is_disabled()) && !def.has_value() is excluded.

I.e, I'm treating the override and default as "equivalent" when the tristate is either disabled or empty, and the optional is in the std::nullopt state.

This makes a lot of logical sense for overrides.is_empty() && !def.has_value(), but I recognize overrides.is_disabled() && !def.has_value() is a bit more of a stretch. However, in the case of delete.retention.ms, its default state is often disabled, and the corresponding cluster property tombstone_retention_ms's default state is often std::nullopt. This, IMO, provides motivation for considering this state in override_if_not_default() in the way it is currently written.

Copy link
Member

Choose a reason for hiding this comment

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

override is considered equivalent to the default are

do you think we could add to the comment a truth table for all 6 cases (or maybe it's 9 if we count the cases where the default has a value and its actually equal to the tristate rather than just semantics equal). then we could use the retention.ms and truth table as an example for override_if_not_default usage.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added truth table in a code comment

src/v/cluster/metadata_cache.cc Outdated Show resolved Hide resolved
src/v/kafka/server/handlers/topics/types.h Show resolved Hide resolved
Comment on lines 161 to 184
// Either parse configuration or return nullopt
inline std::optional<bool>
get_bool_value(const config_map_t& config, std::string_view key) {
if (auto it = config.find(key); it != config.end()) {
try {
// Ignore case.
auto str_value = it->second;
std::transform(
str_value.begin(),
str_value.end(),
str_value.begin(),
[](const auto& c) { return std::tolower(c); });
return string_switch<std::optional<bool>>(str_value)
.match("true", true)
.match("false", false);
} catch (const std::runtime_error&) {
throw boost::bad_lexical_cast();
};
}
return std::nullopt;
}

inline model::shadow_indexing_mode
get_shadow_indexing_mode(const config_map_t& config) {
Copy link
Member

Choose a reason for hiding this comment

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

did these need to move to the header or could we have added a declaration to the header? or alternatively, could the implementation of delete_retention_ms_validator have been in the same .cc file?

Copy link
Contributor Author

@WillemKauf WillemKauf Oct 28, 2024

Choose a reason for hiding this comment

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

I think it is preferred to leave the implementation of delete_retention_ms_validator in validators.h to keep parity with the other definitions.

So, we could leave this as is with the inline definitions for get_bool_value() and get_shadow_indexing_mode() in the header, or I could change it to what you proposed with declarations in types.h and implementations in types.cc.

Please let me know what you prefer.

Copy link
Member

Choose a reason for hiding this comment

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

the general rule of thumb is to be reducing the amount of code in headers. its not any sort of hard and fast rule, but i don't see in this case why it needs to move to the header. is there a dependency issue that makes it hard to do?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved declaration/implementation

src/v/cluster/metadata_cache.cc Show resolved Hide resolved
@vbotbuildovich
Copy link
Collaborator

Retry command for Build#57341

please wait until all jobs are finished before running the slash command

/ci-repeat 1
tests/rptest/tests/topic_recovery_test.py::TopicRecoveryTest.test_fast3@{"cloud_storage_type":1}

Plumb the `delete_retention_ms` config through `topic_configuration`,
and `topic_properties`.

Also modify necessary compatibility sites.

Also modify `tools/offline_log_viewer` to be compatible with the updated
`serde`.
When applying `update_topic_properties_cmd`, there may be some checks
that depend on multiple properties. The current motivating case is
ensuring that `delete.retention.ms` is not enabled at the same time
as any tiered storage properties.

Add `topic_table::topic_multi_property_validation()` to perform these
checks and abort the topic property update if the `properties` are
found to be invalid.
The storage layer will now utilize a topic's configured `delete.retention.ms`
parameter for housekeeping. At the `ntp_config` layer, this is referred to
as `tombstone_retention_ms`.
@WillemKauf
Copy link
Contributor Author

Force push to:

  • Rebase to upstream dev to fix merge conflict
  • Fix bug in std::ostream& operator<<(std::ostream& o, const topic_properties& properties) (extra comma)

Copy link
Contributor

@andrwng andrwng left a comment

Choose a reason for hiding this comment

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

Sorry for the delay looking at this. Looking pretty nice and complete, but have a few nits and questions about code placement themed around simplifying and future-proofing

src/v/kafka/server/handlers/topics/validators.h Outdated Show resolved Hide resolved
src/v/config/configuration.cc Outdated Show resolved Hide resolved
src/v/kafka/server/handlers/topics/types.cc Show resolved Hide resolved
Comment on lines 76 to 103
#We cannot enable delete.retention.ms if any cloud storage properties are also enabled.
test_cases = [
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this cover the entirety of the truth table from the earlier commit? Might be worth duplicating the truth table here

Copy link
Contributor

Choose a reason for hiding this comment

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

Also nit: space between # and the first word

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No it does not, and the test was not really intended to test the truth table for the overrides- more so tiered storage and delete.retention.ms property interaction.

Copy link
Contributor

Choose a reason for hiding this comment

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

Got it. Does it make sense to include a test case for just the delete.retention.ms behavior without tiered storage involvement?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

test_alter_topic_config covers this already I think.

Similar in intention to the `override_if_not_default` overload for
`std::optional<>`. This ensures that `tristate` topic properties may
still display `DEFAULT_CONFIG` instead of `DYNAMIC_TOPIC_CONFIG` in the
case that their value is `{disabled}` and the cluster default is `std::nullopt`.

This is useful for topic properties that may want to default to a `{disabled}`
state without indicating `DYNAMIC_TOPIC_CONFIG` as a source.
Adds configuration for the topic property `delete.retention.ms`
through the `CreateTopic`, `AlterConfig`, and `IncrementalAlterConfig`
Kafka APIs.
// no value => tristate.has_value() == false;
// value present => tristate.has_value() == true;

template<typename T>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunate that this template function had to be moved to the header in order to use it in validators.h.

andrwng
andrwng previously approved these changes Nov 4, 2024
@vbotbuildovich
Copy link
Collaborator

vbotbuildovich commented Nov 5, 2024

Retry command for Build#57557

please wait until all jobs are finished before running the slash command

/ci-repeat 1
tests/rptest/tests/describe_topics_test.py::DescribeTopicsTest.test_describe_topics_with_documentation_and_types
tests/rptest/tests/topic_delete_test.py::TopicDeleteCloudStorageTest.topic_delete_unavailable_test@{"cloud_storage_type":2}

Adding support for `tombstone_retention_ms`, which is a cluster property
that is equivalent to Kafka's `log.cleaner.delete.retention.ms`, but is more precisely
named, and represents the retention time for tombstone records in compacted topics
in `redpanda`.

This controls the default value for the topic level property `delete.retention.ms`.
@WillemKauf
Copy link
Contributor Author

Force push to:

  • Fix doc string in failing describe_topics_test.py ducktape test post changes in configuration.cc

@WillemKauf WillemKauf merged commit 8a949ed into redpanda-data:dev Nov 5, 2024
17 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.

6 participants