Skip to content

4.x: BasicLoadBalancingPolicy.getReplicas() is always empty with Tablets enabled #497

@scrat98

Description

@scrat98

Problem
In Cassandra to calculate a Token we only need keyspace and partition key. TokenFactory (or Partitioner in Scylla) is an internal API and does not exposed https://github.com/apache/cassandra-java-driver/blob/4.x/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java#L313

After introducing the Tablets #379, now we also need a table, but what's most important we need Partitioner, because we can obtain Tablet only having Token and the TabletMap does not provide similar to the TokenMap method where we can pass only partition key without partitioner. https://github.com/scylladb/java-driver/blob/scylla-4.x/core/src/main/java/com/datastax/oss/driver/internal/core/loadbalancing/BasicLoadBalancingPolicy.java#L353

For that reason current implementation relies that Request will have Partitioner, that's not the case, because default implementation returns null for all Statements except of DefaultBoundStatement that delegates to the PreparedStatement.getPartitioner(). But if we'll have a look at DefaultPreparedStatement creation we'll find that Partitioner not null only for scylla CDC tables.
https://github.com/scylladb/java-driver/blob/scylla-4.x/core/src/main/java/com/datastax/oss/driver/internal/core/cql/Conversions.java#L390
https://github.com/scylladb/java-driver/blob/scylla-4.x/core/src/main/java/com/datastax/oss/driver/internal/core/metadata/PartitionerFactory.java#L45

Therefore, partitioner is always null that leads to the empty replica list and breaks load balancing at all.

Solution
According to the doc of Request.getPartitioner() method

The partitioner to use for token-aware routing. If null, the cluster-wide partitioner will be used.

Therefore, it's necessary to obtain TokenFactory also from the DefaultTokenMap, like it does here https://github.com/scylladb/java-driver/blob/scylla-4.x/core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java#L291

Steps to repo

  • Setup multi node scylla cluster.
  • Create keyspace with RF = 1
  • Create simple table (p, c, v)
  • Create prepared statement like "SELECT * FROM table WHERE p = ?"
  • Bind this prepared statement N times with the same partition key
  • Use session.context.loadBalancingPolicy.newQueryPlan(statement)
  • You'll find that queryPlan every time just a round robin of the cluster node, but it must prioritized the same single node each time, because we're using ShardAwarePolicy and the same partition key should point to the same node in our case

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions