From c62865df909cb53b696b188e6a054eff94f1e59d Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Mon, 10 Feb 2025 17:00:57 +0200 Subject: [PATCH 1/3] db/config: add tablets_mode_for_new_keyspaces option The new option deprecates the existing `enable_tablets` option. It will be extended in the next patch with a 3rd value: "enforced" while will enable tablets by default for new keyspace but without the posibility to opt out using the `tablets = {'enabled': false}` keyspace schema option. Signed-off-by: Benny Halevy --- conf/scylla.yaml | 6 ++- cql3/statements/ks_prop_defs.cc | 2 +- db/config.cc | 38 ++++++++++++++++++- db/config.hh | 26 +++++++++++++ docs/architecture/tablets.rst | 2 +- gms/feature_service.cc | 4 +- test/alternator/suite.yaml | 2 +- test/boost/commitlog_cleanup_test.cc | 4 +- test/boost/cql_query_test.cc | 2 +- test/boost/sstable_set_test.cc | 2 +- test/boost/tablets_test.cc | 20 +++++----- .../auth_cluster/test_auth_v2_migration.py | 2 +- .../auth_cluster/test_raft_service_levels.py | 4 +- .../mv/tablets/test_mv_tablets_empty_ip.py | 2 +- test/cluster/mv/test_mv_admission_control.py | 6 +-- test/cluster/mv/test_mv_backlog.py | 6 +-- test/cluster/mv/test_mv_read_concurrency.py | 4 +- test/cluster/mv/test_mv_topology_change.py | 4 +- test/cluster/suite.yaml | 2 +- test/cluster/test_boot_after_ip_change.py | 2 +- .../test_change_replication_factor_1_to_0.py | 4 +- test/cluster/test_different_group0_ids.py | 2 +- test/cluster/test_encryption.py | 2 +- test/cluster/test_fencing.py | 2 +- test/cluster/test_gossip_boot.py | 2 +- test/cluster/test_group0_schema_versioning.py | 4 +- test/cluster/test_raft_fix_broken_snapshot.py | 2 +- test/cluster/test_raft_recovery_basic.py | 2 +- .../test_raft_recovery_majority_loss.py | 2 +- test/cluster/test_raft_recovery_stuck.py | 2 +- test/cluster/test_raft_recovery_user_data.py | 2 +- test/cluster/test_repair.py | 4 +- test/cluster/test_replace_ignore_nodes.py | 2 +- test/cluster/test_table_drop.py | 2 +- test/cluster/test_tablets.py | 30 +++++++-------- test/cluster/test_tablets2.py | 2 +- test/cluster/test_tablets_cql.py | 4 +- test/cluster/test_tablets_migration.py | 8 ++-- .../cluster/test_topology_failure_recovery.py | 2 +- test/cluster/test_topology_ops.py | 2 +- test/cluster/test_topology_ops_encrypted.py | 2 +- .../test_topology_remove_garbage_group0.py | 2 +- test/cluster/test_topology_upgrade.py | 2 +- ..._upgrade_not_stuck_after_recent_removal.py | 2 +- test/cluster/test_topology_upgrade_stuck.py | 2 +- test/cluster/test_truncate_with_tablets.py | 10 ++--- test/cluster/test_view_build_status.py | 8 ++-- .../test_zero_token_nodes_topology_ops.py | 6 +-- test/perf/perf_simple_query.cc | 2 +- test/perf/perf_tablets.cc | 2 +- 50 files changed, 162 insertions(+), 98 deletions(-) diff --git a/conf/scylla.yaml b/conf/scylla.yaml index ba21bd98d1..a8e0a313e0 100644 --- a/conf/scylla.yaml +++ b/conf/scylla.yaml @@ -825,7 +825,9 @@ maintenance_socket: ignore # Guardrail to enable the deprecated feature of CREATE TABLE WITH COMPACT STORAGE. # enable_create_table_with_compact_storage: false -# Enable tablets for new keyspaces. +# Control tablets for new keyspaces. +# Can be set to: disabled|enabled +# # When enabled, newly created keyspaces will have tablets enabled by default. # That can be explicitly disabled in the CREATE KEYSPACE query # by using the `tablets = {'enabled': false}` replication option. @@ -836,7 +838,7 @@ maintenance_socket: ignore # # Note that creating keyspaces with tablets enabled or disabled is irreversible. # The `tablets` option cannot be changed using `ALTER KEYSPACE`. -enable_tablets: true +tablets_mode_for_new_keyspaces: enabled # Enforce RF-rack-valid keyspaces. rf_rack_valid_keyspaces: false diff --git a/cql3/statements/ks_prop_defs.cc b/cql3/statements/ks_prop_defs.cc index 8b5bc17ac4..f9db5576ce 100644 --- a/cql3/statements/ks_prop_defs.cc +++ b/cql3/statements/ks_prop_defs.cc @@ -199,7 +199,7 @@ bool ks_prop_defs::get_durable_writes() const { lw_shared_ptr ks_prop_defs::as_ks_metadata(sstring ks_name, const locator::token_metadata& tm, const gms::feature_service& feat, const db::config& cfg) { auto sc = get_replication_strategy_class().value(); // if tablets options have not been specified, but tablets are globally enabled, set the value to 0 for N.T.S. only - auto enable_tablets = feat.tablets && cfg.enable_tablets(); + auto enable_tablets = feat.tablets && cfg.enable_tablets_by_default(); auto initial_tablets = get_initial_tablets(enable_tablets && locator::abstract_replication_strategy::to_qualified_class_name(sc) == "org.apache.cassandra.locator.NetworkTopologyStrategy" ? std::optional(0) : std::nullopt); auto options = prepare_options(sc, tm, get_replication_options()); return data_dictionary::keyspace_metadata::new_keyspace(ks_name, sc, diff --git a/db/config.cc b/db/config.cc index 9a185a9598..8b352fe94c 100644 --- a/db/config.cc +++ b/db/config.cc @@ -245,6 +245,13 @@ const config_type& config_type_for>() { return ct; } +template <> +const config_type& config_type_for>() { + static config_type ct( + "tablets mode", printable_to_json>); + return ct; +} + template <> const config_type& config_type_for() { static config_type ct("hinted handoff enabled", hinted_handoff_enabled_to_json); @@ -379,6 +386,23 @@ public: } }; +template <> +class convert> { +public: + static bool decode(const Node& node, enum_option& rhs) { + std::string name; + if (!convert::decode(node, name)) { + return false; + } + try { + std::istringstream(name) >> rhs; + } catch (boost::program_options::invalid_option_value&) { + return false; + } + return true; + } +}; + template<> struct convert { static bool decode(const Node& node, db::config::error_injection_at_startup& rhs) { @@ -1372,7 +1396,11 @@ db::config::config(std::shared_ptr exts) , error_injections_at_startup(this, "error_injections_at_startup", error_injection_value_status, {}, "List of error injections that should be enabled on startup.") , topology_barrier_stall_detector_threshold_seconds(this, "topology_barrier_stall_detector_threshold_seconds", value_status::Used, 2, "Report sites blocking topology barrier if it takes longer than this.") - , enable_tablets(this, "enable_tablets", value_status::Used, false, "Enable tablets for newly created keyspaces.") + , enable_tablets(this, "enable_tablets", value_status::Used, false, "Enable tablets for newly created keyspaces. (deprecated)") + , tablets_mode_for_new_keyspaces(this, "tablets_mode_for_new_keyspaces", value_status::Used, tablets_mode_t::mode::unset, "Control tablets for new keyspaces. Can be set to the following values:\n" + "\tdisabled: New keyspaces use vnodes by default, unless enabled by the tablets={'enabled':true} option\n" + "\tenabled: New keyspaces use tablets by default, unless disabled by the tablets={'disabled':true} option\n" + ) , view_flow_control_delay_limit_in_ms(this, "view_flow_control_delay_limit_in_ms", liveness::LiveUpdate, value_status::Used, 1000, "The maximal amount of time that materialized-view update flow control may delay responses " "to try to slow down the client and prevent buildup of unfinished view updates. " @@ -1612,6 +1640,14 @@ std::unordered_map db::tri_mode_restr {"warn", db::tri_mode_restriction_t::mode::WARN}}; } +std::unordered_map db::tablets_mode_t::map() { + return {{"disabled", db::tablets_mode_t::mode::disabled}, + {"0", db::tablets_mode_t::mode::disabled}, + {"enabled", db::tablets_mode_t::mode::enabled}, + {"1", db::tablets_mode_t::mode::enabled}, + }; +} + template struct utils::config_file::named_value; namespace utils { diff --git a/db/config.hh b/db/config.hh index c27aed163c..e936b607d8 100644 --- a/db/config.hh +++ b/db/config.hh @@ -135,6 +135,19 @@ struct replication_strategy_restriction_t { constexpr unsigned default_murmur3_partitioner_ignore_msb_bits = 12; +struct tablets_mode_t { + // The `unset` mode is used internally for backward compatibility + // with the legacy `enable_tablets` option. + // It is defined as -1 as existing test code associates the value + // 0 with `false` and 1 with `true` when read from system.config. + enum class mode : int8_t { + unset = -1, + disabled = 0, + enabled = 1, + }; + static std::unordered_map map(); // for enum_option<> +}; + class config final : public utils::config_file { public: config(); @@ -538,6 +551,19 @@ public: named_value> error_injections_at_startup; named_value topology_barrier_stall_detector_threshold_seconds; named_value enable_tablets; + named_value> tablets_mode_for_new_keyspaces; + + bool enable_tablets_by_default() const noexcept { + switch (tablets_mode_for_new_keyspaces()) { + case tablets_mode_t::mode::unset: + return enable_tablets(); + case tablets_mode_t::mode::disabled: + return false; + case tablets_mode_t::mode::enabled: + return true; + } + } + named_value view_flow_control_delay_limit_in_ms; named_value disk_space_monitor_normal_polling_interval_in_seconds; diff --git a/docs/architecture/tablets.rst b/docs/architecture/tablets.rst index 2b13eddd79..c665c312f6 100644 --- a/docs/architecture/tablets.rst +++ b/docs/architecture/tablets.rst @@ -90,7 +90,7 @@ Enabling Tablets ScyllaDB now uses tablets by default for data distribution. Enabling tablets by default when creating new keyspaces is -controlled by the :confval:`enable_tablets` option. However, tablets only work if +controlled by the :confval:`tablets_mode_for_new_keyspaces` option. However, tablets only work if supported on all nodes within the cluster. When creating a new keyspace with tablets enabled by default, you can still opt-out diff --git a/gms/feature_service.cc b/gms/feature_service.cc index 5204472214..64a23b056b 100644 --- a/gms/feature_service.cc +++ b/gms/feature_service.cc @@ -86,8 +86,8 @@ feature_config feature_config_from_db_config(const db::config& cfg, std::setauto_snapshot.set(false); cfg.db_config->commitlog_sync.set("batch"); - cfg.db_config->enable_tablets.set(true); + cfg.db_config->tablets_mode_for_new_keyspaces.set(db::tablets_mode_t::mode::enabled); cfg.initial_tablets = 1; return do_with_cql_env_thread([](cql_test_env& e) { @@ -173,7 +173,7 @@ SEASTAR_TEST_CASE(test_commitlog_cleanup_record_gc) { auto cfg = cql_test_config(); cfg.db_config->auto_snapshot.set(false); cfg.db_config->commitlog_sync.set("batch"); - cfg.db_config->enable_tablets.set(true); + cfg.db_config->tablets_mode_for_new_keyspaces.set(db::tablets_mode_t::mode::enabled); cfg.initial_tablets = 1; return do_with_cql_env_thread([](cql_test_env& e) { diff --git a/test/boost/cql_query_test.cc b/test/boost/cql_query_test.cc index f8f997100a..c9ec029eba 100644 --- a/test/boost/cql_query_test.cc +++ b/test/boost/cql_query_test.cc @@ -5892,7 +5892,7 @@ SEASTAR_TEST_CASE(test_setting_synchronous_updates_property) { static cql_test_config tablet_cql_test_config() { cql_test_config c; - c.db_config->enable_tablets.set(true); + c.db_config->tablets_mode_for_new_keyspaces.set(db::tablets_mode_t::mode::enabled); return c; } diff --git a/test/boost/sstable_set_test.cc b/test/boost/sstable_set_test.cc index d264337a45..315bfa22e2 100644 --- a/test/boost/sstable_set_test.cc +++ b/test/boost/sstable_set_test.cc @@ -179,7 +179,7 @@ SEASTAR_TEST_CASE(test_partitioned_sstable_set_bytes_on_disk) { SEASTAR_TEST_CASE(test_tablet_sstable_set_copy_ctor) { // enable tablets, to get access to tablet_storage_group_manager cql_test_config cfg; - cfg.db_config->enable_tablets(true); + cfg.db_config->tablets_mode_for_new_keyspaces(db::tablets_mode_t::mode::enabled); return do_with_cql_env_thread([&](cql_test_env& env) { env.execute_cql("CREATE KEYSPACE test_tablet_sstable_set_copy_ctor" diff --git a/test/boost/tablets_test.cc b/test/boost/tablets_test.cc index c6f102b969..e984bbe62d 100644 --- a/test/boost/tablets_test.cc +++ b/test/boost/tablets_test.cc @@ -82,10 +82,10 @@ void verify_tablet_metadata_update(cql_test_env& env, tablet_metadata& tm, std:: } static -cql_test_config tablet_cql_test_config(bool enable_tablets = true) { +cql_test_config tablet_cql_test_config(db::tablets_mode_t::mode enable_tablets = db::tablets_mode_t::mode::enabled) { cql_test_config c; - c.db_config->enable_tablets(enable_tablets); - if (enable_tablets) { + c.db_config->tablets_mode_for_new_keyspaces(enable_tablets); + if (c.db_config->enable_tablets_by_default()) { c.initial_tablets = 2; } return c; @@ -3851,7 +3851,7 @@ future<> test_create_keyspace(sstring ks_name, std::optional tablets_opt, testlog.debug("shard table_count={}", count); return count; }, int64_t(0), std::plus()).get(); - if (tablets_opt.value_or(cfg.db_config->enable_tablets())) { + if (tablets_opt.value_or(cfg.db_config->enable_tablets_by_default())) { if (initial_tablets) { BOOST_REQUIRE_EQUAL(total, initial_tablets); } else { @@ -3866,10 +3866,10 @@ future<> test_create_keyspace(sstring ks_name, std::optional tablets_opt, } // Test that tablets can be explicitly enabled -// when creating a keyspace when the `enable_tablets` -// configuration option is set to `false`. +// when creating a keyspace when the `tablets_mode_for_new_keyspaces` +// configuration option is set to `disabled`. SEASTAR_TEST_CASE(test_explicit_tablets_enable) { - auto cfg = tablet_cql_test_config(false); + auto cfg = tablet_cql_test_config(db::tablets_mode_t::mode::disabled); // By default tablets are disabled co_await test_create_keyspace("test_default_settings", std::nullopt, cfg); @@ -3883,10 +3883,10 @@ SEASTAR_TEST_CASE(test_explicit_tablets_enable) { } // Test that tablets can be explicitly disabled -// when creating a keyspace when the `enable_tablets` -// configuration option is set to `true`. +// when creating a keyspace when the `tablets_mode_for_new_keyspaces` +// configuration option is set to `enabled`. SEASTAR_TEST_CASE(test_explicit_tablets_disable) { - auto cfg = tablet_cql_test_config(true); + auto cfg = tablet_cql_test_config(db::tablets_mode_t::mode::enabled); // By default tablets are enabled co_await test_create_keyspace("test_default_settings", std::nullopt, cfg); diff --git a/test/cluster/auth_cluster/test_auth_v2_migration.py b/test/cluster/auth_cluster/test_auth_v2_migration.py index fac4804897..266bf7b580 100644 --- a/test/cluster/auth_cluster/test_auth_v2_migration.py +++ b/test/cluster/auth_cluster/test_auth_v2_migration.py @@ -149,7 +149,7 @@ async def check_auth_v2_works(manager: ManagerClient, hosts): @pytest.mark.asyncio async def test_auth_v2_migration(request, manager: ManagerClient): # First, force the first node to start in legacy mode - cfg = {**auth_config, 'force_gossip_topology_changes': True, 'enable_tablets': False} + cfg = {**auth_config, 'force_gossip_topology_changes': True, 'tablets_mode_for_new_keyspaces': 'disabled'} servers = [await manager.server_add(config=cfg)] # Enable raft-based node operations for subsequent nodes - they should fall back to diff --git a/test/cluster/auth_cluster/test_raft_service_levels.py b/test/cluster/auth_cluster/test_raft_service_levels.py index 11f987dbe3..fd292ebfe8 100644 --- a/test/cluster/auth_cluster/test_raft_service_levels.py +++ b/test/cluster/auth_cluster/test_raft_service_levels.py @@ -62,7 +62,7 @@ async def test_service_levels_snapshot(manager: ManagerClient): @pytest.mark.asyncio async def test_service_levels_upgrade(request, manager: ManagerClient): # First, force the first node to start in legacy mode - cfg = {**auth_config, 'force_gossip_topology_changes': True, 'enable_tablets': False} + cfg = {**auth_config, 'force_gossip_topology_changes': True, 'tablets_mode_for_new_keyspaces': 'disabled'} servers = [await manager.server_add(config=cfg)] # Enable raft-based node operations for subsequent nodes - they should fall back to @@ -385,7 +385,7 @@ async def test_workload_prioritization_upgrade(manager: ManagerClient): 'authenticator': 'AllowAllAuthenticator', 'authorizer': 'AllowAllAuthorizer', 'force_gossip_topology_changes': True, - 'enable_tablets': False, + 'tablets_mode_for_new_keyspaces': 'disabled', 'error_injections_at_startup': [ { 'name': 'suppress_features', diff --git a/test/cluster/mv/tablets/test_mv_tablets_empty_ip.py b/test/cluster/mv/tablets/test_mv_tablets_empty_ip.py index 2ab96817c6..47de0c474c 100644 --- a/test/cluster/mv/tablets/test_mv_tablets_empty_ip.py +++ b/test/cluster/mv/tablets/test_mv_tablets_empty_ip.py @@ -29,7 +29,7 @@ logger = logging.getLogger(__name__) @pytest.mark.asyncio @skip_mode('release', 'error injections are not supported in release mode') async def test_mv_tablets_empty_ip(manager: ManagerClient): - cfg = {'enable_tablets': True} + cfg = {'tablets_mode_for_new_keyspaces': 'enabled'} servers = await manager.servers_add(4, config = cfg) cql = manager.get_cql() diff --git a/test/cluster/mv/test_mv_admission_control.py b/test/cluster/mv/test_mv_admission_control.py index 2ffd8f2476..80a7c7b0ad 100644 --- a/test/cluster/mv/test_mv_admission_control.py +++ b/test/cluster/mv/test_mv_admission_control.py @@ -29,7 +29,7 @@ logger = logging.getLogger(__name__) @skip_mode('release', "error injections aren't enabled in release mode") async def test_mv_admission_control_exception(manager: ManagerClient) -> None: node_count = 2 - config = {'error_injections_at_startup': ['view_update_limit', 'update_backlog_immediately'], 'enable_tablets': True} + config = {'error_injections_at_startup': ['view_update_limit', 'update_backlog_immediately'], 'tablets_mode_for_new_keyspaces': 'enabled'} servers = await manager.servers_add(node_count, config=config) cql, hosts = await manager.get_ready_cql(servers) async with new_test_keyspace(manager, "WITH replication = {'class': 'NetworkTopologyStrategy', 'replication_factor': 1} AND tablets = {'initial': 1}") as ks: @@ -67,8 +67,8 @@ async def test_mv_admission_control_exception(manager: ManagerClient) -> None: @skip_mode('release', "error injections aren't enabled in release mode") async def test_mv_retried_writes_reach_all_replicas(manager: ManagerClient) -> None: node_count = 4 - servers = await manager.servers_add(node_count - 1, config={'error_injections_at_startup': ['update_backlog_immediately'], 'enable_tablets': True}) - server = await manager.server_add(config={'error_injections_at_startup': ['view_update_limit', 'delay_before_remote_view_update', 'update_backlog_immediately'], 'enable_tablets': True}) + servers = await manager.servers_add(node_count - 1, config={'error_injections_at_startup': ['update_backlog_immediately'], 'tablets_mode_for_new_keyspaces': 'enabled'}) + server = await manager.server_add(config={'error_injections_at_startup': ['view_update_limit', 'delay_before_remote_view_update', 'update_backlog_immediately'], 'tablets_mode_for_new_keyspaces': 'enabled'}) cql, hosts = await manager.get_ready_cql(servers) async with new_test_keyspace(manager, "WITH replication = {'class': 'NetworkTopologyStrategy', 'replication_factor': 3} AND tablets = {'initial': 1}") as ks: diff --git a/test/cluster/mv/test_mv_backlog.py b/test/cluster/mv/test_mv_backlog.py index 96318763aa..c2f1e89865 100644 --- a/test/cluster/mv/test_mv_backlog.py +++ b/test/cluster/mv/test_mv_backlog.py @@ -27,7 +27,7 @@ logger = logging.getLogger(__name__) async def test_view_backlog_increased_after_write(manager: ManagerClient) -> None: node_count = 2 # Use a higher smp to make it more likely that the writes go to a different shard than the coordinator. - servers = await manager.servers_add(node_count, cmdline=['--smp', '5'], config={'error_injections_at_startup': ['never_finish_remote_view_updates'], 'enable_tablets': True}) + servers = await manager.servers_add(node_count, cmdline=['--smp', '5'], config={'error_injections_at_startup': ['never_finish_remote_view_updates'], 'tablets_mode_for_new_keyspaces': 'enabled'}) cql = manager.get_cql() async with new_test_keyspace(manager, "WITH replication = {'class': 'NetworkTopologyStrategy', 'replication_factor': 1} AND tablets = {'initial': 1}") as ks: await cql.run_async(f"CREATE TABLE {ks}.tab (base_key int, view_key int, v text, PRIMARY KEY (base_key, view_key))") @@ -57,7 +57,7 @@ async def test_view_backlog_increased_after_write(manager: ManagerClient) -> Non @skip_mode('release', "error injections aren't enabled in release mode") async def test_gossip_same_backlog(manager: ManagerClient) -> None: node_count = 2 - servers = await manager.servers_add(node_count, config={'error_injections_at_startup': ['view_update_limit', 'update_backlog_immediately'], 'enable_tablets': True}) + servers = await manager.servers_add(node_count, config={'error_injections_at_startup': ['view_update_limit', 'update_backlog_immediately'], 'tablets_mode_for_new_keyspaces': 'enabled'}) cql, hosts = await manager.get_ready_cql(servers) async with new_test_keyspace(manager, "WITH replication = {'class': 'NetworkTopologyStrategy', 'replication_factor': 1} AND tablets = {'initial': 1}") as ks: await cql.run_async(f"CREATE TABLE {ks}.tab (key int, c int, v text, PRIMARY KEY (key, c))") @@ -102,7 +102,7 @@ async def test_gossip_same_backlog(manager: ManagerClient) -> None: async def test_configurable_mv_control_flow_delay(manager: ManagerClient) -> None: node_count = 2 servers = await manager.servers_add(node_count, - config={'error_injections_at_startup': ['update_backlog_immediately', 'view_update_limit', 'skip_updating_local_backlog_via_view_update_backlog_broker'], 'enable_tablets': True}, + config={'error_injections_at_startup': ['update_backlog_immediately', 'view_update_limit', 'skip_updating_local_backlog_via_view_update_backlog_broker'], 'tablets_mode_for_new_keyspaces': 'enabled'}, cmdline=['--smp=1']) cql, hosts = await manager.get_ready_cql(servers) async with new_test_keyspace(manager, "WITH replication = {'class': 'NetworkTopologyStrategy', 'replication_factor': 1} AND tablets = {'initial': 1}") as ks: diff --git a/test/cluster/mv/test_mv_read_concurrency.py b/test/cluster/mv/test_mv_read_concurrency.py index e7cbe4057a..f274949312 100644 --- a/test/cluster/mv/test_mv_read_concurrency.py +++ b/test/cluster/mv/test_mv_read_concurrency.py @@ -29,7 +29,7 @@ async def test_mv_read_concurrency(manager: ManagerClient) -> None: # Disable cache to make reads use the read concurrency semaphore. # Tests remove the rcs multiplier by default, here we use a slightly smaller one (1 instead of default 2) to hit the issue faster. cfg = { - 'enable_tablets': True, + 'tablets_mode_for_new_keyspaces': 'enabled', 'enable_cache': False, 'reader_concurrency_semaphore_serialize_limit_multiplier': 1, 'view_update_reader_concurrency_semaphore_serialize_limit_multiplier': 1, @@ -100,7 +100,7 @@ async def test_mv_read_memory(manager: ManagerClient) -> None: # and we increase the kill limit. Without the view update read before write admission, the test exceeds even the increased limit. # With the admission, the memory usage should stay within the limits and cause no errors. cfg = { - 'enable_tablets': True, + 'tablets_mode_for_new_keyspaces': 'enabled', 'enable_cache': False, 'view_update_reader_concurrency_semaphore_serialize_limit_multiplier': 2, 'view_update_reader_concurrency_semaphore_kill_limit_multiplier': 10 diff --git a/test/cluster/mv/test_mv_topology_change.py b/test/cluster/mv/test_mv_topology_change.py index 15848c0b0c..bc00689c35 100644 --- a/test/cluster/mv/test_mv_topology_change.py +++ b/test/cluster/mv/test_mv_topology_change.py @@ -31,7 +31,7 @@ logger = logging.getLogger(__name__) @skip_mode('release', 'error injections are not supported in release mode') async def test_mv_topology_change(manager: ManagerClient): cfg = {'force_gossip_topology_changes': True, - 'enable_tablets': False, + 'tablets_mode_for_new_keyspaces': 'disabled', 'error_injections_at_startup': ['delay_before_get_view_natural_endpoint']} servers = [await manager.server_add(config=cfg) for _ in range(3)] @@ -97,7 +97,7 @@ async def test_mv_topology_change(manager: ManagerClient): @pytest.mark.asyncio @skip_mode('release', 'error injections are not supported in release mode') async def test_mv_update_on_pending_replica(manager: ManagerClient, intranode): - cfg = {'enable_tablets': True} + cfg = {'tablets_mode_for_new_keyspaces': 'enabled'} cmd = ['--smp', '2'] servers = [await manager.server_add(config=cfg, cmdline=cmd)] diff --git a/test/cluster/suite.yaml b/test/cluster/suite.yaml index 32212d35b5..6c49e178bf 100644 --- a/test/cluster/suite.yaml +++ b/test/cluster/suite.yaml @@ -6,7 +6,7 @@ extra_scylla_config_options: authenticator: AllowAllAuthenticator authorizer: AllowAllAuthorizer enable_user_defined_functions: False - enable_tablets: True + tablets_mode_for_new_keyspaces: enabled run_first: - test_raft_recovery_stuck - test_raft_recovery_basic diff --git a/test/cluster/test_boot_after_ip_change.py b/test/cluster/test_boot_after_ip_change.py index effc64f5ca..04e7ba36cd 100644 --- a/test/cluster/test_boot_after_ip_change.py +++ b/test/cluster/test_boot_after_ip_change.py @@ -21,7 +21,7 @@ async def test_boot_after_ip_change(manager: ManagerClient) -> None: """ cfg = {'enable_user_defined_functions': False, 'force_gossip_topology_changes': True, - 'enable_tablets': False} + 'tablets_mode_for_new_keyspaces': 'disabled'} logger.info(f"Booting initial cluster") servers = [await manager.server_add(config=cfg) for _ in range(2)] await wait_for_token_ring_and_group0_consistency(manager, time.time() + 30) diff --git a/test/cluster/test_change_replication_factor_1_to_0.py b/test/cluster/test_change_replication_factor_1_to_0.py index de43efd4cf..dcb706f1dc 100644 --- a/test/cluster/test_change_replication_factor_1_to_0.py +++ b/test/cluster/test_change_replication_factor_1_to_0.py @@ -27,7 +27,7 @@ logger = logging.getLogger(__name__) ) @pytest.mark.asyncio async def test_change_replication_factor_1_to_0(request: pytest.FixtureRequest, manager: ManagerClient, use_tablets: bool) -> None: - CONFIG = {"endpoint_snitch": "GossipingPropertyFileSnitch", "enable_tablets": str(use_tablets)} + CONFIG = {"endpoint_snitch": "GossipingPropertyFileSnitch", "tablets_mode_for_new_keyspaces": "enabled" if use_tablets else "disabled"} logger.info("Creating a new cluster") for i in range(2): await manager.server_add( @@ -79,7 +79,7 @@ async def test_change_replication_factor_1_to_0(request: pytest.FixtureRequest, ) @pytest.mark.asyncio async def test_change_replication_factor_1_to_0_and_decommission(request: pytest.FixtureRequest, manager: ManagerClient, use_tablets: bool) -> None: - CONFIG = {"endpoint_snitch": "GossipingPropertyFileSnitch", "enable_tablets": str(use_tablets)} + CONFIG = {"endpoint_snitch": "GossipingPropertyFileSnitch", "tablets_mode_for_new_keyspaces": "enabled" if use_tablets else "disabled"} logger.info("Creating a new cluster") for i in range(2): await manager.server_add( diff --git a/test/cluster/test_different_group0_ids.py b/test/cluster/test_different_group0_ids.py index bebfb75ee0..bdb8e19c5c 100644 --- a/test/cluster/test_different_group0_ids.py +++ b/test/cluster/test_different_group0_ids.py @@ -28,7 +28,7 @@ async def test_different_group0_ids(manager: ManagerClient): """ # Consistent topology changes are disabled to use repair based node operations. - cfg = {'force_gossip_topology_changes': True, 'enable_tablets': False} + cfg = {'force_gossip_topology_changes': True, 'tablets_mode_for_new_keyspaces': 'disabled'} scylla_a = await manager.server_add(config = cfg) scylla_b = await manager.server_add(start=False, config = cfg) await manager.server_start(scylla_b.server_id, seeds=[scylla_b.ip_addr]) diff --git a/test/cluster/test_encryption.py b/test/cluster/test_encryption.py index 35b6050f79..e0e505c802 100644 --- a/test/cluster/test_encryption.py +++ b/test/cluster/test_encryption.py @@ -21,7 +21,7 @@ def workdir(): async def test_file_streaming_respects_encryption(request, manager: ManagerClient, workdir): cfg = { - 'enable_tablets': True, + 'tablets_mode_for_new_keyspaces': 'enabled', } cmdline = ['--smp=1'] diff --git a/test/cluster/test_fencing.py b/test/cluster/test_fencing.py index 79eba3d21f..d7f4d0db7b 100644 --- a/test/cluster/test_fencing.py +++ b/test/cluster/test_fencing.py @@ -61,7 +61,7 @@ def all_hints_metrics(metrics: ScyllaMetrics) -> list[str]: @pytest.mark.asyncio @pytest.mark.parametrize("tablets_enabled", [True, False]) async def test_fence_writes(request, manager: ManagerClient, tablets_enabled: bool): - cfg = {'enable_tablets' : tablets_enabled} + cfg = {'tablets_mode_for_new_keyspaces' : 'enabled' if tablets_enabled else 'disabled'} logger.info("Bootstrapping first two nodes") servers = await manager.servers_add(2, config=cfg) diff --git a/test/cluster/test_gossip_boot.py b/test/cluster/test_gossip_boot.py index 930ed2c72e..e547a83b7c 100644 --- a/test/cluster/test_gossip_boot.py +++ b/test/cluster/test_gossip_boot.py @@ -12,7 +12,7 @@ async def test_gossip_boot(manager: ManagerClient): cfg = {'error_injections_at_startup': ['gossiper_replicate_sleep'], 'force_gossip_topology_changes': True, - 'enable_tablets': False} + 'tablets_mode_for_new_keyspaces': 'disabled'} servers = [await manager.server_add(config=cfg, timeout=60) for _ in range(3)] logs = [await manager.server_open_log(s.server_id) for s in servers] diff --git a/test/cluster/test_group0_schema_versioning.py b/test/cluster/test_group0_schema_versioning.py index c72cb1b513..974bbebc37 100644 --- a/test/cluster/test_group0_schema_versioning.py +++ b/test/cluster/test_group0_schema_versioning.py @@ -125,7 +125,7 @@ async def test_schema_versioning_with_recovery(manager: ManagerClient): """ cfg = {'enable_user_defined_functions': False, 'force_gossip_topology_changes': True, - 'enable_tablets': False} + 'tablets_mode_for_new_keyspaces': 'disabled'} logger.info("Booting cluster") servers = [await manager.server_add(config=cfg) for _ in range(3)] cql = manager.get_cql() @@ -295,7 +295,7 @@ async def test_upgrade(manager: ManagerClient): # to simulate a non-Raft cluster. cfg = {'enable_user_defined_functions': False, 'force_gossip_topology_changes': True, - 'enable_tablets': False} + 'tablets_mode_for_new_keyspaces': 'disabled'} logger.info("Booting cluster") servers = [await manager.server_add(config=cfg) for _ in range(2)] cql = manager.get_cql() diff --git a/test/cluster/test_raft_fix_broken_snapshot.py b/test/cluster/test_raft_fix_broken_snapshot.py index 65e147fb3d..32ea735f04 100644 --- a/test/cluster/test_raft_fix_broken_snapshot.py +++ b/test/cluster/test_raft_fix_broken_snapshot.py @@ -36,7 +36,7 @@ async def test_raft_fix_broken_snapshot(manager: ManagerClient): cfg = {'enable_user_defined_functions': False, 'force_gossip_topology_changes': True, - 'enable_tablets': False, + 'tablets_mode_for_new_keyspaces': 'disabled', 'error_injections_at_startup': ['raft_sys_table_storage::bootstrap/init_index_0']} srv = await manager.server_add(config=cfg) cql = manager.get_cql() diff --git a/test/cluster/test_raft_recovery_basic.py b/test/cluster/test_raft_recovery_basic.py index b9cc5f6075..7b8427a976 100644 --- a/test/cluster/test_raft_recovery_basic.py +++ b/test/cluster/test_raft_recovery_basic.py @@ -22,7 +22,7 @@ async def test_raft_recovery_basic(request, manager: ManagerClient): # This test uses the gossip-based recovery procedure. cfg = {'enable_user_defined_functions': False, 'force_gossip_topology_changes': True, - 'enable_tablets': False} + 'tablets_mode_for_new_keyspaces': 'disabled'} cmd = ['--logger-log-level', 'raft=trace'] servers = [await manager.server_add(config=cfg, cmdline=cmd) for _ in range(3)] diff --git a/test/cluster/test_raft_recovery_majority_loss.py b/test/cluster/test_raft_recovery_majority_loss.py index c52a7de517..58cdbce609 100644 --- a/test/cluster/test_raft_recovery_majority_loss.py +++ b/test/cluster/test_raft_recovery_majority_loss.py @@ -32,7 +32,7 @@ async def test_recovery_after_majority_loss(request, manager: ManagerClient): """ cfg = {'enable_user_defined_functions': False, 'force_gossip_topology_changes': True, - 'enable_tablets': False} + 'tablets_mode_for_new_keyspaces': 'disabled'} servers = [await manager.server_add(config=cfg) for _ in range(3)] logging.info("Waiting until driver connects to every server") diff --git a/test/cluster/test_raft_recovery_stuck.py b/test/cluster/test_raft_recovery_stuck.py index 0ad939119b..8716b6d0cb 100644 --- a/test/cluster/test_raft_recovery_stuck.py +++ b/test/cluster/test_raft_recovery_stuck.py @@ -40,7 +40,7 @@ async def test_recover_stuck_raft_recovery(request, manager: ManagerClient): """ cfg = {'enable_user_defined_functions': False, 'force_gossip_topology_changes': True, - 'enable_tablets': False} + 'tablets_mode_for_new_keyspaces': 'disabled'} servers = [await manager.server_add(config=cfg) for _ in range(3)] srv1, *others = servers diff --git a/test/cluster/test_raft_recovery_user_data.py b/test/cluster/test_raft_recovery_user_data.py index 21479424fc..6f9df52e07 100644 --- a/test/cluster/test_raft_recovery_user_data.py +++ b/test/cluster/test_raft_recovery_user_data.py @@ -48,7 +48,7 @@ async def test_raft_recovery_user_data(manager: ManagerClient, remove_dead_nodes # CQL requests. cfg = { 'endpoint_snitch': 'GossipingPropertyFileSnitch', - 'enable_tablets': True, + 'tablets_mode_for_new_keyspaces': 'enabled', 'failure_detector_timeout_in_ms': 2000, } property_file_dc1 = {'dc': 'dc1', 'rack': 'rack1'} diff --git a/test/cluster/test_repair.py b/test/cluster/test_repair.py index 36ad72da6c..1ab8d1b27f 100644 --- a/test/cluster/test_repair.py +++ b/test/cluster/test_repair.py @@ -225,7 +225,7 @@ async def test_batchlog_flush_in_repair_without_cache(manager): @pytest.mark.asyncio @skip_mode('release', 'error injections are not supported in release mode') async def test_repair_abort(manager): - cfg = {'enable_tablets': True} + cfg = {'tablets_mode_for_new_keyspaces': 'enabled'} await manager.server_add(config=cfg) await manager.server_add(config=cfg) servers = await manager.running_servers() @@ -264,7 +264,7 @@ async def test_repair_abort(manager): @skip_mode('release', 'error injections are not supported in release mode') async def test_keyspace_drop_during_data_sync_repair(manager): cfg = { - 'enable_tablets': False, + 'tablets_mode_for_new_keyspaces': 'disabled', 'error_injections_at_startup': ['get_keyspace_erms_throw_no_such_keyspace'] } await manager.server_add(config=cfg) diff --git a/test/cluster/test_replace_ignore_nodes.py b/test/cluster/test_replace_ignore_nodes.py index 23b23213ca..874d9d92ac 100644 --- a/test/cluster/test_replace_ignore_nodes.py +++ b/test/cluster/test_replace_ignore_nodes.py @@ -27,7 +27,7 @@ async def test_replace_ignore_nodes(manager: ManagerClient) -> None: """ cfg = {'enable_user_defined_functions': False, 'force_gossip_topology_changes': True, - 'enable_tablets': False} + 'tablets_mode_for_new_keyspaces': 'disabled'} logger.info(f"Booting initial cluster") servers = [await manager.server_add(config=cfg) for _ in range(7)] s2_id = await manager.get_host_id(servers[2].server_id) diff --git a/test/cluster/test_table_drop.py b/test/cluster/test_table_drop.py index 1869a29c44..a258bdee53 100644 --- a/test/cluster/test_table_drop.py +++ b/test/cluster/test_table_drop.py @@ -8,5 +8,5 @@ async def test_drop_table_during_streaming_receiver_side(manager: ManagerClient) 'enable_repair_based_node_ops': False, 'enable_user_defined_functions': False, 'force_gossip_topology_changes': True, - 'enable_tablets': False + 'tablets_mode_for_new_keyspaces': 'disabled' }) for _ in range(2)] diff --git a/test/cluster/test_tablets.py b/test/cluster/test_tablets.py index 03fdaac935..95837e5bd3 100644 --- a/test/cluster/test_tablets.py +++ b/test/cluster/test_tablets.py @@ -31,7 +31,7 @@ logger = logging.getLogger(__name__) @pytest.mark.asyncio async def test_tablet_replication_factor_enough_nodes(manager: ManagerClient): - cfg = {'enable_user_defined_functions': False, 'enable_tablets': True} + cfg = {'enable_user_defined_functions': False, 'tablets_mode_for_new_keyspaces': 'enabled'} servers = await manager.servers_add(2, config=cfg) cql = manager.get_cql() @@ -49,7 +49,7 @@ async def test_tablet_replication_factor_enough_nodes(manager: ManagerClient): @pytest.mark.asyncio async def test_tablet_scaling_option_is_respected(manager: ManagerClient): # 32 is high enough to ensure we demand more tablets than the default choice. - cfg = {'enable_tablets': True, 'tablets_initial_scale_factor': 32} + cfg = {'tablets_mode_for_new_keyspaces': 'enabled', 'tablets_initial_scale_factor': 32} servers = await manager.servers_add(1, config=cfg, cmdline=['--smp', '2']) cql = manager.get_cql() @@ -64,7 +64,7 @@ async def test_tablet_scaling_option_is_respected(manager: ManagerClient): @pytest.mark.asyncio async def test_tablet_cannot_decommision_below_replication_factor(manager: ManagerClient): logger.info("Bootstrapping cluster") - cfg = {'enable_user_defined_functions': False, 'enable_tablets': True} + cfg = {'enable_user_defined_functions': False, 'tablets_mode_for_new_keyspaces': 'enabled'} servers = await manager.servers_add(4, config=cfg) logger.info("Creating table") @@ -93,7 +93,7 @@ async def test_tablet_cannot_decommision_below_replication_factor(manager: Manag async def test_reshape_with_tablets(manager: ManagerClient): logger.info("Bootstrapping cluster") - cfg = {'enable_user_defined_functions': False, 'enable_tablets': True} + cfg = {'enable_user_defined_functions': False, 'tablets_mode_for_new_keyspaces': 'enabled'} server = (await manager.servers_add(1, config=cfg, cmdline=['--smp', '1']))[0] logger.info("Creating table") @@ -130,7 +130,7 @@ async def test_reshape_with_tablets(manager: ManagerClient): @pytest.mark.parametrize("direction", ["up", "down", "none"]) @pytest.mark.asyncio async def test_tablet_rf_change(manager: ManagerClient, direction): - cfg = {'enable_user_defined_functions': False, 'enable_tablets': True} + cfg = {'enable_user_defined_functions': False, 'tablets_mode_for_new_keyspaces': 'enabled'} servers = await manager.servers_add(3, config=cfg) for s in servers: await manager.api.disable_tablet_balancing(s.ip_addr) @@ -197,7 +197,7 @@ async def test_tablet_mutation_fragments_unowned_partition(manager: ManagerClien """Check that MUTATION_FRAGMENTS() queries handle the case when a partition not owned by the node is attempted to be read.""" cfg = {'enable_user_defined_functions': False, - 'enable_tablets': True } + 'tablets_mode_for_new_keyspaces': 'enabled' } servers = await manager.servers_add(3, config=cfg) cql = manager.get_cql() @@ -222,7 +222,7 @@ async def test_tablet_mutation_fragments_unowned_partition(manager: ManagerClien # See also cqlpy/test_tablets.py::test_alter_tablet_keyspace_rf for basic scenarios tested @pytest.mark.asyncio async def test_multidc_alter_tablets_rf(request: pytest.FixtureRequest, manager: ManagerClient) -> None: - config = {"endpoint_snitch": "GossipingPropertyFileSnitch", "enable_tablets": "true"} + config = {"endpoint_snitch": "GossipingPropertyFileSnitch", "tablets_mode_for_new_keyspaces": "enabled"} logger.info("Creating a new cluster of 2 nodes in 1st DC and 2 nodes in 2nd DC") # we have to have at least 2 nodes in each DC if we want to try setting RF to 2 in each DC @@ -268,7 +268,7 @@ async def test_multidc_alter_tablets_rf(request: pytest.FixtureRequest, manager: # from is migrated away. @pytest.mark.asyncio async def test_saved_readers_tablet_migration(manager: ManagerClient, build_mode): - cfg = {'enable_user_defined_functions': False, 'enable_tablets': True} + cfg = {'enable_user_defined_functions': False, 'tablets_mode_for_new_keyspaces': 'enabled'} if build_mode != "release": cfg['error_injections_at_startup'] = [{'name': 'querier-cache-ttl-seconds', 'value': 999999999}] @@ -340,7 +340,7 @@ async def test_saved_readers_tablet_migration(manager: ManagerClient, build_mode @skip_mode('release', 'error injections are not supported in release mode') async def test_read_of_pending_replica_during_migration(manager: ManagerClient, with_cache): logger.info("Bootstrapping cluster") - cfg = {'enable_user_defined_functions': False, 'enable_tablets': True} + cfg = {'enable_user_defined_functions': False, 'tablets_mode_for_new_keyspaces': 'enabled'} cmdline = [ '--logger-log-level', 'storage_service=debug', '--logger-log-level', 'raft_topology=debug', @@ -407,7 +407,7 @@ async def test_read_of_pending_replica_during_migration(manager: ManagerClient, @pytest.mark.parametrize("replication_strategy", ["NetworkTopologyStrategy", "SimpleStrategy", "EverywhereStrategy", "LocalStrategy"]) @pytest.mark.asyncio async def test_keyspace_creation_cql_vs_config_sanity(manager: ManagerClient, with_tablets, replication_strategy): - cfg = {'enable_tablets': with_tablets} + cfg = {'tablets_mode_for_new_keyspaces': 'enabled' if with_tablets else 'disabled'} server = await manager.server_add(config=cfg) cql = manager.get_cql() @@ -444,13 +444,13 @@ async def test_keyspace_creation_cql_vs_config_sanity(manager: ManagerClient, wi @pytest.mark.asyncio async def test_tablets_and_gossip_topology_changes_are_incompatible(manager: ManagerClient): - cfg = {"enable_tablets": True, "force_gossip_topology_changes": True} + cfg = {"tablets_mode_for_new_keyspaces": "enabled", "force_gossip_topology_changes": True} with pytest.raises(Exception, match="Failed to add server"): await manager.server_add(config=cfg) @pytest.mark.asyncio async def test_tablets_disabled_with_gossip_topology_changes(manager: ManagerClient): - cfg = {"enable_tablets": False, "force_gossip_topology_changes": True} + cfg = {"tablets_mode_for_new_keyspaces": "disabled", "force_gossip_topology_changes": True} await manager.server_add(config=cfg) cql = manager.get_cql() async with new_test_keyspace(manager, "WITH replication = {'class': 'NetworkTopologyStrategy', 'replication_factor': 1}") as ks_name: @@ -475,7 +475,7 @@ async def test_tablet_streaming_with_unbuilt_view(manager: ManagerClient): 4) Once migration completes, the view should have the correct number of rows """ logger.info("Starting Node 1") - cfg = {'enable_user_defined_functions': False, 'enable_tablets': True} + cfg = {'enable_user_defined_functions': False, 'tablets_mode_for_new_keyspaces': 'enabled'} cmdline = [ '--logger-log-level', 'storage_service=debug', '--logger-log-level', 'raft_topology=debug', @@ -531,7 +531,7 @@ async def test_tablet_streaming_with_staged_sstables(manager: ManagerClient): 6) Once migration completes, the view should have the correct number of rows """ logger.info("Starting Node 1") - cfg = {'enable_user_defined_functions': False, 'enable_tablets': True} + cfg = {'enable_user_defined_functions': False, 'tablets_mode_for_new_keyspaces': 'enabled'} cmdline = [ '--logger-log-level', 'storage_service=debug', '--logger-log-level', 'raft_topology=debug', @@ -604,7 +604,7 @@ async def test_orphaned_sstables_on_startup(manager: ManagerClient): 7) Attempting to start node1 should fail as it now has an 'orphaned' sstable """ logger.info("Starting Node 1") - cfg = {'enable_user_defined_functions': False, 'enable_tablets': True} + cfg = {'enable_user_defined_functions': False, 'tablets_mode_for_new_keyspaces': 'enabled'} cmdline = [ '--logger-log-level', 'storage_service=debug', '--logger-log-level', 'raft_topology=debug', diff --git a/test/cluster/test_tablets2.py b/test/cluster/test_tablets2.py index 321750fc64..55c634562c 100644 --- a/test/cluster/test_tablets2.py +++ b/test/cluster/test_tablets2.py @@ -844,7 +844,7 @@ async def test_tablet_cleanup_failure(manager: ManagerClient): @pytest.mark.asyncio async def test_tablet_resharding(manager: ManagerClient): cmdline = ['--smp=3'] - config = {'enable_tablets': True} + config = {'tablets_mode_for_new_keyspaces': 'enabled'} servers = await manager.servers_add(1, cmdline=cmdline) server = servers[0] diff --git a/test/cluster/test_tablets_cql.py b/test/cluster/test_tablets_cql.py index 7683b493bb..7cb6cb00ae 100644 --- a/test/cluster/test_tablets_cql.py +++ b/test/cluster/test_tablets_cql.py @@ -21,7 +21,7 @@ logger = logging.getLogger(__name__) @skip_mode('release', 'error injections are not supported in release mode') async def test_alter_dropped_tablets_keyspace(manager: ManagerClient) -> None: config = { - 'enable_tablets': 'true' + 'tablets_mode_for_new_keyspaces': 'enabled' } logger.info("starting a node (the leader)") @@ -72,7 +72,7 @@ async def test_alter_dropped_tablets_keyspace(manager: ManagerClient) -> None: @skip_mode('release', 'error injections are not supported in release mode') async def test_alter_tablets_keyspace_concurrent_modification(manager: ManagerClient) -> None: config = { - 'enable_tablets': 'true' + 'tablets_mode_for_new_keyspaces': 'enabled' } logger.info("starting a node (the leader)") diff --git a/test/cluster/test_tablets_migration.py b/test/cluster/test_tablets_migration.py index 30e580f63f..975c7daa0b 100644 --- a/test/cluster/test_tablets_migration.py +++ b/test/cluster/test_tablets_migration.py @@ -23,7 +23,7 @@ logger = logging.getLogger(__name__) @pytest.mark.asyncio async def test_tablet_transition_sanity(manager: ManagerClient, action): logger.info("Bootstrapping cluster") - cfg = {'enable_user_defined_functions': False, 'enable_tablets': True} + cfg = {'enable_user_defined_functions': False, 'tablets_mode_for_new_keyspaces': 'enabled'} host_ids = [] servers = [] @@ -105,7 +105,7 @@ async def test_node_failure_during_tablet_migration(manager: ManagerClient, fail pytest.skip('Failing source during target cleanup is pointless') logger.info("Bootstrapping cluster") - cfg = {'enable_user_defined_functions': False, 'enable_tablets': True, 'failure_detector_timeout_in_ms': 2000} + cfg = {'enable_user_defined_functions': False, 'tablets_mode_for_new_keyspaces': 'enabled', 'failure_detector_timeout_in_ms': 2000} host_ids = [] servers = [] @@ -249,7 +249,7 @@ async def test_node_failure_during_tablet_migration(manager: ManagerClient, fail @pytest.mark.asyncio async def test_tablet_back_and_forth_migration(manager: ManagerClient): logger.info("Bootstrapping cluster") - cfg = {'enable_user_defined_functions': False, 'enable_tablets': True} + cfg = {'enable_user_defined_functions': False, 'tablets_mode_for_new_keyspaces': 'enabled'} host_ids = [] servers = [] @@ -299,7 +299,7 @@ async def test_tablet_back_and_forth_migration(manager: ManagerClient): async def test_staging_backlog_is_preserved_with_file_based_streaming(manager: ManagerClient): logger.info("Bootstrapping cluster") # the error injection will halt view updates from staging, allowing migration to transfer the view update backlog. - cfg = {'enable_user_defined_functions': False, 'enable_tablets': True, + cfg = {'enable_user_defined_functions': False, 'tablets_mode_for_new_keyspaces': 'enabled', 'error_injections_at_startup': ['view_update_generator_consume_staging_sstable']} servers = [await manager.server_add(config=cfg)] diff --git a/test/cluster/test_topology_failure_recovery.py b/test/cluster/test_topology_failure_recovery.py index 0fd75c9e17..09095805b0 100644 --- a/test/cluster/test_topology_failure_recovery.py +++ b/test/cluster/test_topology_failure_recovery.py @@ -53,7 +53,7 @@ async def remove_error_on(manager: ManagerClient, error_name: str, servers: list @pytest.mark.asyncio @skip_mode('release', 'error injections are not supported in release mode') async def test_tablet_drain_failure_during_decommission(manager: ManagerClient): - cfg = {'enable_user_defined_functions': False, 'enable_tablets': True} + cfg = {'enable_user_defined_functions': False, 'tablets_mode_for_new_keyspaces': 'enabled'} servers = [await manager.server_add(config=cfg) for _ in range(3)] logs = [await manager.server_open_log(srv.server_id) for srv in servers] diff --git a/test/cluster/test_topology_ops.py b/test/cluster/test_topology_ops.py index 80f803e7c8..a437fef4e6 100644 --- a/test/cluster/test_topology_ops.py +++ b/test/cluster/test_topology_ops.py @@ -22,7 +22,7 @@ logger = logging.getLogger(__name__) @pytest.mark.parametrize("tablets_enabled", [True, False]) async def test_topology_ops(request, manager: ManagerClient, tablets_enabled: bool): """Test basic topology operations using the topology coordinator.""" - cfg = {'enable_tablets' : tablets_enabled} + cfg = {'tablets_mode_for_new_keyspaces': 'enabled' if tablets_enabled else 'disabled'} rf = 3 num_nodes = rf if tablets_enabled: diff --git a/test/cluster/test_topology_ops_encrypted.py b/test/cluster/test_topology_ops_encrypted.py index 15ac5eb3e1..41b11d2611 100644 --- a/test/cluster/test_topology_ops_encrypted.py +++ b/test/cluster/test_topology_ops_encrypted.py @@ -25,7 +25,7 @@ async def test_topology_ops_encrypted(request, manager: ManagerClient, tablets_e d.mkdir() k = d / "system_key" k.write_text('AES/CBC/PKCS5Padding:128:ApvJEoFpQmogvam18bb54g==') - cfg = {'enable_tablets' : tablets_enabled, + cfg = {'tablets_mode_for_new_keyspaces': 'enabled' if tablets_enabled else 'disabled', 'user_info_encryption': {'enabled': True, 'key_provider': 'LocalFileSystemKeyProviderFactory'}, 'system_key_directory': d.as_posix()} rf = 3 diff --git a/test/cluster/test_topology_remove_garbage_group0.py b/test/cluster/test_topology_remove_garbage_group0.py index 079bfda313..0c439f9368 100644 --- a/test/cluster/test_topology_remove_garbage_group0.py +++ b/test/cluster/test_topology_remove_garbage_group0.py @@ -28,7 +28,7 @@ async def test_remove_garbage_group0_members(manager: ManagerClient): # 4 servers, one dead cfg = {'enable_user_defined_functions': False, 'force_gossip_topology_changes': True, - 'enable_tablets': False} + 'tablets_mode_for_new_keyspaces': 'disabled'} servers = [await manager.server_add(config=cfg) for _ in range(4)] # Make sure that the driver has connected to all nodes, and they see each other as NORMAL diff --git a/test/cluster/test_topology_upgrade.py b/test/cluster/test_topology_upgrade.py index e97d2af008..add2c4a38c 100644 --- a/test/cluster/test_topology_upgrade.py +++ b/test/cluster/test_topology_upgrade.py @@ -22,7 +22,7 @@ async def test_topology_upgrade_basic(request, build_mode: str, manager: Manager # First, force the first node to start in legacy mode cfg = { 'force_gossip_topology_changes': True, - 'enable_tablets': False, + 'tablets_mode_for_new_keyspaces': 'disabled', 'ring_delay_ms': 15000 if build_mode == 'debug' else 5000, } diff --git a/test/cluster/test_topology_upgrade_not_stuck_after_recent_removal.py b/test/cluster/test_topology_upgrade_not_stuck_after_recent_removal.py index 13f5d3e597..ca57e92bdc 100644 --- a/test/cluster/test_topology_upgrade_not_stuck_after_recent_removal.py +++ b/test/cluster/test_topology_upgrade_not_stuck_after_recent_removal.py @@ -31,7 +31,7 @@ async def test_topology_upgrade_not_stuck_after_recent_removal(request, manager: # First, force the nodes to start in legacy mode due to the error injection cfg = { 'force_gossip_topology_changes': True, - 'enable_tablets': False, + 'tablets_mode_for_new_keyspaces': 'disabled', } logging.info("Creating a two node cluster") diff --git a/test/cluster/test_topology_upgrade_stuck.py b/test/cluster/test_topology_upgrade_stuck.py index c9f2dbad1e..f5802fdbce 100644 --- a/test/cluster/test_topology_upgrade_stuck.py +++ b/test/cluster/test_topology_upgrade_stuck.py @@ -45,7 +45,7 @@ async def test_topology_upgrade_stuck(request, manager: ManagerClient): """ # First, force the first node to start in legacy mode - cfg = {'force_gossip_topology_changes': True, 'enable_tablets': False} + cfg = {'force_gossip_topology_changes': True, 'tablets_mode_for_new_keyspaces': 'disabled'} servers = [await manager.server_add(config=cfg) for _ in range(5)] to_be_upgraded_node, to_be_isolated_node, *to_be_shutdown_nodes = servers diff --git a/test/cluster/test_truncate_with_tablets.py b/test/cluster/test_truncate_with_tablets.py index a2381939e3..e914007e9e 100644 --- a/test/cluster/test_truncate_with_tablets.py +++ b/test/cluster/test_truncate_with_tablets.py @@ -24,7 +24,7 @@ logger = logging.getLogger(__name__) async def test_truncate_while_migration(manager: ManagerClient): logger.info('Bootstrapping cluster') - cfg = { 'enable_tablets': True, + cfg = { 'tablets_mode_for_new_keyspaces': 'enabled', 'error_injections_at_startup': ['migration_streaming_wait'] } @@ -76,7 +76,7 @@ async def get_raft_leader_and_log(manager: ManagerClient, servers): async def test_truncate_with_concurrent_drop(manager: ManagerClient): logger.info('Bootstrapping cluster') - cfg = { 'enable_tablets': True, + cfg = { 'tablets_mode_for_new_keyspaces': 'enabled', 'error_injections_at_startup': ['truncate_table_wait'] } @@ -127,7 +127,7 @@ async def test_truncate_with_concurrent_drop(manager: ManagerClient): async def test_truncate_while_node_restart(manager: ManagerClient): logger.info('Bootstrapping cluster') - cfg = { 'enable_tablets': True } + cfg = { 'tablets_mode_for_new_keyspaces': 'enabled' } servers = [] servers.append(await manager.server_add(config=cfg)) @@ -175,7 +175,7 @@ async def test_truncate_while_node_restart(manager: ManagerClient): async def test_truncate_with_coordinator_crash(manager: ManagerClient): logger.info('Bootstrapping cluster') - cfg = { 'enable_tablets': True } + cfg = { 'tablets_mode_for_new_keyspaces': 'enabled' } servers = [] servers.append(await manager.server_add(config=cfg)) @@ -221,7 +221,7 @@ async def test_truncate_with_coordinator_crash(manager: ManagerClient): async def test_truncate_while_truncate_already_waiting(manager: ManagerClient): logger.info('Bootstrapping cluster') - cfg = { 'enable_tablets': True, + cfg = { 'tablets_mode_for_new_keyspaces': 'enabled', 'error_injections_at_startup': ['migration_streaming_wait'] } diff --git a/test/cluster/test_view_build_status.py b/test/cluster/test_view_build_status.py index 2aaa0361a0..cd0a1ea88f 100644 --- a/test/cluster/test_view_build_status.py +++ b/test/cluster/test_view_build_status.py @@ -196,7 +196,7 @@ async def test_view_build_status_snapshot(manager: ManagerClient): @pytest.mark.asyncio async def test_view_build_status_migration_to_v2(request, manager: ManagerClient): # First, force the first node to start in legacy mode - cfg = {'force_gossip_topology_changes': True, 'enable_tablets': False} + cfg = {'force_gossip_topology_changes': True, 'tablets_mode_for_new_keyspaces': 'disabled'} servers = [await manager.server_add(config=cfg)] # Enable raft-based node operations for subsequent nodes - they should fall back to @@ -248,7 +248,7 @@ async def test_view_build_status_migration_to_v2(request, manager: ManagerClient @pytest.mark.asyncio async def test_view_build_status_migration_to_v2_with_write_during_migration(request, manager: ManagerClient): # First, force the first node to start in legacy mode - cfg = {'force_gossip_topology_changes': True, 'enable_tablets': False} + cfg = {'force_gossip_topology_changes': True, 'tablets_mode_for_new_keyspaces': 'disabled'} servers = [await manager.server_add(config=cfg)] # Enable raft-based node operations for subsequent nodes - they should fall back to @@ -306,7 +306,7 @@ async def test_view_build_status_migration_to_v2_with_write_during_migration(req @pytest.mark.asyncio async def test_view_build_status_migration_to_v2_barrier(request, manager: ManagerClient): # First, force the first node to start in legacy mode - cfg = {'force_gossip_topology_changes': True, 'enable_tablets': False} + cfg = {'force_gossip_topology_changes': True, 'tablets_mode_for_new_keyspaces': 'disabled'} servers = [await manager.server_add(config=cfg)] # Enable raft-based node operations for subsequent nodes - they should fall back to @@ -424,7 +424,7 @@ async def test_view_build_status_with_replace_node(manager: ManagerClient): @pytest.mark.asyncio async def test_view_build_status_migration_to_v2_with_cleanup(request, manager: ManagerClient): # First, force the first node to start in legacy mode - cfg = {'force_gossip_topology_changes': True, 'enable_tablets': False} + cfg = {'force_gossip_topology_changes': True, 'tablets_mode_for_new_keyspaces': 'disabled'} servers = [await manager.server_add(config=cfg)] # Enable raft-based node operations for subsequent nodes - they should fall back to diff --git a/test/cluster/test_zero_token_nodes_topology_ops.py b/test/cluster/test_zero_token_nodes_topology_ops.py index 20b7df8c6a..3882405d6a 100644 --- a/test/cluster/test_zero_token_nodes_topology_ops.py +++ b/test/cluster/test_zero_token_nodes_topology_ops.py @@ -27,11 +27,11 @@ async def test_zero_token_nodes_topology_ops(manager: ManagerClient, tablets_ena logging.info('Trying to add a zero-token server in the gossip-based topology') await manager.server_add(config={'join_ring': False, 'force_gossip_topology_changes': True, - 'enable_tablets': False}, + 'tablets_mode_for_new_keyspaces': 'disabled'}, expected_error='the raft-based topology is disabled') - normal_cfg = {'enable_tablets': tablets_enabled} - zero_token_cfg = {'enable_tablets': tablets_enabled, 'join_ring': False} + normal_cfg = {'tablets_mode_for_new_keyspaces': 'enabled' if tablets_enabled else 'disabled'} + zero_token_cfg = {'tablets_mode_for_new_keyspaces': 'enabled' if tablets_enabled else 'disabled', 'join_ring': False} logging.info('Adding the first server') server_a = await manager.server_add(config=normal_cfg) diff --git a/test/perf/perf_simple_query.cc b/test/perf/perf_simple_query.cc index b4c8367212..c182a6389c 100644 --- a/test/perf/perf_simple_query.cc +++ b/test/perf/perf_simple_query.cc @@ -579,7 +579,7 @@ int scylla_simple_query_main(int argc, char** argv) { db_cfg->enable_cache(enable_cache); cql_test_config cfg(db_cfg); if (app.configuration().contains("tablets")) { - cfg.db_config->enable_tablets.set(true); + cfg.db_config->tablets_mode_for_new_keyspaces.set(db::tablets_mode_t::mode::enabled); cfg.initial_tablets = app.configuration()["initial-tablets"].as(); } set_from_cli("audit", app, cfg.db_config->audit); diff --git a/test/perf/perf_tablets.cc b/test/perf/perf_tablets.cc index 50906c0c5c..9327d565b2 100644 --- a/test/perf/perf_tablets.cc +++ b/test/perf/perf_tablets.cc @@ -39,7 +39,7 @@ static const size_t MiB = 1 << 20; static cql_test_config tablet_cql_test_config() { cql_test_config c; - c.db_config->enable_tablets.set(true); + c.db_config->tablets_mode_for_new_keyspaces.set(db::tablets_mode_t::mode::enabled); return c; } From 62aeba759b6bf6dada0a2c516d738af88b6c4665 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Sun, 12 Jan 2025 12:49:58 +0200 Subject: [PATCH 2/3] tablets: enforce tablets using tablets_mode_for_new_keyspaces=enforced config option `tablets_mode_for_new_keyspaces=enforced` enables tablets by default for new keyspaces, like `tablets_mode_for_new_keyspaces=enabled`. However, it does not allow to opt-out when creating new keyspaces by setting `tablets = {'enabled': false}`. Refs scylladb/scylla-enterprise#4355 Signed-off-by: Benny Halevy --- conf/scylla.yaml | 6 ++++++ cql3/statements/ks_prop_defs.cc | 9 +++++++-- cql3/statements/ks_prop_defs.hh | 2 +- db/config.cc | 4 +++- db/config.hh | 5 +++++ docs/architecture/tablets.rst | 8 ++++---- gms/feature_service.cc | 2 +- test/boost/tablets_test.cc | 15 +++++++++++++++ 8 files changed, 42 insertions(+), 9 deletions(-) diff --git a/conf/scylla.yaml b/conf/scylla.yaml index a8e0a313e0..795df68148 100644 --- a/conf/scylla.yaml +++ b/conf/scylla.yaml @@ -836,6 +836,12 @@ maintenance_socket: ignore # unless tablets are explicitly enabled in the CREATE KEYSPACE query # by using the `tablets = {'enabled': true}` replication option. # +# When set to `enforced`, newly created keyspaces will always have tablets enabled by default. +# This prevents explicitly disabling tablets in the CREATE KEYSPACE query +# using the `tablets = {'enabled': false}` replication option. +# It also mandates a replication strategy supporting tablets, like +# NetworkTopologyStrategy +# # Note that creating keyspaces with tablets enabled or disabled is irreversible. # The `tablets` option cannot be changed using `ALTER KEYSPACE`. tablets_mode_for_new_keyspaces: enabled diff --git a/cql3/statements/ks_prop_defs.cc b/cql3/statements/ks_prop_defs.cc index f9db5576ce..2a82ebe946 100644 --- a/cql3/statements/ks_prop_defs.cc +++ b/cql3/statements/ks_prop_defs.cc @@ -150,7 +150,7 @@ data_dictionary::storage_options ks_prop_defs::get_storage_options() const { return opts; } -std::optional ks_prop_defs::get_initial_tablets(std::optional default_value) const { +std::optional ks_prop_defs::get_initial_tablets(std::optional default_value, bool enforce_tablets) const { auto tablets_options = get_map(KW_TABLETS); if (!tablets_options) { return default_value; @@ -165,6 +165,9 @@ std::optional ks_prop_defs::get_initial_tablets(std::optional ks_prop_defs::as_ks_metadata(s auto sc = get_replication_strategy_class().value(); // if tablets options have not been specified, but tablets are globally enabled, set the value to 0 for N.T.S. only auto enable_tablets = feat.tablets && cfg.enable_tablets_by_default(); - auto initial_tablets = get_initial_tablets(enable_tablets && locator::abstract_replication_strategy::to_qualified_class_name(sc) == "org.apache.cassandra.locator.NetworkTopologyStrategy" ? std::optional(0) : std::nullopt); + std::optional default_initial_tablets = enable_tablets && locator::abstract_replication_strategy::to_qualified_class_name(sc) == "org.apache.cassandra.locator.NetworkTopologyStrategy" + ? std::optional(0) : std::nullopt; + auto initial_tablets = get_initial_tablets(default_initial_tablets, cfg.enforce_tablets()); auto options = prepare_options(sc, tm, get_replication_options()); return data_dictionary::keyspace_metadata::new_keyspace(ks_name, sc, std::move(options), initial_tablets, get_boolean(KW_DURABLE_WRITES, true), get_storage_options()); diff --git a/cql3/statements/ks_prop_defs.hh b/cql3/statements/ks_prop_defs.hh index 276aefd4df..03a6f0cb62 100644 --- a/cql3/statements/ks_prop_defs.hh +++ b/cql3/statements/ks_prop_defs.hh @@ -60,7 +60,7 @@ public: void validate(); std::map get_replication_options() const; std::optional get_replication_strategy_class() const; - std::optional get_initial_tablets(std::optional default_value) const; + std::optional get_initial_tablets(std::optional default_value, bool enforce_tablets = false) const; data_dictionary::storage_options get_storage_options() const; bool get_durable_writes() const; lw_shared_ptr as_ks_metadata(sstring ks_name, const locator::token_metadata&, const gms::feature_service&, const db::config&); diff --git a/db/config.cc b/db/config.cc index 8b352fe94c..33dde6b56b 100644 --- a/db/config.cc +++ b/db/config.cc @@ -1400,7 +1400,7 @@ db::config::config(std::shared_ptr exts) , tablets_mode_for_new_keyspaces(this, "tablets_mode_for_new_keyspaces", value_status::Used, tablets_mode_t::mode::unset, "Control tablets for new keyspaces. Can be set to the following values:\n" "\tdisabled: New keyspaces use vnodes by default, unless enabled by the tablets={'enabled':true} option\n" "\tenabled: New keyspaces use tablets by default, unless disabled by the tablets={'disabled':true} option\n" - ) + "\tenforced: New keyspaces must use tablets. Tablets cannot be disabled using the CREATE KEYSPACE option") , view_flow_control_delay_limit_in_ms(this, "view_flow_control_delay_limit_in_ms", liveness::LiveUpdate, value_status::Used, 1000, "The maximal amount of time that materialized-view update flow control may delay responses " "to try to slow down the client and prevent buildup of unfinished view updates. " @@ -1645,6 +1645,8 @@ std::unordered_map db::tablets_mode_t::map() {"0", db::tablets_mode_t::mode::disabled}, {"enabled", db::tablets_mode_t::mode::enabled}, {"1", db::tablets_mode_t::mode::enabled}, + {"enforced", db::tablets_mode_t::mode::enforced}, + {"2", db::tablets_mode_t::mode::enforced} }; } diff --git a/db/config.hh b/db/config.hh index e936b607d8..2c0aef0219 100644 --- a/db/config.hh +++ b/db/config.hh @@ -144,6 +144,7 @@ struct tablets_mode_t { unset = -1, disabled = 0, enabled = 1, + enforced = 2 }; static std::unordered_map map(); // for enum_option<> }; @@ -560,9 +561,13 @@ public: case tablets_mode_t::mode::disabled: return false; case tablets_mode_t::mode::enabled: + case tablets_mode_t::mode::enforced: return true; } } + bool enforce_tablets() const noexcept { + return tablets_mode_for_new_keyspaces() == tablets_mode_t::mode::enforced; + } named_value view_flow_control_delay_limit_in_ms; diff --git a/docs/architecture/tablets.rst b/docs/architecture/tablets.rst index c665c312f6..1e6fa01e90 100644 --- a/docs/architecture/tablets.rst +++ b/docs/architecture/tablets.rst @@ -94,11 +94,11 @@ controlled by the :confval:`tablets_mode_for_new_keyspaces` option. However, tab supported on all nodes within the cluster. When creating a new keyspace with tablets enabled by default, you can still opt-out -on a per-keyspace basis. The recommended ``NetworkTopologyStrategy`` for keyspaces -remains *required* even if tablets are disabled. +on a per-keyspace basis using ``CREATE KEYSPACE WITH tablets = {'enabled': false}``, +unless the :confval:`tablets_mode_for_new_keyspaces` option is set to ``enforced``. -You can create a keyspace with tablets -disabled with the ``tablets = {'enabled': false}`` option: +Note: The recommended ``NetworkTopologyStrategy`` for keyspaces +remains *required* even if tablets are disabled. .. code:: cql diff --git a/gms/feature_service.cc b/gms/feature_service.cc index 64a23b056b..eadb69c4d4 100644 --- a/gms/feature_service.cc +++ b/gms/feature_service.cc @@ -87,7 +87,7 @@ feature_config feature_config_from_db_config(const db::config& cfg, std::set +#include #undef SEASTAR_TESTING_MAIN #include #include "test/lib/random_utils.hh" @@ -3899,6 +3900,20 @@ SEASTAR_TEST_CASE(test_explicit_tablets_disable) { co_await test_create_keyspace("test_explictly_enabled_128", true, cfg, 128); } +// Test that when tablets they cannot be explicitly disabled +// when creating a keyspace when the `enable_tablets` +// configuration option is set to `force`. +SEASTAR_TEST_CASE(test_enforce_tablets) { + auto cfg = tablet_cql_test_config(db::tablets_mode_t::mode::enforced); + + // By default tablets are enabled + co_await test_create_keyspace("test_default_settings", std::nullopt, cfg); + + // Tablets cannot be explicitly disabled for a new keyspace + auto f = co_await coroutine::as_future(test_create_keyspace("test_not_explictly_disabled", false, cfg)); + BOOST_REQUIRE_THROW(f.get(), exceptions::configuration_exception); +} + SEASTAR_TEST_CASE(test_recognition_of_deprecated_name_for_resize_transition) { using transition_state = service::topology::transition_state; BOOST_REQUIRE_EQUAL(service::transition_state_from_string("tablet split finalization"), transition_state::tablet_split_finalization); From 9fac0045d132f0e058cc994a33f96e54c1e0ef43 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Mon, 13 Jan 2025 12:21:49 +0200 Subject: [PATCH 3/3] boost/tablets_test: verify failure to create keyspace with tablets and non network replication strategy Signed-off-by: Benny Halevy --- test/boost/tablets_test.cc | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/test/boost/tablets_test.cc b/test/boost/tablets_test.cc index e41252683d..219df156f2 100644 --- a/test/boost/tablets_test.cc +++ b/test/boost/tablets_test.cc @@ -3827,7 +3827,7 @@ SEASTAR_TEST_CASE(test_cleanup_of_deallocated_tablet) { namespace { -future<> test_create_keyspace(sstring ks_name, std::optional tablets_opt, const cql_test_config& cfg, uint64_t initial_tablets = 0) { +future<> test_create_keyspace(sstring ks_name, std::optional tablets_opt, const cql_test_config& cfg, uint64_t initial_tablets = 0, sstring replication_strategy = "NetworkTopologyStrategy") { co_await do_with_cql_env_thread([&] (cql_test_env& e) { sstring extra; if (tablets_opt) { @@ -3841,7 +3841,7 @@ future<> test_create_keyspace(sstring ks_name, std::optional tablets_opt, extra = " and tablets = { 'enabled' : false }"; } } - auto q = format("create keyspace {} with replication = {{ 'class' : 'NetworkTopologyStrategy', 'replication_factor' : 1 }}{};", ks_name, extra); + auto q = format("create keyspace {} with replication = {{ 'class' : '{}', 'replication_factor' : 1 }}{};", ks_name, replication_strategy, extra); testlog.debug("{}", q); e.execute_cql(q).get(); BOOST_REQUIRE(e.local_db().has_keyspace(ks_name)); @@ -3881,6 +3881,14 @@ SEASTAR_TEST_CASE(test_explicit_tablets_enable) { // Tablets can also be explicitly disabled for a new keyspace co_await test_create_keyspace("test_explictly_disabled", false, cfg); + + // Replication strategies that do not support tablets cannot be used when tablets are explicitly enabled + for (const auto& [rs_desc, rs_type] : db::replication_strategy_restriction_t::map()) { + if (rs_type != locator::replication_strategy_type::network_topology) { + auto f = co_await coroutine::as_future(test_create_keyspace("test_unsupported_replication_strategy", true, cfg, 0, rs_desc)); + BOOST_REQUIRE_THROW(f.get(), exceptions::configuration_exception); + } + } } // Test that tablets can be explicitly disabled @@ -3912,6 +3920,14 @@ SEASTAR_TEST_CASE(test_enforce_tablets) { // Tablets cannot be explicitly disabled for a new keyspace auto f = co_await coroutine::as_future(test_create_keyspace("test_not_explictly_disabled", false, cfg)); BOOST_REQUIRE_THROW(f.get(), exceptions::configuration_exception); + + // Replication strategies that do not support tablets cannot be used when tablets are explicitly enabled + for (const auto& [rs_desc, rs_type] : db::replication_strategy_restriction_t::map()) { + if (rs_type != locator::replication_strategy_type::network_topology) { + auto f = co_await coroutine::as_future(test_create_keyspace("test_unsupported_replication_strategy", true, cfg, 0, rs_desc)); + BOOST_REQUIRE_THROW(f.get(), exceptions::configuration_exception); + } + } } SEASTAR_TEST_CASE(test_recognition_of_deprecated_name_for_resize_transition) {