scylla/policies/load_balancing/
mod.rs

1//! Load balancing configurations\
2//! `Session` can use any load balancing policy which implements the `LoadBalancingPolicy` trait\
3//! See [the book](https://rust-driver.docs.scylladb.com/stable/load-balancing/load-balancing.html) for more information
4
5use crate::cluster::{ClusterState, NodeRef};
6use crate::{
7    errors::RequestAttemptError,
8    routing::{Shard, Token},
9};
10use scylla_cql::frame::{response::result::TableSpec, types};
11
12use std::time::Duration;
13
14mod default;
15mod plan;
16pub use default::{DefaultPolicy, DefaultPolicyBuilder, LatencyAwarenessBuilder};
17pub use plan::Plan;
18
19/// Represents info about statement that can be used by load balancing policies.
20#[derive(Default, Clone, Debug)]
21#[non_exhaustive]
22pub struct RoutingInfo<'a> {
23    /// Requested consistency information allows to route requests to the appropriate
24    /// datacenters. E.g. requests with a LOCAL_ONE consistency should be routed to the same
25    /// datacenter.
26    pub consistency: types::Consistency,
27    pub serial_consistency: Option<types::SerialConsistency>,
28
29    /// Information that are the basis of token-aware routing:
30    /// - token, keyspace for vnodes-based routing;
31    /// - token, keyspace, table for tablets-based routing.
32    pub token: Option<Token>,
33    pub table: Option<&'a TableSpec<'a>>,
34
35    /// If, while preparing, we received from the cluster information that the statement is an LWT,
36    /// then we can use this information for routing optimisation. Namely, an optimisation
37    /// can be performed: the request should be routed to the replicas in a predefined order
38    /// (i. e. always try first to contact replica A, then B if it fails, then C, etc.).
39    /// If false, the request should be routed normally.
40    /// Note: this a Scylla-specific optimisation. Therefore, the flag will be always false for Cassandra.
41    pub is_confirmed_lwt: bool,
42}
43
44/// The fallback list of nodes in the request plan.
45///
46/// It is computed on-demand, only if querying the most preferred node fails
47/// (or when speculative execution is triggered).
48pub type FallbackPlan<'a> =
49    Box<dyn Iterator<Item = (NodeRef<'a>, Option<Shard>)> + Send + Sync + 'a>;
50
51/// Policy that decides which nodes and shards to contact for each request.
52///
53/// When a request is prepared to be sent to ScyllaDB/Cassandra, a `LoadBalancingPolicy`
54/// implementation constructs a load balancing plan. That plan is a list of
55/// targets (target is a node + an optional shard) to which
56/// the driver will try to send the request. The first elements of the plan are the targets which are
57/// the best to contact (e.g. they might have the lowest latency).
58///
59/// Most requests are sent on the first try, so the request execution layer rarely needs to know more
60/// than one target from plan. To better optimize that case, `LoadBalancingPolicy` has two methods:
61/// `pick` and `fallback`. `pick` returns the first target to contact for a given request, `fallback`
62/// returns the rest of the load balancing plan.
63///
64/// `fallback` is called not only if a send to `pick`ed node failed (or when executing
65/// speculatively), but also if `pick` returns `None`.
66///
67/// Usually the driver needs only the first node from load balancing plan (most requests are send
68/// successfully, and there is no need to retry).
69///
70/// This trait is used to produce an iterator of nodes to contact for a given request.
71pub trait LoadBalancingPolicy: Send + Sync + std::fmt::Debug {
72    /// Returns the first node to contact for a given request.
73    fn pick<'a>(
74        &'a self,
75        request: &'a RoutingInfo,
76        cluster: &'a ClusterState,
77    ) -> Option<(NodeRef<'a>, Option<Shard>)>;
78
79    /// Returns all contact-appropriate nodes for a given request.
80    fn fallback<'a>(
81        &'a self,
82        request: &'a RoutingInfo,
83        cluster: &'a ClusterState,
84    ) -> FallbackPlan<'a>;
85
86    /// Invoked each time a request succeeds.
87    fn on_request_success(&self, _request: &RoutingInfo, _latency: Duration, _node: NodeRef<'_>) {}
88
89    /// Invoked each time a request fails.
90    fn on_request_failure(
91        &self,
92        _request: &RoutingInfo,
93        _latency: Duration,
94        _node: NodeRef<'_>,
95        _error: &RequestAttemptError,
96    ) {
97    }
98
99    /// Returns the name of load balancing policy.
100    fn name(&self) -> String;
101}