Skip to main content

limbo_core/storage/
database.rs

1use crate::error::LimboError;
2use crate::{io::Completion, Buffer, Result};
3use std::{cell::RefCell, sync::Arc};
4
5/// DatabaseStorage is an interface a database file that consists of pages.
6///
7/// The purpose of this trait is to abstract the upper layers of Limbo from
8/// the storage medium. A database can either be a file on disk, like in SQLite,
9/// or something like a remote page server service.
10pub trait DatabaseStorage: Send + Sync {
11    fn read_page(&self, page_idx: usize, c: Arc<Completion>) -> Result<()>;
12    fn write_page(
13        &self,
14        page_idx: usize,
15        buffer: Arc<RefCell<Buffer>>,
16        c: Arc<Completion>,
17    ) -> Result<()>;
18    fn sync(&self, c: Arc<Completion>) -> Result<()>;
19}
20
21#[cfg(feature = "fs")]
22pub struct DatabaseFile {
23    file: Arc<dyn crate::io::File>,
24}
25
26#[cfg(feature = "fs")]
27unsafe impl Send for DatabaseFile {}
28#[cfg(feature = "fs")]
29unsafe impl Sync for DatabaseFile {}
30
31#[cfg(feature = "fs")]
32impl DatabaseStorage for DatabaseFile {
33    fn read_page(&self, page_idx: usize, c: Arc<Completion>) -> Result<()> {
34        let r = c.as_read();
35        let size = r.buf().len();
36        assert!(page_idx > 0);
37        if !(512..=65536).contains(&size) || size & (size - 1) != 0 {
38            return Err(LimboError::NotADB);
39        }
40        let pos = (page_idx - 1) * size;
41        self.file.pread(pos, c)?;
42        Ok(())
43    }
44
45    fn write_page(
46        &self,
47        page_idx: usize,
48        buffer: Arc<RefCell<Buffer>>,
49        c: Arc<Completion>,
50    ) -> Result<()> {
51        let buffer_size = buffer.borrow().len();
52        assert!(page_idx > 0);
53        assert!(buffer_size >= 512);
54        assert!(buffer_size <= 65536);
55        assert_eq!(buffer_size & (buffer_size - 1), 0);
56        let pos = (page_idx - 1) * buffer_size;
57        self.file.pwrite(pos, buffer, c)?;
58        Ok(())
59    }
60
61    fn sync(&self, c: Arc<Completion>) -> Result<()> {
62        self.file.sync(c)
63    }
64}
65
66#[cfg(feature = "fs")]
67impl DatabaseFile {
68    pub fn new(file: Arc<dyn crate::io::File>) -> Self {
69        Self { file }
70    }
71}
72
73pub struct FileMemoryStorage {
74    file: Arc<dyn crate::io::File>,
75}
76
77unsafe impl Send for FileMemoryStorage {}
78unsafe impl Sync for FileMemoryStorage {}
79
80impl DatabaseStorage for FileMemoryStorage {
81    fn read_page(&self, page_idx: usize, c: Arc<Completion>) -> Result<()> {
82        let r = match *c {
83            Completion::Read(ref r) => r,
84            _ => unreachable!(),
85        };
86        let size = r.buf().len();
87        assert!(page_idx > 0);
88        if !(512..=65536).contains(&size) || size & (size - 1) != 0 {
89            return Err(LimboError::NotADB);
90        }
91        let pos = (page_idx - 1) * size;
92        self.file.pread(pos, c)?;
93        Ok(())
94    }
95
96    fn write_page(
97        &self,
98        page_idx: usize,
99        buffer: Arc<RefCell<Buffer>>,
100        c: Arc<Completion>,
101    ) -> Result<()> {
102        let buffer_size = buffer.borrow().len();
103        assert!(buffer_size >= 512);
104        assert!(buffer_size <= 65536);
105        assert_eq!(buffer_size & (buffer_size - 1), 0);
106        let pos = (page_idx - 1) * buffer_size;
107        self.file.pwrite(pos, buffer, c)?;
108        Ok(())
109    }
110
111    fn sync(&self, c: Arc<Completion>) -> Result<()> {
112        self.file.sync(c)
113    }
114}
115
116impl FileMemoryStorage {
117    pub fn new(file: Arc<dyn crate::io::File>) -> Self {
118        Self { file }
119    }
120}