From 303047f09517a79f170fa778bc3e2c49cda31e37 Mon Sep 17 00:00:00 2001 From: Ariel Weisberg Date: Tue, 20 May 2025 15:32:56 -0400 Subject: [PATCH] Rename transient to witness Remove unused and unimplemented in C* witness_write metric Update transient replication tests to be since 5.1 in anticipation of 5.1 not keeping compatibility with transient replication --- replica_side_filtering_test.py | 16 ++-- ...est.py => witness_replication_ring_test.py | 34 +++---- ...ion_test.py => witness_replication_test.py | 89 +++++++++---------- 3 files changed, 67 insertions(+), 72 deletions(-) rename transient_replication_ring_test.py => witness_replication_ring_test.py (93%) rename transient_replication_test.py => witness_replication_test.py (90%) diff --git a/replica_side_filtering_test.py b/replica_side_filtering_test.py index 0a86d268f2..f689d6113c 100644 --- a/replica_side_filtering_test.py +++ b/replica_side_filtering_test.py @@ -516,7 +516,7 @@ class TestAllowFiltering(ReplicaSideFiltering): def create_index(self): return False - def _test_missed_update_with_transient_replicas(self, missed_by_transient): + def _test_missed_update_with_witness_replicas(self, missed_by_witness): cluster = self.cluster cluster.set_configuration_options(values={'hinted_handoff_enabled': False, 'num_tokens': 1, @@ -541,7 +541,7 @@ def _test_missed_update_with_transient_replicas(self, missed_by_transient): self.session.execute("INSERT INTO t(k, v) VALUES (0, 'old')") # update the previous value with CL=ONE only in one replica - node = cluster.nodelist()[1 if missed_by_transient else 0] + node = cluster.nodelist()[1 if missed_by_witness else 0] node.byteman_submit([mk_bman_path('stop_writes.btm')]) self.session.execute(SimpleStatement("UPDATE t SET v = 'new' WHERE k = 0", consistency_level=CL.ONE)) @@ -549,10 +549,10 @@ def _test_missed_update_with_transient_replicas(self, missed_by_transient): self._assert_none("SELECT * FROM t WHERE v = 'old'") self._assert_one("SELECT * FROM t WHERE v = 'new'", row=[0, 'new']) - @since('4.0') - def test_update_missed_by_transient_replica(self): - self._test_missed_update_with_transient_replicas(missed_by_transient=True) + @since('5.1') + def test_update_missed_by_witness_replica(self): + self._test_missed_update_with_witness_replicas(missed_by_witness=True) - @since('4.0') - def test_update_only_on_transient_replica(self): - self._test_missed_update_with_transient_replicas(missed_by_transient=False) + @since('5.1') + def test_update_only_on_witness_replica(self): + self._test_missed_update_with_witness_replicas(missed_by_witness=False) diff --git a/transient_replication_ring_test.py b/witness_replication_ring_test.py similarity index 93% rename from transient_replication_ring_test.py rename to witness_replication_ring_test.py index 7d7cfb2527..22b235056d 100644 --- a/transient_replication_ring_test.py +++ b/witness_replication_ring_test.py @@ -57,8 +57,8 @@ def new_start(self, *args, **kwargs): startable.start = types.MethodType(new_start, startable) -@since('4.0') -class TestTransientReplicationRing(Tester): +@since('5.1') +class TestWitnessReplicationRing(Tester): keyspace = "ks" table = "tbl" @@ -177,8 +177,8 @@ def test_bootstrap_and_cleanup(self): self.check_expected(sessions, expected) - # Ensure that there is at least some transient data around, because of this if it's missing after bootstrap - # We know we failed to get it from the transient replica losing the range entirely + # Ensure that there is at least some witness data around, because of this if it's missing after bootstrap + # We know we failed to get it from the witness replica losing the range entirely nodes[1].stop(wait_other_notice=True) for i in range(1, 40, 2): @@ -193,7 +193,7 @@ def test_bootstrap_and_cleanup(self): gen_expected(range(0, 21, 2), range(32, 40, 2)), gen_expected(range(1, 11, 2), range(11, 31), range(31, 40, 2))] - # Every node should have some of its fully replicated data and one and two should have some transient data + # Every node should have some of its fully replicated data and one and two should have some witness data self.check_expected(sessions, expected) node4 = new_node(self.cluster, bootstrap=True, token='00040') @@ -204,20 +204,20 @@ def test_bootstrap_and_cleanup(self): expected.append(gen_expected(range(11, 20, 2), range(21, 40))) sessions.append(self.exclusive_cql_connection(node4)) - # Because repair was never run and nodes had transient data it will have data for transient ranges (node1, 11-20) + # Because repair was never run and nodes had witness data it will have data for witness ranges (node1, 11-20) assert_all(sessions[3], self.select(), expected[3], cl=NODELOCAL) - # Node1 no longer transiently replicates 11-20, so cleanup will clean it up - # Node1 also now transiently replicates 21-30 and half the values in that range were repaired + # Node1 no longer witness replicates 11-20, so cleanup will clean it up + # Node1 also now witness replicates 21-30 and half the values in that range were repaired expected[0] = gen_expected(range(0, 11), range(21, 30, 2), range(31, 40)) # Node2 still missing data since it was down during some insertions, it also lost some range (31-40) expected[1] = gen_expected(range(0, 21, 2)) expected[2] = gen_expected(range(1, 11, 2), range(11, 31)) - # Cleanup should only impact if a node lost a range entirely or started to transiently replicate it and the data + # Cleanup should only impact if a node lost a range entirely or started to witness it and the data # was repaired self.check_expected(sessions, expected, nodes, cleanup=True) @@ -249,8 +249,8 @@ def move_test(self, move_token, expected_after_move, expected_after_repair): # Make sure at least a little data is repaired repair_nodes(nodes) - # Ensure that there is at least some transient data around, because of this if it's missing after bootstrap - # We know we failed to get it from the transient replica losing the range entirely + # Ensure that there is at least some witness data around, because of this if it's missing after bootstrap + # We know we failed to get it from the witness replica losing the range entirely nodes[1].stop(wait_other_notice=True) for i in range(1, 40, 2): @@ -357,8 +357,8 @@ def test_decommission(self): # Make sure at least a little data is repaired repair_nodes(nodes) - # Ensure that there is at least some transient data around, because of this if it's missing after bootstrap - # We know we failed to get it from the transient replica losing the range entirely + # Ensure that there is at least some witness data around, because of this if it's missing after bootstrap + # We know we failed to get it from the witness replica losing the range entirely nodes[1].stop(wait_other_notice=True) for i in range(1, 40, 2): @@ -375,7 +375,7 @@ def test_decommission(self): self.check_expected(sessions, expected) - # node1 has transient data we want to see streamed out on move + # node1 has witness data we want to see streamed out on move nodes[3].nodetool('decommission') nodes = nodes[:-1] @@ -392,7 +392,7 @@ def test_decommission(self): repair_nodes(nodes) - # There should be no transient data anywhere + # There should be no witness data anywhere expected = [gen_expected(range(0, 11), range(21, 40)), gen_expected(range(0, 21), range(31, 40)), gen_expected(range(11, 31))] @@ -402,7 +402,7 @@ def test_decommission(self): @pytest.mark.no_vnodes def test_remove(self): - """Test a mix of ring change operations across a mix of transient and repaired/unrepaired data""" + """Test a mix of ring change operations across a mix of witness and repaired/unrepaired data""" node4 = new_node(self.cluster, bootstrap=True, token='00040') patch_start(node4) node4.start(wait_for_binary_proto=True) @@ -423,7 +423,7 @@ def test_remove(self): gen_expected(range(0, 21), range(31, 40)), gen_expected(range(11, 31))] - # Every node should some of its fully replicated data and one and two should have some transient data + # Every node should some of its fully replicated data and one and two should have some witness data self.check_expected(sessions, expected) nodes[0].nodetool('removenode ' + node4_id) diff --git a/transient_replication_test.py b/witness_replication_test.py similarity index 90% rename from transient_replication_test.py rename to witness_replication_test.py index 2f7707e46b..8b8013fe1c 100644 --- a/transient_replication_test.py +++ b/witness_replication_test.py @@ -37,7 +37,6 @@ def __init__(self, node, keyspace, table): self.jmx = JolokiaAgent(node) self.write_latency_mbean = make_mbean("metrics", type="Table", name="WriteLatency", keyspace=keyspace, scope=table) self.speculative_reads_mbean = make_mbean("metrics", type="Table", name="SpeculativeRetries", keyspace=keyspace, scope=table) - self.transient_writes_mbean = make_mbean("metrics", type="Table", name="TransientWrites", keyspace=keyspace, scope=table) @property def write_count(self): @@ -47,10 +46,6 @@ def write_count(self): def speculative_reads(self): return self.jmx.read_attribute(self.speculative_reads_mbean, "Count") - @property - def transient_writes(self): - return self.jmx.read_attribute(self.transient_writes_mbean, "Count") - def start(self): self.jmx.start() @@ -160,8 +155,8 @@ def uuid_or_none(s): assert len(names) == len(repaired_times) == len(pending_repairs) return [SSTable(*a) for a in zip(names, repaired_times, pending_repairs)] -@since('4.0') -class TransientReplicationBase(Tester): +@since('5.1') +class WitnessReplicationBase(Tester): keyspace = "ks" table = "tbl" @@ -179,7 +174,7 @@ def populate(self): def set_nodes(self): self.node1, self.node2, self.node3 = self.nodes - # Make sure digest is not attempted against the transient node + # Make sure digest is not attempted against the witness node self.node3.byteman_submit([mk_bman_path('throw_on_digest.btm')]) def use_lcs(self): @@ -277,12 +272,12 @@ def split(self, arr): def generate_rows(self, partitions, rows): return [[pk, ck, pk+ck] for ck in range(rows) for pk in range(partitions)] -@since('4.0') -class TestTransientReplication(TransientReplicationBase): +@since('5.1') +class TestWitnessReplication(WitnessReplicationBase): @pytest.mark.no_vnodes - def test_transient_noop_write(self): - """ If both full replicas are available, nothing should be written to the transient replica """ + def test_witness_noop_write(self): + """ If both full replicas are available, nothing should be written to the witness replica """ for node in self.nodes: self.assert_has_no_sstables(node) @@ -301,8 +296,8 @@ def test_transient_noop_write(self): self.assert_has_no_sstables(self.node3, flush=True) @pytest.mark.no_vnodes - def test_transient_write(self): - """ If write can't succeed on full replica, it's written to the transient node instead """ + def test_witness_write(self): + """ If write can't succeed on full replica, it's written to the witness node instead """ for node in self.nodes: self.assert_has_no_sstables(node) @@ -322,13 +317,13 @@ def test_transient_write(self): self.assert_local_rows(self.node2, [[1, 1, 1]]) - # transient replica should hold only the second row + # witness replica should hold only the second row self.assert_local_rows(self.node3, [[1, 2, 2]]) @pytest.mark.no_vnodes - def test_transient_full_merge_read(self): - """ When reading, transient replica should serve a missing read """ + def test_witness_full_merge_read(self): + """ When reading, witness replica should serve a missing read """ for node in self.nodes: self.assert_has_no_sstables(node) @@ -341,7 +336,7 @@ def test_transient_full_merge_read(self): # Stop reads from the node that will hold the second row self.node1.stop() - # Whether we're reading from the full node or from the transient node, we should get consistent results + # Whether we're reading from the full node or from the witness node, we should get consistent results for node in [self.node2, self.node3]: assert_all(self.exclusive_cql_connection(node), "SELECT * FROM %s.%s" % (self.keyspace, self.table), @@ -351,7 +346,7 @@ def test_transient_full_merge_read(self): @pytest.mark.no_vnodes def test_srp(self): - """ When reading, transient replica should serve a missing read """ + """ When reading, witness replica should serve a missing read """ for node in self.nodes: self.assert_has_no_sstables(node) @@ -366,23 +361,23 @@ def test_srp(self): # Stop reads from the node that will hold the second row self.node1.stop() - # Whether we're reading from the full node or from the transient node, we should get consistent results + # Whether we're reading from the full node or from the witness node, we should get consistent results assert_all(self.exclusive_cql_connection(self.node3), "SELECT * FROM %s.%s LIMIT 1" % (self.keyspace, self.table), [[1, 2, 2]], cl=ConsistencyLevel.QUORUM) @pytest.mark.no_vnodes - def test_transient_full_merge_read_with_delete_transient_coordinator(self): - self._test_transient_full_merge_read_with_delete(self.node3) + def test_witness_full_merge_read_with_delete_witness_coordinator(self): + self._test_witness_full_merge_read_with_delete(self.node3) @pytest.mark.no_vnodes - def test_transient_full_merge_read_with_delete_full_coordinator(self): - self._test_transient_full_merge_read_with_delete(self.node2) + def test_witness_full_merge_read_with_delete_full_coordinator(self): + self._test_witness_full_merge_read_with_delete(self.node2) @pytest.mark.no_vnodes - def _test_transient_full_merge_read_with_delete(self, coordinator): - """ When reading, transient replica should serve a missing read """ + def _test_witness_full_merge_read_with_delete(self, coordinator): + """ When reading, witness replica should serve a missing read """ for node in self.nodes: self.assert_has_no_sstables(node) @@ -405,7 +400,7 @@ def _test_transient_full_merge_read_with_delete(self, coordinator): @pytest.mark.no_vnodes def test_cheap_quorums(self): - """ writes shouldn't make it to transient nodes """ + """ writes shouldn't make it to witness nodes """ session = self.exclusive_cql_connection(self.node1) for node in self.nodes: self.assert_has_no_sstables(node) @@ -423,7 +418,7 @@ def test_cheap_quorums(self): @pytest.mark.no_vnodes def test_speculative_write(self): - """ if a full replica isn't responding, we should send the write to the transient replica """ + """ if a full replica isn't responding, we should send the write to the witness replica """ session = self.exclusive_cql_connection(self.node1) self.node2.byteman_submit([mk_bman_path('slow_writes.btm')]) @@ -444,14 +439,14 @@ def test_keyspace_rf_changes(self): with pytest.raises(ConfigurationException): session.execute("ALTER KEYSPACE %s WITH REPLICATION={%s}" % (self.keyspace, replication_params)) -@since('4.0') -class TestTransientReplicationRepairStreamEntireSSTable(TransientReplicationBase): +@since('5.1') +class TestWitnessReplicationRepairStreamEntireSSTable(WitnessReplicationBase): stream_entire_sstables = True def _test_speculative_write_repair_cycle(self, primary_range, optimized_repair, repair_coordinator, expect_node3_data, use_lcs=False): """ - if one of the full replicas is not available, data should be written to the transient replica, but removed after incremental repair + if one of the full replicas is not available, data should be written to the witness replica, but removed after incremental repair """ for node in self.nodes: self.assert_has_no_sstables(node) @@ -524,8 +519,8 @@ def test_optimized_primary_range_repair_with_lcs(self): use_lcs=True) @pytest.mark.no_vnodes - def test_transient_incremental_repair(self): - """ transiently replicated ranges should be skipped when coordinating repairs """ + def test_witness_incremental_repair(self): + """ witnessly replicated ranges should be skipped when coordinating repairs """ self._test_speculative_write_repair_cycle(primary_range=True, optimized_repair=False, repair_coordinator=self.node1, @@ -533,7 +528,7 @@ def test_transient_incremental_repair(self): @pytest.mark.no_vnodes def test_full_repair_from_full_replica(self): - """ full repairs shouldn't replicate data to transient replicas """ + """ full repairs shouldn't replicate data to witness replicas """ session = self.exclusive_cql_connection(self.node1) for node in self.nodes: self.assert_has_no_sstables(node) @@ -551,8 +546,8 @@ def test_full_repair_from_full_replica(self): self.assert_has_no_sstables(self.node3, flush=True) @pytest.mark.no_vnodes - def test_full_repair_from_transient_replica(self): - """ full repairs shouldn't replicate data to transient replicas """ + def test_full_repair_from_witness_replica(self): + """ full repairs shouldn't replicate data to witness replicas """ session = self.exclusive_cql_connection(self.node1) for node in self.nodes: self.assert_has_no_sstables(node) @@ -569,13 +564,13 @@ def test_full_repair_from_transient_replica(self): self.assert_has_sstables(self.node2, flush=True) self.assert_has_no_sstables(self.node3, flush=True) -@since('4.0') -class TestTransientReplicationRepairLegacyStreaming(TestTransientReplicationRepairStreamEntireSSTable): +@since('5.1') +class TestWitnessReplicationRepairLegacyStreaming(TestWitnessReplicationRepairStreamEntireSSTable): stream_entire_sstables = False -@since('4.0') -class TestTransientReplicationSpeculativeQueries(TransientReplicationBase): +@since('5.1') +class TestWitnessReplicationSpeculativeQueries(WitnessReplicationBase): def setup_schema(self): session = self.exclusive_cql_connection(self.node1) replication_params = OrderedDict() @@ -587,7 +582,7 @@ def setup_schema(self): @pytest.mark.no_vnodes def test_always_speculate(self): - """ If write can't succeed on full replica, it's written to the transient node instead """ + """ If write can't succeed on full replica, it's written to the witness node instead """ session = self.exclusive_cql_connection(self.node1) session.execute("ALTER TABLE %s.%s WITH speculative_retry = 'ALWAYS';" % (self.keyspace, self.table)) self.insert_row(1, 1, 1) @@ -604,7 +599,7 @@ def test_always_speculate(self): @pytest.mark.no_vnodes def test_custom_speculate(self): - """ If write can't succeed on full replica, it's written to the transient node instead """ + """ If write can't succeed on full replica, it's written to the witness node instead """ session = self.exclusive_cql_connection(self.node1) session.execute("ALTER TABLE %s.%s WITH speculative_retry = '99.99PERCENTILE';" % (self.keyspace, self.table)) self.insert_row(1, 1, 1) @@ -619,8 +614,8 @@ def test_custom_speculate(self): [1, 2, 2]], cl=ConsistencyLevel.QUORUM) -@since('4.0') -class TestMultipleTransientNodes(TransientReplicationBase): +@since('5.1') +class TestMultipleWitnessNodes(WitnessReplicationBase): replication_factor = '5/2' tokens = [0, 1, 2, 3, 4] @@ -635,8 +630,8 @@ def set_nodes(self): @pytest.mark.resource_intensive @pytest.mark.no_vnodes - def test_transient_full_merge_read(self): - """ When reading, transient replica should serve a missing read """ + def test_witness_full_merge_read(self): + """ When reading, witness replica should serve a missing read """ for node in self.nodes: self.assert_has_no_sstables(node) @@ -661,7 +656,7 @@ def test_transient_full_merge_read(self): # Stop reads from the node that will hold the second row self.node1.stop() - # Whether we're reading from the full node or from the transient node, we should get consistent results + # Whether we're reading from the full node or from the witness node, we should get consistent results for node in [self.node2, self.node3, self.node4, self.node5]: assert_all(self.exclusive_cql_connection(node), "SELECT * FROM %s.%s" % (self.keyspace, self.table),