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 20596 : fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
20 20596 : where
21 20596 : S: serde::Serializer,
22 20596 : {
23 20596 : if serializer.is_human_readable() {
24 17005 : serializer.collect_str(self)
25 : } else {
26 3591 : self.0.serialize(serializer)
27 : }
28 20596 : }
29 : }
30 :
31 : impl<'de> Deserialize<'de> for Lsn {
32 17950 : fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
33 17950 : where
34 17950 : D: serde::Deserializer<'de>,
35 17950 : {
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 17729 : fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
54 17729 : where
55 17729 : E: serde::de::Error,
56 17729 : {
57 17729 : Ok(Lsn(v))
58 17729 : }
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 17950 : if deserializer.is_human_readable() {
69 220 : deserializer.deserialize_str(LsnVisitor {
70 220 : is_human_readable_deserializer: true,
71 220 : })
72 : } else {
73 17730 : deserializer.deserialize_u64(LsnVisitor {
74 17730 : is_human_readable_deserializer: false,
75 17730 : })
76 : }
77 17950 : }
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 3762 : pub fn checked_sub<T: Into<u64>>(self, other: T) -> Option<Lsn> {
137 3762 : let other: u64 = other.into();
138 3762 : self.0.checked_sub(other).map(Lsn)
139 3762 : }
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 816657 : pub fn segment_offset(self, seg_sz: usize) -> usize {
165 816657 : (self.0 % seg_sz as u64) as usize
166 816657 : }
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 827958 : pub fn block_offset(self) -> u64 {
183 : const BLCKSZ: u64 = XLOG_BLCKSZ as u64;
184 827958 : self.0 % BLCKSZ
185 827958 : }
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 807821 : pub fn remaining_in_block(self) -> u64 {
206 : const BLCKSZ: u64 = XLOG_BLCKSZ as u64;
207 807821 : BLCKSZ - (self.0 % BLCKSZ)
208 807821 : }
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 11366 : pub fn calc_padding<T: Into<u64>>(self, sz: T) -> u64 {
214 11366 : let sz: u64 = sz.into();
215 11366 : // By using wrapping_sub, we can subtract first and then mod second.
216 11366 : // If it's done the other way around, then we would return a full
217 11366 : // chunk size if we're already at the chunk boundary.
218 11366 : // (Regular subtraction will panic on overflow in debug builds.)
219 11366 : (sz.wrapping_sub(self.0)) % sz
220 11366 : }
221 :
222 : /// Align LSN on 8-byte boundary (alignment of WAL records).
223 5450651 : pub fn align(&self) -> Lsn {
224 5450651 : Lsn((self.0 + 7) & !7)
225 5450651 : }
226 :
227 : /// Align LSN on 8-byte boundary (alignment of WAL records).
228 5280376 : pub fn is_aligned(&self) -> bool {
229 5280376 : *self == self.align()
230 5280376 : }
231 :
232 : /// Return if the LSN is valid
233 : /// mimics postgres XLogRecPtrIsInvalid macro
234 8723777 : pub fn is_valid(self) -> bool {
235 8723777 : self != Lsn::INVALID
236 8723777 : }
237 : }
238 :
239 : impl From<u64> for Lsn {
240 7021 : fn from(n: u64) -> Self {
241 7021 : Lsn(n)
242 7021 : }
243 : }
244 :
245 : impl From<Lsn> for u64 {
246 4936292 : fn from(lsn: Lsn) -> u64 {
247 4936292 : lsn.0
248 4936292 : }
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 691 : fn from_str(s: &str) -> Result<Self, Self::Err> {
258 691 : let mut splitter = s.trim().split('/');
259 691 : if let (Some(left), Some(right), None) = (splitter.next(), splitter.next(), splitter.next())
260 : {
261 691 : let left_num = u32::from_str_radix(left, 16).map_err(|_| LsnParseError)?;
262 688 : let right_num = u32::from_str_radix(right, 16).map_err(|_| LsnParseError)?;
263 686 : Ok(Lsn((left_num as u64) << 32 | right_num as u64))
264 : } else {
265 0 : Err(LsnParseError)
266 : }
267 691 : }
268 : }
269 :
270 : impl fmt::Display for Lsn {
271 5167914 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
272 5167914 : write!(f, "{:X}/{:X}", self.0 >> 32, self.0 & 0xffffffff)
273 5167914 : }
274 : }
275 :
276 : impl fmt::Debug for Lsn {
277 8965 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
278 8965 : write!(f, "{:X}/{:X}", self.0 >> 32, self.0 & 0xffffffff)
279 8965 : }
280 : }
281 :
282 : impl Add<u64> for Lsn {
283 : type Output = Lsn;
284 :
285 2924673 : fn add(self, other: u64) -> Self::Output {
286 2924673 : // panic if the addition overflows.
287 2924673 : Lsn(self.0.checked_add(other).unwrap())
288 2924673 : }
289 : }
290 :
291 : impl AddAssign<u64> for Lsn {
292 1597782 : fn add_assign(&mut self, other: u64) {
293 1597782 : // panic if the addition overflows.
294 1597782 : self.0 = self.0.checked_add(other).unwrap();
295 1597782 : }
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 2071 : pub fn new(val: u64) -> Self {
306 2071 : AtomicLsn {
307 2071 : inner: AtomicU64::new(val),
308 2071 : }
309 2071 : }
310 :
311 : /// Atomically retrieve the `Lsn` value from memory.
312 4805412 : pub fn load(&self) -> Lsn {
313 4805412 : Lsn(self.inner.load(Ordering::Acquire))
314 4805412 : }
315 :
316 : /// Atomically store a new `Lsn` value to memory.
317 1353 : pub fn store(&self, lsn: Lsn) {
318 1353 : self.inner.store(lsn.0, Ordering::Release);
319 1353 : }
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 1144 : pub fn fetch_max(&self, lsn: Lsn) -> Lsn {
332 1144 : let prev = self.inner.fetch_max(lsn.0, Ordering::AcqRel);
333 1144 : Lsn(prev)
334 1144 : }
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 4804414 : fn cnt_advance(&mut self, lsn: Lsn) {
355 4804414 : assert!(self.last <= lsn);
356 4804414 : let new_prev = self.last;
357 4804414 : self.last = lsn;
358 4804414 : self.prev = new_prev;
359 4804414 : }
360 5504327 : fn cnt_value(&self) -> Lsn {
361 5504327 : self.last
362 5504327 : }
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 : }
|