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