From 6c5f395978b34e7b4626ea8605f0eca20ab730d8 Mon Sep 17 00:00:00 2001 From: iximeow Date: Thu, 19 Oct 2023 08:31:39 -0700 Subject: use shiny hostcall to get cache objects as file descriptors --- ci-wasm-frontend/Cargo.toml | 5 +- ci-wasm-frontend/src/main.rs | 222 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 219 insertions(+), 8 deletions(-) diff --git a/ci-wasm-frontend/Cargo.toml b/ci-wasm-frontend/Cargo.toml index 6acbf49..a840d61 100644 --- a/ci-wasm-frontend/Cargo.toml +++ b/ci-wasm-frontend/Cargo.toml @@ -6,7 +6,7 @@ license = "0BSD" edition = "2021" [[bin]] -name = "ci_wasm_frontend" +name = "ci-wasm-frontend" path = "src/main.rs" [dependencies] @@ -23,3 +23,6 @@ libc = "*" [patch.crates-io] rusqlite = { version = "0.26", git = "https://github.com/rkusa/rusqlite.git", branch = "wasi" } libsqlite3-sys = { version = "0.23", git = "https://github.com/rkusa/rusqlite.git", branch = "wasi" } + +[build.release] +lto = "full" diff --git a/ci-wasm-frontend/src/main.rs b/ci-wasm-frontend/src/main.rs index cf96166..8524eea 100644 --- a/ci-wasm-frontend/src/main.rs +++ b/ci-wasm-frontend/src/main.rs @@ -9,31 +9,98 @@ use sqlite_vfs::{DatabaseHandle, LockKind, OpenKind, OpenOptions, Vfs, WalDisabl pub fn main() { eprintln!("version: {}", std::env::var("FASTLY_SERVICE_VERSION").unwrap()); - let r = Request::from_client(); + let mut r = Request::from_client(); let start = std::time::Instant::now(); - sqlite_vfs::register("memvfs", InMemVfs {}, true).unwrap(); + let qs = r.get_query_str(); + let mut registered = false; + let mut vfs = "none?"; - let db = rusqlite::Connection::open_with_flags_and_vfs( + let mut resp = Response::new(); + + let register_start = std::time::Instant::now(); + + if let Some(qs) = qs { + resp.set_header("qs", qs); + if qs.ends_with("vfs=fd") { + sqlite_vfs::register("memvfs", FdVfs {}, true).unwrap(); + vfs = "fd"; + registered = true; + } + } + + if !registered { + sqlite_vfs::register("memvfs", InMemVfs {}, true).unwrap(); + vfs = "inmem"; + } + + let register_done = register_start.elapsed(); + + let db_start = std::time::Instant::now(); + + let db = match rusqlite::Connection::open_with_flags_and_vfs( "state.db", - rusqlite::OpenFlags::SQLITE_OPEN_READ_WRITE, + rusqlite::OpenFlags::SQLITE_OPEN_READ_ONLY, "memvfs", - ).expect("can open db"); + ) { + Ok(db) => db, + Err(e) => { + eprintln!("got error {} at {}", + e, + std::env::var("FASTLY_HOSTNAME").unwrap() + ); + panic!(); + return; + } + }; + + let db_done = db_start.elapsed(); + + let handle_start = std::time::Instant::now(); let resp_body: String = handle_req(db, &r).unwrap(); - let mut resp = Response::new(); resp.set_body(resp_body); // resp.set_content_type(Mime::HTML); // associated item not found in `Mime` ??? resp.set_header("content-type", "text/html"); resp.set_header("version", std::env::var("FASTLY_SERVICE_VERSION").unwrap()); resp.set_header("host", std::env::var("FASTLY_HOSTNAME").unwrap()); - resp.set_header("render-time", start.elapsed().as_micros().to_string()); + resp.set_header("total-time", start.elapsed().as_micros().to_string()); + resp.set_header("render-time", handle_start.elapsed().as_micros().to_string()); + resp.set_header("register-time", register_done.as_micros().to_string()); + resp.set_header("db-time", db_done.as_micros().to_string()); + resp.set_header("vfs", vfs); resp.send_to_client() } +use fastly_shared::FastlyStatus; +#[link(wasm_import_module = "fastly_object_store")] +extern "C" { + #[link_name = "lookup_as_fd"] + pub fn lookup_as_fd( + kv_store_handle: fastly_sys::KVStoreHandle, + key_ptr: *const u8, + key_len: usize, + fd_out: *mut std::ffi::c_int, + ) -> FastlyStatus; +} + +use std::os::wasi::prelude::RawFd; +fn lookup_fd(key: &str) -> Result { + let store = KVStore::open("ci-state") + .map_err(|e| format!("could not open store ci-state: {:?}", e))? + .ok_or_else(|| "ci-state is not an existing store")?; + let mut db_fd: std::ffi::c_int = -1; + let res = unsafe { lookup_as_fd(store.as_handle().as_u32(), key.as_bytes().as_ptr(), key.as_bytes().len(), &mut db_fd) }; + if res != FastlyStatus::OK { + return Err(format!("bad fastly status: {:?}", res)); + } + + Ok(db_fd as RawFd) +} + struct InMemVfsHandle { bytes: Vec } @@ -51,6 +118,7 @@ impl DatabaseHandle for InMemVfsHandle { } fn write_all_at(&mut self, buf: &[u8], offset: u64) -> Result<(), std::io::Error> { + eprintln!("write_all_at {}", offset); Err(std::io::Error::new(ErrorKind::Other, "no can do")) } @@ -59,14 +127,103 @@ impl DatabaseHandle for InMemVfsHandle { } fn set_len(&mut self, size: u64) -> Result<(), std::io::Error> { + eprintln!("set_len {}", size); Err(std::io::Error::new(ErrorKind::Other, "no can do")) } fn lock(&mut self, lock: sqlite_vfs::LockKind) -> Result { + eprintln!("lock {:?}", lock); Ok(true) } fn reserved(&mut self) -> Result { + eprintln!("reserved?"); + Ok(false) + } + + fn current_lock(&self) -> Result { + eprintln!("current_lock"); + Ok(sqlite_vfs::LockKind::None) + + } + + fn wal_index(&self, readonly: bool) -> Result { + eprintln!("wal"); + Ok(WalDisabled::default()) + } + + fn set_chunk_size(&self, chunk_size: usize) -> Result<(), std::io::Error> { + eprintln!("set chunk size {}", chunk_size); + Err(std::io::Error::new(ErrorKind::Other, "no can do")) + } +} + +struct FdVfsHandle { + fd: RawFd, +} + +impl DatabaseHandle for FdVfsHandle { + type WalIndex = WalDisabled; + + fn size(&self) -> Result { + use std::os::fd::{FromRawFd, IntoRawFd}; + let f = unsafe { std::fs::File::from_raw_fd(self.fd) }; + let len = f.metadata().unwrap().len(); + f.into_raw_fd(); + Ok(len) + } + + fn read_exact_at(&mut self, buf: &mut [u8], offset: u64) -> Result<(), std::io::Error> { + let mut remaining = buf; + let mut total_read = 0; + let mut to_read = remaining.len(); + let mut file_offs = offset; + while total_read < to_read { + let n_read = unsafe { + libc::pread( + self.fd, + remaining.as_mut_ptr() as *mut std::ffi::c_void, + remaining.len(), + file_offs as i64, + ) + }; + if n_read == 0 { + panic!("stopped reading?"); + } + if n_read < 0 { + panic!("read err: {}", n_read); + } + let n_read = n_read as usize; + total_read += n_read; + remaining = &mut remaining[(n_read as usize)..]; + } + + Ok(()) + + } + + fn write_all_at(&mut self, buf: &[u8], offset: u64) -> Result<(), std::io::Error> { + eprintln!("write requested"); + Err(std::io::Error::new(ErrorKind::Other, "no can do")) + } + + fn sync(&mut self, data_only: bool) -> Result<(), std::io::Error> { + Ok(()) + } + + fn set_len(&mut self, size: u64) -> Result<(), std::io::Error> { + eprintln!("set len {}", size); + Err(std::io::Error::new(ErrorKind::Other, "no can do")) + } + + fn lock(&mut self, lock: sqlite_vfs::LockKind) -> Result { + + eprintln!("lock {:?}", lock); + Ok(true) + } + + fn reserved(&mut self) -> Result { + eprintln!("reserved requested"); Ok(false) } @@ -101,6 +258,55 @@ impl Vfs for InMemVfs { let bytes = store.lookup_bytes(db).expect("lookup_works").expect("bytes exist"); Ok(InMemVfsHandle { bytes }) +// Ok(FdVfsHandle { fd }) + } + + fn delete(&self, _db: &str) -> Result<(), std::io::Error> { + // do nothing for deletes + Err(std::io::Error::new(ErrorKind::Other, "no can do")) + } + + fn exists(&self, db: &str) -> Result { + Ok(false) + } + + fn temporary_name(&self) -> String { + "temp name".to_string() + } + + fn random(&self, buffer: &mut [i8]) { + rand::Rng::fill(&mut rand::thread_rng(), buffer); + } + + fn sleep(&self, duration: Duration) -> Duration { + let now = Instant::now(); + std::thread::sleep(duration); + now.elapsed() + } +} +struct FdVfs; + +impl Vfs for FdVfs { + type Handle = FdVfsHandle; + + fn open(&self, db: &str, opts: OpenOptions) -> Result { + if opts.kind != OpenKind::MainDb { + return Err(std::io::Error::new(ErrorKind::Other, "no")); + } + + let store = KVStore::open("ci-state") + .expect("can open ci-state") + .expect("ci-state exists"); + + let fd = lookup_fd(db).map_err(|msg| { + std::io::Error::new( + std::io::ErrorKind::Other, + msg, + ) + })?; + +// Ok(InMemVfsHandle { fd }) + Ok(FdVfsHandle { fd }) } fn delete(&self, _db: &str) -> Result<(), std::io::Error> { @@ -128,6 +334,8 @@ impl Vfs for InMemVfs { } pub fn handle_req(db: rusqlite::Connection, req: &Request) -> Result { + println!("hi"); + use ci_lib_core::dbctx::DbCtx; use std::sync::Arc; use std::sync::Mutex; -- cgit v1.1