LCOV - code coverage report
Current view: top level - safekeeper/src - control_file_upgrade.rs (source / functions) Coverage Total Hit
Test: 727bdccc1d7d53837da843959afb612f56da4e79.info Lines: 52.7 % 459 242
Test Date: 2025-01-30 15:18:43 Functions: 21.2 % 85 18

            Line data    Source code
       1              : //! Code to deal with safekeeper control file upgrades
       2              : use std::vec;
       3              : 
       4              : use crate::{
       5              :     safekeeper::{AcceptorState, PgUuid, TermHistory, TermLsn},
       6              :     state::{EvictionState, TimelinePersistentState},
       7              :     wal_backup_partial,
       8              : };
       9              : use anyhow::{bail, Result};
      10              : use pq_proto::SystemId;
      11              : use safekeeper_api::{
      12              :     membership::{Configuration, INVALID_GENERATION},
      13              :     ServerInfo, Term,
      14              : };
      15              : use serde::{Deserialize, Serialize};
      16              : use tracing::*;
      17              : use utils::{
      18              :     bin_ser::LeSer,
      19              :     id::{NodeId, TenantId, TimelineId},
      20              :     lsn::Lsn,
      21              : };
      22              : 
      23              : /// Persistent consensus state of the acceptor.
      24            0 : #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
      25              : struct AcceptorStateV1 {
      26              :     /// acceptor's last term it voted for (advanced in 1 phase)
      27              :     term: Term,
      28              :     /// acceptor's epoch (advanced, i.e. bumped to 'term' when VCL is reached).
      29              :     epoch: Term,
      30              : }
      31              : 
      32            0 : #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
      33              : struct SafeKeeperStateV1 {
      34              :     /// persistent acceptor state
      35              :     acceptor_state: AcceptorStateV1,
      36              :     /// information about server
      37              :     server: ServerInfoV2,
      38              :     /// Unique id of the last *elected* proposer we dealt with. Not needed
      39              :     /// for correctness, exists for monitoring purposes.
      40              :     proposer_uuid: PgUuid,
      41              :     /// part of WAL acknowledged by quorum and available locally
      42              :     commit_lsn: Lsn,
      43              :     /// minimal LSN which may be needed for recovery of some safekeeper (end_lsn
      44              :     /// of last record streamed to everyone)
      45              :     truncate_lsn: Lsn,
      46              :     // Safekeeper starts receiving WAL from this LSN, zeros before it ought to
      47              :     // be skipped during decoding.
      48              :     wal_start_lsn: Lsn,
      49              : }
      50              : 
      51            0 : #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
      52              : pub struct ServerInfoV2 {
      53              :     /// Postgres server version
      54              :     pub pg_version: u32,
      55              :     pub system_id: SystemId,
      56              :     pub tenant_id: TenantId,
      57              :     pub timeline_id: TimelineId,
      58              :     pub wal_seg_size: u32,
      59              : }
      60              : 
      61            0 : #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
      62              : pub struct SafeKeeperStateV2 {
      63              :     /// persistent acceptor state
      64              :     pub acceptor_state: AcceptorState,
      65              :     /// information about server
      66              :     pub server: ServerInfoV2,
      67              :     /// Unique id of the last *elected* proposer we dealt with. Not needed
      68              :     /// for correctness, exists for monitoring purposes.
      69              :     pub proposer_uuid: PgUuid,
      70              :     /// part of WAL acknowledged by quorum and available locally
      71              :     pub commit_lsn: Lsn,
      72              :     /// minimal LSN which may be needed for recovery of some safekeeper (end_lsn
      73              :     /// of last record streamed to everyone)
      74              :     pub truncate_lsn: Lsn,
      75              :     // Safekeeper starts receiving WAL from this LSN, zeros before it ought to
      76              :     // be skipped during decoding.
      77              :     pub wal_start_lsn: Lsn,
      78              : }
      79              : 
      80            4 : #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
      81              : pub struct ServerInfoV3 {
      82              :     /// Postgres server version
      83              :     pub pg_version: u32,
      84              :     pub system_id: SystemId,
      85              :     #[serde(with = "hex")]
      86              :     pub tenant_id: TenantId,
      87              :     #[serde(with = "hex")]
      88              :     pub timeline_id: TimelineId,
      89              :     pub wal_seg_size: u32,
      90              : }
      91              : 
      92            2 : #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
      93              : pub struct SafeKeeperStateV3 {
      94              :     /// persistent acceptor state
      95              :     pub acceptor_state: AcceptorState,
      96              :     /// information about server
      97              :     pub server: ServerInfoV3,
      98              :     /// Unique id of the last *elected* proposer we dealt with. Not needed
      99              :     /// for correctness, exists for monitoring purposes.
     100              :     #[serde(with = "hex")]
     101              :     pub proposer_uuid: PgUuid,
     102              :     /// part of WAL acknowledged by quorum and available locally
     103              :     pub commit_lsn: Lsn,
     104              :     /// minimal LSN which may be needed for recovery of some safekeeper (end_lsn
     105              :     /// of last record streamed to everyone)
     106              :     pub truncate_lsn: Lsn,
     107              :     // Safekeeper starts receiving WAL from this LSN, zeros before it ought to
     108              :     // be skipped during decoding.
     109              :     pub wal_start_lsn: Lsn,
     110              : }
     111              : 
     112            6 : #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
     113              : pub struct SafeKeeperStateV4 {
     114              :     #[serde(with = "hex")]
     115              :     pub tenant_id: TenantId,
     116              :     #[serde(with = "hex")]
     117              :     pub timeline_id: TimelineId,
     118              :     /// persistent acceptor state
     119              :     pub acceptor_state: AcceptorState,
     120              :     /// information about server
     121              :     pub server: ServerInfo,
     122              :     /// Unique id of the last *elected* proposer we dealt with. Not needed
     123              :     /// for correctness, exists for monitoring purposes.
     124              :     #[serde(with = "hex")]
     125              :     pub proposer_uuid: PgUuid,
     126              :     /// Part of WAL acknowledged by quorum and available locally. Always points
     127              :     /// to record boundary.
     128              :     pub commit_lsn: Lsn,
     129              :     /// First LSN not yet offloaded to s3. Useful to persist to avoid finding
     130              :     /// out offloading progress on boot.
     131              :     pub s3_wal_lsn: Lsn,
     132              :     /// Minimal LSN which may be needed for recovery of some safekeeper (end_lsn
     133              :     /// of last record streamed to everyone). Persisting it helps skipping
     134              :     /// recovery in walproposer, generally we compute it from peers. In
     135              :     /// walproposer proto called 'truncate_lsn'.
     136              :     pub peer_horizon_lsn: Lsn,
     137              :     /// LSN of the oldest known checkpoint made by pageserver and successfully
     138              :     /// pushed to s3. We don't remove WAL beyond it. Persisted only for
     139              :     /// informational purposes, we receive it from pageserver (or broker).
     140              :     pub remote_consistent_lsn: Lsn,
     141              :     // Peers and their state as we remember it. Knowing peers themselves is
     142              :     // fundamental; but state is saved here only for informational purposes and
     143              :     // obviously can be stale. (Currently not saved at all, but let's provision
     144              :     // place to have less file version upgrades).
     145              :     pub peers: PersistedPeers,
     146              : }
     147              : 
     148            0 : #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
     149              : pub struct SafeKeeperStateV7 {
     150              :     #[serde(with = "hex")]
     151              :     pub tenant_id: TenantId,
     152              :     #[serde(with = "hex")]
     153              :     pub timeline_id: TimelineId,
     154              :     /// persistent acceptor state
     155              :     pub acceptor_state: AcceptorState,
     156              :     /// information about server
     157              :     pub server: ServerInfo,
     158              :     /// Unique id of the last *elected* proposer we dealt with. Not needed
     159              :     /// for correctness, exists for monitoring purposes.
     160              :     #[serde(with = "hex")]
     161              :     pub proposer_uuid: PgUuid,
     162              :     /// Since which LSN this timeline generally starts. Safekeeper might have
     163              :     /// joined later.
     164              :     pub timeline_start_lsn: Lsn,
     165              :     /// Since which LSN safekeeper has (had) WAL for this timeline.
     166              :     /// All WAL segments next to one containing local_start_lsn are
     167              :     /// filled with data from the beginning.
     168              :     pub local_start_lsn: Lsn,
     169              :     /// Part of WAL acknowledged by quorum *and available locally*. Always points
     170              :     /// to record boundary.
     171              :     pub commit_lsn: Lsn,
     172              :     /// LSN that points to the end of the last backed up segment. Useful to
     173              :     /// persist to avoid finding out offloading progress on boot.
     174              :     pub backup_lsn: Lsn,
     175              :     /// Minimal LSN which may be needed for recovery of some safekeeper (end_lsn
     176              :     /// of last record streamed to everyone). Persisting it helps skipping
     177              :     /// recovery in walproposer, generally we compute it from peers. In
     178              :     /// walproposer proto called 'truncate_lsn'. Updates are currently drived
     179              :     /// only by walproposer.
     180              :     pub peer_horizon_lsn: Lsn,
     181              :     /// LSN of the oldest known checkpoint made by pageserver and successfully
     182              :     /// pushed to s3. We don't remove WAL beyond it. Persisted only for
     183              :     /// informational purposes, we receive it from pageserver (or broker).
     184              :     pub remote_consistent_lsn: Lsn,
     185              :     // Peers and their state as we remember it. Knowing peers themselves is
     186              :     // fundamental; but state is saved here only for informational purposes and
     187              :     // obviously can be stale. (Currently not saved at all, but let's provision
     188              :     // place to have less file version upgrades).
     189              :     pub peers: PersistedPeers,
     190              : }
     191              : 
     192              : /// Persistent information stored on safekeeper node about timeline.
     193              : /// On disk data is prefixed by magic and format version and followed by checksum.
     194            0 : #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
     195              : pub struct SafeKeeperStateV8 {
     196              :     #[serde(with = "hex")]
     197              :     pub tenant_id: TenantId,
     198              :     #[serde(with = "hex")]
     199              :     pub timeline_id: TimelineId,
     200              :     /// persistent acceptor state
     201              :     pub acceptor_state: AcceptorState,
     202              :     /// information about server
     203              :     pub server: ServerInfo,
     204              :     /// Unique id of the last *elected* proposer we dealt with. Not needed
     205              :     /// for correctness, exists for monitoring purposes.
     206              :     #[serde(with = "hex")]
     207              :     pub proposer_uuid: PgUuid,
     208              :     /// Since which LSN this timeline generally starts. Safekeeper might have
     209              :     /// joined later.
     210              :     pub timeline_start_lsn: Lsn,
     211              :     /// Since which LSN safekeeper has (had) WAL for this timeline.
     212              :     /// All WAL segments next to one containing local_start_lsn are
     213              :     /// filled with data from the beginning.
     214              :     pub local_start_lsn: Lsn,
     215              :     /// Part of WAL acknowledged by quorum *and available locally*. Always points
     216              :     /// to record boundary.
     217              :     pub commit_lsn: Lsn,
     218              :     /// LSN that points to the end of the last backed up segment. Useful to
     219              :     /// persist to avoid finding out offloading progress on boot.
     220              :     pub backup_lsn: Lsn,
     221              :     /// Minimal LSN which may be needed for recovery of some safekeeper (end_lsn
     222              :     /// of last record streamed to everyone). Persisting it helps skipping
     223              :     /// recovery in walproposer, generally we compute it from peers. In
     224              :     /// walproposer proto called 'truncate_lsn'. Updates are currently drived
     225              :     /// only by walproposer.
     226              :     pub peer_horizon_lsn: Lsn,
     227              :     /// LSN of the oldest known checkpoint made by pageserver and successfully
     228              :     /// pushed to s3. We don't remove WAL beyond it. Persisted only for
     229              :     /// informational purposes, we receive it from pageserver (or broker).
     230              :     pub remote_consistent_lsn: Lsn,
     231              :     /// Peers and their state as we remember it. Knowing peers themselves is
     232              :     /// fundamental; but state is saved here only for informational purposes and
     233              :     /// obviously can be stale. (Currently not saved at all, but let's provision
     234              :     /// place to have less file version upgrades).
     235              :     pub peers: PersistedPeers,
     236              :     /// Holds names of partial segments uploaded to remote storage. Used to
     237              :     /// clean up old objects without leaving garbage in remote storage.
     238              :     pub partial_backup: wal_backup_partial::State,
     239              : }
     240              : 
     241            0 : #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
     242              : pub struct PersistedPeers(pub Vec<(NodeId, PersistedPeerInfo)>);
     243              : 
     244            0 : #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
     245              : pub struct PersistedPeerInfo {
     246              :     /// LSN up to which safekeeper offloaded WAL to s3.
     247              :     pub backup_lsn: Lsn,
     248              :     /// Term of the last entry.
     249              :     pub term: Term,
     250              :     /// LSN of the last record.
     251              :     pub flush_lsn: Lsn,
     252              :     /// Up to which LSN safekeeper regards its WAL as committed.
     253              :     pub commit_lsn: Lsn,
     254              : }
     255              : 
     256              : impl PersistedPeerInfo {
     257            0 :     pub fn new() -> Self {
     258            0 :         Self {
     259            0 :             backup_lsn: Lsn::INVALID,
     260            0 :             term: safekeeper_api::INITIAL_TERM,
     261            0 :             flush_lsn: Lsn(0),
     262            0 :             commit_lsn: Lsn(0),
     263            0 :         }
     264            0 :     }
     265              : }
     266              : 
     267              : // make clippy happy
     268              : impl Default for PersistedPeerInfo {
     269            0 :     fn default() -> Self {
     270            0 :         Self::new()
     271            0 :     }
     272              : }
     273              : 
     274              : /// Note: SafekeeperStateVn is old name for TimelinePersistentStateVn.
     275           42 : #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
     276              : pub struct TimelinePersistentStateV9 {
     277              :     #[serde(with = "hex")]
     278              :     pub tenant_id: TenantId,
     279              :     #[serde(with = "hex")]
     280              :     pub timeline_id: TimelineId,
     281              :     /// persistent acceptor state
     282              :     pub acceptor_state: AcceptorState,
     283              :     /// information about server
     284              :     pub server: ServerInfo,
     285              :     /// Unique id of the last *elected* proposer we dealt with. Not needed
     286              :     /// for correctness, exists for monitoring purposes.
     287              :     #[serde(with = "hex")]
     288              :     pub proposer_uuid: PgUuid,
     289              :     /// Since which LSN this timeline generally starts. Safekeeper might have
     290              :     /// joined later.
     291              :     pub timeline_start_lsn: Lsn,
     292              :     /// Since which LSN safekeeper has (had) WAL for this timeline.
     293              :     /// All WAL segments next to one containing local_start_lsn are
     294              :     /// filled with data from the beginning.
     295              :     pub local_start_lsn: Lsn,
     296              :     /// Part of WAL acknowledged by quorum *and available locally*. Always points
     297              :     /// to record boundary.
     298              :     pub commit_lsn: Lsn,
     299              :     /// LSN that points to the end of the last backed up segment. Useful to
     300              :     /// persist to avoid finding out offloading progress on boot.
     301              :     pub backup_lsn: Lsn,
     302              :     /// Minimal LSN which may be needed for recovery of some safekeeper (end_lsn
     303              :     /// of last record streamed to everyone). Persisting it helps skipping
     304              :     /// recovery in walproposer, generally we compute it from peers. In
     305              :     /// walproposer proto called 'truncate_lsn'. Updates are currently drived
     306              :     /// only by walproposer.
     307              :     pub peer_horizon_lsn: Lsn,
     308              :     /// LSN of the oldest known checkpoint made by pageserver and successfully
     309              :     /// pushed to s3. We don't remove WAL beyond it. Persisted only for
     310              :     /// informational purposes, we receive it from pageserver (or broker).
     311              :     pub remote_consistent_lsn: Lsn,
     312              :     /// Peers and their state as we remember it. Knowing peers themselves is
     313              :     /// fundamental; but state is saved here only for informational purposes and
     314              :     /// obviously can be stale. (Currently not saved at all, but let's provision
     315              :     /// place to have less file version upgrades).
     316              :     pub peers: PersistedPeers,
     317              :     /// Holds names of partial segments uploaded to remote storage. Used to
     318              :     /// clean up old objects without leaving garbage in remote storage.
     319              :     pub partial_backup: wal_backup_partial::State,
     320              :     /// Eviction state of the timeline. If it's Offloaded, we should download
     321              :     /// WAL files from remote storage to serve the timeline.
     322              :     pub eviction_state: EvictionState,
     323              : }
     324              : 
     325            0 : pub fn upgrade_control_file(buf: &[u8], version: u32) -> Result<TimelinePersistentState> {
     326            0 :     // migrate to storing full term history
     327            0 :     if version == 1 {
     328            0 :         info!("reading safekeeper control file version {}", version);
     329            0 :         let oldstate = SafeKeeperStateV1::des(&buf[..buf.len()])?;
     330            0 :         let ac = AcceptorState {
     331            0 :             term: oldstate.acceptor_state.term,
     332            0 :             term_history: TermHistory(vec![TermLsn {
     333            0 :                 term: oldstate.acceptor_state.epoch,
     334            0 :                 lsn: Lsn(0),
     335            0 :             }]),
     336            0 :         };
     337            0 :         return Ok(TimelinePersistentState {
     338            0 :             tenant_id: oldstate.server.tenant_id,
     339            0 :             timeline_id: oldstate.server.timeline_id,
     340            0 :             mconf: Configuration::empty(),
     341            0 :             acceptor_state: ac,
     342            0 :             server: ServerInfo {
     343            0 :                 pg_version: oldstate.server.pg_version,
     344            0 :                 system_id: oldstate.server.system_id,
     345            0 :                 wal_seg_size: oldstate.server.wal_seg_size,
     346            0 :             },
     347            0 :             proposer_uuid: oldstate.proposer_uuid,
     348            0 :             timeline_start_lsn: Lsn(0),
     349            0 :             local_start_lsn: Lsn(0),
     350            0 :             commit_lsn: oldstate.commit_lsn,
     351            0 :             backup_lsn: Lsn(0),
     352            0 :             peer_horizon_lsn: oldstate.truncate_lsn,
     353            0 :             remote_consistent_lsn: Lsn(0),
     354            0 :             partial_backup: wal_backup_partial::State::default(),
     355            0 :             eviction_state: EvictionState::Present,
     356            0 :             creation_ts: std::time::SystemTime::UNIX_EPOCH,
     357            0 :         });
     358              :     // migrate to hexing some ids
     359            0 :     } else if version == 2 {
     360            0 :         info!("reading safekeeper control file version {}", version);
     361            0 :         let oldstate = SafeKeeperStateV2::des(&buf[..buf.len()])?;
     362            0 :         let server = ServerInfo {
     363            0 :             pg_version: oldstate.server.pg_version,
     364            0 :             system_id: oldstate.server.system_id,
     365            0 :             wal_seg_size: oldstate.server.wal_seg_size,
     366            0 :         };
     367            0 :         return Ok(TimelinePersistentState {
     368            0 :             tenant_id: oldstate.server.tenant_id,
     369            0 :             timeline_id: oldstate.server.timeline_id,
     370            0 :             mconf: Configuration::empty(),
     371            0 :             acceptor_state: oldstate.acceptor_state,
     372            0 :             server,
     373            0 :             proposer_uuid: oldstate.proposer_uuid,
     374            0 :             timeline_start_lsn: Lsn(0),
     375            0 :             local_start_lsn: Lsn(0),
     376            0 :             commit_lsn: oldstate.commit_lsn,
     377            0 :             backup_lsn: Lsn(0),
     378            0 :             peer_horizon_lsn: oldstate.truncate_lsn,
     379            0 :             remote_consistent_lsn: Lsn(0),
     380            0 :             partial_backup: wal_backup_partial::State::default(),
     381            0 :             eviction_state: EvictionState::Present,
     382            0 :             creation_ts: std::time::SystemTime::UNIX_EPOCH,
     383            0 :         });
     384              :     // migrate to moving tenant_id/timeline_id to the top and adding some lsns
     385            0 :     } else if version == 3 {
     386            0 :         info!("reading safekeeper control file version {version}");
     387            0 :         let oldstate = SafeKeeperStateV3::des(&buf[..buf.len()])?;
     388            0 :         let server = ServerInfo {
     389            0 :             pg_version: oldstate.server.pg_version,
     390            0 :             system_id: oldstate.server.system_id,
     391            0 :             wal_seg_size: oldstate.server.wal_seg_size,
     392            0 :         };
     393            0 :         return Ok(TimelinePersistentState {
     394            0 :             tenant_id: oldstate.server.tenant_id,
     395            0 :             timeline_id: oldstate.server.timeline_id,
     396            0 :             mconf: Configuration::empty(),
     397            0 :             acceptor_state: oldstate.acceptor_state,
     398            0 :             server,
     399            0 :             proposer_uuid: oldstate.proposer_uuid,
     400            0 :             timeline_start_lsn: Lsn(0),
     401            0 :             local_start_lsn: Lsn(0),
     402            0 :             commit_lsn: oldstate.commit_lsn,
     403            0 :             backup_lsn: Lsn(0),
     404            0 :             peer_horizon_lsn: oldstate.truncate_lsn,
     405            0 :             remote_consistent_lsn: Lsn(0),
     406            0 :             partial_backup: wal_backup_partial::State::default(),
     407            0 :             eviction_state: EvictionState::Present,
     408            0 :             creation_ts: std::time::SystemTime::UNIX_EPOCH,
     409            0 :         });
     410              :     // migrate to having timeline_start_lsn
     411            0 :     } else if version == 4 {
     412            0 :         info!("reading safekeeper control file version {}", version);
     413            0 :         let oldstate = SafeKeeperStateV4::des(&buf[..buf.len()])?;
     414            0 :         let server = ServerInfo {
     415            0 :             pg_version: oldstate.server.pg_version,
     416            0 :             system_id: oldstate.server.system_id,
     417            0 :             wal_seg_size: oldstate.server.wal_seg_size,
     418            0 :         };
     419            0 :         return Ok(TimelinePersistentState {
     420            0 :             tenant_id: oldstate.tenant_id,
     421            0 :             timeline_id: oldstate.timeline_id,
     422            0 :             mconf: Configuration::empty(),
     423            0 :             acceptor_state: oldstate.acceptor_state,
     424            0 :             server,
     425            0 :             proposer_uuid: oldstate.proposer_uuid,
     426            0 :             timeline_start_lsn: Lsn(0),
     427            0 :             local_start_lsn: Lsn(0),
     428            0 :             commit_lsn: oldstate.commit_lsn,
     429            0 :             backup_lsn: Lsn::INVALID,
     430            0 :             peer_horizon_lsn: oldstate.peer_horizon_lsn,
     431            0 :             remote_consistent_lsn: Lsn(0),
     432            0 :             partial_backup: wal_backup_partial::State::default(),
     433            0 :             eviction_state: EvictionState::Present,
     434            0 :             creation_ts: std::time::SystemTime::UNIX_EPOCH,
     435            0 :         });
     436            0 :     } else if version == 5 {
     437            0 :         info!("reading safekeeper control file version {}", version);
     438            0 :         let mut oldstate = TimelinePersistentState::des(&buf[..buf.len()])?;
     439            0 :         if oldstate.timeline_start_lsn != Lsn(0) {
     440            0 :             return Ok(oldstate);
     441            0 :         }
     442            0 : 
     443            0 :         // set special timeline_start_lsn because we don't know the real one
     444            0 :         info!("setting timeline_start_lsn and local_start_lsn to Lsn(1)");
     445            0 :         oldstate.timeline_start_lsn = Lsn(1);
     446            0 :         oldstate.local_start_lsn = Lsn(1);
     447            0 : 
     448            0 :         return Ok(oldstate);
     449            0 :     } else if version == 6 {
     450            0 :         info!("reading safekeeper control file version {}", version);
     451            0 :         let mut oldstate = TimelinePersistentState::des(&buf[..buf.len()])?;
     452            0 :         if oldstate.server.pg_version != 0 {
     453            0 :             return Ok(oldstate);
     454            0 :         }
     455            0 : 
     456            0 :         // set pg_version to the default v14
     457            0 :         info!("setting pg_version to 140005");
     458            0 :         oldstate.server.pg_version = 140005;
     459            0 : 
     460            0 :         return Ok(oldstate);
     461            0 :     } else if version == 7 {
     462            0 :         info!("reading safekeeper control file version {}", version);
     463            0 :         let oldstate = SafeKeeperStateV7::des(&buf[..buf.len()])?;
     464              : 
     465            0 :         return Ok(TimelinePersistentState {
     466            0 :             tenant_id: oldstate.tenant_id,
     467            0 :             timeline_id: oldstate.timeline_id,
     468            0 :             mconf: Configuration::empty(),
     469            0 :             acceptor_state: oldstate.acceptor_state,
     470            0 :             server: oldstate.server,
     471            0 :             proposer_uuid: oldstate.proposer_uuid,
     472            0 :             timeline_start_lsn: oldstate.timeline_start_lsn,
     473            0 :             local_start_lsn: oldstate.local_start_lsn,
     474            0 :             commit_lsn: oldstate.commit_lsn,
     475            0 :             backup_lsn: oldstate.backup_lsn,
     476            0 :             peer_horizon_lsn: oldstate.peer_horizon_lsn,
     477            0 :             remote_consistent_lsn: oldstate.remote_consistent_lsn,
     478            0 :             partial_backup: wal_backup_partial::State::default(),
     479            0 :             eviction_state: EvictionState::Present,
     480            0 :             creation_ts: std::time::SystemTime::UNIX_EPOCH,
     481            0 :         });
     482            0 :     } else if version == 8 {
     483            0 :         let oldstate = SafeKeeperStateV8::des(&buf[..buf.len()])?;
     484              : 
     485            0 :         return Ok(TimelinePersistentState {
     486            0 :             tenant_id: oldstate.tenant_id,
     487            0 :             timeline_id: oldstate.timeline_id,
     488            0 :             mconf: Configuration::empty(),
     489            0 :             acceptor_state: oldstate.acceptor_state,
     490            0 :             server: oldstate.server,
     491            0 :             proposer_uuid: oldstate.proposer_uuid,
     492            0 :             timeline_start_lsn: oldstate.timeline_start_lsn,
     493            0 :             local_start_lsn: oldstate.local_start_lsn,
     494            0 :             commit_lsn: oldstate.commit_lsn,
     495            0 :             backup_lsn: oldstate.backup_lsn,
     496            0 :             peer_horizon_lsn: oldstate.peer_horizon_lsn,
     497            0 :             remote_consistent_lsn: oldstate.remote_consistent_lsn,
     498            0 :             partial_backup: oldstate.partial_backup,
     499            0 :             eviction_state: EvictionState::Present,
     500            0 :             creation_ts: std::time::SystemTime::UNIX_EPOCH,
     501            0 :         });
     502            0 :     } else if version == 9 {
     503            0 :         let oldstate = TimelinePersistentStateV9::des(&buf[..buf.len()])?;
     504            0 :         return Ok(TimelinePersistentState {
     505            0 :             tenant_id: oldstate.tenant_id,
     506            0 :             timeline_id: oldstate.timeline_id,
     507            0 :             mconf: Configuration::empty(),
     508            0 :             acceptor_state: oldstate.acceptor_state,
     509            0 :             server: oldstate.server,
     510            0 :             proposer_uuid: oldstate.proposer_uuid,
     511            0 :             timeline_start_lsn: oldstate.timeline_start_lsn,
     512            0 :             local_start_lsn: oldstate.local_start_lsn,
     513            0 :             commit_lsn: oldstate.commit_lsn,
     514            0 :             backup_lsn: oldstate.backup_lsn,
     515            0 :             peer_horizon_lsn: oldstate.peer_horizon_lsn,
     516            0 :             remote_consistent_lsn: oldstate.remote_consistent_lsn,
     517            0 :             partial_backup: oldstate.partial_backup,
     518            0 :             eviction_state: oldstate.eviction_state,
     519            0 :             creation_ts: std::time::SystemTime::UNIX_EPOCH,
     520            0 :         });
     521            0 :     }
     522            0 : 
     523            0 :     // TODO: persist the file back to the disk after upgrade
     524            0 :     // TODO: think about backward compatibility and rollbacks
     525            0 : 
     526            0 :     bail!("unsupported safekeeper control file version {}", version)
     527            0 : }
     528              : 
     529              : // Used as a temp hack to make forward compatibility test work. Should be
     530              : // removed after PR adding v10 is merged.
     531           14 : pub fn downgrade_v10_to_v9(state: &TimelinePersistentState) -> TimelinePersistentStateV9 {
     532           14 :     assert!(state.mconf.generation == INVALID_GENERATION);
     533           14 :     TimelinePersistentStateV9 {
     534           14 :         tenant_id: state.tenant_id,
     535           14 :         timeline_id: state.timeline_id,
     536           14 :         acceptor_state: state.acceptor_state.clone(),
     537           14 :         server: state.server.clone(),
     538           14 :         proposer_uuid: state.proposer_uuid,
     539           14 :         timeline_start_lsn: state.timeline_start_lsn,
     540           14 :         local_start_lsn: state.local_start_lsn,
     541           14 :         commit_lsn: state.commit_lsn,
     542           14 :         backup_lsn: state.backup_lsn,
     543           14 :         peer_horizon_lsn: state.peer_horizon_lsn,
     544           14 :         remote_consistent_lsn: state.remote_consistent_lsn,
     545           14 :         peers: PersistedPeers(vec![]),
     546           14 :         partial_backup: state.partial_backup.clone(),
     547           14 :         eviction_state: state.eviction_state,
     548           14 :     }
     549           14 : }
     550              : 
     551              : #[cfg(test)]
     552              : mod tests {
     553              :     use std::str::FromStr;
     554              : 
     555              :     use utils::{id::NodeId, Hex};
     556              : 
     557              :     use crate::control_file_upgrade::PersistedPeerInfo;
     558              : 
     559              :     use super::*;
     560              : 
     561              :     #[test]
     562            1 :     fn roundtrip_v1() {
     563            1 :         let tenant_id = TenantId::from_str("cf0480929707ee75372337efaa5ecf96").unwrap();
     564            1 :         let timeline_id = TimelineId::from_str("112ded66422aa5e953e5440fa5427ac4").unwrap();
     565            1 :         let state = SafeKeeperStateV1 {
     566            1 :             acceptor_state: AcceptorStateV1 {
     567            1 :                 term: 42,
     568            1 :                 epoch: 43,
     569            1 :             },
     570            1 :             server: ServerInfoV2 {
     571            1 :                 pg_version: 14,
     572            1 :                 system_id: 0x1234567887654321,
     573            1 :                 tenant_id,
     574            1 :                 timeline_id,
     575            1 :                 wal_seg_size: 0x12345678,
     576            1 :             },
     577            1 :             proposer_uuid: {
     578            1 :                 let mut arr = timeline_id.as_arr();
     579            1 :                 arr.reverse();
     580            1 :                 arr
     581            1 :             },
     582            1 :             commit_lsn: Lsn(1234567800),
     583            1 :             truncate_lsn: Lsn(123456780),
     584            1 :             wal_start_lsn: Lsn(1234567800 - 8),
     585            1 :         };
     586            1 : 
     587            1 :         let ser = state.ser().unwrap();
     588            1 :         #[rustfmt::skip]
     589            1 :         let expected = [
     590            1 :             // term
     591            1 :             0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     592            1 :             // epoch
     593            1 :             0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     594            1 :             // pg_version
     595            1 :             0x0e, 0x00, 0x00, 0x00,
     596            1 :             // system_id
     597            1 :             0x21, 0x43, 0x65, 0x87, 0x78, 0x56, 0x34, 0x12,
     598            1 :             // tenant_id
     599            1 :             0xcf, 0x04, 0x80, 0x92, 0x97, 0x07, 0xee, 0x75, 0x37, 0x23, 0x37, 0xef, 0xaa, 0x5e, 0xcf, 0x96,
     600            1 :             // timeline_id
     601            1 :             0x11, 0x2d, 0xed, 0x66, 0x42, 0x2a, 0xa5, 0xe9, 0x53, 0xe5, 0x44, 0x0f, 0xa5, 0x42, 0x7a, 0xc4,
     602            1 :             // wal_seg_size
     603            1 :             0x78, 0x56, 0x34, 0x12,
     604            1 :             // proposer_uuid
     605            1 :             0xc4, 0x7a, 0x42, 0xa5, 0x0f, 0x44, 0xe5, 0x53, 0xe9, 0xa5, 0x2a, 0x42, 0x66, 0xed, 0x2d, 0x11,
     606            1 :             // commit_lsn
     607            1 :             0x78, 0x02, 0x96, 0x49, 0x00, 0x00, 0x00, 0x00,
     608            1 :             // truncate_lsn
     609            1 :             0x0c, 0xcd, 0x5b, 0x07, 0x00, 0x00, 0x00, 0x00,
     610            1 :             // wal_start_lsn
     611            1 :             0x70, 0x02, 0x96, 0x49, 0x00, 0x00, 0x00, 0x00,
     612            1 :         ];
     613            1 : 
     614            1 :         assert_eq!(Hex(&ser), Hex(&expected));
     615              : 
     616            1 :         let deser = SafeKeeperStateV1::des(&ser).unwrap();
     617            1 : 
     618            1 :         assert_eq!(state, deser);
     619            1 :     }
     620              : 
     621              :     #[test]
     622            1 :     fn roundtrip_v2() {
     623            1 :         let tenant_id = TenantId::from_str("cf0480929707ee75372337efaa5ecf96").unwrap();
     624            1 :         let timeline_id = TimelineId::from_str("112ded66422aa5e953e5440fa5427ac4").unwrap();
     625            1 :         let state = SafeKeeperStateV2 {
     626            1 :             acceptor_state: AcceptorState {
     627            1 :                 term: 42,
     628            1 :                 term_history: TermHistory(vec![TermLsn {
     629            1 :                     lsn: Lsn(0x1),
     630            1 :                     term: 41,
     631            1 :                 }]),
     632            1 :             },
     633            1 :             server: ServerInfoV2 {
     634            1 :                 pg_version: 14,
     635            1 :                 system_id: 0x1234567887654321,
     636            1 :                 tenant_id,
     637            1 :                 timeline_id,
     638            1 :                 wal_seg_size: 0x12345678,
     639            1 :             },
     640            1 :             proposer_uuid: {
     641            1 :                 let mut arr = timeline_id.as_arr();
     642            1 :                 arr.reverse();
     643            1 :                 arr
     644            1 :             },
     645            1 :             commit_lsn: Lsn(1234567800),
     646            1 :             truncate_lsn: Lsn(123456780),
     647            1 :             wal_start_lsn: Lsn(1234567800 - 8),
     648            1 :         };
     649            1 : 
     650            1 :         let ser = state.ser().unwrap();
     651            1 :         let expected = [
     652            1 :             0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
     653            1 :             0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
     654            1 :             0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x21, 0x43, 0x65, 0x87, 0x78, 0x56,
     655            1 :             0x34, 0x12, 0xcf, 0x04, 0x80, 0x92, 0x97, 0x07, 0xee, 0x75, 0x37, 0x23, 0x37, 0xef,
     656            1 :             0xaa, 0x5e, 0xcf, 0x96, 0x11, 0x2d, 0xed, 0x66, 0x42, 0x2a, 0xa5, 0xe9, 0x53, 0xe5,
     657            1 :             0x44, 0x0f, 0xa5, 0x42, 0x7a, 0xc4, 0x78, 0x56, 0x34, 0x12, 0xc4, 0x7a, 0x42, 0xa5,
     658            1 :             0x0f, 0x44, 0xe5, 0x53, 0xe9, 0xa5, 0x2a, 0x42, 0x66, 0xed, 0x2d, 0x11, 0x78, 0x02,
     659            1 :             0x96, 0x49, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xcd, 0x5b, 0x07, 0x00, 0x00, 0x00, 0x00,
     660            1 :             0x70, 0x02, 0x96, 0x49, 0x00, 0x00, 0x00, 0x00,
     661            1 :         ];
     662            1 : 
     663            1 :         assert_eq!(Hex(&ser), Hex(&expected));
     664              : 
     665            1 :         let deser = SafeKeeperStateV2::des(&ser).unwrap();
     666            1 : 
     667            1 :         assert_eq!(state, deser);
     668            1 :     }
     669              : 
     670              :     #[test]
     671            1 :     fn roundtrip_v3() {
     672            1 :         let tenant_id = TenantId::from_str("cf0480929707ee75372337efaa5ecf96").unwrap();
     673            1 :         let timeline_id = TimelineId::from_str("112ded66422aa5e953e5440fa5427ac4").unwrap();
     674            1 :         let state = SafeKeeperStateV3 {
     675            1 :             acceptor_state: AcceptorState {
     676            1 :                 term: 42,
     677            1 :                 term_history: TermHistory(vec![TermLsn {
     678            1 :                     lsn: Lsn(0x1),
     679            1 :                     term: 41,
     680            1 :                 }]),
     681            1 :             },
     682            1 :             server: ServerInfoV3 {
     683            1 :                 pg_version: 14,
     684            1 :                 system_id: 0x1234567887654321,
     685            1 :                 tenant_id,
     686            1 :                 timeline_id,
     687            1 :                 wal_seg_size: 0x12345678,
     688            1 :             },
     689            1 :             proposer_uuid: {
     690            1 :                 let mut arr = timeline_id.as_arr();
     691            1 :                 arr.reverse();
     692            1 :                 arr
     693            1 :             },
     694            1 :             commit_lsn: Lsn(1234567800),
     695            1 :             truncate_lsn: Lsn(123456780),
     696            1 :             wal_start_lsn: Lsn(1234567800 - 8),
     697            1 :         };
     698            1 : 
     699            1 :         let ser = state.ser().unwrap();
     700            1 :         let expected = [
     701            1 :             0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
     702            1 :             0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
     703            1 :             0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x21, 0x43, 0x65, 0x87, 0x78, 0x56,
     704            1 :             0x34, 0x12, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x66, 0x30, 0x34,
     705            1 :             0x38, 0x30, 0x39, 0x32, 0x39, 0x37, 0x30, 0x37, 0x65, 0x65, 0x37, 0x35, 0x33, 0x37,
     706            1 :             0x32, 0x33, 0x33, 0x37, 0x65, 0x66, 0x61, 0x61, 0x35, 0x65, 0x63, 0x66, 0x39, 0x36,
     707            1 :             0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x31, 0x32, 0x64, 0x65, 0x64,
     708            1 :             0x36, 0x36, 0x34, 0x32, 0x32, 0x61, 0x61, 0x35, 0x65, 0x39, 0x35, 0x33, 0x65, 0x35,
     709            1 :             0x34, 0x34, 0x30, 0x66, 0x61, 0x35, 0x34, 0x32, 0x37, 0x61, 0x63, 0x34, 0x78, 0x56,
     710            1 :             0x34, 0x12, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x34, 0x37, 0x61,
     711            1 :             0x34, 0x32, 0x61, 0x35, 0x30, 0x66, 0x34, 0x34, 0x65, 0x35, 0x35, 0x33, 0x65, 0x39,
     712            1 :             0x61, 0x35, 0x32, 0x61, 0x34, 0x32, 0x36, 0x36, 0x65, 0x64, 0x32, 0x64, 0x31, 0x31,
     713            1 :             0x78, 0x02, 0x96, 0x49, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xcd, 0x5b, 0x07, 0x00, 0x00,
     714            1 :             0x00, 0x00, 0x70, 0x02, 0x96, 0x49, 0x00, 0x00, 0x00, 0x00,
     715            1 :         ];
     716            1 : 
     717            1 :         assert_eq!(Hex(&ser), Hex(&expected));
     718              : 
     719            1 :         let deser = SafeKeeperStateV3::des(&ser).unwrap();
     720            1 : 
     721            1 :         assert_eq!(state, deser);
     722            1 :     }
     723              : 
     724              :     #[test]
     725            1 :     fn roundtrip_v4() {
     726            1 :         let tenant_id = TenantId::from_str("cf0480929707ee75372337efaa5ecf96").unwrap();
     727            1 :         let timeline_id = TimelineId::from_str("112ded66422aa5e953e5440fa5427ac4").unwrap();
     728            1 :         let state = SafeKeeperStateV4 {
     729            1 :             tenant_id,
     730            1 :             timeline_id,
     731            1 :             acceptor_state: AcceptorState {
     732            1 :                 term: 42,
     733            1 :                 term_history: TermHistory(vec![TermLsn {
     734            1 :                     lsn: Lsn(0x1),
     735            1 :                     term: 41,
     736            1 :                 }]),
     737            1 :             },
     738            1 :             server: ServerInfo {
     739            1 :                 pg_version: 14,
     740            1 :                 system_id: 0x1234567887654321,
     741            1 :                 wal_seg_size: 0x12345678,
     742            1 :             },
     743            1 :             proposer_uuid: {
     744            1 :                 let mut arr = timeline_id.as_arr();
     745            1 :                 arr.reverse();
     746            1 :                 arr
     747            1 :             },
     748            1 :             peers: PersistedPeers(vec![(
     749            1 :                 NodeId(1),
     750            1 :                 PersistedPeerInfo {
     751            1 :                     backup_lsn: Lsn(1234567000),
     752            1 :                     term: 42,
     753            1 :                     flush_lsn: Lsn(1234567800 - 8),
     754            1 :                     commit_lsn: Lsn(1234567600),
     755            1 :                 },
     756            1 :             )]),
     757            1 :             commit_lsn: Lsn(1234567800),
     758            1 :             s3_wal_lsn: Lsn(1234567300),
     759            1 :             peer_horizon_lsn: Lsn(9999999),
     760            1 :             remote_consistent_lsn: Lsn(1234560000),
     761            1 :         };
     762            1 : 
     763            1 :         let ser = state.ser().unwrap();
     764            1 :         let expected = [
     765            1 :             0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x66, 0x30, 0x34, 0x38, 0x30,
     766            1 :             0x39, 0x32, 0x39, 0x37, 0x30, 0x37, 0x65, 0x65, 0x37, 0x35, 0x33, 0x37, 0x32, 0x33,
     767            1 :             0x33, 0x37, 0x65, 0x66, 0x61, 0x61, 0x35, 0x65, 0x63, 0x66, 0x39, 0x36, 0x20, 0x00,
     768            1 :             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x31, 0x32, 0x64, 0x65, 0x64, 0x36, 0x36,
     769            1 :             0x34, 0x32, 0x32, 0x61, 0x61, 0x35, 0x65, 0x39, 0x35, 0x33, 0x65, 0x35, 0x34, 0x34,
     770            1 :             0x30, 0x66, 0x61, 0x35, 0x34, 0x32, 0x37, 0x61, 0x63, 0x34, 0x2a, 0x00, 0x00, 0x00,
     771            1 :             0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00,
     772            1 :             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     773            1 :             0x0e, 0x00, 0x00, 0x00, 0x21, 0x43, 0x65, 0x87, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56,
     774            1 :             0x34, 0x12, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x34, 0x37, 0x61,
     775            1 :             0x34, 0x32, 0x61, 0x35, 0x30, 0x66, 0x34, 0x34, 0x65, 0x35, 0x35, 0x33, 0x65, 0x39,
     776            1 :             0x61, 0x35, 0x32, 0x61, 0x34, 0x32, 0x36, 0x36, 0x65, 0x64, 0x32, 0x64, 0x31, 0x31,
     777            1 :             0x78, 0x02, 0x96, 0x49, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x96, 0x49, 0x00, 0x00,
     778            1 :             0x00, 0x00, 0x7f, 0x96, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x95, 0x49,
     779            1 :             0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
     780            1 :             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0xff, 0x95, 0x49, 0x00, 0x00, 0x00, 0x00,
     781            1 :             0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x02, 0x96, 0x49, 0x00, 0x00,
     782            1 :             0x00, 0x00, 0xb0, 0x01, 0x96, 0x49, 0x00, 0x00, 0x00, 0x00,
     783            1 :         ];
     784            1 : 
     785            1 :         assert_eq!(Hex(&ser), Hex(&expected));
     786              : 
     787            1 :         let deser = SafeKeeperStateV4::des(&ser).unwrap();
     788            1 : 
     789            1 :         assert_eq!(state, deser);
     790            1 :     }
     791              : }
        

Generated by: LCOV version 2.1-beta