Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a315610

Browse files
committedMar 2, 2025·
WIP: use std file_lock
1 parent 8db7482 commit a315610

File tree

7 files changed

+134
-207
lines changed

7 files changed

+134
-207
lines changed
 

‎.github/workflows/ci.yml

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ jobs:
4343
- name: Install Rust
4444
if: steps.rust-cache.outputs.cache-hit != 'true'
4545
run: |
46+
rustup default nightly-2025-02-25
4647
rustup component add rustfmt
4748
rustup component add clippy
4849

‎Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pyo3-build-config = { version = "0.22.0", optional = true }
2121
log = { version = "0.4.17", optional = true }
2222
pyo3 = { version = "0.22.0", features=["extension-module", "abi3-py37"], optional = true }
2323

24-
[target.'cfg(unix)'.dependencies]
24+
[target.'cfg(target_os = "macos")'.dependencies]
2525
libc = "0.2.104"
2626

2727
# Common test/bench dependencies

‎rust-toolchain

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.85
1+
nightly-2025-02-25

‎src/tree_store/page_store/file_backend/mod.rs

+4-9
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
1-
#[cfg(any(unix, target_os = "wasi"))]
2-
mod unix;
3-
#[cfg(any(unix, target_os = "wasi"))]
4-
pub use unix::FileBackend;
5-
6-
#[cfg(windows)]
7-
mod windows;
8-
#[cfg(windows)]
9-
pub use windows::FileBackend;
1+
#[cfg(any(windows, unix, target_os = "wasi"))]
2+
mod optimized;
3+
#[cfg(any(windows, unix, target_os = "wasi"))]
4+
pub use optimized::FileBackend;
105

116
#[cfg(not(any(windows, unix, target_os = "wasi")))]
127
mod fallback;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
use crate::{DatabaseError, Result, StorageBackend};
2+
use std::fs::File;
3+
use std::io;
4+
5+
#[cfg(feature = "logging")]
6+
use log::warn;
7+
8+
#[cfg(unix)]
9+
use std::os::unix::fs::FileExt;
10+
11+
#[cfg(windows)]
12+
use std::os::windows::fs::FileExt;
13+
14+
#[cfg(target_os = "wasi")]
15+
use std::os::wasi::fs::FileExt;
16+
17+
#[cfg(target_os = "macos")]
18+
use std::os::unix::io::AsRawFd;
19+
20+
/// Stores a database as a file on-disk.
21+
#[derive(Debug)]
22+
pub struct FileBackend {
23+
lock_supported: bool,
24+
file: File,
25+
}
26+
27+
impl FileBackend {
28+
/// Creates a new backend which stores data to the given file.
29+
pub fn new(file: File) -> Result<Self, DatabaseError> {
30+
match file.try_lock() {
31+
Ok(locked) => {
32+
if locked {
33+
Ok(Self {
34+
file,
35+
lock_supported: true,
36+
})
37+
} else {
38+
Err(DatabaseError::DatabaseAlreadyOpen)
39+
}
40+
}
41+
Err(err) if err.kind() == io::ErrorKind::Unsupported => {
42+
#[cfg(feature = "logging")]
43+
warn!(
44+
"File locks not supported on this platform. You must ensure that only a single process opens the database file, at a time"
45+
);
46+
47+
Ok(Self {
48+
file,
49+
lock_supported: false,
50+
})
51+
}
52+
Err(err) => Err(err.into()),
53+
}
54+
}
55+
}
56+
57+
impl StorageBackend for FileBackend {
58+
fn len(&self) -> Result<u64, io::Error> {
59+
Ok(self.file.metadata()?.len())
60+
}
61+
62+
#[cfg(any(unix, target_os = "wasi"))]
63+
fn read(&self, offset: u64, len: usize) -> Result<Vec<u8>, io::Error> {
64+
let mut buffer = vec![0; len];
65+
self.file.read_exact_at(&mut buffer, offset)?;
66+
Ok(buffer)
67+
}
68+
69+
#[cfg(windows)]
70+
fn read(&self, mut offset: u64, len: usize) -> std::result::Result<Vec<u8>, io::Error> {
71+
let mut buffer = vec![0; len];
72+
let mut data_offset = 0;
73+
while data_offset < buffer.len() {
74+
let read = self.file.seek_read(&mut buffer[data_offset..], offset)?;
75+
offset += read as u64;
76+
data_offset += read;
77+
}
78+
Ok(buffer)
79+
}
80+
81+
fn set_len(&self, len: u64) -> Result<(), io::Error> {
82+
self.file.set_len(len)
83+
}
84+
85+
#[cfg(not(target_os = "macos"))]
86+
fn sync_data(&self, _: bool) -> Result<(), io::Error> {
87+
self.file.sync_data()
88+
}
89+
90+
#[cfg(target_os = "macos")]
91+
fn sync_data(&self, eventual: bool) -> Result<(), io::Error> {
92+
if eventual {
93+
let code = unsafe { libc::fcntl(self.file.as_raw_fd(), libc::F_BARRIERFSYNC) };
94+
if code == -1 {
95+
Err(io::Error::last_os_error())
96+
} else {
97+
Ok(())
98+
}
99+
} else {
100+
self.file.sync_data()
101+
}
102+
}
103+
104+
#[cfg(any(unix, target_os = "wasi"))]
105+
fn write(&self, offset: u64, data: &[u8]) -> Result<(), io::Error> {
106+
self.file.write_all_at(data, offset)
107+
}
108+
109+
#[cfg(windows)]
110+
fn write(&self, mut offset: u64, data: &[u8]) -> std::result::Result<(), io::Error> {
111+
let mut data_offset = 0;
112+
while data_offset < data.len() {
113+
let written = self.file.seek_write(&data[data_offset..], offset)?;
114+
offset += written as u64;
115+
data_offset += written;
116+
}
117+
Ok(())
118+
}
119+
}
120+
121+
impl Drop for FileBackend {
122+
fn drop(&mut self) {
123+
if self.lock_supported {
124+
let _ = self.file.unlock();
125+
}
126+
}
127+
}

‎src/tree_store/page_store/file_backend/unix.rs

-95
This file was deleted.

‎src/tree_store/page_store/file_backend/windows.rs

-101
This file was deleted.

0 commit comments

Comments
 (0)
Please sign in to comment.