highlandcows_isam/
store.rs1use std::fs::{File, OpenOptions};
16use std::io::{Read, Seek, SeekFrom, Write};
17use std::path::Path;
18
19use serde::de::DeserializeOwned;
20use serde::Serialize;
21
22use crate::error::IsamResult;
23
24pub const STATUS_ALIVE: u8 = 0;
25pub const STATUS_TOMBSTONE: u8 = 1;
26
27#[derive(Debug, Clone, Copy)]
30pub struct RecordRef {
31 pub offset: u64,
33 pub len: u32,
35}
36
37pub struct DataStore {
38 file: File,
39}
40
41impl DataStore {
42 pub fn create(path: &Path) -> IsamResult<Self> {
44 let file = OpenOptions::new()
45 .read(true)
46 .write(true)
47 .create(true)
48 .truncate(true)
49 .open(path)?;
50 Ok(Self { file })
51 }
52
53 pub fn open(path: &Path) -> IsamResult<Self> {
55 let file = OpenOptions::new().read(true).write(true).open(path)?;
56 Ok(Self { file })
57 }
58
59 pub fn append<K, V>(&mut self, key: &K, value: &V) -> IsamResult<RecordRef>
64 where
65 K: Serialize,
66 V: Serialize,
67 {
68 let key_bytes = bincode::serialize(key)?;
71 let val_bytes = bincode::serialize(value)?;
72
73 let offset = self.file.seek(SeekFrom::End(0))?;
76
77 let key_len = key_bytes.len() as u32;
78 let val_len = val_bytes.len() as u32;
79
80 self.file.write_all(&[STATUS_ALIVE])?;
83 self.file.write_all(&key_len.to_le_bytes())?;
84 self.file.write_all(&val_len.to_le_bytes())?;
85 self.file.write_all(&key_bytes)?;
86 self.file.write_all(&val_bytes)?;
87
88 let len = 1 + 4 + 4 + key_len + val_len;
90 Ok(RecordRef { offset, len })
91 }
92
93 pub fn append_tombstone<K>(&mut self, key: &K) -> IsamResult<()>
99 where
100 K: Serialize,
101 {
102 let key_bytes = bincode::serialize(key)?;
103 self.file.seek(SeekFrom::End(0))?;
104
105 let key_len = key_bytes.len() as u32;
106 let val_len: u32 = 0;
107
108 self.file.write_all(&[STATUS_TOMBSTONE])?;
109 self.file.write_all(&key_len.to_le_bytes())?;
110 self.file.write_all(&val_len.to_le_bytes())?;
111 self.file.write_all(&key_bytes)?;
112 Ok(())
113 }
114
115 pub fn read_value<V>(&mut self, rec: RecordRef) -> IsamResult<V>
119 where
120 V: DeserializeOwned,
121 {
122 self.file.seek(SeekFrom::Start(rec.offset))?;
124
125 let mut header = [0u8; 9];
127 self.file.read_exact(&mut header)?;
128
129 let _status = header[0];
130 let key_len = u32::from_le_bytes(header[1..5].try_into().unwrap()) as usize;
131 let val_len = u32::from_le_bytes(header[5..9].try_into().unwrap()) as usize;
132
133 self.file.seek(SeekFrom::Current(key_len as i64))?;
135
136 let mut val_buf = vec![0u8; val_len];
138 self.file.read_exact(&mut val_buf)?;
139 let value: V = bincode::deserialize(&val_buf)?;
140 Ok(value)
141 }
142
143 pub fn read_record_raw(&mut self, offset: u64) -> IsamResult<(u8, Vec<u8>, Vec<u8>)> {
147 self.file.seek(SeekFrom::Start(offset))?;
148
149 let mut header = [0u8; 9];
150 self.file.read_exact(&mut header)?;
151
152 let status = header[0];
153 let key_len = u32::from_le_bytes(header[1..5].try_into().unwrap()) as usize;
154 let val_len = u32::from_le_bytes(header[5..9].try_into().unwrap()) as usize;
155
156 let mut key_buf = vec![0u8; key_len];
157 self.file.read_exact(&mut key_buf)?;
158
159 let mut val_buf = vec![0u8; val_len];
160 self.file.read_exact(&mut val_buf)?;
161
162 Ok((status, key_buf, val_buf))
163 }
164
165 pub fn write_raw_record(
168 &mut self,
169 status: u8,
170 key_bytes: &[u8],
171 val_bytes: &[u8],
172 ) -> IsamResult<RecordRef> {
173 let offset = self.file.seek(SeekFrom::End(0))?;
174
175 let key_len = key_bytes.len() as u32;
176 let val_len = val_bytes.len() as u32;
177
178 self.file.write_all(&[status])?;
179 self.file.write_all(&key_len.to_le_bytes())?;
180 self.file.write_all(&val_len.to_le_bytes())?;
181 self.file.write_all(key_bytes)?;
182 self.file.write_all(val_bytes)?;
183
184 let len = 1 + 4 + 4 + key_len + val_len;
185 Ok(RecordRef { offset, len })
186 }
187
188 pub fn flush(&mut self) -> IsamResult<()> {
190 self.file.flush()?;
191 Ok(())
192 }
193
194 pub fn fsync(&mut self) -> IsamResult<()> {
196 self.file.flush()?;
197 self.file.sync_all()?;
198 Ok(())
199 }
200}