Prove pooled workspace request isolation
This commit is contained in:
@@ -58,7 +58,7 @@ if [[ "$action" == "list" ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$action" == "run" ]]; then
|
if [[ "$action" == "run" ]]; then
|
||||||
groups=(demo http site doc-gate security task-lifetime starter tcp)
|
groups=(demo http site doc-gate security task-lifetime pool-isolation starter tcp)
|
||||||
if [[ "$include_kill" == "1" ]]; then
|
if [[ "$include_kill" == "1" ]]; then
|
||||||
groups+=(wasm-kill)
|
groups+=(wasm-kill)
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -384,6 +384,33 @@ void cli_run_task_lifetime_smoke()
|
|||||||
cli_test_case("uce_task_lifetime:delayed callback after request return", res.status == 200 && cli_contains(res.body, "late task scheduled") && cli_contains(observed, "late callback ran"), "status=" + std::to_string(res.status) + " observed=" + cli_truncate(observed));
|
cli_test_case("uce_task_lifetime:delayed callback after request return", res.status == 200 && cli_contains(res.body, "late task scheduled") && cli_contains(observed, "late callback ran"), "status=" + std::to_string(res.status) + " observed=" + cli_truncate(observed));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cli_run_pool_isolation()
|
||||||
|
{
|
||||||
|
DValue worker_counts;
|
||||||
|
bool clean = true;
|
||||||
|
String detail;
|
||||||
|
for(u64 i = 0; i < 64; i++)
|
||||||
|
{
|
||||||
|
String token = "request-" + std::to_string(i);
|
||||||
|
CliHttpResponse res = cli_frontend("/tests/pool-isolation.uce?token=" + token);
|
||||||
|
StringList parts = split(trim(res.body), "|");
|
||||||
|
bool current = res.status == 200 && parts.size() == 3 &&
|
||||||
|
parts[0] == "fresh" && parts[1] == token && int_val(parts[2]) > 0;
|
||||||
|
if(!current && detail == "")
|
||||||
|
detail = "request=" + std::to_string(i) + " status=" + std::to_string(res.status) + " body=" + cli_truncate(res.body);
|
||||||
|
clean = clean && current;
|
||||||
|
if(parts.size() == 3)
|
||||||
|
worker_counts[parts[2]] = worker_counts[parts[2]].to_u64() + 1;
|
||||||
|
}
|
||||||
|
bool reused = false;
|
||||||
|
worker_counts.each([&](DValue count, String) {
|
||||||
|
if(count.to_u64() > 1)
|
||||||
|
reused = true;
|
||||||
|
});
|
||||||
|
cli_test_case("uce_pool_isolation:recycled slots reset request state", clean && reused,
|
||||||
|
clean && reused ? "64 requests retained fresh globals, constructors, ONCE, context, and worker identity" : first(detail, "no worker served a repeated request"));
|
||||||
|
}
|
||||||
|
|
||||||
void cli_run_tcp_smoke()
|
void cli_run_tcp_smoke()
|
||||||
{
|
{
|
||||||
u64 fd80 = socket_connect("127.0.0.1", 80);
|
u64 fd80 = socket_connect("127.0.0.1", 80);
|
||||||
@@ -413,7 +440,7 @@ void cli_run_wasm_kill(bool include_kill)
|
|||||||
void cli_print_list(bool include_kill)
|
void cli_print_list(bool include_kill)
|
||||||
{
|
{
|
||||||
print("UCE CLI test groups:\n");
|
print("UCE CLI test groups:\n");
|
||||||
print(" demo, http, site, doc-gate, security, task-lifetime, starter, tcp");
|
print(" demo, http, site, doc-gate, security, task-lifetime, pool-isolation, starter, tcp");
|
||||||
if(include_kill)
|
if(include_kill)
|
||||||
print(", wasm-kill");
|
print(", wasm-kill");
|
||||||
print("\n");
|
print("\n");
|
||||||
@@ -434,6 +461,8 @@ bool cli_run_group(String group, bool skip_local_service_pages, bool include_kil
|
|||||||
cli_run_security_smoke();
|
cli_run_security_smoke();
|
||||||
else if(group == "task-lifetime")
|
else if(group == "task-lifetime")
|
||||||
cli_run_task_lifetime_smoke();
|
cli_run_task_lifetime_smoke();
|
||||||
|
else if(group == "pool-isolation")
|
||||||
|
cli_run_pool_isolation();
|
||||||
else if(group == "starter")
|
else if(group == "starter")
|
||||||
cli_run_starter_parity();
|
cli_run_starter_parity();
|
||||||
else if(group == "tcp")
|
else if(group == "tcp")
|
||||||
@@ -472,7 +501,7 @@ CLI(Request& context)
|
|||||||
cli_run_group(group, input["skip_local_service_pages"].to_bool(), include_kill);
|
cli_run_group(group, input["skip_local_service_pages"].to_bool(), include_kill);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for(String item : { "demo", "http", "site", "doc-gate", "security", "task-lifetime", "starter", "tcp" })
|
for(String item : { "demo", "http", "site", "doc-gate", "security", "task-lifetime", "pool-isolation", "starter", "tcp" })
|
||||||
cli_run_group(item, input["skip_local_service_pages"].to_bool(), include_kill);
|
cli_run_group(item, input["skip_local_service_pages"].to_bool(), include_kill);
|
||||||
cli_run_group("wasm-kill", input["skip_local_service_pages"].to_bool(), include_kill);
|
cli_run_group("wasm-kill", input["skip_local_service_pages"].to_bool(), include_kill);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
u64 pool_request_global = 0;
|
||||||
|
u64 pool_constructor_value = 0;
|
||||||
|
|
||||||
|
struct PoolIsolationConstructor
|
||||||
|
{
|
||||||
|
PoolIsolationConstructor()
|
||||||
|
{
|
||||||
|
pool_constructor_value = 17;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
PoolIsolationConstructor pool_isolation_constructor;
|
||||||
|
|
||||||
|
ONCE(Request& context)
|
||||||
|
{
|
||||||
|
pool_request_global++;
|
||||||
|
}
|
||||||
|
|
||||||
|
RENDER(Request& context)
|
||||||
|
{
|
||||||
|
String token = context.get["token"];
|
||||||
|
bool clean = pool_request_global == 1 &&
|
||||||
|
pool_constructor_value == 17 &&
|
||||||
|
context.call["pool-leak"].to_string() == "" &&
|
||||||
|
context.props["pool-leak"].to_string() == "";
|
||||||
|
DValue perf = request_perf();
|
||||||
|
print(clean ? "fresh|" : "leaked|", token, "|", (u64)perf["worker_pid"].to_u64());
|
||||||
|
|
||||||
|
pool_request_global = 999;
|
||||||
|
pool_constructor_value = 999;
|
||||||
|
context.call["pool-leak"] = token;
|
||||||
|
context.props["pool-leak"] = token;
|
||||||
|
context.get["token"] = "dirty";
|
||||||
|
}
|
||||||
@@ -1201,6 +1201,10 @@ private:
|
|||||||
{
|
{
|
||||||
wasmtime::Config config;
|
wasmtime::Config config;
|
||||||
wasmtime::PoolAllocationConfig pool;
|
wasmtime::PoolAllocationConfig pool;
|
||||||
|
// A workspace owns one core plus at most table_headroom side modules;
|
||||||
|
// side modules import its single memory/table. Keep allocator capacity at
|
||||||
|
// the existing handler-table boundary instead of imposing its 1000-slot default.
|
||||||
|
pool.total_core_instances(4097);
|
||||||
config.pooling_allocation_strategy(pool);
|
config.pooling_allocation_strategy(pool);
|
||||||
config.epoch_interruption(true);
|
config.epoch_interruption(true);
|
||||||
// CRITICAL: the host (linux_fastcgi.cpp) installs its own SIGSEGV/SIGILL/
|
// CRITICAL: the host (linux_fastcgi.cpp) installs its own SIGSEGV/SIGILL/
|
||||||
|
|||||||
Reference in New Issue
Block a user