bonsai/lib.rs
1//! bonsai, a small B-tree engine built to understand how Postgres stores,
2//! indexes and recovers data.
3
4use std::num::{NonZeroU32, NonZeroU64};
5
6pub mod storage;
7
8/// A position (in bytes) in the write-ahead log, also called an LSN (Log Sequence Number).
9/// Postgres's `XLogRecPtr`, from
10/// [xlogdefs.h](https://github.com/postgres/postgres/blob/master/src/include/access/xlogdefs.h).
11///
12/// Holds a non-zero `u64`. 0 is Postgres's `InvalidXLogRecPtr`, so `None` stands for it
13/// in an `Option<XLogRecPtr>`.
14///
15/// See [WAL Internals](https://www.postgresql.org/docs/current/wal-internals.html).
16#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
17pub struct XLogRecPtr(NonZeroU64);
18
19impl XLogRecPtr {
20 /// The LSN stored as `raw`, or `None` if `raw` is 0.
21 pub fn from_raw(raw: u64) -> Option<Self> {
22 NonZeroU64::new(raw).map(XLogRecPtr)
23 }
24}
25
26impl From<XLogRecPtr> for u64 {
27 fn from(lsn: XLogRecPtr) -> Self {
28 lsn.0.get()
29 }
30}
31
32const _: () = assert!(size_of::<Option<XLogRecPtr>>() == size_of::<u64>());
33
34/// Identifies a transaction, also called an XID. Postgres's `TransactionId`. See
35/// [transam.h](https://github.com/postgres/postgres/blob/master/src/include/access/transam.h).
36///
37/// Holds a non-zero `u32`. 0 is Postgres's `InvalidTransactionId`, so `None` stands for it
38/// in an `Option<TransactionId>`.
39///
40/// XIDs wrap around after 2^32, and are compared "on a circle" (`TransactionIdPrecedes`):
41/// An XID counts the 2^31 IDs after it as newer and the ones before it as older.
42///
43/// See [Transactions and Identifiers](https://www.postgresql.org/docs/current/transaction-id.html)
44/// and [Preventing Transaction ID Wraparound Failures](https://www.postgresql.org/docs/current/routine-vacuuming.html#VACUUM-FOR-WRAPAROUND).
45#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
46pub struct TransactionId(NonZeroU32);
47
48impl TransactionId {
49 /// The ID stored as `raw`, or `None` if `raw` is 0.
50 pub fn from_raw(raw: u32) -> Option<Self> {
51 NonZeroU32::new(raw).map(TransactionId)
52 }
53}
54
55impl From<TransactionId> for u32 {
56 fn from(xid: TransactionId) -> Self {
57 xid.0.get()
58 }
59}
60
61// 0 can't be a `NonZeroU32`, so `Option` uses it for `None` and costs no space.
62const _: () = assert!(size_of::<Option<TransactionId>>() == size_of::<u32>());