1#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
3pub struct Lsn(pub u64);
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
7pub struct PageId(pub u64);
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
11pub struct TxnId(pub u64);
12
13#[derive(
15 Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
16)]
17pub struct NodeId(pub u64);
18
19#[derive(
21 Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
22)]
23pub struct EdgeId(pub u64);
24
25#[derive(Debug)]
27pub enum Error {
28 Io(std::io::Error),
29 InvalidMagic,
30 ChecksumMismatch,
31 VersionMismatch,
32 NotFound,
33 AlreadyExists,
34 InvalidArgument(String),
35 Corruption(String),
36 OutOfMemory,
37 Unimplemented,
38 DecryptionFailed,
40 WriterBusy,
42 EncryptionAuthFailed,
46 WriteWriteConflict {
50 node_id: u64,
51 },
52 NodeHasEdges {
54 node_id: u64,
55 },
56 QueryTimeout,
61 ReadOnly,
67}
68
69impl std::fmt::Display for Error {
70 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71 match self {
72 Error::Io(e) => write!(f, "I/O error: {e}"),
73 Error::InvalidMagic => write!(f, "invalid magic bytes"),
74 Error::ChecksumMismatch => write!(f, "checksum mismatch"),
75 Error::VersionMismatch => write!(f, "version mismatch"),
76 Error::NotFound => write!(f, "not found"),
77 Error::AlreadyExists => write!(f, "already exists"),
78 Error::InvalidArgument(s) => write!(f, "invalid argument: {s}"),
79 Error::Corruption(s) => write!(f, "corruption: {s}"),
80 Error::OutOfMemory => write!(f, "out of memory"),
81 Error::Unimplemented => write!(f, "not yet implemented"),
82 Error::DecryptionFailed => write!(f, "decryption failed: wrong key or corrupted data"),
83 Error::WriterBusy => write!(f, "writer busy: a write transaction is already active"),
84 Error::EncryptionAuthFailed => write!(
85 f,
86 "encryption authentication failed: wrong key or corrupted ciphertext"
87 ),
88 Error::WriteWriteConflict { node_id } => write!(
89 f,
90 "write-write conflict on node {node_id}: another transaction modified this node"
91 ),
92 Error::NodeHasEdges { node_id } => write!(
93 f,
94 "node {node_id} has attached edges and cannot be deleted without removing them first"
95 ),
96 Error::QueryTimeout => write!(f, "query timeout: deadline exceeded"),
97 Error::ReadOnly => write!(
98 f,
99 "read-only transaction: mutation statements are not allowed in ReadTx::query"
100 ),
101 }
102 }
103}
104
105impl std::error::Error for Error {
106 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
107 match self {
108 Error::Io(e) => Some(e),
109 _ => None,
110 }
111 }
112}
113
114impl From<std::io::Error> for Error {
115 fn from(e: std::io::Error) -> Self {
116 Error::Io(e)
117 }
118}
119
120pub type Result<T> = std::result::Result<T, Error>;
122
123pub fn col_id_of(name: &str) -> u32 {
132 const FNV_PRIME: u32 = 16_777_619;
133 const OFFSET_BASIS: u32 = 2_166_136_261;
134 let mut hash = OFFSET_BASIS;
135 for byte in name.bytes() {
136 hash ^= byte as u32;
137 hash = hash.wrapping_mul(FNV_PRIME);
138 }
139 hash
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn page_id_roundtrip() {
148 let id = PageId(42);
149 assert_eq!(id.0, 42);
150 }
151
152 #[test]
153 fn lsn_ordering() {
154 assert!(Lsn(1) < Lsn(2));
155 }
156
157 #[test]
158 fn txn_id_copy() {
159 let t = TxnId(99);
160 let t2 = t;
161 assert_eq!(t, t2);
162 }
163
164 #[test]
165 fn node_id_packing_roundtrip() {
166 let label_id: u64 = 3;
167 let slot_id: u64 = 0x0000_BEEF_CAFE;
168 let packed = (label_id << 48) | (slot_id & 0x0000_FFFF_FFFF_FFFF);
169 let node = NodeId(packed);
170 let recovered_label = node.0 >> 48;
171 let recovered_slot = node.0 & 0x0000_FFFF_FFFF_FFFF;
172 assert_eq!(recovered_label, label_id);
173 assert_eq!(recovered_slot, slot_id);
174 }
175
176 #[test]
177 fn error_display() {
178 let e = Error::InvalidMagic;
179 assert!(!e.to_string().is_empty());
180 }
181}