diff --git a/scylla/src/transport/cluster.rs b/scylla/src/transport/cluster.rs index 309fe58157..59ca67b4bc 100644 --- a/scylla/src/transport/cluster.rs +++ b/scylla/src/transport/cluster.rs @@ -185,6 +185,7 @@ impl Cluster { &None, host_filter.as_deref(), TabletsInfo::new(), + &HashMap::new(), ) .await; cluster_data.wait_until_all_pools_are_initialized().await; @@ -278,6 +279,7 @@ impl ClusterData { used_keyspace: &Option, host_filter: Option<&dyn HostFilter>, mut tablets: TabletsInfo, + old_keyspaces: &HashMap, ) -> Self { // Create new updated known_peers and ring let mut new_known_peers: HashMap> = @@ -323,6 +325,26 @@ impl ClusterData { } } + let keyspaces: HashMap = metadata + .keyspaces + .into_iter() + .filter_map(|(ks_name, ks)| match ks { + Ok(ks) => Some((ks_name, ks)), + Err(e) => { + if let Some(old_ks) = old_keyspaces.get(&ks_name) { + warn!("Encountered an error while processing metadata of keyspace \"{ks_name}\": {e}.\ + Re-using older version of this keyspace metadata"); + Some((ks_name, old_ks.clone())) + } else { + warn!("Encountered an error while processing metadata of keyspace \"{ks_name}\": {e}.\ + No previous version of this keyspace metadata found, so it will not be\ + present in ClusterData until next refresh."); + None + } + } + }) + .collect(); + { let removed_nodes = { let mut removed_nodes = HashSet::new(); @@ -336,7 +358,7 @@ impl ClusterData { }; let table_predicate = |spec: &TableSpec| { - if let Some(ks) = metadata.keyspaces.get(spec.ks_name()) { + if let Some(ks) = keyspaces.get(spec.ks_name()) { ks.tables.contains_key(spec.table_name()) } else { false @@ -364,7 +386,6 @@ impl ClusterData { ) } - let keyspaces = metadata.keyspaces; let (locator, keyspaces) = tokio::task::spawn_blocking(move || { let keyspace_strategies = keyspaces.values().map(|ks| &ks.strategy); let locator = ReplicaLocator::new(ring.into_iter(), keyspace_strategies, tablets); @@ -706,6 +727,7 @@ impl ClusterWorker { &self.used_keyspace, self.host_filter.as_deref(), cluster_data.locator.tablets.clone(), + &cluster_data.keyspaces, ) .await, ); diff --git a/scylla/src/transport/load_balancing/default.rs b/scylla/src/transport/load_balancing/default.rs index 16fd6ac9aa..6c4d237cd7 100644 --- a/scylla/src/transport/load_balancing/default.rs +++ b/scylla/src/transport/load_balancing/default.rs @@ -1410,6 +1410,7 @@ mod tests { &None, None, TabletsInfo::new(), + &HashMap::new(), ) .await } @@ -1440,6 +1441,7 @@ mod tests { &None, None, TabletsInfo::new(), + &HashMap::new(), ) .await } @@ -2489,6 +2491,7 @@ mod tests { Some(&FHostFilter) }, TabletsInfo::new(), + &HashMap::new(), ) .await; diff --git a/scylla/src/transport/locator/mod.rs b/scylla/src/transport/locator/mod.rs index 6770b7b5b8..61b0ae8d83 100644 --- a/scylla/src/transport/locator/mod.rs +++ b/scylla/src/transport/locator/mod.rs @@ -857,21 +857,39 @@ mod tests { check( 160, None, - &metadata.keyspaces.get(KEYSPACE_NTS_RF_3).unwrap().strategy, + &metadata + .keyspaces + .get(KEYSPACE_NTS_RF_3) + .unwrap() + .as_ref() + .unwrap() + .strategy, TABLE_NTS_RF_3, vec![F, A, C, D, G, E], ); check( 160, None, - &metadata.keyspaces.get(KEYSPACE_NTS_RF_2).unwrap().strategy, + &metadata + .keyspaces + .get(KEYSPACE_NTS_RF_2) + .unwrap() + .as_ref() + .unwrap() + .strategy, TABLE_NTS_RF_2, vec![F, A, D, G], ); check( 160, None, - &metadata.keyspaces.get(KEYSPACE_SS_RF_2).unwrap().strategy, + &metadata + .keyspaces + .get(KEYSPACE_SS_RF_2) + .unwrap() + .as_ref() + .unwrap() + .strategy, TABLE_SS_RF_2, vec![F, A], ); @@ -879,21 +897,39 @@ mod tests { check( 160, Some("eu"), - &metadata.keyspaces.get(KEYSPACE_NTS_RF_3).unwrap().strategy, + &metadata + .keyspaces + .get(KEYSPACE_NTS_RF_3) + .unwrap() + .as_ref() + .unwrap() + .strategy, TABLE_NTS_RF_3, vec![A, C, G], ); check( 160, Some("us"), - &metadata.keyspaces.get(KEYSPACE_NTS_RF_3).unwrap().strategy, + &metadata + .keyspaces + .get(KEYSPACE_NTS_RF_3) + .unwrap() + .as_ref() + .unwrap() + .strategy, TABLE_NTS_RF_3, vec![F, D, E], ); check( 160, Some("eu"), - &metadata.keyspaces.get(KEYSPACE_SS_RF_2).unwrap().strategy, + &metadata + .keyspaces + .get(KEYSPACE_SS_RF_2) + .unwrap() + .as_ref() + .unwrap() + .strategy, TABLE_SS_RF_2, vec![A], ); diff --git a/scylla/src/transport/locator/precomputed_replicas.rs b/scylla/src/transport/locator/precomputed_replicas.rs index 69851df507..08f3feaa01 100644 --- a/scylla/src/transport/locator/precomputed_replicas.rs +++ b/scylla/src/transport/locator/precomputed_replicas.rs @@ -231,14 +231,14 @@ mod tests { let mut metadata = mock_metadata_for_token_aware_tests(); metadata.keyspaces = [( "SimpleStrategy{rf=2}".into(), - Keyspace { + Ok(Keyspace { strategy: Strategy::SimpleStrategy { replication_factor: 2, }, tables: HashMap::new(), views: HashMap::new(), user_defined_types: HashMap::new(), - }, + }), )] .iter() .cloned() @@ -251,7 +251,7 @@ mod tests { metadata .keyspaces .values() - .map(|keyspace| &keyspace.strategy), + .map(|keyspace| &keyspace.as_ref().unwrap().strategy), ); let check = |token, replication_factor, expected_node_ids| { @@ -293,7 +293,7 @@ mod tests { metadata .keyspaces .values() - .map(|keyspace| &keyspace.strategy), + .map(|keyspace| &keyspace.as_ref().unwrap().strategy), ); let check = |token, dc, replication_factor, expected_node_ids| { diff --git a/scylla/src/transport/locator/test.rs b/scylla/src/transport/locator/test.rs index 2622eb99a6..cf67ef758d 100644 --- a/scylla/src/transport/locator/test.rs +++ b/scylla/src/transport/locator/test.rs @@ -120,18 +120,18 @@ pub(crate) fn mock_metadata_for_token_aware_tests() -> Metadata { let keyspaces = [ ( KEYSPACE_SS_RF_2.into(), - Keyspace { + Ok(Keyspace { strategy: Strategy::SimpleStrategy { replication_factor: 2, }, tables: HashMap::new(), views: HashMap::new(), user_defined_types: HashMap::new(), - }, + }), ), ( KEYSPACE_NTS_RF_2.into(), - Keyspace { + Ok(Keyspace { strategy: Strategy::NetworkTopologyStrategy { datacenter_repfactors: [("eu".to_owned(), 2), ("us".to_owned(), 2)] .into_iter() @@ -140,11 +140,11 @@ pub(crate) fn mock_metadata_for_token_aware_tests() -> Metadata { tables: HashMap::new(), views: HashMap::new(), user_defined_types: HashMap::new(), - }, + }), ), ( KEYSPACE_NTS_RF_3.into(), - Keyspace { + Ok(Keyspace { strategy: Strategy::NetworkTopologyStrategy { datacenter_repfactors: [("eu".to_owned(), 3), ("us".to_owned(), 3)] .into_iter() @@ -153,7 +153,7 @@ pub(crate) fn mock_metadata_for_token_aware_tests() -> Metadata { tables: HashMap::new(), views: HashMap::new(), user_defined_types: HashMap::new(), - }, + }), ), ] .iter() @@ -201,7 +201,10 @@ pub(crate) fn create_ring(metadata: &Metadata) -> impl Iterator ReplicaLocator { let ring = create_ring(metadata); - let strategies = metadata.keyspaces.values().map(|ks| &ks.strategy); + let strategies = metadata + .keyspaces + .values() + .map(|ks| &ks.as_ref().unwrap().strategy); ReplicaLocator::new(ring, strategies, TabletsInfo::new()) } diff --git a/scylla/src/transport/topology.rs b/scylla/src/transport/topology.rs index 943ff3f8ed..4bb591b5db 100644 --- a/scylla/src/transport/topology.rs +++ b/scylla/src/transport/topology.rs @@ -70,7 +70,7 @@ pub(crate) struct MetadataReader { /// Describes all metadata retrieved from the cluster pub(crate) struct Metadata { pub(crate) peers: Vec, - pub(crate) keyspaces: HashMap, + pub(crate) keyspaces: HashMap>, } #[non_exhaustive] // <- so that we can add more fields in a backwards-compatible way @@ -280,7 +280,7 @@ pub struct UserDefinedType { /// Represents a user defined type whose definition is missing from the metadata. #[derive(Clone, Debug, Error)] #[error("Missing UDT: {keyspace}, {name}")] -struct MissingUserDefinedType { +pub(crate) struct MissingUserDefinedType { name: String, keyspace: String, } @@ -791,17 +791,6 @@ async fn query_metadata( return Err(MetadataError::Peers(PeersMetadataError::EmptyTokenLists).into()); } - let keyspaces = keyspaces - .into_iter() - .filter_map(|(ks_name, ks)| match ks { - Ok(ks) => Some((ks_name, ks)), - Err(e) => { - warn!("Error while processing keyspace \"{ks_name}\": {e}"); - None - } - }) - .collect(); - Ok(Metadata { peers, keyspaces }) }