LCOV - code coverage report
Current view: top level - safekeeper/tests/walproposer_sim - simulation_logs.rs (source / functions) Coverage Total Hit
Test: 190869232aac3a234374e5bb62582e91cf5f5818.info Lines: 96.6 % 119 115
Test Date: 2024-02-23 13:21:27 Functions: 27.8 % 54 15

            Line data    Source code
       1              : use desim::proto::SimEvent;
       2              : use tracing::debug;
       3              : 
       4       284029 : #[derive(Debug, Clone, PartialEq, Eq)]
       5              : enum NodeKind {
       6              :     Unknown,
       7              :     Safekeeper,
       8              :     WalProposer,
       9              : }
      10              : 
      11              : impl Default for NodeKind {
      12        84107 :     fn default() -> Self {
      13        84107 :         Self::Unknown
      14        84107 :     }
      15              : }
      16              : 
      17              : /// Simulation state of walproposer/safekeeper, derived from the simulation logs.
      18        84107 : #[derive(Clone, Debug, Default)]
      19              : struct NodeInfo {
      20              :     kind: NodeKind,
      21              : 
      22              :     // walproposer
      23              :     is_sync: bool,
      24              :     term: u64,
      25              :     epoch_lsn: u64,
      26              : 
      27              :     // safekeeper
      28              :     commit_lsn: u64,
      29              :     flush_lsn: u64,
      30              : }
      31              : 
      32              : impl NodeInfo {
      33       149342 :     fn init_kind(&mut self, kind: NodeKind) {
      34       149342 :         if self.kind == NodeKind::Unknown {
      35        84109 :             self.kind = kind;
      36        84109 :         } else {
      37        65233 :             assert!(self.kind == kind);
      38              :         }
      39       149342 :     }
      40              : 
      41       149342 :     fn started(&mut self, data: &str) {
      42       149342 :         let mut parts = data.split(';');
      43       149342 :         assert!(parts.next().unwrap() == "started");
      44       149342 :         match parts.next().unwrap() {
      45       149342 :             "safekeeper" => {
      46        77239 :                 self.init_kind(NodeKind::Safekeeper);
      47        77239 :             }
      48        72103 :             "walproposer" => {
      49        72103 :                 self.init_kind(NodeKind::WalProposer);
      50        72103 :                 let is_sync: u8 = parts.next().unwrap().parse().unwrap();
      51        72103 :                 self.is_sync = is_sync != 0;
      52        72103 :             }
      53            0 :             _ => unreachable!(),
      54              :         }
      55       149342 :     }
      56              : }
      57              : 
      58              : /// Global state of the simulation, derived from the simulation logs.
      59         4002 : #[derive(Debug, Default)]
      60              : struct GlobalState {
      61              :     nodes: Vec<NodeInfo>,
      62              :     commit_lsn: u64,
      63              :     write_lsn: u64,
      64              :     max_write_lsn: u64,
      65              : 
      66              :     written_wal: u64,
      67              :     written_records: u64,
      68              : }
      69              : 
      70              : impl GlobalState {
      71         4002 :     fn new() -> Self {
      72         4002 :         Default::default()
      73         4002 :     }
      74              : 
      75       288250 :     fn get(&mut self, id: u32) -> &mut NodeInfo {
      76       288250 :         let id = id as usize;
      77       288250 :         if id >= self.nodes.len() {
      78        84107 :             self.nodes.resize(id + 1, NodeInfo::default());
      79       204143 :         }
      80       288250 :         &mut self.nodes[id]
      81       288250 :     }
      82              : }
      83              : 
      84              : /// Try to find inconsistencies in the simulation log.
      85         4002 : pub fn validate_events(events: Vec<SimEvent>) {
      86         4002 :     const INITDB_LSN: u64 = 21623024;
      87         4002 : 
      88         4002 :     let hook = std::panic::take_hook();
      89         4002 :     scopeguard::defer_on_success! {
      90         4002 :         std::panic::set_hook(hook);
      91         4002 :     };
      92              : 
      93         4002 :     let mut state = GlobalState::new();
      94         4002 :     state.max_write_lsn = INITDB_LSN;
      95              : 
      96       222798 :     for event in events {
      97       218796 :         debug!("{:?}", event);
      98              : 
      99       218796 :         let node = state.get(event.node);
     100       218796 :         if event.data.starts_with("started;") {
     101       149342 :             node.started(&event.data);
     102       149342 :             continue;
     103        69454 :         }
     104        69454 :         assert!(node.kind != NodeKind::Unknown);
     105              : 
     106              :         // drop reference to unlock state
     107        69454 :         let mut node = node.clone();
     108        69454 : 
     109        69454 :         let mut parts = event.data.split(';');
     110        69454 :         match node.kind {
     111        58278 :             NodeKind::Safekeeper => match parts.next().unwrap() {
     112        58278 :                 "tli_loaded" => {
     113        58278 :                     let flush_lsn: u64 = parts.next().unwrap().parse().unwrap();
     114        58278 :                     let commit_lsn: u64 = parts.next().unwrap().parse().unwrap();
     115        58278 :                     node.flush_lsn = flush_lsn;
     116        58278 :                     node.commit_lsn = commit_lsn;
     117        58278 :                 }
     118            0 :                 _ => unreachable!(),
     119              :             },
     120              :             NodeKind::WalProposer => {
     121        11176 :                 match parts.next().unwrap() {
     122        11176 :                     "prop_elected" => {
     123         5869 :                         let prop_lsn: u64 = parts.next().unwrap().parse().unwrap();
     124         5869 :                         let prop_term: u64 = parts.next().unwrap().parse().unwrap();
     125         5869 :                         let prev_lsn: u64 = parts.next().unwrap().parse().unwrap();
     126         5869 :                         let prev_term: u64 = parts.next().unwrap().parse().unwrap();
     127         5869 : 
     128         5869 :                         assert!(prop_lsn >= prev_lsn);
     129         5869 :                         assert!(prop_term >= prev_term);
     130              : 
     131         5869 :                         assert!(prop_lsn >= state.commit_lsn);
     132              : 
     133         5869 :                         if prop_lsn > state.write_lsn {
     134          432 :                             assert!(prop_lsn <= state.max_write_lsn);
     135          432 :                             debug!(
     136            2 :                                 "moving write_lsn up from {} to {}",
     137            2 :                                 state.write_lsn, prop_lsn
     138            2 :                             );
     139          432 :                             state.write_lsn = prop_lsn;
     140         5437 :                         }
     141         5869 :                         if prop_lsn < state.write_lsn {
     142         1011 :                             debug!(
     143            2 :                                 "moving write_lsn down from {} to {}",
     144            2 :                                 state.write_lsn, prop_lsn
     145            2 :                             );
     146         1011 :                             state.write_lsn = prop_lsn;
     147         4858 :                         }
     148              : 
     149         5869 :                         node.epoch_lsn = prop_lsn;
     150         5869 :                         node.term = prop_term;
     151              :                     }
     152         5307 :                     "write_wal" => {
     153         2771 :                         assert!(!node.is_sync);
     154         2771 :                         let start_lsn: u64 = parts.next().unwrap().parse().unwrap();
     155         2771 :                         let end_lsn: u64 = parts.next().unwrap().parse().unwrap();
     156         2771 :                         let cnt: u64 = parts.next().unwrap().parse().unwrap();
     157         2771 : 
     158         2771 :                         let size = end_lsn - start_lsn;
     159         2771 :                         state.written_wal += size;
     160         2771 :                         state.written_records += cnt;
     161         2771 : 
     162         2771 :                         // TODO: If we allow writing WAL before winning the election
     163         2771 : 
     164         2771 :                         assert!(start_lsn >= state.commit_lsn);
     165         2771 :                         assert!(end_lsn >= start_lsn);
     166              :                         // assert!(start_lsn == state.write_lsn);
     167         2771 :                         state.write_lsn = end_lsn;
     168         2771 : 
     169         2771 :                         if end_lsn > state.max_write_lsn {
     170         2326 :                             state.max_write_lsn = end_lsn;
     171         2326 :                         }
     172              :                     }
     173         2536 :                     "commit_lsn" => {
     174         2536 :                         let lsn: u64 = parts.next().unwrap().parse().unwrap();
     175         2536 :                         assert!(lsn >= state.commit_lsn);
     176         2536 :                         state.commit_lsn = lsn;
     177              :                     }
     178            0 :                     _ => unreachable!(),
     179              :                 }
     180              :             }
     181            0 :             _ => unreachable!(),
     182              :         }
     183              : 
     184              :         // update the node in the state struct
     185        69454 :         *state.get(event.node) = node;
     186              :     }
     187         4002 : }
        

Generated by: LCOV version 2.1-beta