Plain POSIX files: remove commit on close (fs.rs)
Staging every write until close broke tempfile, git, and SQLite, which expect normal files. Actors that need an atomic publish write a temporary file and rename it; the SDK has write_atomic for that.
This commit is contained in:
+13
-42
@@ -15,21 +15,15 @@ use wasmtime::component::{Component, Linker, ResourceTable};
|
||||
use wasmtime::{Config, Engine, Store};
|
||||
use wasmtime_wasi::cli::{AsyncStdinStream, AsyncStdoutStream};
|
||||
use wasmtime_wasi::p2::bindings::Command;
|
||||
use wasmtime_wasi::p2::bindings::filesystem::{preopens, types};
|
||||
use wasmtime_wasi::{FsPerms, I32Exit, WasiCtx, WasiCtxView, WasiView};
|
||||
use wasmtime_wasi_http::{WasiHttpCtx, WasiHttpCtxView, WasiHttpHooks, WasiHttpView};
|
||||
|
||||
use crate::fs::{ActorFs, ActorFsData, FsExt, Mount};
|
||||
|
||||
pub struct WasiPart {
|
||||
ctx: WasiCtx,
|
||||
table: ResourceTable,
|
||||
}
|
||||
|
||||
impl WasiView for WasiPart {
|
||||
fn ctx(&mut self) -> WasiCtxView<'_> {
|
||||
WasiCtxView { ctx: &mut self.ctx, table: &mut self.table }
|
||||
}
|
||||
/// A host folder that the guest sees at `guest`.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Mount {
|
||||
pub guest: String,
|
||||
pub host: PathBuf,
|
||||
pub writable: bool,
|
||||
}
|
||||
|
||||
pub struct HttpHooks {
|
||||
@@ -67,28 +61,21 @@ impl WasiHttpHooks for HttpHooks {
|
||||
}
|
||||
|
||||
pub struct ActorState {
|
||||
wasi: WasiPart,
|
||||
fsx: FsExt,
|
||||
ctx: WasiCtx,
|
||||
table: ResourceTable,
|
||||
http: WasiHttpCtx,
|
||||
hooks: HttpHooks,
|
||||
}
|
||||
|
||||
impl WasiView for ActorState {
|
||||
fn ctx(&mut self) -> WasiCtxView<'_> {
|
||||
self.wasi.ctx()
|
||||
WasiCtxView { ctx: &mut self.ctx, table: &mut self.table }
|
||||
}
|
||||
}
|
||||
|
||||
impl WasiHttpView for ActorState {
|
||||
fn http(&mut self) -> WasiHttpCtxView<'_> {
|
||||
WasiHttpCtxView { ctx: &mut self.http, table: &mut self.wasi.table, hooks: &mut self.hooks }
|
||||
}
|
||||
}
|
||||
|
||||
fn actor_fs(s: &mut ActorState) -> ActorFs<'_> {
|
||||
ActorFs {
|
||||
inner: wasmtime_wasi::filesystem::WasiFilesystemView::filesystem(&mut s.wasi),
|
||||
ext: &mut s.fsx,
|
||||
WasiHttpCtxView { ctx: &mut self.http, table: &mut self.table, hooks: &mut self.hooks }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,12 +95,6 @@ pub enum Exit {
|
||||
Trap(String),
|
||||
}
|
||||
|
||||
impl Exit {
|
||||
pub fn is_clean(&self) -> bool {
|
||||
matches!(self, Exit::Clean)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Exit {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
@@ -243,11 +224,6 @@ impl Runtime {
|
||||
let mut linker: Linker<ActorState> = Linker::new(&engine);
|
||||
wasmtime_wasi::p2::add_to_linker_async(&mut linker)?;
|
||||
wasmtime_wasi_http::p2::add_only_http_to_linker_async(&mut linker)?;
|
||||
// Replace the filesystem with the commit-on-close layer.
|
||||
linker.allow_shadowing(true);
|
||||
types::add_to_linker::<ActorState, ActorFsData>(&mut linker, actor_fs)?;
|
||||
preopens::add_to_linker::<ActorState, ActorFsData>(&mut linker, actor_fs)?;
|
||||
linker.allow_shadowing(false);
|
||||
|
||||
// Time slices: every 10 ms each running guest yields to the scheduler.
|
||||
let ticker = engine.clone();
|
||||
@@ -294,8 +270,8 @@ impl Runtime {
|
||||
.with_context(|| format!("mount {} at {}", m.host.display(), m.guest))?;
|
||||
}
|
||||
let state = ActorState {
|
||||
wasi: WasiPart { ctx: b.build(), table: ResourceTable::new() },
|
||||
fsx: FsExt::new(cfg.mounts),
|
||||
ctx: b.build(),
|
||||
table: ResourceTable::new(),
|
||||
http: WasiHttpCtx::new(),
|
||||
hooks: HttpHooks { allow: cfg.network },
|
||||
};
|
||||
@@ -321,7 +297,7 @@ impl Runtime {
|
||||
cmd.wasi_cli_run().call_run(&mut store).await
|
||||
}
|
||||
.await;
|
||||
let exit = match result {
|
||||
match result {
|
||||
Ok(Ok(())) => Exit::Clean,
|
||||
Ok(Err(())) => Exit::Code(1),
|
||||
Err(e) => match e.downcast_ref::<I32Exit>() {
|
||||
@@ -334,12 +310,7 @@ impl Runtime {
|
||||
Exit::Trap(short_trap(&full))
|
||||
}
|
||||
},
|
||||
};
|
||||
// Process exit closes every file, so a clean exit commits.
|
||||
if exit.is_clean() {
|
||||
store.data_mut().fsx.commit_all();
|
||||
}
|
||||
exit
|
||||
});
|
||||
|
||||
Ok(Instance { stdin: Some(host_in), stdout: line_rx, task })
|
||||
|
||||
Reference in New Issue
Block a user