Skip to content

Commit c14edfa

Browse files
committed
policies: treat SERIAL/LOCAL_SERIAL consistency as LWT for routing
Statements with SERIAL or LOCAL_SERIAL consistency level are serialized through the Paxos path on the server, but TokenAwarePolicy only checked is_lwt() (from server prepare metadata) when deciding whether to skip replica shuffling. This meant serial-consistency reads could be routed with shuffled replicas instead of the deterministic order needed for optimal Paxos coordination. Now TokenAwarePolicy also checks the statement's consistency level and skips shuffling for SERIAL/LOCAL_SERIAL, matching LWT routing behavior. Fixes: #886
1 parent cf01c3f commit c14edfa

2 files changed

Lines changed: 30 additions & 1 deletion

File tree

cassandra/policies.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ def make_query_plan(self, working_keyspace=None, query=None):
514514
else:
515515
replicas = self._cluster_metadata.get_replicas(keyspace, query.routing_key)
516516

517-
if self.shuffle_replicas and not query.is_lwt():
517+
if self.shuffle_replicas and not query.is_lwt() and not ConsistencyLevel.is_serial(query.consistency_level):
518518
shuffle(replicas)
519519

520520
def yield_in_order(hosts):

tests/unit/test_policies.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -944,6 +944,35 @@ def _assert_shuffle(self, patched_shuffle, cluster, keyspace, routing_key):
944944
assert patched_shuffle.call_count == 1
945945

946946

947+
@patch('cassandra.policies.shuffle')
948+
def test_no_shuffle_for_serial_consistency(self, patched_shuffle):
949+
"""
950+
Test to validate that replicas are not shuffled when the statement
951+
has SERIAL or LOCAL_SERIAL consistency level, since such statements
952+
should be routed like LWT requests.
953+
@jira_ticket PYTHON-1394
954+
@expected_result shuffle should not be called for serial consistency
955+
956+
@test_category policy
957+
"""
958+
for cl in (ConsistencyLevel.SERIAL, ConsistencyLevel.LOCAL_SERIAL):
959+
for cluster in (self._prepare_cluster_with_vnodes(), self._prepare_cluster_with_tablets()):
960+
patched_shuffle.reset_mock()
961+
hosts = cluster.metadata.all_hosts()
962+
child_policy = Mock()
963+
child_policy.make_query_plan.return_value = hosts
964+
child_policy.distance.return_value = HostDistance.LOCAL
965+
966+
policy = TokenAwarePolicy(child_policy, shuffle_replicas=True)
967+
policy.populate(cluster, hosts)
968+
969+
query = Statement(routing_key='routing_key')
970+
query.consistency_level = cl
971+
list(policy.make_query_plan('keyspace', query))
972+
assert patched_shuffle.call_count == 0, \
973+
"shuffle should not be called for consistency level %s" % cl
974+
975+
947976
class ConvictionPolicyTest(unittest.TestCase):
948977
def test_not_implemented(self):
949978
"""

0 commit comments

Comments
 (0)