Skip to content

Commit a4f9ecd

Browse files
committed
cluster: define and implement cass_cluster_set_load_balance_rack_aware[_n]
This is an extension introduced by Scylla's fork of cpp-driver. See: scylladb/cpp-driver@9691ec0 Note: I removed this part of the docstring: ``` * With empty local_rack and local_dc, default local_dc and local_rack * is chosen from the first connected contact point, * and no remote hosts are considered in query plans. * If relying on this mechanism, be sure to use only contact * points from the local rack. ``` There are multiple reasons for this: - this behaviour does not make much sense, and we should not mimic it IMO - rust-driver does not behave like this - this is not even true for cpp-driver Why it's not true for cpp-driver: If you carefully study the changes introduced to cpp-driver in the aforementioned commit, you will notice that it's not possible for the driver to use rack aware policy with an empty strings. This is because API functions reject empty string, thus RackAwarePolicy object is never constructed in such case. ``` CassError cass_cluster_set_load_balance_rack_aware_n(CassCluster* cluster, const char* local_dc, size_t local_dc_length, const char* local_rack, size_t local_rack_length) { if (local_dc == NULL || local_dc_length == 0 || local_rack == NULL || local_rack_length == 0) { return CASS_ERROR_LIB_BAD_PARAMS; } cluster->config().set_load_balancing_policy(new RackAwarePolicy( String(local_dc, local_dc_length), String(local_rack, local_rack_length))); return CASS_OK; } ``` Why is this part of docstring included in cpp-driver then? No idea. Maybe, because `cass_cluster_set_load_balance_dc_aware` mentions something similar for empty (non-specified) dc. However, in this case it's true, since dc awareness is enabled by default in cpp-driver. See the docstring: ``` * Configures the cluster to use DC-aware load balancing. * For each query, all live nodes in a primary 'local' DC are tried first, * followed by any node from other DCs. * * <b>Note:</b> This is the default, and does not need to be called unless * switching an existing from another policy or changing settings. * Without further configuration, a default local_dc is chosen from the * first connected contact point, and no remote hosts are considered in * query plans. If relying on this mechanism, be sure to use only contact * points from the local DC. ```
1 parent 3379c0d commit a4f9ecd

File tree

3 files changed

+165
-1
lines changed

3 files changed

+165
-1
lines changed

include/cassandra.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2219,6 +2219,46 @@ cass_cluster_set_load_balance_dc_aware_n(CassCluster* cluster,
22192219
unsigned used_hosts_per_remote_dc,
22202220
cass_bool_t allow_remote_dcs_for_local_cl);
22212221

2222+
2223+
/**
2224+
* Configures the cluster to use Rack-aware load balancing.
2225+
* For each query, all live nodes in a primary 'local' rack are tried first,
2226+
* followed by nodes from local DC and then nodes from other DCs.
2227+
*
2228+
* @public @memberof CassCluster
2229+
*
2230+
* @param[in] cluster
2231+
* @param[in] local_dc The primary data center to try first
2232+
* @param[in] local_rack The primary rack to try first
2233+
* @return CASS_OK if successful, otherwise an error occurred
2234+
*/
2235+
CASS_EXPORT CassError
2236+
cass_cluster_set_load_balance_rack_aware(CassCluster* cluster,
2237+
const char* local_dc,
2238+
const char* local_rack);
2239+
2240+
2241+
/**
2242+
* Same as cass_cluster_set_load_balance_rack_aware(), but with lengths for string
2243+
* parameters.
2244+
*
2245+
* @public @memberof CassCluster
2246+
*
2247+
* @param[in] cluster
2248+
* @param[in] local_dc
2249+
* @param[in] local_dc_length
2250+
* @return same as cass_cluster_set_load_balance_dc_aware()
2251+
*
2252+
* @see cass_cluster_set_load_balance_dc_aware()
2253+
*/
2254+
CASS_EXPORT CassError
2255+
cass_cluster_set_load_balance_rack_aware_n(CassCluster* cluster,
2256+
const char* local_dc,
2257+
size_t local_dc_length,
2258+
const char* local_rack,
2259+
size_t local_rack_length);
2260+
2261+
22222262
/**
22232263
* Configures the cluster to use token-aware request routing or not.
22242264
*

scylla-rust-wrapper/extern/cassandra.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,6 +1087,7 @@ cass_execution_profile_set_load_balance_dc_aware_n(CassExecProfile* profile,
10871087
unsigned used_hosts_per_remote_dc,
10881088
cass_bool_t allow_remote_dcs_for_local_cl);
10891089

1090+
10901091
/**
10911092
* Configures the execution profile to use token-aware request routing or not.
10921093
*
@@ -2219,6 +2220,52 @@ cass_cluster_set_load_balance_dc_aware_n(CassCluster* cluster,
22192220
unsigned used_hosts_per_remote_dc,
22202221
cass_bool_t allow_remote_dcs_for_local_cl);
22212222

2223+
2224+
/**
2225+
* Configures the cluster to use Rack-aware load balancing.
2226+
* For each query, all live nodes in a primary 'local' rack are tried first,
2227+
* followed by nodes from local DC and then nodes from other DCs.
2228+
*
2229+
* With empty local_rack and local_dc, default local_dc and local_rack
2230+
* is chosen from the first connected contact point,
2231+
* and no remote hosts are considered in query plans.
2232+
* If relying on this mechanism, be sure to use only contact
2233+
* points from the local rack.
2234+
*
2235+
* @public @memberof CassCluster
2236+
*
2237+
* @param[in] cluster
2238+
* @param[in] local_dc The primary data center to try first
2239+
* @param[in] local_rack The primary rack to try first
2240+
* @return CASS_OK if successful, otherwise an error occurred
2241+
*/
2242+
CASS_EXPORT CassError
2243+
cass_cluster_set_load_balance_rack_aware(CassCluster* cluster,
2244+
const char* local_dc,
2245+
const char* local_rack);
2246+
2247+
2248+
/**
2249+
* Same as cass_cluster_set_load_balance_rack_aware(), but with lengths for string
2250+
* parameters.
2251+
*
2252+
* @public @memberof CassCluster
2253+
*
2254+
* @param[in] cluster
2255+
* @param[in] local_dc
2256+
* @param[in] local_dc_length
2257+
* @return same as cass_cluster_set_load_balance_dc_aware()
2258+
*
2259+
* @see cass_cluster_set_load_balance_dc_aware()
2260+
*/
2261+
CASS_EXPORT CassError
2262+
cass_cluster_set_load_balance_rack_aware_n(CassCluster* cluster,
2263+
const char* local_dc,
2264+
size_t local_dc_length,
2265+
const char* local_rack,
2266+
size_t local_rack_length);
2267+
2268+
22222269
/**
22232270
* Configures the cluster to use token-aware request routing or not.
22242271
*

scylla-rust-wrapper/src/cluster.rs

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ pub(crate) struct LoadBalancingConfig {
4242
pub(crate) token_awareness_enabled: bool,
4343
pub(crate) token_aware_shuffling_replicas_enabled: bool,
4444
pub(crate) dc_awareness: Option<DcAwareness>,
45+
pub(crate) rack_awareness: Option<RackAwareness>,
4546
pub(crate) latency_awareness_enabled: bool,
4647
pub(crate) latency_awareness_builder: LatencyAwarenessBuilder,
4748
}
@@ -55,11 +56,18 @@ impl LoadBalancingConfig {
5556
builder =
5657
builder.enable_shuffling_replicas(self.token_aware_shuffling_replicas_enabled);
5758
}
58-
if let Some(dc_awareness) = self.dc_awareness {
59+
60+
// Prioritize rack awareness if user for some reason set both rack+dc and dc preferencies.
61+
if let Some(rack_awareness) = self.rack_awareness {
62+
builder = builder
63+
.prefer_datacenter_and_rack(rack_awareness.local_dc, rack_awareness.local_rack)
64+
.permit_dc_failover(true)
65+
} else if let Some(dc_awareness) = self.dc_awareness {
5966
builder = builder
6067
.prefer_datacenter(dc_awareness.local_dc)
6168
.permit_dc_failover(true)
6269
}
70+
6371
if self.latency_awareness_enabled {
6472
builder = builder.latency_awareness(self.latency_awareness_builder);
6573
}
@@ -72,6 +80,7 @@ impl Default for LoadBalancingConfig {
7280
token_awareness_enabled: true,
7381
token_aware_shuffling_replicas_enabled: true,
7482
dc_awareness: None,
83+
rack_awareness: None,
7584
latency_awareness_enabled: false,
7685
latency_awareness_builder: Default::default(),
7786
}
@@ -83,6 +92,12 @@ pub(crate) struct DcAwareness {
8392
pub(crate) local_dc: String,
8493
}
8594

95+
#[derive(Clone, Debug)]
96+
pub(crate) struct RackAwareness {
97+
pub(crate) local_dc: String,
98+
pub(crate) local_rack: String,
99+
}
100+
86101
#[derive(Clone)]
87102
pub struct CassCluster {
88103
session_builder: SessionBuilder,
@@ -477,6 +492,68 @@ pub unsafe extern "C" fn cass_cluster_set_load_balance_dc_aware_n(
477492
)
478493
}
479494

495+
#[no_mangle]
496+
pub unsafe extern "C" fn cass_cluster_set_load_balance_rack_aware(
497+
cluster_raw: *mut CassCluster,
498+
local_dc_raw: *const c_char,
499+
local_rack_raw: *const c_char,
500+
) -> CassError {
501+
cass_cluster_set_load_balance_rack_aware_n(
502+
cluster_raw,
503+
local_dc_raw,
504+
strlen(local_dc_raw),
505+
local_rack_raw,
506+
strlen(local_rack_raw),
507+
)
508+
}
509+
510+
#[no_mangle]
511+
pub unsafe extern "C" fn cass_cluster_set_load_balance_rack_aware_n(
512+
cluster_raw: *mut CassCluster,
513+
local_dc_raw: *const c_char,
514+
local_dc_length: size_t,
515+
local_rack_raw: *const c_char,
516+
local_rack_length: size_t,
517+
) -> CassError {
518+
let cluster = ptr_to_ref_mut(cluster_raw);
519+
520+
set_load_balance_rack_aware_n(
521+
&mut cluster.load_balancing_config,
522+
local_dc_raw,
523+
local_dc_length,
524+
local_rack_raw,
525+
local_rack_length,
526+
)
527+
}
528+
529+
unsafe fn set_load_balance_rack_aware_n(
530+
load_balancing_config: &mut LoadBalancingConfig,
531+
local_dc_raw: *const c_char,
532+
local_dc_length: size_t,
533+
local_rack_raw: *const c_char,
534+
local_rack_length: size_t,
535+
) -> CassError {
536+
let (local_dc, local_rack) = match (
537+
ptr_to_cstr_n(local_dc_raw, local_dc_length),
538+
ptr_to_cstr_n(local_rack_raw, local_rack_length),
539+
) {
540+
(Some(local_dc_str), Some(local_rack_str))
541+
if local_dc_length > 0 && local_rack_length > 0 =>
542+
{
543+
(local_dc_str.to_owned(), local_rack_str.to_owned())
544+
}
545+
// One of them is either null pointer, is an empty string or is not a proper utf-8.
546+
_ => return CassError::CASS_ERROR_LIB_BAD_PARAMS,
547+
};
548+
549+
load_balancing_config.rack_awareness = Some(RackAwareness {
550+
local_dc,
551+
local_rack,
552+
});
553+
554+
CassError::CASS_OK
555+
}
556+
480557
#[no_mangle]
481558
pub unsafe extern "C" fn cass_cluster_set_cloud_secure_connection_bundle_n(
482559
_cluster_raw: *mut CassCluster,

0 commit comments

Comments
 (0)