LCOV - differential code coverage report
Current view: top level - pageserver/src - failpoint_support.rs (source / functions) Coverage Total Hit UBC CBC
Current: f6946e90941b557c917ac98cd5a7e9506d180f3e.info Lines: 87.0 % 46 40 6 40
Current Date: 2023-10-19 02:04:12 Functions: 100.0 % 10 10 10
Baseline: c8637f37369098875162f194f92736355783b050.info
Baseline Date: 2023-10-18 20:25:20

           TLA  Line data    Source code
       1                 : /// use with fail::cfg("$name", "return(2000)")
       2                 : ///
       3                 : /// The effect is similar to a "sleep(2000)" action, i.e. we sleep for the
       4                 : /// specified time (in milliseconds). The main difference is that we use async
       5                 : /// tokio sleep function. Another difference is that we print lines to the log,
       6                 : /// which can be useful in tests to check that the failpoint was hit.
       7                 : #[macro_export]
       8                 : macro_rules! __failpoint_sleep_millis_async {
       9                 :     ($name:literal) => {{
      10                 :         // If the failpoint is used with a "return" action, set should_sleep to the
      11                 :         // returned value (as string). Otherwise it's set to None.
      12                 :         let should_sleep = (|| {
      13                 :             ::fail::fail_point!($name, |x| x);
      14                 :             ::std::option::Option::None
      15                 :         })();
      16                 : 
      17                 :         // Sleep if the action was a returned value
      18                 :         if let ::std::option::Option::Some(duration_str) = should_sleep {
      19                 :             $crate::failpoint_support::failpoint_sleep_helper($name, duration_str).await
      20                 :         }
      21                 :     }};
      22                 : }
      23                 : pub use __failpoint_sleep_millis_async as sleep_millis_async;
      24                 : 
      25                 : // Helper function used by the macro. (A function has nicer scoping so we
      26                 : // don't need to decorate everything with "::")
      27                 : #[doc(hidden)]
      28 CBC          16 : pub(crate) async fn failpoint_sleep_helper(name: &'static str, duration_str: String) {
      29              16 :     let millis = duration_str.parse::<u64>().unwrap();
      30              16 :     let d = std::time::Duration::from_millis(millis);
      31                 : 
      32              16 :     tracing::info!("failpoint {:?}: sleeping for {:?}", name, d);
      33              16 :     tokio::time::sleep(d).await;
      34              16 :     tracing::info!("failpoint {:?}: sleep done", name);
      35              16 : }
      36                 : 
      37             560 : pub fn init() -> fail::FailScenario<'static> {
      38             560 :     // The failpoints lib provides support for parsing the `FAILPOINTS` env var.
      39             560 :     // We want non-default behavior for `exit`, though, so, we handle it separately.
      40             560 :     //
      41             560 :     // Format for FAILPOINTS is "name=actions" separated by ";".
      42             560 :     let actions = std::env::var("FAILPOINTS");
      43             560 :     if actions.is_ok() {
      44              11 :         std::env::remove_var("FAILPOINTS");
      45             549 :     } else {
      46             549 :         // let the library handle non-utf8, or nothing for not present
      47             549 :     }
      48                 : 
      49             560 :     let scenario = fail::FailScenario::setup();
      50                 : 
      51             560 :     if let Ok(val) = actions {
      52              11 :         val.split(';')
      53              11 :             .enumerate()
      54              11 :             .map(|(i, s)| s.split_once('=').ok_or((i, s)))
      55              11 :             .for_each(|res| {
      56              11 :                 let (name, actions) = match res {
      57              11 :                     Ok(t) => t,
      58 UBC           0 :                     Err((i, s)) => {
      59               0 :                         panic!(
      60               0 :                             "startup failpoints: missing action on the {}th failpoint; try `{s}=return`",
      61               0 :                             i + 1,
      62               0 :                         );
      63                 :                     }
      64                 :                 };
      65 CBC          11 :                 if let Err(e) = apply_failpoint(name, actions) {
      66 UBC           0 :                     panic!("startup failpoints: failed to apply failpoint {name}={actions}: {e}");
      67 CBC          11 :                 }
      68              11 :             });
      69             549 :     }
      70                 : 
      71             560 :     scenario
      72             560 : }
      73                 : 
      74             224 : pub(crate) fn apply_failpoint(name: &str, actions: &str) -> Result<(), String> {
      75             224 :     if actions == "exit" {
      76               9 :         fail::cfg_callback(name, exit_failpoint)
      77                 :     } else {
      78             215 :         fail::cfg(name, actions)
      79                 :     }
      80             224 : }
      81                 : 
      82                 : #[inline(never)]
      83               8 : fn exit_failpoint() {
      84               8 :     tracing::info!("Exit requested by failpoint");
      85               8 :     std::process::exit(1);
      86                 : }
        

Generated by: LCOV version 2.1-beta