@@ -6,7 +6,7 @@ use scylla_cql::frame::response::error::DbError;
66use std:: { future:: Future , sync:: Arc , time:: Duration } ;
77use tracing:: { trace_span, warn, Instrument } ;
88
9- use crate :: errors:: QueryError ;
9+ use crate :: errors:: { RequestAttemptError , RequestError } ;
1010use crate :: observability:: metrics:: Metrics ;
1111
1212/// Context is passed as an argument to `SpeculativeExecutionPolicy` methods
@@ -85,94 +85,95 @@ impl SpeculativeExecutionPolicy for PercentileSpeculativeExecutionPolicy {
8585///
8686/// We should ignore errors such that their presence when executing the request
8787/// on one node, does not imply that the same error will appear during retry on some other node.
88- fn can_be_ignored < ResT > ( result : & Result < ResT , QueryError > ) -> bool {
88+ fn can_be_ignored < ResT > ( result : & Result < ResT , RequestError > ) -> bool {
8989 match result {
9090 Ok ( _) => false ,
9191 // Do not remove this lint!
9292 // It's there for a reason - we don't want new variants
9393 // automatically fall under `_` pattern when they are introduced.
9494 #[ deny( clippy:: wildcard_enum_match_arm) ]
9595 Err ( e) => match e {
96- // Errors that will almost certainly appear for other nodes as well
97- QueryError :: BadQuery ( _)
98- | QueryError :: CqlRequestSerialization ( _)
99- | QueryError :: BodyExtensionsParseError ( _)
100- | QueryError :: CqlResultParseError ( _)
101- | QueryError :: CqlErrorParseError ( _)
102- | QueryError :: ProtocolError ( _) => false ,
103-
104- // EmptyPlan is not returned by `Session::execute_query`.
105- // It is represented by None, which is then transformed
106- // to QueryError::EmptyPlan by the caller
107- // (either here is speculative_execution module, or for non-speculative execution).
108- // I believe this should not be ignored, since we do not expect it here.
109- QueryError :: EmptyPlan => false ,
110-
111- // Errors that should not appear here, thus should not be ignored
112- #[ allow( deprecated) ]
113- QueryError :: NextRowError ( _)
114- | QueryError :: IntoLegacyQueryResultError ( _)
115- | QueryError :: TimeoutError
116- | QueryError :: RequestTimeout ( _)
117- | QueryError :: MetadataError ( _) => false ,
118-
119- // Errors that can be ignored
120- QueryError :: BrokenConnection ( _)
121- | QueryError :: UnableToAllocStreamId
122- | QueryError :: ConnectionPoolError ( _) => true ,
123-
124- // Handle DbErrors
125- QueryError :: DbError ( db_error, _) => {
96+ // This error should not appear it. Anyway, if it possibly could
97+ // in the future, it should not be ignored.
98+ RequestError :: EmptyPlan => false ,
99+
100+ // Can try on another node.
101+ RequestError :: ConnectionPoolError { .. } => true ,
102+
103+ RequestError :: LastAttemptError ( e) => {
126104 // Do not remove this lint!
127105 // It's there for a reason - we don't want new variants
128106 // automatically fall under `_` pattern when they are introduced.
129107 #[ deny( clippy:: wildcard_enum_match_arm) ]
130- match db_error {
131- // Errors that will almost certainly appear on other nodes as well
132- DbError :: SyntaxError
133- | DbError :: Invalid
134- | DbError :: AlreadyExists { .. }
135- | DbError :: Unauthorized
136- | DbError :: ProtocolError => false ,
137-
138- // Errors that should not appear there - thus, should not be ignored.
139- DbError :: AuthenticationError | DbError :: Other ( _) => false ,
140-
141- // For now, let's assume that UDF failure is not transient - don't ignore it
142- // TODO: investigate
143- DbError :: FunctionFailure { .. } => false ,
144-
145- // Not sure when these can appear - don't ignore them
146- // TODO: Investigate these errors
147- DbError :: ConfigError | DbError :: TruncateError => false ,
148-
149- // Errors that we can ignore and perform a retry on some other node
150- DbError :: Unavailable { .. }
151- | DbError :: Overloaded
152- | DbError :: IsBootstrapping
153- | DbError :: ReadTimeout { .. }
154- | DbError :: WriteTimeout { .. }
155- | DbError :: ReadFailure { .. }
156- | DbError :: WriteFailure { .. }
157- // Preparation may succeed on some other node.
158- | DbError :: Unprepared { .. }
159- | DbError :: ServerError
160- | DbError :: RateLimitReached { .. } => true ,
108+ match e {
109+ // Errors that will almost certainly appear for other nodes as well
110+ RequestAttemptError :: SerializationError ( _)
111+ | RequestAttemptError :: CqlRequestSerialization ( _)
112+ | RequestAttemptError :: BodyExtensionsParseError ( _)
113+ | RequestAttemptError :: CqlResultParseError ( _)
114+ | RequestAttemptError :: CqlErrorParseError ( _)
115+ | RequestAttemptError :: UnexpectedResponse ( _)
116+ | RequestAttemptError :: RepreparedIdChanged { .. }
117+ | RequestAttemptError :: RepreparedIdMissingInBatch => false ,
118+
119+ // Errors that can be ignored
120+ RequestAttemptError :: BrokenConnectionError ( _)
121+ | RequestAttemptError :: UnableToAllocStreamId => true ,
122+
123+ // Handle DbErrors
124+ RequestAttemptError :: DbError ( db_error, _) => {
125+ // Do not remove this lint!
126+ // It's there for a reason - we don't want new variants
127+ // automatically fall under `_` pattern when they are introduced.
128+ #[ deny( clippy:: wildcard_enum_match_arm) ]
129+ match db_error {
130+ // Errors that will almost certainly appear on other nodes as well
131+ DbError :: SyntaxError
132+ | DbError :: Invalid
133+ | DbError :: AlreadyExists { .. }
134+ | DbError :: Unauthorized
135+ | DbError :: ProtocolError => false ,
136+
137+ // Errors that should not appear there - thus, should not be ignored.
138+ DbError :: AuthenticationError | DbError :: Other ( _) => false ,
139+
140+ // For now, let's assume that UDF failure is not transient - don't ignore it
141+ // TODO: investigate
142+ DbError :: FunctionFailure { .. } => false ,
143+
144+ // Not sure when these can appear - don't ignore them
145+ // TODO: Investigate these errors
146+ DbError :: ConfigError | DbError :: TruncateError => false ,
147+
148+ // Errors that we can ignore and perform a retry on some other node
149+ DbError :: Unavailable { .. }
150+ | DbError :: Overloaded
151+ | DbError :: IsBootstrapping
152+ | DbError :: ReadTimeout { .. }
153+ | DbError :: WriteTimeout { .. }
154+ | DbError :: ReadFailure { .. }
155+ | DbError :: WriteFailure { .. }
156+ // Preparation may succeed on some other node.
157+ | DbError :: Unprepared { .. }
158+ | DbError :: ServerError
159+ | DbError :: RateLimitReached { .. } => true ,
160+ }
161161 }
162+ }
162163 }
163164 } ,
164165 }
165166}
166167
167- const EMPTY_PLAN_ERROR : QueryError = QueryError :: EmptyPlan ;
168+ const EMPTY_PLAN_ERROR : RequestError = RequestError :: EmptyPlan ;
168169
169170pub ( crate ) async fn execute < QueryFut , ResT > (
170171 policy : & dyn SpeculativeExecutionPolicy ,
171172 context : & Context ,
172173 query_runner_generator : impl Fn ( bool ) -> QueryFut ,
173- ) -> Result < ResT , QueryError >
174+ ) -> Result < ResT , RequestError >
174175where
175- QueryFut : Future < Output = Option < Result < ResT , QueryError > > > ,
176+ QueryFut : Future < Output = Option < Result < ResT , RequestError > > > ,
176177{
177178 let mut retries_remaining = policy. max_retry_count ( context) ;
178179 let retry_interval = policy. retry_interval ( context) ;
0 commit comments