mod search;
mod transient;
use std::future::Future;
use super::{SavepointOp, SavepointOperation};
pub use search::*;
pub use transient::*;
pub trait BatchIsolation: SavepointOperation {
fn run_isolated<'a, T, V, E, F>(
&'a mut self,
items: &'a [T],
f: F,
) -> impl Future<Output = Result<Vec<Result<V, E>>, sqlx::Error>> + 'a
where
T: 'a,
V: 'a,
E: 'a,
F: AsyncFnOnce(&mut SavepointOp<'_>, &T) -> Result<V, E> + Clone + Sync + 'a,
{
async move {
let mut outcomes = Vec::with_capacity(items.len());
for item in items {
let f = f.clone();
outcomes.push(self.with_savepoint(async |sp| f(sp, item).await).await?);
}
Ok(outcomes)
}
}
fn run_bisected<'a, T, E, F>(
&'a mut self,
items: &'a [T],
budget: BisectBudget,
f: F,
) -> impl Future<Output = Result<BisectOutcomes<E>, sqlx::Error>> + 'a
where
T: 'a,
E: std::error::Error + 'static,
F: AsyncFnOnce(&mut SavepointOp<'_>, &[T]) -> Result<(), E> + Clone + Sync + 'a,
{
self.run_bisected_with(
items,
budget,
TransientPolicy::new(sqlstate_is_transient::<E> as fn(&E) -> bool),
f,
)
}
fn run_bisected_with<'a, T, E, F, P>(
&'a mut self,
items: &'a [T],
budget: BisectBudget,
policy: TransientPolicy<P>,
f: F,
) -> impl Future<Output = Result<BisectOutcomes<E>, sqlx::Error>> + 'a
where
T: 'a,
E: std::fmt::Display + 'a,
P: Fn(&E) -> bool + 'a,
F: AsyncFnOnce(&mut SavepointOp<'_>, &[T]) -> Result<(), E> + Clone + Sync + 'a,
{
async move {
let mut search = BisectSearch::new(items.len(), budget)
.with_max_transient_retries(policy.max_retries);
while let Some(range) = search.next_range() {
let f = f.clone();
let slice = &items[range.clone()];
let verdict = match self.with_savepoint(async |sp| f(sp, slice).await).await? {
Ok(()) => ProbeVerdict::Clean,
Err(error) if (policy.is_transient)(&error) => ProbeVerdict::Transient(error),
Err(error) => ProbeVerdict::Failed(error),
};
if let Err(limit) = search.report(range, verdict) {
return Err(sqlx::Error::Protocol(match search.last_error() {
Some(error) => format!("{limit}; last error: {error}"),
None => limit.to_string(),
}));
}
}
Ok(search.into_outcomes())
}
}
}
impl<T: SavepointOperation + ?Sized> BatchIsolation for T {}