LCOV - code coverage report
Current view: top level - pageserver/src - failpoint_support.rs (source / functions) Coverage Total Hit
Test: 8ac049b474321fdc72ddcb56d7165153a1a900e8.info Lines: 87.0 % 46 40
Test Date: 2023-09-06 10:18:01 Functions: 100.0 % 10 10

            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           15 : pub(crate) async fn failpoint_sleep_helper(name: &'static str, duration_str: String) {
      29           15 :     let millis = duration_str.parse::<u64>().unwrap();
      30           15 :     let d = std::time::Duration::from_millis(millis);
      31              : 
      32           15 :     tracing::info!("failpoint {:?}: sleeping for {:?}", name, d);
      33           15 :     tokio::time::sleep(d).await;
      34           15 :     tracing::info!("failpoint {:?}: sleep done", name);
      35           15 : }
      36              : 
      37          575 : pub fn init() -> fail::FailScenario<'static> {
      38          575 :     // The failpoints lib provides support for parsing the `FAILPOINTS` env var.
      39          575 :     // We want non-default behavior for `exit`, though, so, we handle it separately.
      40          575 :     //
      41          575 :     // Format for FAILPOINTS is "name=actions" separated by ";".
      42          575 :     let actions = std::env::var("FAILPOINTS");
      43          575 :     if actions.is_ok() {
      44           10 :         std::env::remove_var("FAILPOINTS");
      45          565 :     } else {
      46          565 :         // let the library handle non-utf8, or nothing for not present
      47          565 :     }
      48              : 
      49          575 :     let scenario = fail::FailScenario::setup();
      50              : 
      51          575 :     if let Ok(val) = actions {
      52           10 :         val.split(';')
      53           10 :             .enumerate()
      54           10 :             .map(|(i, s)| s.split_once('=').ok_or((i, s)))
      55           10 :             .for_each(|res| {
      56           10 :                 let (name, actions) = match res {
      57           10 :                     Ok(t) => t,
      58            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           10 :                 if let Err(e) = apply_failpoint(name, actions) {
      66            0 :                     panic!("startup failpoints: failed to apply failpoint {name}={actions}: {e}");
      67           10 :                 }
      68           10 :             });
      69          565 :     }
      70              : 
      71          575 :     scenario
      72          575 : }
      73              : 
      74          261 : pub(crate) fn apply_failpoint(name: &str, actions: &str) -> Result<(), String> {
      75          261 :     if actions == "exit" {
      76            7 :         fail::cfg_callback(name, exit_failpoint)
      77              :     } else {
      78          254 :         fail::cfg(name, actions)
      79              :     }
      80          261 : }
      81              : 
      82              : #[inline(never)]
      83            6 : fn exit_failpoint() {
      84            6 :     tracing::info!("Exit requested by failpoint");
      85            6 :     std::process::exit(1);
      86              : }
        

Generated by: LCOV version 2.1-beta