From 339031b6c309b8409129bdb33c8c3edd4d7f8ba3 Mon Sep 17 00:00:00 2001 From: udo Date: Sat, 18 Jul 2026 02:32:28 +0000 Subject: [PATCH] Avoid repeated warm request dispatch work --- docs/wasm-runtime-architecture.md | 11 +++++++++++ src/linux_fastcgi.cpp | 13 +++++++++---- src/wasm/backend.cpp | 6 +++++- src/wasm/worker.cpp | 1 + 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/docs/wasm-runtime-architecture.md b/docs/wasm-runtime-architecture.md index 275e432..16142ac 100644 --- a/docs/wasm-runtime-architecture.md +++ b/docs/wasm-runtime-architecture.md @@ -152,6 +152,11 @@ host imports into a store-independent Wasmtime `InstancePre`, and births then drops one empty workspace. This preserves Wasmtime's fork boundary while preventing the first request assigned to each worker from paying engine, linker, or pre-instantiation startup. +Server configuration is immutable by that point. The worker therefore retains +one native `DValue` view of it; each request's temporary context tree references +that view while UCEB is encoded, avoiding a repeated native tree copy. The guest +still decodes the bytes into its fresh request tree. Request parameters, body, +cookies, session, call data, and response state are never retained this way. Startup duration or failure is written to the service log. The serialized core module lives in the configured writable cache root rather than beside the possibly root-owned deployed `core.wasm`; freshness still uses the deployed @@ -260,6 +265,12 @@ module cache, adding a visible cold-start request. Request state remains bounded by the fresh workspace and the normal per-request database/resource cleanup; faulted workers still exit and are replaced by the parent. +A warm entry artifact is checked for compiler/source freshness once before +dispatch. A missing or stale artifact is compiled (or demand-prioritized) and +then checked again before execution. The second check belongs only to that +state-changing branch; repeating it immediately after a successful warm check +adds no freshness guarantee. + The request context remains UCEB2 so application `context.call` semantics do not fork into a private transport type. Validated decode trees move into the request rather than being deep-copied twice; the historical by-value diff --git a/src/linux_fastcgi.cpp b/src/linux_fastcgi.cpp index deaf5af..4154cbc 100644 --- a/src/linux_fastcgi.cpp +++ b/src/linux_fastcgi.cpp @@ -439,9 +439,13 @@ int handle_cli_complete(FastCGIRequest& request) // been removed, so a unit that still cannot be served by wasm is a // request failure instead of a fallback path. SharedUnit* cli_compile_state = 0; - if(!wasm_backend_should_handle(request, cli_unit)) + bool cli_wasm_ready = wasm_backend_should_handle(request, cli_unit); + if(!cli_wasm_ready) + { cli_compile_state = get_shared_unit(&request, cli_unit); - if(wasm_backend_should_handle(request, cli_unit)) + cli_wasm_ready = wasm_backend_should_handle(request, cli_unit); + } + if(cli_wasm_ready) { String wasm_error = wasm_backend_serve(request, cli_unit, "cli"); if(wasm_error != "") @@ -596,8 +600,9 @@ int handle_complete(FastCGIRequest& request) { // be served by wasm becomes a clean 500 request failure. SharedUnit* entry_compile_state = 0; auto wasm_ready = [&](const String& unit) -> bool { - if(!wasm_backend_should_handle(request, unit)) - entry_compile_state = get_shared_unit(&request, unit); + if(wasm_backend_should_handle(request, unit)) + return(true); + entry_compile_state = get_shared_unit(&request, unit); return(wasm_backend_should_handle(request, unit)); }; auto fail_wasm_unavailable = [&](const String& handler) { diff --git a/src/wasm/backend.cpp b/src/wasm/backend.cpp index df64661..107ba54 100644 --- a/src/wasm/backend.cpp +++ b/src/wasm/backend.cpp @@ -68,6 +68,10 @@ static String wasm_backend_ensure_started(Request* context) } g_wasm_worker = new WasmWorker(wc); + // Server configuration is finalized before render workers start. Retain one + // native tree so per-request UCEB encoding can reference it without rebuilding + // dozens of identical nodes; the guest still decodes it into fresh state. + g_wasm_worker->server_config_context = cfg; g_wasm_init_error = g_wasm_worker->init(); if(g_wasm_init_error == "") g_wasm_init_error = wasm_worker_prepare(*g_wasm_worker); @@ -156,7 +160,7 @@ String wasm_backend_serve(Request& request, const String& entry_unit, const Stri ctx[key][entry.first] = entry.second; }; if(request.server) - copy_map(request.server->config, "server_config"); + ctx["server_config"].set_reference(&g_wasm_worker->server_config_context); copy_map(request.params, "params"); copy_map(request.get, "get"); copy_map(request.post, "post"); diff --git a/src/wasm/worker.cpp b/src/wasm/worker.cpp index 03b5f2c..b14773b 100644 --- a/src/wasm/worker.cpp +++ b/src/wasm/worker.cpp @@ -973,6 +973,7 @@ public: std::optional core_module; std::optional core_linker; std::unique_ptr core_instance_pre; + DValue server_config_context; struct CoreImport { String module;