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