@@ -1116,7 +1116,8 @@ impl Session {
11161116 } ;
11171117
11181118 self . handle_set_keyspace_response ( & response) . await ?;
1119- self . handle_auto_await_schema_agreement ( & response) . await ?;
1119+ self . handle_auto_await_schema_agreement ( & response, coordinator. node ( ) . host_id )
1120+ . await ?;
11201121
11211122 let ( result, paging_state_response) =
11221123 response. into_query_result_and_paging_state ( coordinator) ?;
@@ -1144,10 +1145,12 @@ impl Session {
11441145 async fn handle_auto_await_schema_agreement (
11451146 & self ,
11461147 response : & NonErrorQueryResponse ,
1148+ coordinator_id : Uuid ,
11471149 ) -> Result < ( ) , ExecutionError > {
11481150 if self . schema_agreement_automatic_waiting {
11491151 if response. as_schema_change ( ) . is_some ( ) {
1150- self . await_schema_agreement ( ) . await ?;
1152+ self . await_schema_agreement_with_required_node ( Some ( coordinator_id) )
1153+ . await ?;
11511154 }
11521155
11531156 if self . refresh_metadata_on_auto_schema_agreement
@@ -1489,7 +1492,8 @@ impl Session {
14891492 } ;
14901493
14911494 self . handle_set_keyspace_response ( & response) . await ?;
1492- self . handle_auto_await_schema_agreement ( & response) . await ?;
1495+ self . handle_auto_await_schema_agreement ( & response, coordinator. node ( ) . host_id )
1496+ . await ?;
14931497
14941498 let ( result, paging_state_response) =
14951499 response. into_query_result_and_paging_state ( coordinator) ?;
@@ -2160,10 +2164,19 @@ impl Session {
21602164 ///
21612165 /// Issues an agreement check each `Session::schema_agreement_interval`.
21622166 /// Loops indefinitely until the agreement is reached.
2163- async fn await_schema_agreement_indefinitely ( & self ) -> Result < Uuid , SchemaAgreementError > {
2167+ ///
2168+ /// If `required_node` is Some, only returns Ok if this node successfully
2169+ /// returned its schema version during the agreement process.
2170+ async fn await_schema_agreement_indefinitely (
2171+ & self ,
2172+ required_node : Option < Uuid > ,
2173+ ) -> Result < Uuid , SchemaAgreementError > {
21642174 loop {
21652175 tokio:: time:: sleep ( self . schema_agreement_interval ) . await ;
2166- if let Some ( agreed_version) = self . check_schema_agreement ( ) . await ? {
2176+ if let Some ( agreed_version) = self
2177+ . check_schema_agreement_with_required_node ( required_node)
2178+ . await ?
2179+ {
21672180 return Ok ( agreed_version) ;
21682181 }
21692182 }
@@ -2177,7 +2190,29 @@ impl Session {
21772190 pub async fn await_schema_agreement ( & self ) -> Result < Uuid , SchemaAgreementError > {
21782191 timeout (
21792192 self . schema_agreement_timeout ,
2180- self . await_schema_agreement_indefinitely ( ) ,
2193+ self . await_schema_agreement_indefinitely ( None ) ,
2194+ )
2195+ . await
2196+ . unwrap_or ( Err ( SchemaAgreementError :: Timeout (
2197+ self . schema_agreement_timeout ,
2198+ ) ) )
2199+ }
2200+
2201+ /// Awaits schema agreement among all reachable nodes.
2202+ ///
2203+ /// Issues an agreement check each `Session::schema_agreement_interval`.
2204+ /// If agreement is not reached in `Session::schema_agreement_timeout`,
2205+ /// `SchemaAgreementError::Timeout` is returned.
2206+ ///
2207+ /// If `required_node` is Some, only returns Ok if this node successfully
2208+ /// returned its schema version during the agreement process.
2209+ async fn await_schema_agreement_with_required_node (
2210+ & self ,
2211+ required_node : Option < Uuid > ,
2212+ ) -> Result < Uuid , SchemaAgreementError > {
2213+ timeout (
2214+ self . schema_agreement_timeout ,
2215+ self . await_schema_agreement_indefinitely ( required_node) ,
21812216 )
21822217 . await
21832218 . unwrap_or ( Err ( SchemaAgreementError :: Timeout (
@@ -2189,14 +2224,54 @@ impl Session {
21892224 ///
21902225 /// If so, returns that agreed upon version.
21912226 pub async fn check_schema_agreement ( & self ) -> Result < Option < Uuid > , SchemaAgreementError > {
2227+ self . check_schema_agreement_with_required_node ( None ) . await
2228+ }
2229+
2230+ /// Checks if all reachable nodes have the same schema version.
2231+ /// If so, returns that agreed upon version.
2232+ ///
2233+ /// If `required_node` is Some, only returns Ok if this node successfully
2234+ /// returned its schema version.
2235+ async fn check_schema_agreement_with_required_node (
2236+ & self ,
2237+ required_node : Option < Uuid > ,
2238+ ) -> Result < Option < Uuid > , SchemaAgreementError > {
21922239 let cluster_state = self . get_cluster_state ( ) ;
21932240 // The iterator is guaranteed to be nonempty.
21942241 let per_node_connections = cluster_state. iter_working_connections_per_node ( ) ?;
21952242
21962243 // Therefore, this iterator is guaranteed to be nonempty, too.
2197- let handles = per_node_connections. map ( Session :: read_node_schema_version) ;
2244+ let handles = per_node_connections. map ( |( host_id, pool) | async move {
2245+ ( host_id, Session :: read_node_schema_version ( pool) . await )
2246+ } ) ;
21982247 // Hence, this is nonempty, too.
2199- let versions_results = try_join_all ( handles) . await ?;
2248+ let versions_results = join_all ( handles) . await ;
2249+
2250+ // Verify that required host is present, and returned success.
2251+ if let Some ( required_node) = required_node {
2252+ match versions_results
2253+ . iter ( )
2254+ . find ( |( host_id, _) | * host_id == required_node)
2255+ {
2256+ Some ( ( _, Ok ( SchemaNodeResult :: Success ( _version) ) ) ) => ( ) ,
2257+ // For other connections we can ignore Broken error, but for required
2258+ // host we need an actual schema version.
2259+ Some ( ( _, Ok ( SchemaNodeResult :: BrokenConnection ( e) ) ) ) => {
2260+ return Err ( SchemaAgreementError :: RequestError (
2261+ RequestAttemptError :: BrokenConnectionError ( e. clone ( ) ) ,
2262+ ) )
2263+ }
2264+ Some ( ( _, Err ( e) ) ) => return Err ( e. clone ( ) ) ,
2265+ None => return Err ( SchemaAgreementError :: RequiredHostAbsent ( required_node) ) ,
2266+ }
2267+ }
2268+
2269+ // Now we no longer need all the errors. We can return if there is
2270+ // irrecoverable one, and collect the Ok values otherwise.
2271+ let versions_results: Vec < _ > = versions_results
2272+ . into_iter ( )
2273+ . map ( |( _, result) | result)
2274+ . try_collect ( ) ?;
22002275
22012276 // unwrap is safe because iterator is still not empty.
22022277 let local_version = match versions_results
0 commit comments