1use crate::error::{LogError, Result};
8use noxu_latch::{ExclusiveLatch, ExclusiveLatchGuard};
9use noxu_sync::Mutex;
10use std::fs::File;
11use std::sync::Arc;
12
13use crate::posio;
14
15pub struct FileHandle {
20 file: Mutex<Option<File>>,
22 latch: Arc<ExclusiveLatch>,
24 log_version: u32,
26 file_num: u32,
28}
29
30impl FileHandle {
31 pub fn new(file_num: u32) -> Self {
35 let latch =
36 Arc::new(ExclusiveLatch::named(format!("file_{:08x}", file_num)));
37
38 FileHandle { file: Mutex::new(None), latch, log_version: 0, file_num }
39 }
40
41 pub fn init(&mut self, file: File, log_version: u32) {
43 let mut f = self.file.lock();
44 assert!(f.is_none(), "FileHandle already initialized");
45 *f = Some(file);
46 self.log_version = log_version;
47 }
48
49 pub fn file_num(&self) -> u32 {
51 self.file_num
52 }
53
54 pub fn log_version(&self) -> u32 {
56 self.log_version
57 }
58
59 pub fn is_initialized(&self) -> bool {
61 self.file.lock().is_some()
62 }
63
64 pub fn acquire(&self) -> Result<FileHandleGuard<'_>> {
69 let _latch_guard = self
70 .latch
71 .acquire()
72 .map_err(|e| LogError::LatchTimeout(e.to_string()))?;
73 Ok(FileHandleGuard { handle: self, _latch_guard })
74 }
75
76 pub fn try_acquire(&self) -> Option<FileHandleGuard<'_>> {
80 self.latch
81 .try_acquire()
82 .map(|_latch_guard| FileHandleGuard { handle: self, _latch_guard })
83 }
84
85 pub fn close(&mut self) -> Result<()> {
89 if let Some(file) = self.file.lock().take() {
90 drop(file); }
92 Ok(())
93 }
94}
95
96impl Drop for FileHandle {
97 fn drop(&mut self) {
98 let _ = self.close();
99 }
100}
101
102pub struct FileHandleGuard<'a> {
104 handle: &'a FileHandle,
105 _latch_guard: ExclusiveLatchGuard<'a>,
106}
107
108impl<'a> FileHandleGuard<'a> {
109 pub fn read_at(&mut self, offset: u64, buf: &mut [u8]) -> Result<usize> {
125 let file_guard = self.handle.file.lock();
126 let file = file_guard.as_ref().ok_or_else(|| {
127 LogError::Internal("FileHandle not initialized".to_string())
128 })?;
129 Ok(posio::read_at(file, buf, offset)?)
130 }
131
132 pub fn read_exact_at(&mut self, offset: u64, buf: &mut [u8]) -> Result<()> {
137 let file_guard = self.handle.file.lock();
138 let file = file_guard.as_ref().ok_or_else(|| {
139 LogError::Internal("FileHandle not initialized".to_string())
140 })?;
141 posio::read_exact_at(file, buf, offset)?;
142 Ok(())
143 }
144
145 pub fn write_at(&mut self, offset: u64, buf: &[u8]) -> Result<usize> {
162 let file_guard = self.handle.file.lock();
163 let file = file_guard.as_ref().ok_or_else(|| {
164 LogError::Internal("FileHandle not initialized".to_string())
165 })?;
166 posio::write_all_at(file, buf, offset)?;
167 Ok(buf.len())
168 }
169
170 pub fn sync(&mut self) -> Result<()> {
176 let file_guard = self.handle.file.lock();
177 let file = file_guard.as_ref().ok_or_else(|| {
178 LogError::Internal("FileHandle not initialized".to_string())
179 })?;
180 file.sync_all()?;
181 Ok(())
182 }
183
184 pub fn sync_data(&mut self) -> Result<()> {
192 let file_guard = self.handle.file.lock();
193 let file = file_guard.as_ref().ok_or_else(|| {
194 LogError::Internal("FileHandle not initialized".to_string())
195 })?;
196 file.sync_data()?;
197 Ok(())
198 }
199
200 pub fn is_empty(&mut self) -> Result<bool> {
202 Ok(self.len()? == 0)
203 }
204
205 pub fn len(&mut self) -> Result<u64> {
207 let file_guard = self.handle.file.lock();
208 let file = file_guard.as_ref().ok_or_else(|| {
209 LogError::Internal("FileHandle not initialized".to_string())
210 })?;
211 Ok(file.metadata()?.len())
212 }
213
214 pub fn truncate(&mut self, len: u64) -> Result<()> {
216 let file_guard = self.handle.file.lock();
217 let file = file_guard.as_ref().ok_or_else(|| {
218 LogError::Internal("FileHandle not initialized".to_string())
219 })?;
220 file.set_len(len)?;
221 Ok(())
222 }
223
224 pub fn file_num(&self) -> u32 {
226 self.handle.file_num()
227 }
228
229 pub fn log_version(&self) -> u32 {
231 self.handle.log_version()
232 }
233}
234
235#[cfg(test)]
236mod tests {
237 use super::*;
238 use std::io::Write;
239 use tempfile::NamedTempFile;
240
241 #[test]
242 fn test_file_handle_basic() {
243 let mut temp_file = NamedTempFile::new().unwrap();
244 temp_file.write_all(b"Hello, world!").unwrap();
245 temp_file.flush().unwrap();
246
247 let file = File::open(temp_file.path()).unwrap();
248
249 let mut handle = FileHandle::new(0);
250 handle.init(file, 1);
251
252 assert_eq!(handle.file_num(), 0);
253 assert_eq!(handle.log_version(), 1);
254 assert!(handle.is_initialized());
255 }
256
257 #[test]
258 fn test_file_handle_read_write() {
259 let temp_file = NamedTempFile::new().unwrap();
260 let file = File::options()
261 .read(true)
262 .write(true)
263 .open(temp_file.path())
264 .unwrap();
265
266 let mut handle = FileHandle::new(0);
267 handle.init(file, 1);
268
269 {
270 let mut guard = handle.acquire().expect("acquire");
271 guard.write_at(0, b"test data").unwrap();
272 guard.sync().unwrap();
273 }
274
275 {
276 let mut guard = handle.acquire().expect("acquire");
277 let mut buf = vec![0u8; 9];
278 let n = guard.read_at(0, &mut buf).unwrap();
279 assert_eq!(n, 9);
280 assert_eq!(&buf, b"test data");
281 }
282 }
283
284 #[test]
285 fn test_file_handle_new_uninitialized() {
286 let handle = FileHandle::new(42);
287 assert_eq!(handle.file_num(), 42);
288 assert_eq!(handle.log_version(), 0);
289 assert!(!handle.is_initialized());
290 }
291
292 #[test]
293 fn test_file_handle_log_version_set_on_init() {
294 let temp_file = NamedTempFile::new().unwrap();
295 let file = File::open(temp_file.path()).unwrap();
296 let mut handle = FileHandle::new(7);
297 handle.init(file, 5);
298 assert_eq!(handle.log_version(), 5);
299 assert!(handle.is_initialized());
300 }
301
302 #[test]
303 fn test_file_handle_file_num_preserved() {
304 let mut handle = FileHandle::new(0xFF);
305 let temp_file = NamedTempFile::new().unwrap();
306 let file = File::open(temp_file.path()).unwrap();
307 handle.init(file, 1);
308 assert_eq!(handle.file_num(), 0xFF);
309 }
310
311 #[test]
312 fn test_file_handle_close_uninitialised() {
313 let mut handle = FileHandle::new(0);
314 assert!(handle.close().is_ok());
316 assert!(!handle.is_initialized());
317 }
318
319 #[test]
320 fn test_file_handle_close_initialized() {
321 let temp_file = NamedTempFile::new().unwrap();
322 let file = File::open(temp_file.path()).unwrap();
323 let mut handle = FileHandle::new(1);
324 handle.init(file, 1);
325 assert!(handle.is_initialized());
326 assert!(handle.close().is_ok());
327 assert!(!handle.is_initialized());
328 }
329
330 #[test]
331 fn test_file_handle_guard_file_num() {
332 let temp_file = NamedTempFile::new().unwrap();
333 let file = File::open(temp_file.path()).unwrap();
334 let mut handle = FileHandle::new(99);
335 handle.init(file, 3);
336 let guard = handle.acquire().expect("acquire");
337 assert_eq!(guard.file_num(), 99);
338 assert_eq!(guard.log_version(), 3);
339 }
340
341 #[test]
342 fn test_file_handle_guard_read_exact() {
343 let temp_file = NamedTempFile::new().unwrap();
344 let file = File::options()
345 .read(true)
346 .write(true)
347 .open(temp_file.path())
348 .unwrap();
349 let mut handle = FileHandle::new(0);
350 handle.init(file, 1);
351
352 {
353 let mut guard = handle.acquire().expect("acquire");
354 guard.write_at(0, b"hello").unwrap();
355 }
356 {
357 let mut guard = handle.acquire().expect("acquire");
358 let mut buf = vec![0u8; 5];
359 guard.read_exact_at(0, &mut buf).unwrap();
360 assert_eq!(&buf, b"hello");
361 }
362 }
363
364 #[test]
365 fn test_file_handle_guard_len_and_is_empty() {
366 let temp_file = NamedTempFile::new().unwrap();
367 let file = File::options()
368 .read(true)
369 .write(true)
370 .open(temp_file.path())
371 .unwrap();
372 let mut handle = FileHandle::new(0);
373 handle.init(file, 1);
374
375 {
376 let mut guard = handle.acquire().expect("acquire");
377 assert!(guard.is_empty().unwrap());
378 assert_eq!(guard.len().unwrap(), 0);
379 guard.write_at(0, b"abc").unwrap();
380 }
381 {
382 let mut guard = handle.acquire().expect("acquire");
383 assert!(!guard.is_empty().unwrap());
384 assert_eq!(guard.len().unwrap(), 3);
385 }
386 }
387
388 #[test]
389 fn test_file_handle_guard_truncate() {
390 let temp_file = NamedTempFile::new().unwrap();
391 let file = File::options()
392 .read(true)
393 .write(true)
394 .open(temp_file.path())
395 .unwrap();
396 let mut handle = FileHandle::new(0);
397 handle.init(file, 1);
398
399 {
400 let mut guard = handle.acquire().expect("acquire");
401 guard.write_at(0, b"hello world").unwrap();
402 }
403 {
404 let mut guard = handle.acquire().expect("acquire");
405 guard.truncate(5).unwrap();
406 assert_eq!(guard.len().unwrap(), 5);
407 }
408 }
409
410 #[test]
411 fn test_file_handle_try_acquire() {
412 let temp_file = NamedTempFile::new().unwrap();
413 let file = File::open(temp_file.path()).unwrap();
414 let mut handle = FileHandle::new(0);
415 handle.init(file, 1);
416
417 let guard = handle.try_acquire();
418 assert!(guard.is_some());
419 drop(guard);
421 let guard2 = handle.try_acquire();
422 assert!(guard2.is_some());
423 }
424
425 #[test]
426 fn test_file_handle_read_at_offset() {
427 let temp_file = NamedTempFile::new().unwrap();
428 let file = File::options()
429 .read(true)
430 .write(true)
431 .open(temp_file.path())
432 .unwrap();
433 let mut handle = FileHandle::new(0);
434 handle.init(file, 1);
435
436 {
437 let mut guard = handle.acquire().expect("acquire");
438 guard.write_at(0, b"ABCDEF").unwrap();
439 }
440 {
441 let mut guard = handle.acquire().expect("acquire");
442 let mut buf = vec![0u8; 3];
443 let n = guard.read_at(2, &mut buf).unwrap();
444 assert_eq!(n, 3);
445 assert_eq!(&buf, b"CDE");
446 }
447 }
448
449 #[test]
450 fn test_file_handle_write_at_offset() {
451 let temp_file = NamedTempFile::new().unwrap();
452 let file = File::options()
453 .read(true)
454 .write(true)
455 .open(temp_file.path())
456 .unwrap();
457 let mut handle = FileHandle::new(0);
458 handle.init(file, 1);
459
460 {
461 let mut guard = handle.acquire().expect("acquire");
462 guard.write_at(0, b"XXXXXXXX").unwrap();
463 guard.write_at(2, b"AB").unwrap();
464 }
465 {
466 let mut guard = handle.acquire().expect("acquire");
467 let mut buf = vec![0u8; 8];
468 guard.read_exact_at(0, &mut buf).unwrap();
469 assert_eq!(&buf[2..4], b"AB");
470 }
471 }
472}