Skip to main content

clt_database/mvcc/
yield_points.rs

1use std::fmt::Debug;
2
3use crate::LimboError;
4
5/// YieldPoint is a descriptor for one safe yield boundary in a state machine.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7pub struct YieldPoint {
8    pub ordinal: u8,
9    pub point_count: u8,
10}
11
12/// External hook consulted at safe state machine boundaries to decide whether to synthesize a yield.
13pub trait YieldInjector: Debug + Send + Sync {
14    /// Returns whether to synthetically yield at the current `YieldPoint`.
15    /// `selection_key` picks the deterministic yield plan for this logical operation.
16    /// `instance_id` distinguishes one live state machine/cursor from another so
17    /// they do not share yield bookkeeping.
18    fn should_yield(&self, instance_id: u64, selection_key: u64, point: YieldPoint) -> bool;
19}
20
21/// External hook consulted at safe state machine boundaries to decide whether to synthesize
22/// an error return. Mirrors `YieldInjector` but produces an `Err` instead of a yield, so tests
23/// can reproduce mid-state-machine failures (e.g. an I/O error after `remove_tx` ran but before
24/// the connection cache was cleared) without requiring a real fault in the I/O layer.
25pub trait FailureInjector: Debug + Send + Sync {
26    /// Returns `Some(err)` if the state machine should synthetically fail at this point.
27    /// Same selection_key / instance_id semantics as `YieldInjector`.
28    fn should_fail(
29        &self,
30        instance_id: u64,
31        selection_key: u64,
32        point: YieldPoint,
33    ) -> Option<LimboError>;
34}
35
36// At a safe resumable boundary, ask the active yield injector whether this
37// state machine should return a synthetic TransitionResult::Io yield here.
38macro_rules! inject_transition_yield {
39    ($state_machine:expr, $point:expr) => {{
40        #[cfg(any(clt_turso_tests, injected_yields))]
41        {
42            use $crate::mvcc::yield_hooks::ProvidesYieldContext;
43            let yield_context = $state_machine.yield_context();
44            if let Some(result) = crate::mvcc::yield_hooks::maybe_inject_transition_yield(
45                yield_context.injector.as_ref(),
46                yield_context.instance_id,
47                yield_context.selection_key,
48                $point,
49            ) {
50                return Ok(result);
51            }
52        }
53    }};
54}
55
56pub(crate) use inject_transition_yield;
57
58// At a safe resumable boundary, ask the active yield injector whether this
59// state machine should return a synthetic IOResult::IO yield here.
60macro_rules! inject_io_yield {
61    ($state_machine:expr, $point:expr) => {{
62        #[cfg(any(clt_turso_tests, injected_yields))]
63        {
64            use $crate::mvcc::yield_hooks::ProvidesYieldContext;
65            let yield_context = $state_machine.yield_context();
66            if let Some(result) = crate::mvcc::yield_hooks::maybe_inject_io_yield(
67                yield_context.injector.as_ref(),
68                yield_context.instance_id,
69                yield_context.selection_key,
70                $point,
71            ) {
72                return Ok(result);
73            }
74        }
75    }};
76}
77
78pub(crate) use inject_io_yield;
79
80// At a safe resumable boundary, ask the active failure injector whether this
81// state machine should return Err here. Used to reproduce mid-commit failures
82// in tests without requiring a real I/O fault.
83macro_rules! inject_transition_failure {
84    ($state_machine:expr, $point:expr) => {{
85        #[cfg(any(clt_turso_tests, injected_yields))]
86        {
87            use $crate::mvcc::yield_hooks::ProvidesYieldContext;
88            let yield_context = $state_machine.yield_context();
89            if let Some(err) = crate::mvcc::yield_hooks::maybe_inject_transition_failure(
90                yield_context.failure_injector.as_ref(),
91                yield_context.instance_id,
92                yield_context.selection_key,
93                $point,
94            ) {
95                return Err(err);
96            }
97        }
98    }};
99}
100
101pub(crate) use inject_transition_failure;