Skip to main content

limbo_core/io/
generic.rs

1use super::MemoryIO;
2use crate::{Clock, Completion, File, Instant, LimboError, OpenFlags, Result, IO};
3use std::cell::RefCell;
4use std::io::{Read, Seek, Write};
5use std::sync::Arc;
6use tracing::{debug, trace};
7
8pub struct GenericIO {}
9
10impl GenericIO {
11    pub fn new() -> Result<Self> {
12        debug!("Using IO backend 'generic'");
13        Ok(Self {})
14    }
15}
16
17unsafe impl Send for GenericIO {}
18unsafe impl Sync for GenericIO {}
19
20impl IO for GenericIO {
21    fn open_file(&self, path: &str, flags: OpenFlags, _direct: bool) -> Result<Arc<dyn File>> {
22        trace!("open_file(path = {})", path);
23        let mut file = std::fs::File::options();
24        file.read(true);
25
26        if !flags.contains(OpenFlags::ReadOnly) {
27            file.write(true);
28            file.create(flags.contains(OpenFlags::Create));
29        }
30
31        let file = file.open(path)?;
32        Ok(Arc::new(GenericFile {
33            file: RefCell::new(file),
34        }))
35    }
36
37    fn wait_for_completion(&self, c: Arc<Completion>) -> Result<()> {
38        while !c.is_completed() {
39            self.run_once()?;
40        }
41        Ok(())
42    }
43
44    fn run_once(&self) -> Result<()> {
45        Ok(())
46    }
47
48    fn generate_random_number(&self) -> i64 {
49        let mut buf = [0u8; 8];
50        getrandom::fill(&mut buf).expect("getrandom failed");
51        i64::from_ne_bytes(buf)
52    }
53
54    fn get_memory_io(&self) -> Arc<MemoryIO> {
55        Arc::new(MemoryIO::new())
56    }
57}
58
59impl Clock for GenericIO {
60    fn now(&self) -> Instant {
61        let now = chrono::Local::now();
62        Instant {
63            secs: now.timestamp(),
64            micros: now.timestamp_subsec_micros(),
65        }
66    }
67}
68
69pub struct GenericFile {
70    file: RefCell<std::fs::File>,
71}
72
73unsafe impl Send for GenericFile {}
74unsafe impl Sync for GenericFile {}
75
76impl File for GenericFile {
77    // Since we let the OS handle the locking, file locking is not supported on the generic IO implementation
78    // No-op implementation allows compilation but provides no actual file locking.
79    fn lock_file(&self, _exclusive: bool) -> Result<()> {
80        Ok(())
81    }
82
83    fn unlock_file(&self) -> Result<()> {
84        Ok(())
85    }
86
87    fn pread(&self, pos: usize, c: Arc<Completion>) -> Result<()> {
88        let mut file = self.file.borrow_mut();
89        file.seek(std::io::SeekFrom::Start(pos as u64))?;
90        {
91            let r = match *c {
92                Completion::Read(ref r) => r,
93                _ => unreachable!(),
94            };
95            let mut buf = r.buf_mut();
96            let buf = buf.as_mut_slice();
97            file.read_exact(buf)?;
98        }
99        c.complete(0);
100        Ok(())
101    }
102
103    fn pwrite(
104        &self,
105        pos: usize,
106        buffer: Arc<RefCell<crate::Buffer>>,
107        c: Arc<Completion>,
108    ) -> Result<()> {
109        let mut file = self.file.borrow_mut();
110        file.seek(std::io::SeekFrom::Start(pos as u64))?;
111        let buf = buffer.borrow();
112        let buf = buf.as_slice();
113        file.write_all(buf)?;
114        c.complete(buf.len() as i32);
115        Ok(())
116    }
117
118    fn sync(&self, c: Arc<Completion>) -> Result<()> {
119        let file = self.file.borrow_mut();
120        file.sync_all().map_err(LimboError::IOError)?;
121        c.complete(0);
122        Ok(())
123    }
124
125    fn size(&self) -> Result<u64> {
126        let file = self.file.borrow();
127        Ok(file.metadata()?.len())
128    }
129
130    fn truncate(&self, len: usize, c: Arc<Completion>) -> Result<()> {
131        let file = self.file.borrow_mut();
132        file.set_len(len as u64).map_err(LimboError::IOError)?;
133        c.complete(0);
134        Ok(())
135    }
136}
137
138impl Drop for GenericFile {
139    fn drop(&mut self) {
140        self.unlock_file().expect("Failed to unlock file");
141    }
142}