LCOV - code coverage report
Current view: top level - libs/utils/src - lsn.rs (source / functions) Coverage Total Hit
Test: b9d67f908f91f00e353a27440ba89f642a869959.info Lines: 85.6 % 326 279
Test Date: 2024-11-19 21:44:13 Functions: 59.6 % 104 62

            Line data    Source code
       1              : #![warn(missing_docs)]
       2              : 
       3              : use serde::{de::Visitor, Deserialize, Serialize};
       4              : use std::fmt;
       5              : use std::ops::{Add, AddAssign};
       6              : use std::str::FromStr;
       7              : use std::sync::atomic::{AtomicU64, Ordering};
       8              : 
       9              : use crate::seqwait::MonotonicCounter;
      10              : 
      11              : /// Transaction log block size in bytes
      12              : pub const XLOG_BLCKSZ: u32 = 8192;
      13              : 
      14              : /// A Postgres LSN (Log Sequence Number), also known as an XLogRecPtr
      15              : #[derive(Clone, Copy, Default, Eq, Ord, PartialEq, PartialOrd, Hash)]
      16              : pub struct Lsn(pub u64);
      17              : 
      18              : impl Serialize for Lsn {
      19        20658 :     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
      20        20658 :     where
      21        20658 :         S: serde::Serializer,
      22        20658 :     {
      23        20658 :         if serializer.is_human_readable() {
      24        17065 :             serializer.collect_str(self)
      25              :         } else {
      26         3593 :             self.0.serialize(serializer)
      27              :         }
      28        20658 :     }
      29              : }
      30              : 
      31              : impl<'de> Deserialize<'de> for Lsn {
      32        23705 :     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
      33        23705 :     where
      34        23705 :         D: serde::Deserializer<'de>,
      35        23705 :     {
      36              :         struct LsnVisitor {
      37              :             is_human_readable_deserializer: bool,
      38              :         }
      39              : 
      40              :         impl Visitor<'_> for LsnVisitor {
      41              :             type Value = Lsn;
      42              : 
      43            2 :             fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
      44            2 :                 if self.is_human_readable_deserializer {
      45            1 :                     formatter.write_str(
      46            1 :                         "value in form of hex string({upper_u32_hex}/{lower_u32_hex}) representing u64 integer",
      47            1 :                     )
      48              :                 } else {
      49            1 :                     formatter.write_str("value in form of integer(u64)")
      50              :                 }
      51            2 :             }
      52              : 
      53        23484 :             fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
      54        23484 :             where
      55        23484 :                 E: serde::de::Error,
      56        23484 :             {
      57        23484 :                 Ok(Lsn(v))
      58        23484 :             }
      59              : 
      60          219 :             fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
      61          219 :             where
      62          219 :                 E: serde::de::Error,
      63          219 :             {
      64          219 :                 Lsn::from_str(v).map_err(|e| E::custom(e))
      65          219 :             }
      66              :         }
      67              : 
      68        23705 :         if deserializer.is_human_readable() {
      69          220 :             deserializer.deserialize_str(LsnVisitor {
      70          220 :                 is_human_readable_deserializer: true,
      71          220 :             })
      72              :         } else {
      73        23485 :             deserializer.deserialize_u64(LsnVisitor {
      74        23485 :                 is_human_readable_deserializer: false,
      75        23485 :             })
      76              :         }
      77        23705 :     }
      78              : }
      79              : 
      80              : /// Allows (de)serialization of an `Lsn` always as `u64`.
      81              : ///
      82              : /// ### Example
      83              : ///
      84              : /// ```rust
      85              : /// # use serde::{Serialize, Deserialize};
      86              : /// use utils::lsn::Lsn;
      87              : ///
      88              : /// #[derive(PartialEq, Serialize, Deserialize, Debug)]
      89              : /// struct Foo {
      90              : ///   #[serde(with = "utils::lsn::serde_as_u64")]
      91              : ///   always_u64: Lsn,
      92              : /// }
      93              : ///
      94              : /// let orig = Foo { always_u64: Lsn(1234) };
      95              : ///
      96              : /// let res = serde_json::to_string(&orig).unwrap();
      97              : /// assert_eq!(res, r#"{"always_u64":1234}"#);
      98              : ///
      99              : /// let foo = serde_json::from_str::<Foo>(&res).unwrap();
     100              : /// assert_eq!(foo, orig);
     101              : /// ```
     102              : ///
     103              : pub mod serde_as_u64 {
     104              :     use super::Lsn;
     105              : 
     106              :     /// Serializes the Lsn as u64 disregarding the human readability of the format.
     107              :     ///
     108              :     /// Meant to be used via `#[serde(with = "...")]` or `#[serde(serialize_with = "...")]`.
     109            0 :     pub fn serialize<S: serde::Serializer>(lsn: &Lsn, serializer: S) -> Result<S::Ok, S::Error> {
     110              :         use serde::Serialize;
     111            0 :         lsn.0.serialize(serializer)
     112            0 :     }
     113              : 
     114              :     /// Deserializes the Lsn as u64 disregarding the human readability of the format.
     115              :     ///
     116              :     /// Meant to be used via `#[serde(with = "...")]` or `#[serde(deserialize_with = "...")]`.
     117            0 :     pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<Lsn, D::Error> {
     118              :         use serde::Deserialize;
     119            0 :         u64::deserialize(deserializer).map(Lsn)
     120            0 :     }
     121              : }
     122              : 
     123              : /// We tried to parse an LSN from a string, but failed
     124            0 : #[derive(Debug, PartialEq, Eq, thiserror::Error)]
     125              : #[error("LsnParseError")]
     126              : pub struct LsnParseError;
     127              : 
     128              : impl Lsn {
     129              :     /// Maximum possible value for an LSN
     130              :     pub const MAX: Lsn = Lsn(u64::MAX);
     131              : 
     132              :     /// Invalid value for InvalidXLogRecPtr, as defined in xlogdefs.h
     133              :     pub const INVALID: Lsn = Lsn(0);
     134              : 
     135              :     /// Subtract a number, returning None on overflow.
     136         4917 :     pub fn checked_sub<T: Into<u64>>(self, other: T) -> Option<Lsn> {
     137         4917 :         let other: u64 = other.into();
     138         4917 :         self.0.checked_sub(other).map(Lsn)
     139         4917 :     }
     140              : 
     141              :     /// Subtract a number, saturating at numeric bounds instead of overflowing.
     142            0 :     pub fn saturating_sub<T: Into<u64>>(self, other: T) -> Lsn {
     143            0 :         Lsn(self.0.saturating_sub(other.into()))
     144            0 :     }
     145              : 
     146              :     /// Subtract a number, returning the difference as i128 to avoid overflow.
     147      4803014 :     pub fn widening_sub<T: Into<u64>>(self, other: T) -> i128 {
     148      4803014 :         let other: u64 = other.into();
     149      4803014 :         i128::from(self.0) - i128::from(other)
     150      4803014 :     }
     151              : 
     152              :     /// Parse an LSN from a string in the form `0000000000000000`
     153         4967 :     pub fn from_hex<S>(s: S) -> Result<Self, LsnParseError>
     154         4967 :     where
     155         4967 :         S: AsRef<str>,
     156         4967 :     {
     157         4967 :         let s: &str = s.as_ref();
     158         4967 :         let n = u64::from_str_radix(s, 16).or(Err(LsnParseError))?;
     159         4960 :         Ok(Lsn(n))
     160         4967 :     }
     161              : 
     162              :     /// Compute the offset into a segment
     163              :     #[inline]
     164       817998 :     pub fn segment_offset(self, seg_sz: usize) -> usize {
     165       817998 :         (self.0 % seg_sz as u64) as usize
     166       817998 :     }
     167              : 
     168              :     /// Compute LSN of the segment start.
     169              :     #[inline]
     170            0 :     pub fn segment_lsn(self, seg_sz: usize) -> Lsn {
     171            0 :         Lsn(self.0 - (self.0 % seg_sz as u64))
     172            0 :     }
     173              : 
     174              :     /// Compute the segment number
     175              :     #[inline]
     176        16547 :     pub fn segment_number(self, seg_sz: usize) -> u64 {
     177        16547 :         self.0 / seg_sz as u64
     178        16547 :     }
     179              : 
     180              :     /// Compute the offset into a block
     181              :     #[inline]
     182       829949 :     pub fn block_offset(self) -> u64 {
     183              :         const BLCKSZ: u64 = XLOG_BLCKSZ as u64;
     184       829949 :         self.0 % BLCKSZ
     185       829949 :     }
     186              : 
     187              :     /// Compute the block offset of the first byte of this Lsn within this
     188              :     /// segment
     189              :     #[inline]
     190            0 :     pub fn page_lsn(self) -> Lsn {
     191            0 :         Lsn(self.0 - self.block_offset())
     192            0 :     }
     193              : 
     194              :     /// Compute the block offset of the first byte of this Lsn within this
     195              :     /// segment
     196              :     #[inline]
     197            0 :     pub fn page_offset_in_segment(self, seg_sz: usize) -> u64 {
     198            0 :         (self.0 - self.block_offset()) - self.segment_lsn(seg_sz).0
     199            0 :     }
     200              : 
     201              :     /// Compute the bytes remaining in this block
     202              :     ///
     203              :     /// If the LSN is already at the block boundary, it will return `XLOG_BLCKSZ`.
     204              :     #[inline]
     205       809461 :     pub fn remaining_in_block(self) -> u64 {
     206              :         const BLCKSZ: u64 = XLOG_BLCKSZ as u64;
     207       809461 :         BLCKSZ - (self.0 % BLCKSZ)
     208       809461 :     }
     209              : 
     210              :     /// Compute the bytes remaining to fill a chunk of some size
     211              :     ///
     212              :     /// If the LSN is already at the chunk boundary, it will return 0.
     213        12016 :     pub fn calc_padding<T: Into<u64>>(self, sz: T) -> u64 {
     214        12016 :         let sz: u64 = sz.into();
     215        12016 :         // By using wrapping_sub, we can subtract first and then mod second.
     216        12016 :         // If it's done the other way around, then we would return a full
     217        12016 :         // chunk size if we're already at the chunk boundary.
     218        12016 :         // (Regular subtraction will panic on overflow in debug builds.)
     219        12016 :         (sz.wrapping_sub(self.0)) % sz
     220        12016 :     }
     221              : 
     222              :     /// Align LSN on 8-byte boundary (alignment of WAL records).
     223      5451647 :     pub fn align(&self) -> Lsn {
     224      5451647 :         Lsn((self.0 + 7) & !7)
     225      5451647 :     }
     226              : 
     227              :     /// Align LSN on 8-byte boundary (alignment of WAL records).
     228      5280380 :     pub fn is_aligned(&self) -> bool {
     229      5280380 :         *self == self.align()
     230      5280380 :     }
     231              : 
     232              :     /// Return if the LSN is valid
     233              :     /// mimics postgres XLogRecPtrIsInvalid macro
     234      8723826 :     pub fn is_valid(self) -> bool {
     235      8723826 :         self != Lsn::INVALID
     236      8723826 :     }
     237              : }
     238              : 
     239              : impl From<u64> for Lsn {
     240        11873 :     fn from(n: u64) -> Self {
     241        11873 :         Lsn(n)
     242        11873 :     }
     243              : }
     244              : 
     245              : impl From<Lsn> for u64 {
     246      4949165 :     fn from(lsn: Lsn) -> u64 {
     247      4949165 :         lsn.0
     248      4949165 :     }
     249              : }
     250              : 
     251              : impl FromStr for Lsn {
     252              :     type Err = LsnParseError;
     253              : 
     254              :     /// Parse an LSN from a string in the form `00000000/00000000`
     255              :     ///
     256              :     /// If the input string is missing the '/' character, then use `Lsn::from_hex`
     257          807 :     fn from_str(s: &str) -> Result<Self, Self::Err> {
     258          807 :         let mut splitter = s.trim().split('/');
     259          807 :         if let (Some(left), Some(right), None) = (splitter.next(), splitter.next(), splitter.next())
     260              :         {
     261          807 :             let left_num = u32::from_str_radix(left, 16).map_err(|_| LsnParseError)?;
     262          804 :             let right_num = u32::from_str_radix(right, 16).map_err(|_| LsnParseError)?;
     263          802 :             Ok(Lsn((left_num as u64) << 32 | right_num as u64))
     264              :         } else {
     265            0 :             Err(LsnParseError)
     266              :         }
     267          807 :     }
     268              : }
     269              : 
     270              : impl fmt::Display for Lsn {
     271      5168157 :     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     272      5168157 :         write!(f, "{:X}/{:X}", self.0 >> 32, self.0 & 0xffffffff)
     273      5168157 :     }
     274              : }
     275              : 
     276              : impl fmt::Debug for Lsn {
     277         8998 :     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     278         8998 :         write!(f, "{:X}/{:X}", self.0 >> 32, self.0 & 0xffffffff)
     279         8998 :     }
     280              : }
     281              : 
     282              : impl Add<u64> for Lsn {
     283              :     type Output = Lsn;
     284              : 
     285      2925790 :     fn add(self, other: u64) -> Self::Output {
     286      2925790 :         // panic if the addition overflows.
     287      2925790 :         Lsn(self.0.checked_add(other).unwrap())
     288      2925790 :     }
     289              : }
     290              : 
     291              : impl AddAssign<u64> for Lsn {
     292      1601868 :     fn add_assign(&mut self, other: u64) {
     293      1601868 :         // panic if the addition overflows.
     294      1601868 :         self.0 = self.0.checked_add(other).unwrap();
     295      1601868 :     }
     296              : }
     297              : 
     298              : /// An [`Lsn`] that can be accessed atomically.
     299              : pub struct AtomicLsn {
     300              :     inner: AtomicU64,
     301              : }
     302              : 
     303              : impl AtomicLsn {
     304              :     /// Creates a new atomic `Lsn`.
     305         2091 :     pub fn new(val: u64) -> Self {
     306         2091 :         AtomicLsn {
     307         2091 :             inner: AtomicU64::new(val),
     308         2091 :         }
     309         2091 :     }
     310              : 
     311              :     /// Atomically retrieve the `Lsn` value from memory.
     312      4805422 :     pub fn load(&self) -> Lsn {
     313      4805422 :         Lsn(self.inner.load(Ordering::Acquire))
     314      4805422 :     }
     315              : 
     316              :     /// Atomically store a new `Lsn` value to memory.
     317         1357 :     pub fn store(&self, lsn: Lsn) {
     318         1357 :         self.inner.store(lsn.0, Ordering::Release);
     319         1357 :     }
     320              : 
     321              :     /// Adds to the current value, returning the previous value.
     322              :     ///
     323              :     /// This operation will panic on overflow.
     324            1 :     pub fn fetch_add(&self, val: u64) -> Lsn {
     325            1 :         let prev = self.inner.fetch_add(val, Ordering::AcqRel);
     326            1 :         assert!(prev.checked_add(val).is_some(), "AtomicLsn overflow");
     327            1 :         Lsn(prev)
     328            1 :     }
     329              : 
     330              :     /// Atomically sets the Lsn to the max of old and new value, returning the old value.
     331         1146 :     pub fn fetch_max(&self, lsn: Lsn) -> Lsn {
     332         1146 :         let prev = self.inner.fetch_max(lsn.0, Ordering::AcqRel);
     333         1146 :         Lsn(prev)
     334         1146 :     }
     335              : }
     336              : 
     337              : impl From<Lsn> for AtomicLsn {
     338            6 :     fn from(lsn: Lsn) -> Self {
     339            6 :         Self::new(lsn.0)
     340            6 :     }
     341              : }
     342              : 
     343              : /// Pair of LSN's pointing to the end of the last valid record and previous one
     344              : #[derive(Debug, Clone, Copy)]
     345              : pub struct RecordLsn {
     346              :     /// LSN at the end of the current record
     347              :     pub last: Lsn,
     348              :     /// LSN at the end of the previous record
     349              :     pub prev: Lsn,
     350              : }
     351              : 
     352              : /// Expose `self.last` as counter to be able to use RecordLsn in SeqWait
     353              : impl MonotonicCounter<Lsn> for RecordLsn {
     354      4804416 :     fn cnt_advance(&mut self, lsn: Lsn) {
     355      4804416 :         assert!(self.last <= lsn);
     356      4804416 :         let new_prev = self.last;
     357      4804416 :         self.last = lsn;
     358      4804416 :         self.prev = new_prev;
     359      4804416 :     }
     360      5504757 :     fn cnt_value(&self) -> Lsn {
     361      5504757 :         self.last
     362      5504757 :     }
     363              : }
     364              : 
     365              : /// Implements  [`rand::distributions::uniform::UniformSampler`] so we can sample [`Lsn`]s.
     366              : ///
     367              : /// This is used by the `pagebench` pageserver benchmarking tool.
     368              : pub struct LsnSampler(<u64 as rand::distributions::uniform::SampleUniform>::Sampler);
     369              : 
     370              : impl rand::distributions::uniform::SampleUniform for Lsn {
     371              :     type Sampler = LsnSampler;
     372              : }
     373              : 
     374              : impl rand::distributions::uniform::UniformSampler for LsnSampler {
     375              :     type X = Lsn;
     376              : 
     377            0 :     fn new<B1, B2>(low: B1, high: B2) -> Self
     378            0 :     where
     379            0 :         B1: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
     380            0 :         B2: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
     381            0 :     {
     382            0 :         Self(
     383            0 :             <u64 as rand::distributions::uniform::SampleUniform>::Sampler::new(
     384            0 :                 low.borrow().0,
     385            0 :                 high.borrow().0,
     386            0 :             ),
     387            0 :         )
     388            0 :     }
     389              : 
     390            0 :     fn new_inclusive<B1, B2>(low: B1, high: B2) -> Self
     391            0 :     where
     392            0 :         B1: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
     393            0 :         B2: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
     394            0 :     {
     395            0 :         Self(
     396            0 :             <u64 as rand::distributions::uniform::SampleUniform>::Sampler::new_inclusive(
     397            0 :                 low.borrow().0,
     398            0 :                 high.borrow().0,
     399            0 :             ),
     400            0 :         )
     401            0 :     }
     402              : 
     403            0 :     fn sample<R: rand::prelude::Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
     404            0 :         Lsn(self.0.sample(rng))
     405            0 :     }
     406              : }
     407              : 
     408              : #[cfg(test)]
     409              : mod tests {
     410              :     use crate::bin_ser::BeSer;
     411              : 
     412              :     use super::*;
     413              : 
     414              :     use serde_assert::{Deserializer, Serializer, Token, Tokens};
     415              : 
     416              :     #[test]
     417            1 :     fn test_lsn_strings() {
     418            1 :         assert_eq!("12345678/AAAA5555".parse(), Ok(Lsn(0x12345678AAAA5555)));
     419            1 :         assert_eq!("aaaa/bbbb".parse(), Ok(Lsn(0x0000AAAA0000BBBB)));
     420            1 :         assert_eq!("1/A".parse(), Ok(Lsn(0x000000010000000A)));
     421            1 :         assert_eq!("0/0".parse(), Ok(Lsn(0)));
     422            1 :         "ABCDEFG/12345678".parse::<Lsn>().unwrap_err();
     423            1 :         "123456789/AAAA5555".parse::<Lsn>().unwrap_err();
     424            1 :         "12345678/AAAA55550".parse::<Lsn>().unwrap_err();
     425            1 :         "-1/0".parse::<Lsn>().unwrap_err();
     426            1 :         "1/-1".parse::<Lsn>().unwrap_err();
     427            1 : 
     428            1 :         assert_eq!(format!("{}", Lsn(0x12345678AAAA5555)), "12345678/AAAA5555");
     429            1 :         assert_eq!(format!("{}", Lsn(0x000000010000000A)), "1/A");
     430              : 
     431            1 :         assert_eq!(
     432            1 :             Lsn::from_hex("12345678AAAA5555"),
     433            1 :             Ok(Lsn(0x12345678AAAA5555))
     434            1 :         );
     435            1 :         assert_eq!(Lsn::from_hex("0"), Ok(Lsn(0)));
     436            1 :         assert_eq!(Lsn::from_hex("F12345678AAAA5555"), Err(LsnParseError));
     437              : 
     438            1 :         let expected_lsn = Lsn(0x3C490F8);
     439            1 :         assert_eq!(" 0/3C490F8".parse(), Ok(expected_lsn));
     440            1 :         assert_eq!("0/3C490F8 ".parse(), Ok(expected_lsn));
     441            1 :         assert_eq!(" 0/3C490F8 ".parse(), Ok(expected_lsn));
     442            1 :     }
     443              : 
     444              :     #[test]
     445            1 :     fn test_lsn_math() {
     446            1 :         assert_eq!(Lsn(1234) + 11u64, Lsn(1245));
     447              : 
     448            1 :         assert_eq!(
     449            1 :             {
     450            1 :                 let mut lsn = Lsn(1234);
     451            1 :                 lsn += 11u64;
     452            1 :                 lsn
     453            1 :             },
     454            1 :             Lsn(1245)
     455            1 :         );
     456              : 
     457            1 :         assert_eq!(Lsn(1234).checked_sub(1233u64), Some(Lsn(1)));
     458            1 :         assert_eq!(Lsn(1234).checked_sub(1235u64), None);
     459              : 
     460            1 :         assert_eq!(Lsn(1235).widening_sub(1234u64), 1);
     461            1 :         assert_eq!(Lsn(1234).widening_sub(1235u64), -1);
     462            1 :         assert_eq!(Lsn(u64::MAX).widening_sub(0u64), i128::from(u64::MAX));
     463            1 :         assert_eq!(Lsn(0).widening_sub(u64::MAX), -i128::from(u64::MAX));
     464              : 
     465            1 :         let seg_sz: usize = 16 * 1024 * 1024;
     466            1 :         assert_eq!(Lsn(0x1000007).segment_offset(seg_sz), 7);
     467            1 :         assert_eq!(Lsn(0x1000007).segment_number(seg_sz), 1u64);
     468              : 
     469            1 :         assert_eq!(Lsn(0x4007).block_offset(), 7u64);
     470            1 :         assert_eq!(Lsn(0x4000).block_offset(), 0u64);
     471            1 :         assert_eq!(Lsn(0x4007).remaining_in_block(), 8185u64);
     472            1 :         assert_eq!(Lsn(0x4000).remaining_in_block(), 8192u64);
     473              : 
     474            1 :         assert_eq!(Lsn(0xffff01).calc_padding(seg_sz as u64), 255u64);
     475            1 :         assert_eq!(Lsn(0x2000000).calc_padding(seg_sz as u64), 0u64);
     476            1 :         assert_eq!(Lsn(0xffff01).calc_padding(8u32), 7u64);
     477            1 :         assert_eq!(Lsn(0xffff00).calc_padding(8u32), 0u64);
     478            1 :     }
     479              : 
     480              :     #[test]
     481            1 :     fn test_atomic_lsn() {
     482            1 :         let lsn = AtomicLsn::new(0);
     483            1 :         assert_eq!(lsn.fetch_add(1234), Lsn(0));
     484            1 :         assert_eq!(lsn.load(), Lsn(1234));
     485            1 :         lsn.store(Lsn(5678));
     486            1 :         assert_eq!(lsn.load(), Lsn(5678));
     487              : 
     488            1 :         assert_eq!(lsn.fetch_max(Lsn(6000)), Lsn(5678));
     489            1 :         assert_eq!(lsn.fetch_max(Lsn(5000)), Lsn(6000));
     490            1 :     }
     491              : 
     492              :     #[test]
     493            1 :     fn test_lsn_serde() {
     494            1 :         let original_lsn = Lsn(0x0123456789abcdef);
     495            1 :         let expected_readable_tokens = Tokens(vec![Token::U64(0x0123456789abcdef)]);
     496            1 :         let expected_non_readable_tokens =
     497            1 :             Tokens(vec![Token::Str(String::from("1234567/89ABCDEF"))]);
     498            1 : 
     499            1 :         // Testing human_readable ser/de
     500            1 :         let serializer = Serializer::builder().is_human_readable(false).build();
     501            1 :         let readable_ser_tokens = original_lsn.serialize(&serializer).unwrap();
     502            1 :         assert_eq!(readable_ser_tokens, expected_readable_tokens);
     503              : 
     504            1 :         let mut deserializer = Deserializer::builder()
     505            1 :             .is_human_readable(false)
     506            1 :             .tokens(readable_ser_tokens)
     507            1 :             .build();
     508            1 :         let des_lsn = Lsn::deserialize(&mut deserializer).unwrap();
     509            1 :         assert_eq!(des_lsn, original_lsn);
     510              : 
     511              :         // Testing NON human_readable ser/de
     512            1 :         let serializer = Serializer::builder().is_human_readable(true).build();
     513            1 :         let non_readable_ser_tokens = original_lsn.serialize(&serializer).unwrap();
     514            1 :         assert_eq!(non_readable_ser_tokens, expected_non_readable_tokens);
     515              : 
     516            1 :         let mut deserializer = Deserializer::builder()
     517            1 :             .is_human_readable(true)
     518            1 :             .tokens(non_readable_ser_tokens)
     519            1 :             .build();
     520            1 :         let des_lsn = Lsn::deserialize(&mut deserializer).unwrap();
     521            1 :         assert_eq!(des_lsn, original_lsn);
     522              : 
     523              :         // Testing mismatching ser/de
     524            1 :         let serializer = Serializer::builder().is_human_readable(false).build();
     525            1 :         let non_readable_ser_tokens = original_lsn.serialize(&serializer).unwrap();
     526            1 : 
     527            1 :         let mut deserializer = Deserializer::builder()
     528            1 :             .is_human_readable(true)
     529            1 :             .tokens(non_readable_ser_tokens)
     530            1 :             .build();
     531            1 :         Lsn::deserialize(&mut deserializer).unwrap_err();
     532            1 : 
     533            1 :         let serializer = Serializer::builder().is_human_readable(true).build();
     534            1 :         let readable_ser_tokens = original_lsn.serialize(&serializer).unwrap();
     535            1 : 
     536            1 :         let mut deserializer = Deserializer::builder()
     537            1 :             .is_human_readable(false)
     538            1 :             .tokens(readable_ser_tokens)
     539            1 :             .build();
     540            1 :         Lsn::deserialize(&mut deserializer).unwrap_err();
     541            1 :     }
     542              : 
     543              :     #[test]
     544            1 :     fn test_lsn_ensure_roundtrip() {
     545            1 :         let original_lsn = Lsn(0xaaaabbbb);
     546            1 : 
     547            1 :         let serializer = Serializer::builder().is_human_readable(false).build();
     548            1 :         let ser_tokens = original_lsn.serialize(&serializer).unwrap();
     549            1 : 
     550            1 :         let mut deserializer = Deserializer::builder()
     551            1 :             .is_human_readable(false)
     552            1 :             .tokens(ser_tokens)
     553            1 :             .build();
     554            1 : 
     555            1 :         let des_lsn = Lsn::deserialize(&mut deserializer).unwrap();
     556            1 :         assert_eq!(des_lsn, original_lsn);
     557            1 :     }
     558              : 
     559              :     #[test]
     560            1 :     fn test_lsn_bincode_serde() {
     561            1 :         let lsn = Lsn(0x0123456789abcdef);
     562            1 :         let expected_bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];
     563            1 : 
     564            1 :         let ser_bytes = lsn.ser().unwrap();
     565            1 :         assert_eq!(ser_bytes, expected_bytes);
     566              : 
     567            1 :         let des_lsn = Lsn::des(&ser_bytes).unwrap();
     568            1 :         assert_eq!(des_lsn, lsn);
     569            1 :     }
     570              : 
     571              :     #[test]
     572            1 :     fn test_lsn_bincode_ensure_roundtrip() {
     573            1 :         let original_lsn = Lsn(0x01_02_03_04_05_06_07_08);
     574            1 :         let expected_bytes = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
     575            1 : 
     576            1 :         let ser_bytes = original_lsn.ser().unwrap();
     577            1 :         assert_eq!(ser_bytes, expected_bytes);
     578              : 
     579            1 :         let des_lsn = Lsn::des(&ser_bytes).unwrap();
     580            1 :         assert_eq!(des_lsn, original_lsn);
     581            1 :     }
     582              : }
        

Generated by: LCOV version 2.1-beta