Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add WASI support #583

Merged
merged 23 commits into from
May 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
0ba3dfc
feat: WASI support
GregoryConrad May 21, 2023
4d065c9
Merge branch 'cberner:master' into master
GregoryConrad May 21, 2023
2d5b1b9
docs: change feature comment to be consistent with others
GregoryConrad May 22, 2023
85f0ce0
Merge branch 'cberner:master' into master
GregoryConrad May 24, 2023
abd5764
fix: improved WASI compilation warnings/errors
GregoryConrad May 24, 2023
f5f2f7e
fix: allow compiling tests for WASI
GregoryConrad May 24, 2023
58837ee
docs: clarify what some deps are for
GregoryConrad May 24, 2023
3891da5
test: fix some test failures due to tempfile
GregoryConrad May 25, 2023
1448cfc
revert: "test: fix some test failures due to tempfile"
GregoryConrad May 25, 2023
5388a42
test: update tests to use CWD as tmpdir
GregoryConrad May 25, 2023
fbfed53
test: fix remaining WASI tests
GregoryConrad May 25, 2023
420b1db
test: re-enable unused import warning
GregoryConrad May 26, 2023
b9adeda
ci: enable WASI testing in CI
GregoryConrad May 26, 2023
b776ed1
refactor: remove need for wasi feature
GregoryConrad May 26, 2023
3547ff1
refactor: wasi target clean ups
GregoryConrad May 26, 2023
509749b
ci: switch WASI test runner to macos
GregoryConrad May 27, 2023
c4271a3
Merge branch 'master' into master
GregoryConrad May 27, 2023
918f850
ci: manually specify wasi as target
GregoryConrad May 27, 2023
6698d99
test: fix up remaining tests for WASI
GregoryConrad May 27, 2023
c489ef5
ci: hopefully fix missing nightly toolchain
GregoryConrad May 27, 2023
d042b2b
style: fix some lints from nightly clippy
GregoryConrad May 27, 2023
8b6c296
test: remove unused import on wasi
GregoryConrad May 27, 2023
d32cefb
test: switch tests to use create_tempfile function
GregoryConrad May 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,12 @@ jobs:
pip3 install --upgrade pip
pip3 install maturin
just test_py

- name: Run WASI tests
if: startsWith(matrix.os, 'macos')
run: |
rustup toolchain install nightly
rustup target add wasm32-wasi
brew install wasmtime
cargo install cargo-wasi
just test_wasi
8 changes: 6 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,17 @@ libc = "0.2.104"
log = {version = "0.4.17", optional = true }
pyo3 = {version = "0.18.0", features=["extension-module", "abi3-py37"], optional = true }

# Common test/bench dependencies
[dev-dependencies]
rand = "0.8"
tempfile = "3.5.0"

# Just benchmarking dependencies
[target.'cfg(not(target_os = "wasi"))'.dev-dependencies]
Copy link
Contributor Author

@GregoryConrad GregoryConrad May 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really hate this, but I don't think there is any other way to do benchmark specific dependencies (and you can't create a benching feature either because you can't have optional dev dependencies). If you have any ideas though, I am all ears.

(This divides test specific deps and benchmark specific deps, since essentially none of the benchmark deps compile to WASI)

ctrlc = "3.2.3"
fastrand = "1.9.0"
rand = "0.8"
lmdb-rkv = "0.14.0"
sanakirja = "1.3.3"
tempfile = "3.5.0"
sled = "0.34.7"
rocksdb = "0.21.0"
libc = "0.2.99"
Expand Down
5 changes: 4 additions & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,14 @@ install_py: pre
test: pre
RUST_BACKTRACE=1 cargo test

test_wasi: pre
CARGO_TARGET_WASM32_WASI_RUNNER="wasmtime --mapdir=/::$TMPDIR" cargo +nightly wasi test -- --nocapture

bench bench='lmdb_benchmark': pre
cargo bench --bench {{bench}}

watch +args='test':
cargo watch --clear --exec "{{args}}"
cargo watch --clear --exec "{{args}}"

fuzz: pre
cargo fuzz run --sanitizer=none fuzz_redb -- -max_len=100000
Expand Down
18 changes: 8 additions & 10 deletions src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,7 @@ impl Builder {
/// Set the amount of memory (in bytes) used for caching data
pub fn set_cache_size(&mut self, bytes: usize) -> &mut Self {
// TODO: allow dynamic expansion of the read/write cache
self.read_cache_size_bytes = bytes * 9 / 10;
self.read_cache_size_bytes = bytes / 10 * 9;
GregoryConrad marked this conversation as resolved.
Show resolved Hide resolved
self.write_cache_size_bytes = bytes / 10;
self
}
Expand Down Expand Up @@ -810,13 +810,11 @@ impl std::fmt::Debug for Database {

#[cfg(test)]
mod test {
use tempfile::NamedTempFile;

use crate::{Database, Durability, Error, ReadableTable, TableDefinition};

#[test]
fn small_pages() {
let tmpfile: NamedTempFile = NamedTempFile::new().unwrap();
let tmpfile = crate::create_tempfile();

let db = Database::builder()
.set_page_size(512)
Expand All @@ -833,7 +831,7 @@ mod test {

#[test]
fn small_pages2() {
let tmpfile: NamedTempFile = NamedTempFile::new().unwrap();
let tmpfile = crate::create_tempfile();

let db = Database::builder()
.set_page_size(512)
Expand Down Expand Up @@ -927,7 +925,7 @@ mod test {

#[test]
fn small_pages3() {
let tmpfile: NamedTempFile = NamedTempFile::new().unwrap();
let tmpfile = crate::create_tempfile();

let db = Database::builder()
.set_page_size(1024)
Expand Down Expand Up @@ -960,7 +958,7 @@ mod test {

#[test]
fn small_pages4() {
let tmpfile: NamedTempFile = NamedTempFile::new().unwrap();
let tmpfile = crate::create_tempfile();

let db = Database::builder()
.set_cache_size(1024 * 1024)
Expand Down Expand Up @@ -997,7 +995,7 @@ mod test {

#[test]
fn crash_regression1() {
let tmpfile: NamedTempFile = NamedTempFile::new().unwrap();
let tmpfile = crate::create_tempfile();

let db = Database::builder()
.set_cache_size(1024 * 1024)
Expand All @@ -1020,7 +1018,7 @@ mod test {

#[test]
fn crash_regression2() {
let tmpfile: NamedTempFile = NamedTempFile::new().unwrap();
let tmpfile = crate::create_tempfile();

let db = Database::builder()
.set_cache_size(48101213 / 5)
Expand Down Expand Up @@ -1101,7 +1099,7 @@ mod test {

#[test]
fn dynamic_shrink() {
let tmpfile: NamedTempFile = NamedTempFile::new().unwrap();
let tmpfile = crate::create_tempfile();
let table_definition: TableDefinition<u64, &[u8]> = TableDefinition::new("x");
let big_value = vec![0u8; 1024];

Expand Down
11 changes: 11 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
clippy::cast_sign_loss,
clippy::disallowed_methods
)]
// TODO remove this once wasi no longer requires nightly
#![cfg_attr(target_os = "wasi", feature(wasi_ext))]

pub use db::{
Builder, Database, MultimapTableDefinition, MultimapTableHandle, TableDefinition, TableHandle,
Expand Down Expand Up @@ -37,3 +39,12 @@ mod transactions;
mod tree_store;
mod tuple_types;
mod types;

#[cfg(test)]
GregoryConrad marked this conversation as resolved.
Show resolved Hide resolved
fn create_tempfile() -> tempfile::NamedTempFile {
if cfg!(target_os = "wasi") {
tempfile::NamedTempFile::new_in("/").unwrap()
} else {
tempfile::NamedTempFile::new().unwrap()
}
}
4 changes: 2 additions & 2 deletions src/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ impl<'db, 'txn, K: RedbKey + 'static, V: RedbValue + 'static> Table<'db, 'txn, K
let first = self
.iter()?
.next()
.map(|x| x.map(|(key, _)| K::as_bytes(key.value().borrow()).as_ref().to_vec()));
.map(|x| x.map(|(key, _)| K::as_bytes(&key.value()).as_ref().to_vec()));
if let Some(owned_key) = first {
let owned_key = owned_key?;
let key = K::from_bytes(&owned_key);
Expand All @@ -65,7 +65,7 @@ impl<'db, 'txn, K: RedbKey + 'static, V: RedbValue + 'static> Table<'db, 'txn, K
.iter()?
.rev()
.next()
.map(|x| x.map(|(key, _)| K::as_bytes(key.value().borrow()).as_ref().to_vec()));
.map(|x| x.map(|(key, _)| K::as_bytes(&key.value()).as_ref().to_vec()));
if let Some(owned_key) = last {
let owned_key = owned_key?;
let key = K::from_bytes(&owned_key);
Expand Down
3 changes: 1 addition & 2 deletions src/transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1078,13 +1078,12 @@ impl<'a> Drop for ReadTransaction<'a> {
#[cfg(test)]
mod test {
use crate::{Database, TableDefinition};
use tempfile::NamedTempFile;

const X: TableDefinition<&str, &str> = TableDefinition::new("x");

#[test]
fn transaction_id_persistence() {
let tmpfile: NamedTempFile = NamedTempFile::new().unwrap();
let tmpfile = crate::create_tempfile();
let db = Database::create(tmpfile.path()).unwrap();
let write_txn = db.begin_write().unwrap();
{
Expand Down
4 changes: 2 additions & 2 deletions src/tree_store/btree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ impl<'a, K: RedbKey + 'a, V: RedbValue + 'a> BtreeMut<'a, K, V> {
MutateHelper::new(&mut root, FreePolicy::Never, self.mem, &mut free_on_drop);
for entry in iter {
// TODO: optimize so that we don't have to call safe_delete in a loop
assert!(operation.safe_delete(entry?.key().borrow())?.is_some());
assert!(operation.safe_delete(&entry?.key())?.is_some());
}

let result = BtreeDrain::new(
Expand Down Expand Up @@ -304,7 +304,7 @@ impl<'a, K: RedbKey + 'a, V: RedbValue + 'a> BtreeMut<'a, K, V> {
// TODO: optimize so that we don't have to call safe_delete in a loop
let entry = entry?;
if predicate(entry.key(), entry.value()) {
assert!(operation.safe_delete(entry.key().borrow())?.is_some());
assert!(operation.safe_delete(&entry.key())?.is_some());
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/tree_store/page_store/file_lock/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#[cfg(unix)]
#[cfg(any(unix, target_os = "wasi"))]
mod unix;
#[cfg(unix)]
#[cfg(any(unix, target_os = "wasi"))]
pub(super) use unix::LockedFile;

#[cfg(windows)]
Expand Down
24 changes: 22 additions & 2 deletions src/tree_store/page_store/file_lock/unix.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
// TODO once Rust's libc has flock implemented for WASI, this file needs to be revisited.
// What needs to be changed is commented below.
// See also: https://github.com/WebAssembly/wasi-filesystem/issues/2

// Remove this line once wasi-libc has flock
#![cfg_attr(target_os = "wasi", allow(unused_imports))]

use crate::{Error, Result};
use std::fs::File;
use std::io;
use std::os::unix::fs::FileExt;
use std::os::unix::io::AsRawFd;

#[cfg(unix)]
use std::os::unix::{fs::FileExt, io::AsRawFd};

#[cfg(target_os = "wasi")]
use std::os::wasi::{fs::FileExt, io::AsRawFd};

pub(crate) struct LockedFile {
file: File,
}

impl LockedFile {
// This is a no-op until we get flock in wasi-libc.
// Delete this function when we get flock.
#[cfg(target_os = "wasi")]
pub(crate) fn new(file: File) -> Result<Self> {
Ok(Self { file })
}

#[cfg(unix)] // remove this line when wasi-libc gets flock
pub(crate) fn new(file: File) -> Result<Self> {
let fd = file.as_raw_fd();
let result = unsafe { libc::flock(fd, libc::LOCK_EX | libc::LOCK_NB) };
Expand Down Expand Up @@ -41,6 +60,7 @@ impl LockedFile {
}
}

#[cfg(unix)] // remove this line when wasi-libc gets flock
impl Drop for LockedFile {
fn drop(&mut self) {
unsafe { libc::flock(self.file.as_raw_fd(), libc::LOCK_UN) };
Expand Down
7 changes: 3 additions & 4 deletions src/tree_store/page_store/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,13 +399,12 @@ mod test {
use std::fs::OpenOptions;
use std::io::{Read, Seek, SeekFrom, Write};
use std::mem::size_of;
use tempfile::NamedTempFile;

const X: TableDefinition<&str, &str> = TableDefinition::new("x");

#[test]
fn repair_allocator_checksums() {
let tmpfile: NamedTempFile = NamedTempFile::new().unwrap();
let tmpfile = crate::create_tempfile();
let db = Database::builder().create(tmpfile.path()).unwrap();
let write_txn = db.begin_write().unwrap();
{
Expand Down Expand Up @@ -517,7 +516,7 @@ mod test {

#[test]
fn repair_empty() {
let tmpfile: NamedTempFile = NamedTempFile::new().unwrap();
let tmpfile = crate::create_tempfile();
let db = Database::builder().create(tmpfile.path()).unwrap();
drop(db);

Expand All @@ -544,7 +543,7 @@ mod test {

#[test]
fn repair_insert_reserve_regression() {
let tmpfile: NamedTempFile = NamedTempFile::new().unwrap();
let tmpfile = crate::create_tempfile();
let db = Database::builder().create(tmpfile.path()).unwrap();

let def: TableDefinition<&str, &[u8]> = TableDefinition::new("x");
Expand Down
4 changes: 2 additions & 2 deletions src/tree_store/page_store/page_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,7 @@ impl TransactionalMemory {
// Trim surplus file space, before finalizing the commit
let shrunk = self.try_shrink(&mut state, &mut layout)?;

let mut secondary = state.header.secondary_slot_mut();
let secondary = state.header.secondary_slot_mut();
secondary.transaction_id = transaction_id;
secondary.user_root = data_root;
secondary.system_root = system_root;
Expand Down Expand Up @@ -877,7 +877,7 @@ impl TransactionalMemory {

let mut state = self.state.lock().unwrap();
let layout = self.layout.lock().unwrap();
let mut secondary = state.header.secondary_slot_mut();
let secondary = state.header.secondary_slot_mut();
secondary.transaction_id = transaction_id;
secondary.user_root = data_root;
secondary.system_root = system_root;
Expand Down
Loading