LCOV - differential code coverage report
Current view: top level - safekeeper/src - control_file_upgrade.rs (source / functions) Coverage Total Hit UBC CBC
Current: cd44433dd675caa99df17a61b18949c8387e2242.info Lines: 65.0 % 354 230 124 230
Current Date: 2024-01-09 02:06:09 Functions: 35.9 % 153 55 98 55
Baseline: 66c52a629a0f4a503e193045e0df4c77139e344b.info
Baseline Date: 2024-01-08 15:34:46

           TLA  Line data    Source code
       1                 : //! Code to deal with safekeeper control file upgrades
       2                 : use crate::safekeeper::{
       3                 :     AcceptorState, PersistedPeers, PgUuid, SafeKeeperState, ServerInfo, Term, TermHistory, TermLsn,
       4                 : };
       5                 : use anyhow::{bail, Result};
       6                 : use pq_proto::SystemId;
       7                 : use serde::{Deserialize, Serialize};
       8                 : use tracing::*;
       9                 : use utils::{
      10                 :     bin_ser::LeSer,
      11                 :     id::{TenantId, TimelineId},
      12                 :     lsn::Lsn,
      13                 : };
      14                 : 
      15                 : /// Persistent consensus state of the acceptor.
      16 CBC           2 : #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
      17                 : struct AcceptorStateV1 {
      18                 :     /// acceptor's last term it voted for (advanced in 1 phase)
      19                 :     term: Term,
      20                 :     /// acceptor's epoch (advanced, i.e. bumped to 'term' when VCL is reached).
      21                 :     epoch: Term,
      22                 : }
      23                 : 
      24               2 : #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
      25                 : struct SafeKeeperStateV1 {
      26                 :     /// persistent acceptor state
      27                 :     acceptor_state: AcceptorStateV1,
      28                 :     /// information about server
      29                 :     server: ServerInfoV2,
      30                 :     /// Unique id of the last *elected* proposer we dealt with. Not needed
      31                 :     /// for correctness, exists for monitoring purposes.
      32                 :     proposer_uuid: PgUuid,
      33                 :     /// part of WAL acknowledged by quorum and available locally
      34                 :     commit_lsn: Lsn,
      35                 :     /// minimal LSN which may be needed for recovery of some safekeeper (end_lsn
      36                 :     /// of last record streamed to everyone)
      37                 :     truncate_lsn: Lsn,
      38                 :     // Safekeeper starts receiving WAL from this LSN, zeros before it ought to
      39                 :     // be skipped during decoding.
      40                 :     wal_start_lsn: Lsn,
      41                 : }
      42                 : 
      43               4 : #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
      44                 : pub struct ServerInfoV2 {
      45                 :     /// Postgres server version
      46                 :     pub pg_version: u32,
      47                 :     pub system_id: SystemId,
      48                 :     pub tenant_id: TenantId,
      49                 :     pub timeline_id: TimelineId,
      50                 :     pub wal_seg_size: u32,
      51                 : }
      52                 : 
      53               2 : #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
      54                 : pub struct SafeKeeperStateV2 {
      55                 :     /// persistent acceptor state
      56                 :     pub acceptor_state: AcceptorState,
      57                 :     /// information about server
      58                 :     pub server: ServerInfoV2,
      59                 :     /// Unique id of the last *elected* proposer we dealt with. Not needed
      60                 :     /// for correctness, exists for monitoring purposes.
      61                 :     pub proposer_uuid: PgUuid,
      62                 :     /// part of WAL acknowledged by quorum and available locally
      63                 :     pub commit_lsn: Lsn,
      64                 :     /// minimal LSN which may be needed for recovery of some safekeeper (end_lsn
      65                 :     /// of last record streamed to everyone)
      66                 :     pub truncate_lsn: Lsn,
      67                 :     // Safekeeper starts receiving WAL from this LSN, zeros before it ought to
      68                 :     // be skipped during decoding.
      69                 :     pub wal_start_lsn: Lsn,
      70                 : }
      71                 : 
      72               2 : #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
      73                 : pub struct ServerInfoV3 {
      74                 :     /// Postgres server version
      75                 :     pub pg_version: u32,
      76                 :     pub system_id: SystemId,
      77                 :     #[serde(with = "hex")]
      78                 :     pub tenant_id: TenantId,
      79                 :     #[serde(with = "hex")]
      80                 :     pub timeline_id: TimelineId,
      81                 :     pub wal_seg_size: u32,
      82                 : }
      83                 : 
      84               2 : #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
      85                 : pub struct SafeKeeperStateV3 {
      86                 :     /// persistent acceptor state
      87                 :     pub acceptor_state: AcceptorState,
      88                 :     /// information about server
      89                 :     pub server: ServerInfoV3,
      90                 :     /// Unique id of the last *elected* proposer we dealt with. Not needed
      91                 :     /// for correctness, exists for monitoring purposes.
      92                 :     #[serde(with = "hex")]
      93                 :     pub proposer_uuid: PgUuid,
      94                 :     /// part of WAL acknowledged by quorum and available locally
      95                 :     pub commit_lsn: Lsn,
      96                 :     /// minimal LSN which may be needed for recovery of some safekeeper (end_lsn
      97                 :     /// of last record streamed to everyone)
      98                 :     pub truncate_lsn: Lsn,
      99                 :     // Safekeeper starts receiving WAL from this LSN, zeros before it ought to
     100                 :     // be skipped during decoding.
     101                 :     pub wal_start_lsn: Lsn,
     102                 : }
     103                 : 
     104               3 : #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
     105                 : pub struct SafeKeeperStateV4 {
     106                 :     #[serde(with = "hex")]
     107                 :     pub tenant_id: TenantId,
     108                 :     #[serde(with = "hex")]
     109                 :     pub timeline_id: TimelineId,
     110                 :     /// persistent acceptor state
     111                 :     pub acceptor_state: AcceptorState,
     112                 :     /// information about server
     113                 :     pub server: ServerInfo,
     114                 :     /// Unique id of the last *elected* proposer we dealt with. Not needed
     115                 :     /// for correctness, exists for monitoring purposes.
     116                 :     #[serde(with = "hex")]
     117                 :     pub proposer_uuid: PgUuid,
     118                 :     /// Part of WAL acknowledged by quorum and available locally. Always points
     119                 :     /// to record boundary.
     120                 :     pub commit_lsn: Lsn,
     121                 :     /// First LSN not yet offloaded to s3. Useful to persist to avoid finding
     122                 :     /// out offloading progress on boot.
     123                 :     pub s3_wal_lsn: Lsn,
     124                 :     /// Minimal LSN which may be needed for recovery of some safekeeper (end_lsn
     125                 :     /// of last record streamed to everyone). Persisting it helps skipping
     126                 :     /// recovery in walproposer, generally we compute it from peers. In
     127                 :     /// walproposer proto called 'truncate_lsn'.
     128                 :     pub peer_horizon_lsn: Lsn,
     129                 :     /// LSN of the oldest known checkpoint made by pageserver and successfully
     130                 :     /// pushed to s3. We don't remove WAL beyond it. Persisted only for
     131                 :     /// informational purposes, we receive it from pageserver (or broker).
     132                 :     pub remote_consistent_lsn: Lsn,
     133                 :     // Peers and their state as we remember it. Knowing peers themselves is
     134                 :     // fundamental; but state is saved here only for informational purposes and
     135                 :     // obviously can be stale. (Currently not saved at all, but let's provision
     136                 :     // place to have less file version upgrades).
     137                 :     pub peers: PersistedPeers,
     138                 : }
     139                 : 
     140 UBC           0 : pub fn upgrade_control_file(buf: &[u8], version: u32) -> Result<SafeKeeperState> {
     141               0 :     // migrate to storing full term history
     142               0 :     if version == 1 {
     143               0 :         info!("reading safekeeper control file version {}", version);
     144               0 :         let oldstate = SafeKeeperStateV1::des(&buf[..buf.len()])?;
     145               0 :         let ac = AcceptorState {
     146               0 :             term: oldstate.acceptor_state.term,
     147               0 :             term_history: TermHistory(vec![TermLsn {
     148               0 :                 term: oldstate.acceptor_state.epoch,
     149               0 :                 lsn: Lsn(0),
     150               0 :             }]),
     151               0 :         };
     152               0 :         return Ok(SafeKeeperState {
     153               0 :             tenant_id: oldstate.server.tenant_id,
     154               0 :             timeline_id: oldstate.server.timeline_id,
     155               0 :             acceptor_state: ac,
     156               0 :             server: ServerInfo {
     157               0 :                 pg_version: oldstate.server.pg_version,
     158               0 :                 system_id: oldstate.server.system_id,
     159               0 :                 wal_seg_size: oldstate.server.wal_seg_size,
     160               0 :             },
     161               0 :             proposer_uuid: oldstate.proposer_uuid,
     162               0 :             timeline_start_lsn: Lsn(0),
     163               0 :             local_start_lsn: Lsn(0),
     164               0 :             commit_lsn: oldstate.commit_lsn,
     165               0 :             backup_lsn: Lsn(0),
     166               0 :             peer_horizon_lsn: oldstate.truncate_lsn,
     167               0 :             remote_consistent_lsn: Lsn(0),
     168               0 :             peers: PersistedPeers(vec![]),
     169               0 :         });
     170                 :     // migrate to hexing some ids
     171               0 :     } else if version == 2 {
     172               0 :         info!("reading safekeeper control file version {}", version);
     173               0 :         let oldstate = SafeKeeperStateV2::des(&buf[..buf.len()])?;
     174               0 :         let server = ServerInfo {
     175               0 :             pg_version: oldstate.server.pg_version,
     176               0 :             system_id: oldstate.server.system_id,
     177               0 :             wal_seg_size: oldstate.server.wal_seg_size,
     178               0 :         };
     179               0 :         return Ok(SafeKeeperState {
     180               0 :             tenant_id: oldstate.server.tenant_id,
     181               0 :             timeline_id: oldstate.server.timeline_id,
     182               0 :             acceptor_state: oldstate.acceptor_state,
     183               0 :             server,
     184               0 :             proposer_uuid: oldstate.proposer_uuid,
     185               0 :             timeline_start_lsn: Lsn(0),
     186               0 :             local_start_lsn: Lsn(0),
     187               0 :             commit_lsn: oldstate.commit_lsn,
     188               0 :             backup_lsn: Lsn(0),
     189               0 :             peer_horizon_lsn: oldstate.truncate_lsn,
     190               0 :             remote_consistent_lsn: Lsn(0),
     191               0 :             peers: PersistedPeers(vec![]),
     192               0 :         });
     193                 :     // migrate to moving tenant_id/timeline_id to the top and adding some lsns
     194               0 :     } else if version == 3 {
     195               0 :         info!("reading safekeeper control file version {version}");
     196               0 :         let oldstate = SafeKeeperStateV3::des(&buf[..buf.len()])?;
     197               0 :         let server = ServerInfo {
     198               0 :             pg_version: oldstate.server.pg_version,
     199               0 :             system_id: oldstate.server.system_id,
     200               0 :             wal_seg_size: oldstate.server.wal_seg_size,
     201               0 :         };
     202               0 :         return Ok(SafeKeeperState {
     203               0 :             tenant_id: oldstate.server.tenant_id,
     204               0 :             timeline_id: oldstate.server.timeline_id,
     205               0 :             acceptor_state: oldstate.acceptor_state,
     206               0 :             server,
     207               0 :             proposer_uuid: oldstate.proposer_uuid,
     208               0 :             timeline_start_lsn: Lsn(0),
     209               0 :             local_start_lsn: Lsn(0),
     210               0 :             commit_lsn: oldstate.commit_lsn,
     211               0 :             backup_lsn: Lsn(0),
     212               0 :             peer_horizon_lsn: oldstate.truncate_lsn,
     213               0 :             remote_consistent_lsn: Lsn(0),
     214               0 :             peers: PersistedPeers(vec![]),
     215               0 :         });
     216                 :     // migrate to having timeline_start_lsn
     217               0 :     } else if version == 4 {
     218               0 :         info!("reading safekeeper control file version {}", version);
     219               0 :         let oldstate = SafeKeeperStateV4::des(&buf[..buf.len()])?;
     220               0 :         let server = ServerInfo {
     221               0 :             pg_version: oldstate.server.pg_version,
     222               0 :             system_id: oldstate.server.system_id,
     223               0 :             wal_seg_size: oldstate.server.wal_seg_size,
     224               0 :         };
     225               0 :         return Ok(SafeKeeperState {
     226               0 :             tenant_id: oldstate.tenant_id,
     227               0 :             timeline_id: oldstate.timeline_id,
     228               0 :             acceptor_state: oldstate.acceptor_state,
     229               0 :             server,
     230               0 :             proposer_uuid: oldstate.proposer_uuid,
     231               0 :             timeline_start_lsn: Lsn(0),
     232               0 :             local_start_lsn: Lsn(0),
     233               0 :             commit_lsn: oldstate.commit_lsn,
     234               0 :             backup_lsn: Lsn::INVALID,
     235               0 :             peer_horizon_lsn: oldstate.peer_horizon_lsn,
     236               0 :             remote_consistent_lsn: Lsn(0),
     237               0 :             peers: PersistedPeers(vec![]),
     238               0 :         });
     239               0 :     } else if version == 5 {
     240               0 :         info!("reading safekeeper control file version {}", version);
     241               0 :         let mut oldstate = SafeKeeperState::des(&buf[..buf.len()])?;
     242               0 :         if oldstate.timeline_start_lsn != Lsn(0) {
     243               0 :             return Ok(oldstate);
     244               0 :         }
     245               0 : 
     246               0 :         // set special timeline_start_lsn because we don't know the real one
     247               0 :         info!("setting timeline_start_lsn and local_start_lsn to Lsn(1)");
     248               0 :         oldstate.timeline_start_lsn = Lsn(1);
     249               0 :         oldstate.local_start_lsn = Lsn(1);
     250               0 : 
     251               0 :         return Ok(oldstate);
     252               0 :     } else if version == 6 {
     253               0 :         info!("reading safekeeper control file version {}", version);
     254               0 :         let mut oldstate = SafeKeeperState::des(&buf[..buf.len()])?;
     255               0 :         if oldstate.server.pg_version != 0 {
     256               0 :             return Ok(oldstate);
     257               0 :         }
     258               0 : 
     259               0 :         // set pg_version to the default v14
     260               0 :         info!("setting pg_version to 140005");
     261               0 :         oldstate.server.pg_version = 140005;
     262               0 : 
     263               0 :         return Ok(oldstate);
     264               0 :     }
     265               0 :     bail!("unsupported safekeeper control file version {}", version)
     266               0 : }
     267                 : 
     268                 : #[cfg(test)]
     269                 : mod tests {
     270                 :     use std::str::FromStr;
     271                 : 
     272                 :     use utils::{id::NodeId, Hex};
     273                 : 
     274                 :     use crate::safekeeper::PersistedPeerInfo;
     275                 : 
     276                 :     use super::*;
     277                 : 
     278 CBC           1 :     #[test]
     279               1 :     fn roundtrip_v1() {
     280               1 :         let tenant_id = TenantId::from_str("cf0480929707ee75372337efaa5ecf96").unwrap();
     281               1 :         let timeline_id = TimelineId::from_str("112ded66422aa5e953e5440fa5427ac4").unwrap();
     282               1 :         let state = SafeKeeperStateV1 {
     283               1 :             acceptor_state: AcceptorStateV1 {
     284               1 :                 term: 42,
     285               1 :                 epoch: 43,
     286               1 :             },
     287               1 :             server: ServerInfoV2 {
     288               1 :                 pg_version: 14,
     289               1 :                 system_id: 0x1234567887654321,
     290               1 :                 tenant_id,
     291               1 :                 timeline_id,
     292               1 :                 wal_seg_size: 0x12345678,
     293               1 :             },
     294               1 :             proposer_uuid: {
     295               1 :                 let mut arr = timeline_id.as_arr();
     296               1 :                 arr.reverse();
     297               1 :                 arr
     298               1 :             },
     299               1 :             commit_lsn: Lsn(1234567800),
     300               1 :             truncate_lsn: Lsn(123456780),
     301               1 :             wal_start_lsn: Lsn(1234567800 - 8),
     302               1 :         };
     303               1 : 
     304               1 :         let ser = state.ser().unwrap();
     305               1 :         #[rustfmt::skip]
     306               1 :         let expected = [
     307               1 :             // term
     308               1 :             0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     309               1 :             // epoch
     310               1 :             0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     311               1 :             // pg_version
     312               1 :             0x0e, 0x00, 0x00, 0x00,
     313               1 :             // system_id
     314               1 :             0x21, 0x43, 0x65, 0x87, 0x78, 0x56, 0x34, 0x12,
     315               1 :             // tenant_id
     316               1 :             0xcf, 0x04, 0x80, 0x92, 0x97, 0x07, 0xee, 0x75, 0x37, 0x23, 0x37, 0xef, 0xaa, 0x5e, 0xcf, 0x96,
     317               1 :             // timeline_id
     318               1 :             0x11, 0x2d, 0xed, 0x66, 0x42, 0x2a, 0xa5, 0xe9, 0x53, 0xe5, 0x44, 0x0f, 0xa5, 0x42, 0x7a, 0xc4,
     319               1 :             // wal_seg_size
     320               1 :             0x78, 0x56, 0x34, 0x12,
     321               1 :             // proposer_uuid
     322               1 :             0xc4, 0x7a, 0x42, 0xa5, 0x0f, 0x44, 0xe5, 0x53, 0xe9, 0xa5, 0x2a, 0x42, 0x66, 0xed, 0x2d, 0x11,
     323               1 :             // commit_lsn
     324               1 :             0x78, 0x02, 0x96, 0x49, 0x00, 0x00, 0x00, 0x00,
     325               1 :             // truncate_lsn
     326               1 :             0x0c, 0xcd, 0x5b, 0x07, 0x00, 0x00, 0x00, 0x00,
     327               1 :             // wal_start_lsn
     328               1 :             0x70, 0x02, 0x96, 0x49, 0x00, 0x00, 0x00, 0x00,
     329               1 :         ];
     330               1 : 
     331               1 :         assert_eq!(Hex(&ser), Hex(&expected));
     332                 : 
     333               1 :         let deser = SafeKeeperStateV1::des(&ser).unwrap();
     334               1 : 
     335               1 :         assert_eq!(state, deser);
     336               1 :     }
     337                 : 
     338               1 :     #[test]
     339               1 :     fn roundtrip_v2() {
     340               1 :         let tenant_id = TenantId::from_str("cf0480929707ee75372337efaa5ecf96").unwrap();
     341               1 :         let timeline_id = TimelineId::from_str("112ded66422aa5e953e5440fa5427ac4").unwrap();
     342               1 :         let state = SafeKeeperStateV2 {
     343               1 :             acceptor_state: AcceptorState {
     344               1 :                 term: 42,
     345               1 :                 term_history: TermHistory(vec![TermLsn {
     346               1 :                     lsn: Lsn(0x1),
     347               1 :                     term: 41,
     348               1 :                 }]),
     349               1 :             },
     350               1 :             server: ServerInfoV2 {
     351               1 :                 pg_version: 14,
     352               1 :                 system_id: 0x1234567887654321,
     353               1 :                 tenant_id,
     354               1 :                 timeline_id,
     355               1 :                 wal_seg_size: 0x12345678,
     356               1 :             },
     357               1 :             proposer_uuid: {
     358               1 :                 let mut arr = timeline_id.as_arr();
     359               1 :                 arr.reverse();
     360               1 :                 arr
     361               1 :             },
     362               1 :             commit_lsn: Lsn(1234567800),
     363               1 :             truncate_lsn: Lsn(123456780),
     364               1 :             wal_start_lsn: Lsn(1234567800 - 8),
     365               1 :         };
     366               1 : 
     367               1 :         let ser = state.ser().unwrap();
     368               1 :         let expected = [
     369               1 :             0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
     370               1 :             0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
     371               1 :             0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x21, 0x43, 0x65, 0x87, 0x78, 0x56,
     372               1 :             0x34, 0x12, 0xcf, 0x04, 0x80, 0x92, 0x97, 0x07, 0xee, 0x75, 0x37, 0x23, 0x37, 0xef,
     373               1 :             0xaa, 0x5e, 0xcf, 0x96, 0x11, 0x2d, 0xed, 0x66, 0x42, 0x2a, 0xa5, 0xe9, 0x53, 0xe5,
     374               1 :             0x44, 0x0f, 0xa5, 0x42, 0x7a, 0xc4, 0x78, 0x56, 0x34, 0x12, 0xc4, 0x7a, 0x42, 0xa5,
     375               1 :             0x0f, 0x44, 0xe5, 0x53, 0xe9, 0xa5, 0x2a, 0x42, 0x66, 0xed, 0x2d, 0x11, 0x78, 0x02,
     376               1 :             0x96, 0x49, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xcd, 0x5b, 0x07, 0x00, 0x00, 0x00, 0x00,
     377               1 :             0x70, 0x02, 0x96, 0x49, 0x00, 0x00, 0x00, 0x00,
     378               1 :         ];
     379               1 : 
     380               1 :         assert_eq!(Hex(&ser), Hex(&expected));
     381                 : 
     382               1 :         let deser = SafeKeeperStateV2::des(&ser).unwrap();
     383               1 : 
     384               1 :         assert_eq!(state, deser);
     385               1 :     }
     386                 : 
     387               1 :     #[test]
     388               1 :     fn roundtrip_v3() {
     389               1 :         let tenant_id = TenantId::from_str("cf0480929707ee75372337efaa5ecf96").unwrap();
     390               1 :         let timeline_id = TimelineId::from_str("112ded66422aa5e953e5440fa5427ac4").unwrap();
     391               1 :         let state = SafeKeeperStateV3 {
     392               1 :             acceptor_state: AcceptorState {
     393               1 :                 term: 42,
     394               1 :                 term_history: TermHistory(vec![TermLsn {
     395               1 :                     lsn: Lsn(0x1),
     396               1 :                     term: 41,
     397               1 :                 }]),
     398               1 :             },
     399               1 :             server: ServerInfoV3 {
     400               1 :                 pg_version: 14,
     401               1 :                 system_id: 0x1234567887654321,
     402               1 :                 tenant_id,
     403               1 :                 timeline_id,
     404               1 :                 wal_seg_size: 0x12345678,
     405               1 :             },
     406               1 :             proposer_uuid: {
     407               1 :                 let mut arr = timeline_id.as_arr();
     408               1 :                 arr.reverse();
     409               1 :                 arr
     410               1 :             },
     411               1 :             commit_lsn: Lsn(1234567800),
     412               1 :             truncate_lsn: Lsn(123456780),
     413               1 :             wal_start_lsn: Lsn(1234567800 - 8),
     414               1 :         };
     415               1 : 
     416               1 :         let ser = state.ser().unwrap();
     417               1 :         let expected = [
     418               1 :             0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
     419               1 :             0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
     420               1 :             0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x21, 0x43, 0x65, 0x87, 0x78, 0x56,
     421               1 :             0x34, 0x12, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x66, 0x30, 0x34,
     422               1 :             0x38, 0x30, 0x39, 0x32, 0x39, 0x37, 0x30, 0x37, 0x65, 0x65, 0x37, 0x35, 0x33, 0x37,
     423               1 :             0x32, 0x33, 0x33, 0x37, 0x65, 0x66, 0x61, 0x61, 0x35, 0x65, 0x63, 0x66, 0x39, 0x36,
     424               1 :             0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x31, 0x32, 0x64, 0x65, 0x64,
     425               1 :             0x36, 0x36, 0x34, 0x32, 0x32, 0x61, 0x61, 0x35, 0x65, 0x39, 0x35, 0x33, 0x65, 0x35,
     426               1 :             0x34, 0x34, 0x30, 0x66, 0x61, 0x35, 0x34, 0x32, 0x37, 0x61, 0x63, 0x34, 0x78, 0x56,
     427               1 :             0x34, 0x12, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x34, 0x37, 0x61,
     428               1 :             0x34, 0x32, 0x61, 0x35, 0x30, 0x66, 0x34, 0x34, 0x65, 0x35, 0x35, 0x33, 0x65, 0x39,
     429               1 :             0x61, 0x35, 0x32, 0x61, 0x34, 0x32, 0x36, 0x36, 0x65, 0x64, 0x32, 0x64, 0x31, 0x31,
     430               1 :             0x78, 0x02, 0x96, 0x49, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xcd, 0x5b, 0x07, 0x00, 0x00,
     431               1 :             0x00, 0x00, 0x70, 0x02, 0x96, 0x49, 0x00, 0x00, 0x00, 0x00,
     432               1 :         ];
     433               1 : 
     434               1 :         assert_eq!(Hex(&ser), Hex(&expected));
     435                 : 
     436               1 :         let deser = SafeKeeperStateV3::des(&ser).unwrap();
     437               1 : 
     438               1 :         assert_eq!(state, deser);
     439               1 :     }
     440                 : 
     441               1 :     #[test]
     442               1 :     fn roundtrip_v4() {
     443               1 :         let tenant_id = TenantId::from_str("cf0480929707ee75372337efaa5ecf96").unwrap();
     444               1 :         let timeline_id = TimelineId::from_str("112ded66422aa5e953e5440fa5427ac4").unwrap();
     445               1 :         let state = SafeKeeperStateV4 {
     446               1 :             tenant_id,
     447               1 :             timeline_id,
     448               1 :             acceptor_state: AcceptorState {
     449               1 :                 term: 42,
     450               1 :                 term_history: TermHistory(vec![TermLsn {
     451               1 :                     lsn: Lsn(0x1),
     452               1 :                     term: 41,
     453               1 :                 }]),
     454               1 :             },
     455               1 :             server: ServerInfo {
     456               1 :                 pg_version: 14,
     457               1 :                 system_id: 0x1234567887654321,
     458               1 :                 wal_seg_size: 0x12345678,
     459               1 :             },
     460               1 :             proposer_uuid: {
     461               1 :                 let mut arr = timeline_id.as_arr();
     462               1 :                 arr.reverse();
     463               1 :                 arr
     464               1 :             },
     465               1 :             peers: PersistedPeers(vec![(
     466               1 :                 NodeId(1),
     467               1 :                 PersistedPeerInfo {
     468               1 :                     backup_lsn: Lsn(1234567000),
     469               1 :                     term: 42,
     470               1 :                     flush_lsn: Lsn(1234567800 - 8),
     471               1 :                     commit_lsn: Lsn(1234567600),
     472               1 :                 },
     473               1 :             )]),
     474               1 :             commit_lsn: Lsn(1234567800),
     475               1 :             s3_wal_lsn: Lsn(1234567300),
     476               1 :             peer_horizon_lsn: Lsn(9999999),
     477               1 :             remote_consistent_lsn: Lsn(1234560000),
     478               1 :         };
     479               1 : 
     480               1 :         let ser = state.ser().unwrap();
     481               1 :         let expected = [
     482               1 :             0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x66, 0x30, 0x34, 0x38, 0x30,
     483               1 :             0x39, 0x32, 0x39, 0x37, 0x30, 0x37, 0x65, 0x65, 0x37, 0x35, 0x33, 0x37, 0x32, 0x33,
     484               1 :             0x33, 0x37, 0x65, 0x66, 0x61, 0x61, 0x35, 0x65, 0x63, 0x66, 0x39, 0x36, 0x20, 0x00,
     485               1 :             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x31, 0x32, 0x64, 0x65, 0x64, 0x36, 0x36,
     486               1 :             0x34, 0x32, 0x32, 0x61, 0x61, 0x35, 0x65, 0x39, 0x35, 0x33, 0x65, 0x35, 0x34, 0x34,
     487               1 :             0x30, 0x66, 0x61, 0x35, 0x34, 0x32, 0x37, 0x61, 0x63, 0x34, 0x2a, 0x00, 0x00, 0x00,
     488               1 :             0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00,
     489               1 :             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     490               1 :             0x0e, 0x00, 0x00, 0x00, 0x21, 0x43, 0x65, 0x87, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56,
     491               1 :             0x34, 0x12, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x34, 0x37, 0x61,
     492               1 :             0x34, 0x32, 0x61, 0x35, 0x30, 0x66, 0x34, 0x34, 0x65, 0x35, 0x35, 0x33, 0x65, 0x39,
     493               1 :             0x61, 0x35, 0x32, 0x61, 0x34, 0x32, 0x36, 0x36, 0x65, 0x64, 0x32, 0x64, 0x31, 0x31,
     494               1 :             0x78, 0x02, 0x96, 0x49, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x96, 0x49, 0x00, 0x00,
     495               1 :             0x00, 0x00, 0x7f, 0x96, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x95, 0x49,
     496               1 :             0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
     497               1 :             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0xff, 0x95, 0x49, 0x00, 0x00, 0x00, 0x00,
     498               1 :             0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x02, 0x96, 0x49, 0x00, 0x00,
     499               1 :             0x00, 0x00, 0xb0, 0x01, 0x96, 0x49, 0x00, 0x00, 0x00, 0x00,
     500               1 :         ];
     501               1 : 
     502               1 :         assert_eq!(Hex(&ser), Hex(&expected));
     503                 : 
     504               1 :         let deser = SafeKeeperStateV4::des(&ser).unwrap();
     505               1 : 
     506               1 :         assert_eq!(state, deser);
     507               1 :     }
     508                 : }
        

Generated by: LCOV version 2.1-beta