feoxdb/core/store/
persistence.rs1use std::io::{self, Read, Seek};
2use std::sync::atomic::Ordering;
3use std::sync::Arc;
4
5use crate::constants::*;
6use crate::core::record::Record;
7use crate::error::{FeoxError, Result};
8use crate::storage::format::get_format;
9
10use super::FeoxStore;
11
12impl FeoxStore {
13 pub fn flush_all(&self) -> Result<()> {
30 if !self.memory_only {
31 if let Some(ref wb) = self.write_buffer {
33 wb.force_flush()?;
34 }
35
36 if let Some(ref disk_io) = self.disk_io {
37 let mut metadata = self._metadata.write();
39 metadata.total_records = self.stats.record_count.load(Ordering::Relaxed) as u64;
40 metadata.total_size = self.stats.disk_usage.load(Ordering::Relaxed);
41 metadata.fragmentation = self.free_space.read().get_fragmentation();
42 metadata.update();
43
44 disk_io.write().write_metadata(metadata.as_bytes())?;
46 disk_io.write().flush()?;
47 }
48 }
49 Ok(())
50 }
51
52 pub(super) fn load_value_from_disk(&self, record: &Record) -> Result<Vec<u8>> {
53 let sector = record.sector.load(Ordering::Acquire);
54 if self.memory_only || sector == 0 {
55 return Err(FeoxError::InvalidRecord);
56 }
57
58 let metadata_version = self._metadata.read().version;
60 let format = get_format(metadata_version);
61
62 let total_size = format.total_size(record.key.len(), record.value_len);
64 let sectors_needed = total_size.div_ceil(FEOX_BLOCK_SIZE);
65
66 let disk_io = self
68 .disk_io
69 .as_ref()
70 .ok_or_else(|| {
71 FeoxError::IoError(io::Error::new(
72 io::ErrorKind::NotFound,
73 "No disk IO available",
74 ))
75 })?
76 .read();
77
78 let data = disk_io.read_sectors_sync(sector, sectors_needed as u64)?;
79
80 let offset = format.value_offset(record.key.len());
82 if offset + record.value_len > data.len() {
83 return Err(FeoxError::InvalidRecord);
84 }
85
86 Ok(data[offset..offset + record.value_len].to_vec())
87 }
88
89 pub(super) fn open_device(
90 &mut self,
91 device_path: &Option<String>,
92 file_size: Option<u64>,
93 ) -> Result<()> {
94 if let Some(path) = device_path {
95 use std::fs::OpenOptions;
97 #[cfg(target_os = "linux")]
98 use std::os::unix::fs::OpenOptionsExt;
99
100 #[cfg(unix)]
101 let (file, use_direct_io) = if std::path::Path::new("/.dockerenv").exists() {
102 let file = OpenOptions::new()
103 .read(true)
104 .write(true)
105 .create(true)
106 .truncate(false)
107 .open(path)
108 .map_err(FeoxError::IoError)?;
109 (file, false) } else {
111 #[cfg(target_os = "linux")]
113 {
114 match OpenOptions::new()
116 .read(true)
117 .write(true)
118 .create(true)
119 .truncate(false)
120 .custom_flags(libc::O_DIRECT)
121 .open(path)
122 {
123 Ok(file) => (file, true), Err(_) => {
125 let file = OpenOptions::new()
127 .read(true)
128 .write(true)
129 .create(true)
130 .truncate(false)
131 .open(path)
132 .map_err(FeoxError::IoError)?;
133 (file, false)
134 }
135 }
136 }
137 #[cfg(not(target_os = "linux"))]
138 {
139 let file = OpenOptions::new()
140 .read(true)
141 .write(true)
142 .create(true)
143 .truncate(false)
144 .open(path)
145 .map_err(FeoxError::IoError)?;
146 (file, false) }
148 };
149
150 #[cfg(not(unix))]
151 let file = OpenOptions::new()
152 .read(true)
153 .write(true)
154 .create(true)
155 .truncate(false)
156 .open(path)
157 .map_err(FeoxError::IoError)?;
158
159 let metadata = file.metadata().map_err(FeoxError::IoError)?;
161 self.device_size = metadata.len();
162
163 let was_newly_created = self.device_size == 0;
165
166 if was_newly_created {
167 let target_size = file_size.unwrap_or(DEFAULT_DEVICE_SIZE);
169 file.set_len(target_size).map_err(FeoxError::IoError)?;
170 self.device_size = target_size;
171
172 self.free_space.write().initialize(self.device_size)?;
174
175 let mut metadata = self._metadata.write();
176 metadata.device_size = self.device_size;
177 metadata.update();
178 } else {
179 let is_empty_file = {
182 let mut temp_file = file.try_clone().map_err(FeoxError::IoError)?;
183 temp_file
184 .metadata()
185 .map(|m| {
186 if m.len() > 0 {
188 let mut buffer = vec![0u8; std::cmp::min(4096, m.len() as usize)];
189 temp_file.seek(std::io::SeekFrom::Start(0)).ok();
190 temp_file.read_exact(&mut buffer).ok();
191 buffer.iter().all(|&b| b == 0)
192 } else {
193 false
194 }
195 })
196 .unwrap_or(false)
197 };
198
199 if is_empty_file {
200 self.free_space.write().initialize(self.device_size)?;
202 } else {
203 self.free_space.write().set_device_size(self.device_size);
205 }
206 }
207
208 #[cfg(unix)]
209 {
210 use std::os::unix::io::AsRawFd;
211 let file_arc = Arc::new(file);
212 let fd = file_arc.as_raw_fd();
213 self.device_fd = Some(fd);
214 self.device_file = Some(file_arc.as_ref().try_clone().map_err(FeoxError::IoError)?);
216 let disk_io = crate::storage::io::DiskIO::new(file_arc, use_direct_io)?;
217 self.disk_io = Some(Arc::new(parking_lot::RwLock::new(disk_io)));
218 }
219
220 #[cfg(not(unix))]
221 {
222 self.device_file = Some(file.try_clone().map_err(FeoxError::IoError)?);
224 let disk_io = crate::storage::io::DiskIO::new_from_file(file)?;
225 self.disk_io = Some(Arc::new(parking_lot::RwLock::new(disk_io)));
226 }
227
228 let disk_io = self.disk_io.as_ref().unwrap().read();
229
230 if !was_newly_created {
232 if let Ok(metadata_bytes) = disk_io.read_metadata() {
233 if let Some(loaded_metadata) =
234 crate::storage::metadata::Metadata::from_bytes(&metadata_bytes)
235 {
236 self.stats
238 .disk_usage
239 .store(loaded_metadata.total_size, Ordering::Relaxed);
240 *self._metadata.write() = loaded_metadata;
241 }
242 }
243 }
244 }
245 Ok(())
246 }
247}
248
249impl Drop for FeoxStore {
250 fn drop(&mut self) {
251 if let Some(mut sweeper) = self.ttl_sweeper.write().take() {
253 sweeper.stop();
254 }
255
256 if let Some(ref wb) = self.write_buffer {
258 wb.initiate_shutdown();
259 }
260
261 if !self.memory_only {
263 if let Some(ref disk_io) = self.disk_io {
264 let mut metadata = self._metadata.write();
266 metadata.total_records = self.stats.record_count.load(Ordering::Relaxed) as u64;
267 metadata.total_size = self.stats.disk_usage.load(Ordering::Relaxed);
268 metadata.fragmentation = self.free_space.read().get_fragmentation();
269 metadata.update();
270
271 let _ = disk_io.write().write_metadata(metadata.as_bytes());
273 let _ = disk_io.write().flush();
274 }
275 }
276
277 if let Some(wb_arc) = self.write_buffer.take() {
279 if let Ok(wb) = Arc::try_unwrap(wb_arc) {
281 let mut wb_mut = wb;
283 wb_mut.complete_shutdown();
284 }
285 }
287
288 if let Some(ref disk_io) = self.disk_io {
290 disk_io.write().shutdown();
291 }
292 }
293}