Skip to content

Commit

Permalink
Merge pull request #695 from psarna/wasistub
Browse files Browse the repository at this point in the history
Support compiling libSQL to Wasm with virtual WAL
  • Loading branch information
psarna committed Nov 26, 2023
2 parents b52dcc8 + 3b0d30f commit c24c91c
Show file tree
Hide file tree
Showing 8 changed files with 648 additions and 2 deletions.
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ members = [
"xtask",
]

exclude = [ "./libsql-sqlite3/ext/crr" ]
exclude = [
"./libsql-sqlite3/ext/crr",
"./libsql-sqlite3/ext/libsql-wasi-demo",
]

[profile.release]
codegen-units = 1
Expand Down
3 changes: 2 additions & 1 deletion libsql-sqlite3/Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -1688,6 +1688,7 @@ fiddle: sqlite3.c shell.c
#
wasi: sqlite3.c sqlite3.h
clang --target=wasm32-unknown-wasi \
-I . \
-DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_UTF16 \
-DSQLITE_OMIT_SHARED_CACHE -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_SHARED_MEM=1 \
-DSQLITE_TEMP_STORE=2 \
Expand All @@ -1699,7 +1700,7 @@ wasi: sqlite3.c sqlite3.h
-Wl,--export-all \
-o libsql.wasm \
-v \
sqlite3.c
sqlite3.c ext/wasi/vfs.c


#
Expand Down
2 changes: 2 additions & 0 deletions libsql-sqlite3/ext/libsql-wasi-demo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Cargo.lock
target/
14 changes: 14 additions & 0 deletions libsql-sqlite3/ext/libsql-wasi-demo/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "libsql-wasi-demo"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
anyhow = "1.0.75"
rand = "0.8.5"
tracing = "0.1.40"
tracing-subscriber = "0.3.18"
wasmtime = "15.0.0"
wasmtime-wasi = "15.0.0"
69 changes: 69 additions & 0 deletions libsql-sqlite3/ext/libsql-wasi-demo/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
pub mod memory;
mod vfs;

type State = WasiCtx;

use anyhow::Context;
use wasmtime::{Engine, Linker, Module, Store};
use wasmtime_wasi::{WasiCtx, WasiCtxBuilder};

fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt::try_init().ok();
let engine = Engine::default();

let libsql_module = Module::from_file(&engine, "../../libsql.wasm")?;

let mut linker = Linker::new(&engine);
vfs::link(&mut linker)?;
wasmtime_wasi::add_to_linker(&mut linker, |s| s)?;

let wasi = WasiCtxBuilder::new()
.inherit_stdio()
.inherit_args()?
.build();

let mut store = Store::new(&engine, wasi);
let instance = linker.instantiate(&mut store, &libsql_module)?;

let malloc = instance.get_typed_func::<i32, i32>(&mut store, "malloc")?;
let free = instance.get_typed_func::<i32, ()>(&mut store, "free")?;

let memory = instance
.get_memory(&mut store, "memory")
.context("memory export not found")?;

let db_path = malloc.call(&mut store, 16)?;
memory.write(&mut store, db_path as usize, b"/tmp/wasm-demo.db\0")?;

let libsql_wasi_init = instance.get_typed_func::<(), ()>(&mut store, "libsql_wasi_init")?;
let open_func = instance.get_typed_func::<i32, i32>(&mut store, "libsql_wasi_open_db")?;
let exec_func = instance.get_typed_func::<(i32, i32), i32>(&mut store, "libsql_wasi_exec")?;
let close_func = instance.get_typed_func::<i32, i32>(&mut store, "sqlite3_close")?;

libsql_wasi_init.call(&mut store, ())?;
let db = open_func.call(&mut store, db_path)?;

let sql = malloc.call(&mut store, 64)?;
memory.write(&mut store, sql as usize, b"PRAGMA journal_mode=WAL;\0")?;
let rc = exec_func.call(&mut store, (db, sql))?;
free.call(&mut store, sql)?;
if rc != 0 {
anyhow::bail!("Failed to execute SQL");
}

let sql = malloc.call(&mut store, 64)?;
memory.write(
&mut store,
sql as usize,
b"CREATE TABLE testme(id, v1, v2);\0",
)?;
let rc = exec_func.call(&mut store, (db, sql))?;
free.call(&mut store, sql)?;

let _ = close_func.call(&mut store, db)?;
free.call(&mut store, db_path)?;

println!("rc: {rc}");

Ok(())
}
67 changes: 67 additions & 0 deletions libsql-sqlite3/ext/libsql-wasi-demo/src/memory.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Shamelessly stolen from Honza - thx man!!!

use anyhow::{bail, ensure, Context as _, Result};

pub type Ptr = i32;

pub fn slice(memory: &[u8], ptr: Ptr, len: usize) -> Result<&[u8]> {
let ptr = ptr as usize;
ensure!(ptr != 0 && ptr <= memory.len(), "Invalid pointer");
ensure!(ptr + len <= memory.len(), "Invalid pointer and length");
Ok(&memory[ptr..][..len])
}

pub fn slice_mut(memory: &mut [u8], ptr: Ptr, len: usize) -> Result<&mut [u8]> {
let ptr = ptr as usize;
ensure!(ptr != 0 && ptr <= memory.len(), "Invalid pointer");
ensure!(ptr + len <= memory.len(), "Invalid pointer and length");
Ok(&mut memory[ptr..][..len])
}

pub fn read_vec(memory: &[u8], ptr: Ptr, len: usize) -> Result<Vec<u8>> {
slice(memory, ptr, len).map(|slice| slice.to_vec())
}

pub fn read_cstr(memory: &[u8], cstr_ptr: Ptr) -> Result<String> {
let Some(data) = read_cstr_bytes(memory, cstr_ptr) else {
bail!("Invalid pointer to C string")
};
String::from_utf8(data).context("Invalid data in C string")
}

pub fn read_cstr_or_null(memory: &[u8], cstr_ptr: Ptr) -> Result<Option<String>> {
if cstr_ptr != 0 {
read_cstr(memory, cstr_ptr).map(Some)
} else {
Ok(None)
}
}

pub fn read_cstr_lossy(memory: &[u8], cstr_ptr: Ptr) -> String {
match read_cstr_bytes(memory, cstr_ptr) {
Some(data) => match String::from_utf8(data) {
Ok(string) => string,
Err(err) => String::from_utf8_lossy(err.as_bytes()).into_owned(),
},
None => String::new(),
}
}

pub fn read_cstr_bytes(memory: &[u8], cstr_ptr: Ptr) -> Option<Vec<u8>> {
let cstr_ptr = cstr_ptr as usize;
if cstr_ptr == 0 || cstr_ptr >= memory.len() {
return None;
}

let data = &memory[cstr_ptr..];
let mut strlen = 0;
loop {
match data.get(strlen) {
None => return None,
Some(0) => break,
Some(_) => strlen += 1,
}
}

Some(data[..strlen].to_vec())
}

0 comments on commit c24c91c

Please sign in to comment.