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 QueryMemoryExceeded,
73}
74
75impl std::fmt::Display for Error {
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 match self {
78 Error::Io(e) => write!(f, "I/O error: {e}"),
79 Error::InvalidMagic => write!(f, "invalid magic bytes"),
80 Error::ChecksumMismatch => write!(f, "checksum mismatch"),
81 Error::VersionMismatch => write!(f, "version mismatch"),
82 Error::NotFound => write!(f, "not found"),
83 Error::AlreadyExists => write!(f, "already exists"),
84 Error::InvalidArgument(s) => write!(f, "invalid argument: {s}"),
85 Error::Corruption(s) => write!(f, "corruption: {s}"),
86 Error::OutOfMemory => write!(f, "out of memory"),
87 Error::Unimplemented => write!(f, "not yet implemented"),
88 Error::DecryptionFailed => write!(f, "decryption failed: wrong key or corrupted data"),
89 Error::WriterBusy => write!(f, "writer busy: a write transaction is already active"),
90 Error::EncryptionAuthFailed => write!(
91 f,
92 "encryption authentication failed: wrong key or corrupted ciphertext"
93 ),
94 Error::WriteWriteConflict { node_id } => write!(
95 f,
96 "write-write conflict on node {node_id}: another transaction modified this node"
97 ),
98 Error::NodeHasEdges { node_id } => write!(
99 f,
100 "node {node_id} has attached edges and cannot be deleted without removing them first"
101 ),
102 Error::QueryTimeout => write!(f, "query timeout: deadline exceeded"),
103 Error::ReadOnly => write!(
104 f,
105 "read-only transaction: mutation statements are not allowed in ReadTx::query"
106 ),
107 Error::QueryMemoryExceeded => write!(
108 f,
109 "query memory exceeded: BFS frontier exceeded the configured memory limit"
110 ),
111 }
112 }
113}
114
115impl std::error::Error for Error {
116 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
117 match self {
118 Error::Io(e) => Some(e),
119 _ => None,
120 }
121 }
122}
123
124impl From<std::io::Error> for Error {
125 fn from(e: std::io::Error) -> Self {
126 Error::Io(e)
127 }
128}
129
130pub type Result<T> = std::result::Result<T, Error>;
132
133pub fn col_id_of(name: &str) -> u32 {
142 const FNV_PRIME: u32 = 16_777_619;
143 const OFFSET_BASIS: u32 = 2_166_136_261;
144 let mut hash = OFFSET_BASIS;
145 for byte in name.bytes() {
146 hash ^= byte as u32;
147 hash = hash.wrapping_mul(FNV_PRIME);
148 }
149 hash
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155
156 #[test]
157 fn page_id_roundtrip() {
158 let id = PageId(42);
159 assert_eq!(id.0, 42);
160 }
161
162 #[test]
163 fn lsn_ordering() {
164 assert!(Lsn(1) < Lsn(2));
165 }
166
167 #[test]
168 fn txn_id_copy() {
169 let t = TxnId(99);
170 let t2 = t;
171 assert_eq!(t, t2);
172 }
173
174 #[test]
175 fn node_id_packing_roundtrip() {
176 let label_id: u64 = 3;
177 let slot_id: u64 = 0x0000_BEEF_CAFE;
178 let packed = (label_id << 48) | (slot_id & 0x0000_FFFF_FFFF_FFFF);
179 let node = NodeId(packed);
180 let recovered_label = node.0 >> 48;
181 let recovered_slot = node.0 & 0x0000_FFFF_FFFF_FFFF;
182 assert_eq!(recovered_label, label_id);
183 assert_eq!(recovered_slot, slot_id);
184 }
185
186 #[test]
187 fn error_display() {
188 let e = Error::InvalidMagic;
189 assert!(!e.to_string().is_empty());
190 }
191}