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 44690 : fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
22 44690 : where
23 44690 : S: serde::Serializer,
24 44690 : {
25 44690 : if serializer.is_human_readable() {
26 36020 : serializer.collect_str(self)
27 : } else {
28 8670 : self.0.serialize(serializer)
29 : }
30 9 : }
31 : }
32 :
33 : impl<'de> Deserialize<'de> for Lsn {
34 6247 : fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
35 6247 : where
36 6247 : D: serde::Deserializer<'de>,
37 6247 : {
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 1 : )
50 : } else {
51 1 : formatter.write_str("value in form of integer(u64)")
52 : }
53 2 : }
54 :
55 5728 : fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
56 5728 : where
57 5728 : E: serde::de::Error,
58 5728 : {
59 5728 : Ok(Lsn(v))
60 5728 : }
61 :
62 517 : fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
63 517 : where
64 517 : E: serde::de::Error,
65 517 : {
66 517 : Lsn::from_str(v).map_err(|e| E::custom(e))
67 517 : }
68 : }
69 :
70 6247 : if deserializer.is_human_readable() {
71 518 : deserializer.deserialize_str(LsnVisitor {
72 518 : is_human_readable_deserializer: true,
73 518 : })
74 : } else {
75 5729 : deserializer.deserialize_u64(LsnVisitor {
76 5729 : is_human_readable_deserializer: false,
77 5729 : })
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 4582 : pub fn checked_sub<T: Into<u64>>(self, other: T) -> Option<Lsn> {
139 4582 : let other: u64 = other.into();
140 4582 : self.0.checked_sub(other).map(Lsn)
141 4582 : }
142 :
143 : /// Subtract a number, saturating at numeric bounds instead of overflowing.
144 14 : pub fn saturating_sub<T: Into<u64>>(self, other: T) -> Lsn {
145 14 : Lsn(self.0.saturating_sub(other.into()))
146 14 : }
147 :
148 : /// Subtract a number, returning the difference as i128 to avoid overflow.
149 9606024 : pub fn widening_sub<T: Into<u64>>(self, other: T) -> i128 {
150 9606024 : let other: u64 = other.into();
151 9606024 : i128::from(self.0) - i128::from(other)
152 9606024 : }
153 :
154 : /// Parse an LSN from a string in the form `0000000000000000`
155 10851 : pub fn from_hex<S>(s: S) -> Result<Self, LsnParseError>
156 10851 : where
157 10851 : S: AsRef<str>,
158 10851 : {
159 10851 : let s: &str = s.as_ref();
160 10851 : let n = u64::from_str_radix(s, 16).or(Err(LsnParseError))?;
161 10838 : Ok(Lsn(n))
162 3 : }
163 :
164 : /// Compute the offset into a segment
165 : #[inline]
166 1579573 : pub fn segment_offset(self, seg_sz: usize) -> usize {
167 1579573 : (self.0 % seg_sz as u64) as usize
168 1579573 : }
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 14 : }
175 :
176 : /// Compute the segment number
177 : #[inline]
178 17279 : pub fn segment_number(self, seg_sz: usize) -> u64 {
179 17279 : self.0 / seg_sz as u64
180 17279 : }
181 :
182 : /// Compute the offset into a block
183 : #[inline]
184 1590788 : pub fn block_offset(self) -> u64 {
185 : const BLCKSZ: u64 = XLOG_BLCKSZ as u64;
186 1590788 : self.0 % BLCKSZ
187 1590788 : }
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 5 : }
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 5 : }
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 1557561 : pub fn remaining_in_block(self) -> u64 {
208 : const BLCKSZ: u64 = XLOG_BLCKSZ as u64;
209 1557561 : BLCKSZ - (self.0 % BLCKSZ)
210 1557561 : }
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 11992 : pub fn calc_padding<T: Into<u64>>(self, sz: T) -> u64 {
216 11992 : let sz: u64 = sz.into();
217 11992 : // By using wrapping_sub, we can subtract first and then mod second.
218 11992 : // If it's done the other way around, then we would return a full
219 11992 : // chunk size if we're already at the chunk boundary.
220 11992 : // (Regular subtraction will panic on overflow in debug builds.)
221 11992 : (sz.wrapping_sub(self.0)) % sz
222 11992 : }
223 :
224 : /// Align LSN on 8-byte boundary (alignment of WAL records).
225 10878588 : pub fn align(&self) -> Lsn {
226 10878588 : Lsn((self.0 + 7) & !7)
227 10878588 : }
228 :
229 : /// Align LSN on 8-byte boundary (alignment of WAL records).
230 10561646 : pub fn is_aligned(&self) -> bool {
231 10561646 : *self == self.align()
232 10561646 : }
233 :
234 : /// Return if the LSN is valid
235 : /// mimics postgres XLogRecPtrIsInvalid macro
236 17449666 : pub fn is_valid(self) -> bool {
237 17449666 : self != Lsn::INVALID
238 17449666 : }
239 : }
240 :
241 : impl From<u64> for Lsn {
242 21901 : fn from(n: u64) -> Self {
243 21901 : Lsn(n)
244 21901 : }
245 : }
246 :
247 : impl From<Lsn> for u64 {
248 9828613 : fn from(lsn: Lsn) -> u64 {
249 9828613 : lsn.0
250 9828613 : }
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 1292 : fn from_str(s: &str) -> Result<Self, Self::Err> {
260 1292 : let mut splitter = s.trim().split('/');
261 1292 : if let (Some(left), Some(right), None) = (splitter.next(), splitter.next(), splitter.next())
262 : {
263 1292 : let left_num = u32::from_str_radix(left, 16).map_err(|_| LsnParseError)?;
264 1289 : let right_num = u32::from_str_radix(right, 16).map_err(|_| LsnParseError)?;
265 1287 : Ok(Lsn(((left_num as u64) << 32) | right_num as u64))
266 : } else {
267 0 : Err(LsnParseError)
268 : }
269 1292 : }
270 : }
271 :
272 : impl fmt::Display for Lsn {
273 10335404 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
274 10335404 : write!(f, "{:X}/{:X}", self.0 >> 32, self.0 & 0xffffffff)
275 10335404 : }
276 : }
277 :
278 : impl fmt::Debug for Lsn {
279 96754 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
280 96754 : write!(f, "{:X}/{:X}", self.0 >> 32, self.0 & 0xffffffff)
281 96754 : }
282 : }
283 :
284 : impl Add<u64> for Lsn {
285 : type Output = Lsn;
286 :
287 8105071 : fn add(self, other: u64) -> Self::Output {
288 8105071 : // panic if the addition overflows.
289 8105071 : Lsn(self.0.checked_add(other).unwrap())
290 8105071 : }
291 : }
292 :
293 : impl AddAssign<u64> for Lsn {
294 1931499 : fn add_assign(&mut self, other: u64) {
295 1931499 : // panic if the addition overflows.
296 1931499 : self.0 = self.0.checked_add(other).unwrap();
297 1931499 : }
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 4569 : pub fn new(val: u64) -> Self {
308 4569 : AtomicLsn {
309 4569 : inner: AtomicU64::new(val),
310 4569 : }
311 4569 : }
312 :
313 : /// Atomically retrieve the `Lsn` value from memory.
314 9610790 : pub fn load(&self) -> Lsn {
315 9610790 : Lsn(self.inner.load(Ordering::Acquire))
316 9610790 : }
317 :
318 : /// Atomically store a new `Lsn` value to memory.
319 2849 : pub fn store(&self, lsn: Lsn) {
320 2849 : self.inner.store(lsn.0, Ordering::Release);
321 2849 : }
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 2358 : pub fn fetch_max(&self, lsn: Lsn) -> Lsn {
334 2358 : let prev = self.inner.fetch_max(lsn.0, Ordering::AcqRel);
335 2358 : Lsn(prev)
336 2358 : }
337 : }
338 :
339 : impl From<Lsn> for AtomicLsn {
340 44 : fn from(lsn: Lsn) -> Self {
341 44 : Self::new(lsn.0)
342 44 : }
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 9608920 : fn cnt_advance(&mut self, lsn: Lsn) {
357 9608920 : assert!(self.last <= lsn);
358 9608920 : let new_prev = self.last;
359 9608920 : self.last = lsn;
360 9608920 : self.prev = new_prev;
361 9608920 : }
362 11006625 : fn cnt_value(&self) -> Lsn {
363 11006625 : self.last
364 11006625 : }
365 : }
366 :
367 : /// Implements [`rand::distributions::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::distributions::uniform::SampleUniform>::Sampler);
371 :
372 : impl rand::distributions::uniform::SampleUniform for Lsn {
373 : type Sampler = LsnSampler;
374 : }
375 :
376 : impl rand::distributions::uniform::UniformSampler for LsnSampler {
377 : type X = Lsn;
378 :
379 0 : fn new<B1, B2>(low: B1, high: B2) -> Self
380 0 : where
381 0 : B1: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
382 0 : B2: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
383 0 : {
384 0 : Self(
385 0 : <u64 as rand::distributions::uniform::SampleUniform>::Sampler::new(
386 0 : low.borrow().0,
387 0 : high.borrow().0,
388 0 : ),
389 0 : )
390 0 : }
391 :
392 0 : fn new_inclusive<B1, B2>(low: B1, high: B2) -> Self
393 0 : where
394 0 : B1: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
395 0 : B2: rand::distributions::uniform::SampleBorrow<Self::X> + Sized,
396 0 : {
397 0 : Self(
398 0 : <u64 as rand::distributions::uniform::SampleUniform>::Sampler::new_inclusive(
399 0 : low.borrow().0,
400 0 : high.borrow().0,
401 0 : ),
402 0 : )
403 0 : }
404 :
405 0 : fn sample<R: rand::prelude::Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
406 0 : Lsn(self.0.sample(rng))
407 0 : }
408 : }
409 :
410 : #[cfg(test)]
411 : mod tests {
412 : use serde_assert::{Deserializer, Serializer, Token, Tokens};
413 :
414 : use super::*;
415 : use crate::bin_ser::BeSer;
416 :
417 : #[test]
418 1 : fn test_lsn_strings() {
419 1 : assert_eq!("12345678/AAAA5555".parse(), Ok(Lsn(0x12345678AAAA5555)));
420 1 : assert_eq!("aaaa/bbbb".parse(), Ok(Lsn(0x0000AAAA0000BBBB)));
421 1 : assert_eq!("1/A".parse(), Ok(Lsn(0x000000010000000A)));
422 1 : assert_eq!("0/0".parse(), Ok(Lsn(0)));
423 1 : "ABCDEFG/12345678".parse::<Lsn>().unwrap_err();
424 1 : "123456789/AAAA5555".parse::<Lsn>().unwrap_err();
425 1 : "12345678/AAAA55550".parse::<Lsn>().unwrap_err();
426 1 : "-1/0".parse::<Lsn>().unwrap_err();
427 1 : "1/-1".parse::<Lsn>().unwrap_err();
428 1 :
429 1 : assert_eq!(format!("{}", Lsn(0x12345678AAAA5555)), "12345678/AAAA5555");
430 1 : assert_eq!(format!("{}", Lsn(0x000000010000000A)), "1/A");
431 :
432 1 : assert_eq!(
433 1 : Lsn::from_hex("12345678AAAA5555"),
434 1 : Ok(Lsn(0x12345678AAAA5555))
435 1 : );
436 1 : assert_eq!(Lsn::from_hex("0"), Ok(Lsn(0)));
437 1 : assert_eq!(Lsn::from_hex("F12345678AAAA5555"), Err(LsnParseError));
438 :
439 1 : let expected_lsn = Lsn(0x3C490F8);
440 1 : assert_eq!(" 0/3C490F8".parse(), Ok(expected_lsn));
441 1 : assert_eq!("0/3C490F8 ".parse(), Ok(expected_lsn));
442 1 : assert_eq!(" 0/3C490F8 ".parse(), Ok(expected_lsn));
443 1 : }
444 :
445 : #[test]
446 1 : fn test_lsn_math() {
447 1 : assert_eq!(Lsn(1234) + 11u64, Lsn(1245));
448 :
449 1 : assert_eq!(
450 1 : {
451 1 : let mut lsn = Lsn(1234);
452 1 : lsn += 11u64;
453 1 : lsn
454 1 : },
455 1 : Lsn(1245)
456 1 : );
457 :
458 1 : assert_eq!(Lsn(1234).checked_sub(1233u64), Some(Lsn(1)));
459 1 : assert_eq!(Lsn(1234).checked_sub(1235u64), None);
460 :
461 1 : assert_eq!(Lsn(1235).widening_sub(1234u64), 1);
462 1 : assert_eq!(Lsn(1234).widening_sub(1235u64), -1);
463 1 : assert_eq!(Lsn(u64::MAX).widening_sub(0u64), i128::from(u64::MAX));
464 1 : assert_eq!(Lsn(0).widening_sub(u64::MAX), -i128::from(u64::MAX));
465 :
466 1 : let seg_sz: usize = 16 * 1024 * 1024;
467 1 : assert_eq!(Lsn(0x1000007).segment_offset(seg_sz), 7);
468 1 : assert_eq!(Lsn(0x1000007).segment_number(seg_sz), 1u64);
469 :
470 1 : assert_eq!(Lsn(0x4007).block_offset(), 7u64);
471 1 : assert_eq!(Lsn(0x4000).block_offset(), 0u64);
472 1 : assert_eq!(Lsn(0x4007).remaining_in_block(), 8185u64);
473 1 : assert_eq!(Lsn(0x4000).remaining_in_block(), 8192u64);
474 :
475 1 : assert_eq!(Lsn(0xffff01).calc_padding(seg_sz as u64), 255u64);
476 1 : assert_eq!(Lsn(0x2000000).calc_padding(seg_sz as u64), 0u64);
477 1 : assert_eq!(Lsn(0xffff01).calc_padding(8u32), 7u64);
478 1 : assert_eq!(Lsn(0xffff00).calc_padding(8u32), 0u64);
479 1 : }
480 :
481 : #[test]
482 1 : fn test_atomic_lsn() {
483 1 : let lsn = AtomicLsn::new(0);
484 1 : assert_eq!(lsn.fetch_add(1234), Lsn(0));
485 1 : assert_eq!(lsn.load(), Lsn(1234));
486 1 : lsn.store(Lsn(5678));
487 1 : assert_eq!(lsn.load(), Lsn(5678));
488 :
489 1 : assert_eq!(lsn.fetch_max(Lsn(6000)), Lsn(5678));
490 1 : assert_eq!(lsn.fetch_max(Lsn(5000)), Lsn(6000));
491 1 : }
492 :
493 : #[test]
494 1 : fn test_lsn_serde() {
495 1 : let original_lsn = Lsn(0x0123456789abcdef);
496 1 : let expected_readable_tokens = Tokens(vec![Token::U64(0x0123456789abcdef)]);
497 1 : let expected_non_readable_tokens =
498 1 : Tokens(vec![Token::Str(String::from("1234567/89ABCDEF"))]);
499 1 :
500 1 : // Testing human_readable ser/de
501 1 : let serializer = Serializer::builder().is_human_readable(false).build();
502 1 : let readable_ser_tokens = original_lsn.serialize(&serializer).unwrap();
503 1 : assert_eq!(readable_ser_tokens, expected_readable_tokens);
504 :
505 1 : let mut deserializer = Deserializer::builder()
506 1 : .is_human_readable(false)
507 1 : .tokens(readable_ser_tokens)
508 1 : .build();
509 1 : let des_lsn = Lsn::deserialize(&mut deserializer).unwrap();
510 1 : assert_eq!(des_lsn, original_lsn);
511 :
512 : // Testing NON human_readable ser/de
513 1 : let serializer = Serializer::builder().is_human_readable(true).build();
514 1 : let non_readable_ser_tokens = original_lsn.serialize(&serializer).unwrap();
515 1 : assert_eq!(non_readable_ser_tokens, expected_non_readable_tokens);
516 :
517 1 : let mut deserializer = Deserializer::builder()
518 1 : .is_human_readable(true)
519 1 : .tokens(non_readable_ser_tokens)
520 1 : .build();
521 1 : let des_lsn = Lsn::deserialize(&mut deserializer).unwrap();
522 1 : assert_eq!(des_lsn, original_lsn);
523 :
524 : // Testing mismatching ser/de
525 1 : let serializer = Serializer::builder().is_human_readable(false).build();
526 1 : let non_readable_ser_tokens = original_lsn.serialize(&serializer).unwrap();
527 1 :
528 1 : let mut deserializer = Deserializer::builder()
529 1 : .is_human_readable(true)
530 1 : .tokens(non_readable_ser_tokens)
531 1 : .build();
532 1 : Lsn::deserialize(&mut deserializer).unwrap_err();
533 1 :
534 1 : let serializer = Serializer::builder().is_human_readable(true).build();
535 1 : let readable_ser_tokens = original_lsn.serialize(&serializer).unwrap();
536 1 :
537 1 : let mut deserializer = Deserializer::builder()
538 1 : .is_human_readable(false)
539 1 : .tokens(readable_ser_tokens)
540 1 : .build();
541 1 : Lsn::deserialize(&mut deserializer).unwrap_err();
542 1 : }
543 :
544 : #[test]
545 1 : fn test_lsn_ensure_roundtrip() {
546 1 : let original_lsn = Lsn(0xaaaabbbb);
547 1 :
548 1 : let serializer = Serializer::builder().is_human_readable(false).build();
549 1 : let ser_tokens = original_lsn.serialize(&serializer).unwrap();
550 1 :
551 1 : let mut deserializer = Deserializer::builder()
552 1 : .is_human_readable(false)
553 1 : .tokens(ser_tokens)
554 1 : .build();
555 1 :
556 1 : let des_lsn = Lsn::deserialize(&mut deserializer).unwrap();
557 1 : assert_eq!(des_lsn, original_lsn);
558 1 : }
559 :
560 : #[test]
561 1 : fn test_lsn_bincode_serde() {
562 1 : let lsn = Lsn(0x0123456789abcdef);
563 1 : let expected_bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];
564 1 :
565 1 : let ser_bytes = lsn.ser().unwrap();
566 1 : assert_eq!(ser_bytes, expected_bytes);
567 :
568 1 : let des_lsn = Lsn::des(&ser_bytes).unwrap();
569 1 : assert_eq!(des_lsn, lsn);
570 1 : }
571 :
572 : #[test]
573 1 : fn test_lsn_bincode_ensure_roundtrip() {
574 1 : let original_lsn = Lsn(0x01_02_03_04_05_06_07_08);
575 1 : let expected_bytes = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
576 1 :
577 1 : let ser_bytes = original_lsn.ser().unwrap();
578 1 : assert_eq!(ser_bytes, expected_bytes);
579 :
580 1 : let des_lsn = Lsn::des(&ser_bytes).unwrap();
581 1 : assert_eq!(des_lsn, original_lsn);
582 1 : }
583 : }
|