This commit is contained in:
root
2026-06-15 21:42:50 +00:00
parent 34a97e2577
commit 99cd92fb4a
126 changed files with 1615 additions and 1057 deletions
+23 -20
View File
@@ -1,7 +1,7 @@
// W4 — FastCGI backend glue for the W3 wasm workspace runtime.
//
// Included into the native server TU (src/linux_fastcgi.cpp) after uce_lib.cpp,
// so it shares String/DValue/config and the UCEB1 codec. Provides a
// so it shares String/DValue/config and the UCEB2 codec. Provides a
// Always-on wasm backend: every unit request is served through a per-request
// wasm workspace. The legacy native dlopen execution path has been removed.
@@ -50,9 +50,9 @@ static String wasm_backend_ensure_started(Request* context)
for(const char* key : { "BIN_DIRECTORY", "SESSION_PATH", "TMP_UPLOAD_PATH" })
if(cfg[key] != "")
wc.write_roots.push_back(cfg[key]);
wc.memory_limit = (int64_t)config_u64("WASM_MEMORY_LIMIT_BYTES", 512ull * 1024 * 1024);
wc.epoch_deadline_ticks = config_u64("WASM_EPOCH_DEADLINE_TICKS", 200);
wc.verbose = config_bool("WASM_BACKEND_VERBOSE", false);
wc.memory_limit = (int64_t)to_u64(cfg["WASM_MEMORY_LIMIT_BYTES"], 512ull * 1024 * 1024);
wc.epoch_deadline_ticks = to_u64(cfg["WASM_EPOCH_DEADLINE_TICKS"], 200);
wc.verbose = to_bool(cfg["WASM_BACKEND_VERBOSE"], false);
g_wasm_worker = new WasmWorker(wc);
g_wasm_init_error = g_wasm_worker->init();
@@ -65,7 +65,7 @@ static String wasm_backend_ensure_started(Request* context)
g_wasm_epoch_running.store(true);
WasmWorker* worker = g_wasm_worker;
u64 period_ms = config_u64("WASM_EPOCH_PERIOD_MS", 50);
u64 period_ms = to_u64(cfg["WASM_EPOCH_PERIOD_MS"], 50);
g_wasm_epoch_ticker = new std::thread([worker, period_ms] {
while(g_wasm_epoch_running.load())
{
@@ -84,12 +84,13 @@ static bool wasm_artifact_exists(Request* context, const String& entry_unit)
struct stat wasm_st;
if(stat(wasm_path.c_str(), &wasm_st) != 0 || !S_ISREG(wasm_st.st_mode))
return(false);
// Require the artifact to be newer than the source. If it is stale,
// dispatch compiles the unit on demand and then rechecks this predicate.
struct stat src_st;
if(stat(entry_unit.c_str(), &src_st) != 0 || !S_ISREG(src_st.st_mode))
// Require the artifact to satisfy the full compiler freshness check. Source
// mtime alone misses runtime/unit ABI changes, setup-template changes, and
// metadata mismatches, which can leave stale wasm with old imports.
bool source_missing = false;
if(compiler_unit_needs_recompile(context, entry_unit, &source_missing))
return(false);
if(wasm_st.st_mtime < src_st.st_mtime)
if(source_missing)
return(false);
return(true);
}
@@ -151,23 +152,25 @@ String wasm_backend_serve(Request& request, const String& entry_unit, const Stri
if(!response.ok)
return(response.error == "" ? String("wasm workspace failed") : response.error);
// Any handler may have called ws_send/ws_close (not just WS handlers). If it
// left dispatch commands, flush the batch to the central WS broker, which owns
// all connections and resolves each command's target (id/scope/broadcast)
// against the full registry. This is the only path WS data takes out — the
// workspace owns no connections.
if(DValue* cmds = response.meta.key("ws_commands"))
// Any handler may have called ws_send/ws_close (not just WS handlers). Flush the
// websocket batch whenever either command frames or an updated per-connection
// state are present. This is the only path WS data takes out; the workspace
// owns no connections.
DValue* cmds = response.meta.key("ws_commands");
DValue* cstate = response.meta.key("ws_connection_state");
if(cmds || cstate)
{
DValue batch;
batch["commands"] = *cmds;
if(DValue* cstate = response.meta.key("ws_connection_state"))
if(cmds)
batch["commands"] = *cmds;
if(cstate)
{
batch["connection_id"] = request.resources.websocket_connection_id;
batch["connection_state"] = *cstate;
}
StringMap dispatch_params;
dispatch_params["UCE_WS_DISPATCH"] = "1";
String broker_socket = first(request.server ? request.server->config["WS_BROKER_SOCKET_PATH"] : String(),
String broker_socket = first(request.server->config["WS_BROKER_SOCKET_PATH"],
"/run/uce/ws-broker.sock");
fcgi_forward_request(broker_socket, dispatch_params, ucb_encode(batch), 5);
}
@@ -182,7 +185,7 @@ String wasm_backend_serve(Request& request, const String& entry_unit, const Stri
// Diagnostic timing headers are opt-in: they leak workspace internals and
// belong to the W5 benchmark harness, not public responses.
if(config_bool("WASM_BACKEND_VERBOSE", false))
if(to_bool(request.server->config["WASM_BACKEND_VERBOSE"], false))
{
request.header["X-UCE-Backend"] = "wasm";
request.header["X-UCE-Wasm-Workspace-Birth-Us"] = std::to_string(response.workspace_birth_us);