From ea6d6ebfc4d2858371087c11e950377dea103064 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Thu, 7 Sep 2023 19:53:18 -0700 Subject: [PATCH] refactor(proxy-wasm) improve pwexec resurrection and instance lifecycle The main goal of this overhaul is to simplify `on_context_create`, make it fully re-entrant *and* properly handle instance recycling at the same time. The way to do so, in my opinion, was to move `pwexec` creation where `rexec` already was. In other words, always lookup the context id in the instance rbtree, and if not found, create it. This means that surrounding code also needed big overhauls. It also removes the reference counting poor man's GC of the older implementation. The code became really ugly by then so I took the time to also review this module's code structure instead of making a *very* ugly commit. This new ngx_proxy_wasm.c file should be much easier to read and follow now. One change I do not fully like is moving the `next_id` to a global counter, but we do not have a "global proxy-wasm conf" object yet. I also started thinking about pre-allocating a number of `pwexecs` (like `worker_connections`) and use free/busy queue that all filter chains can dip into to get a context id + context memory zone. Perhaps for a later time. --- src/common/proxy_wasm/ngx_proxy_wasm.c | 1825 +++++++++-------- src/common/proxy_wasm/ngx_proxy_wasm.h | 38 +- src/common/proxy_wasm/ngx_proxy_wasm_host.c | 25 +- src/common/proxy_wasm/ngx_proxy_wasm_util.c | 46 +- src/http/ngx_http_wasm_module.c | 7 +- src/http/ngx_http_wasm_util.c | 2 +- src/http/proxy_wasm/ngx_http_proxy_wasm.h | 2 +- .../proxy_wasm/ngx_http_proxy_wasm_dispatch.c | 2 +- src/wasm/vm/ngx_wavm.c | 6 +- t/03-proxy_wasm/003-on_tick.t | 6 +- .../007-on_http_instance_isolation.t | 23 +- .../hfuncs/114-proxy_set_http_request_body.t | 3 +- .../hfuncs/119-proxy_properties_get_ngx.t | 6 - .../hfuncs/120-proxy_properties_get_host.t | 13 +- .../hfuncs/122-proxy_properties_set_host.t | 11 +- .../hfuncs/123-proxy_properties_set_ngx.t | 6 +- t/04-openresty/ffi/103-proxy_wasm_attach.t | 8 +- 17 files changed, 1083 insertions(+), 946 deletions(-) diff --git a/src/common/proxy_wasm/ngx_proxy_wasm.c b/src/common/proxy_wasm/ngx_proxy_wasm.c index ff67c5009..534cdead9 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm.c @@ -10,115 +10,62 @@ #endif -static ngx_int_t ngx_proxy_wasm_init_abi(ngx_proxy_wasm_filter_t *filter); -static ngx_int_t ngx_proxy_wasm_start_filter(ngx_proxy_wasm_filter_t *filter); -static void ngx_proxy_wasm_instance_destroy(ngx_proxy_wasm_instance_t *ictx); -static ngx_proxy_wasm_err_e ngx_proxy_wasm_on_start( - ngx_proxy_wasm_instance_t *ictx, ngx_proxy_wasm_filter_t *filter, - unsigned start); +#define ngx_proxy_wasm_store_init(s, p) \ + (s)->pool = (p); \ + ngx_queue_init(&(s)->sweep); \ + ngx_queue_init(&(s)->free); \ + ngx_queue_init(&(s)->busy) + + +static ngx_proxy_wasm_err_e ngx_proxy_wasm_create_context( + ngx_proxy_wasm_filter_t *filter, ngx_proxy_wasm_ctx_t *pwctx, + ngx_uint_t id, ngx_proxy_wasm_exec_t *in, ngx_proxy_wasm_exec_t **out); static void ngx_proxy_wasm_on_log(ngx_proxy_wasm_exec_t *pwexec); static void ngx_proxy_wasm_on_done(ngx_proxy_wasm_exec_t *pwexec); static ngx_int_t ngx_proxy_wasm_on_tick(ngx_proxy_wasm_exec_t *pwexec); +static ngx_proxy_wasm_filter_t *ngx_proxy_wasm_lookup_filter(ngx_uint_t id); +static ngx_proxy_wasm_exec_t *ngx_proxy_wasm_lookup_root_ctx( + ngx_proxy_wasm_instance_t *ictx, ngx_uint_t id); +static ngx_proxy_wasm_exec_t *ngx_proxy_wasm_lookup_ctx( + ngx_proxy_wasm_instance_t *ictx, ngx_uint_t id); +static ngx_int_t ngx_proxy_wasm_filter_init_abi( + ngx_proxy_wasm_filter_t *filter); +static ngx_int_t ngx_proxy_wasm_filter_start(ngx_proxy_wasm_filter_t *filter); +static void ngx_proxy_wasm_instance_update( + ngx_proxy_wasm_instance_t *ictx, ngx_proxy_wasm_exec_t *pwexec); +static void ngx_proxy_wasm_instance_invalidate(ngx_proxy_wasm_instance_t *ictx); +static void ngx_proxy_wasm_instance_destroy(ngx_proxy_wasm_instance_t *ictx); +static void ngx_proxy_wasm_store_destroy(ngx_proxy_wasm_store_t *store); +static void ngx_proxy_wasm_store_sweep(ngx_proxy_wasm_store_t *store); +#if 0 +static void ngx_proxy_wasm_store_schedule_sweep_handler(ngx_event_t *ev); +static void ngx_proxy_wasm_store_schedule_sweep(ngx_proxy_wasm_store_t *store); +#endif +static ngx_uint_t next_id = 1; static ngx_rbtree_t ngx_proxy_wasm_filters_rbtree; static ngx_rbtree_node_t ngx_proxy_wasm_filters_sentinel; -static ngx_proxy_wasm_filter_t * -ngx_proxy_wasm_filter_lookup(ngx_uint_t id) -{ - ngx_rbtree_t *rbtree; - ngx_rbtree_node_t *node, *sentinel; - ngx_proxy_wasm_filter_t *filter; - - rbtree = &ngx_proxy_wasm_filters_rbtree; - node = rbtree->root; - sentinel = rbtree->sentinel; - - while (node != sentinel) { - - if (id != node->key) { - node = (id < node->key) ? node->left : node->right; - continue; - } - - filter = ngx_rbtree_data(node, ngx_proxy_wasm_filter_t, node); - - return filter; - } - - return NULL; -} - - -static ngx_proxy_wasm_exec_t * -ngx_proxy_wasm_root_lookup(ngx_proxy_wasm_instance_t *ictx, ngx_uint_t id) -{ - ngx_rbtree_t *rbtree; - ngx_rbtree_node_t *node, *sentinel; - ngx_proxy_wasm_exec_t *pwexec; - - rbtree = &ictx->root_ctxs; - node = rbtree->root; - sentinel = rbtree->sentinel; - - while (node != sentinel) { - - if (id != node->key) { - node = (id < node->key) ? node->left : node->right; - continue; - } - - pwexec = ngx_rbtree_data(node, ngx_proxy_wasm_exec_t, node); - - return pwexec; - } - - return NULL; -} - - -static ngx_proxy_wasm_exec_t * -ngx_proxy_wasm_ctx_lookup(ngx_proxy_wasm_instance_t *ictx, ngx_uint_t id) -{ - ngx_rbtree_t *rbtree; - ngx_rbtree_node_t *node, *sentinel; - ngx_proxy_wasm_exec_t *pwexec; - - rbtree = &ictx->tree_ctxs; - node = rbtree->root; - sentinel = rbtree->sentinel; - - while (node != sentinel) { - - if (id != node->key) { - node = (id < node->key) ? node->left : node->right; - continue; - } - - pwexec = ngx_rbtree_data(node, ngx_proxy_wasm_exec_t, node); - - return pwexec; - } - - return NULL; -} +/* context - root */ void -ngx_proxy_wasm_init(ngx_conf_t *cf) +ngx_proxy_wasm_init(ngx_conf_t *cf, ngx_proxy_wasm_store_t *gstore) { ngx_rbtree_init(&ngx_proxy_wasm_filters_rbtree, &ngx_proxy_wasm_filters_sentinel, ngx_rbtree_insert_value); ngx_proxy_wasm_properties_init(cf); + + ngx_proxy_wasm_store_init(gstore, cf->pool); } void -ngx_proxy_wasm_exit() +ngx_proxy_wasm_exit(ngx_proxy_wasm_store_t *gstore) { ngx_rbtree_node_t **root_node, **sentinel, *node; ngx_proxy_wasm_filter_t *filter; @@ -132,17 +79,15 @@ ngx_proxy_wasm_exit() ngx_rbtree_delete(&ngx_proxy_wasm_filters_rbtree, node); - ngx_log_debug1(NGX_LOG_DEBUG_WASM, filter->log, 0, - "proxy_wasm releasing \"%V\" filter instance", - filter->name); - ngx_proxy_wasm_store_destroy(filter->store); } + + ngx_proxy_wasm_store_destroy(gstore); } -ngx_uint_t -ngx_proxy_wasm_id(ngx_str_t *name, ngx_str_t *config, uintptr_t data) +static ngx_uint_t +get_filter_id(ngx_str_t *name, ngx_str_t *config, uintptr_t data) { u_char buf[NGX_INT64_LEN]; uint32_t hash; @@ -178,12 +123,12 @@ ngx_proxy_wasm_load(ngx_proxy_wasm_filter_t *filter, ngx_log_t *log) filter->log = log; filter->name = &filter->module->name; - filter->id = ngx_proxy_wasm_id(filter->name, &filter->config, filter->data); + filter->id = get_filter_id(filter->name, &filter->config, filter->data); filter->node.key = filter->id; ngx_rbtree_insert(&ngx_proxy_wasm_filters_rbtree, &filter->node); - if (ngx_proxy_wasm_init_abi(filter) != NGX_OK) { + if (ngx_proxy_wasm_filter_init_abi(filter) != NGX_OK) { return NGX_ERROR; } @@ -217,7 +162,7 @@ ngx_proxy_wasm_start(ngx_cycle_t *cycle) { filter = ngx_rbtree_data(node, ngx_proxy_wasm_filter_t, node); - rc = ngx_proxy_wasm_start_filter(filter); + rc = ngx_proxy_wasm_filter_start(filter); if (rc != NGX_OK) { ngx_proxy_wasm_log_error(NGX_LOG_EMERG, filter->log, filter->ecode, "failed initializing \"%V\" filter", @@ -232,6 +177,9 @@ ngx_proxy_wasm_start(ngx_cycle_t *cycle) } +/* context - stream */ + + ngx_proxy_wasm_ctx_t * ngx_proxy_wasm_ctx_alloc(ngx_pool_t *pool) { @@ -260,15 +208,11 @@ ngx_proxy_wasm_ctx_t * ngx_proxy_wasm_ctx(ngx_uint_t *filter_ids, size_t nfilters, ngx_uint_t isolation, ngx_proxy_wasm_subsystem_t *subsys, void *data) { - size_t i; - ngx_uint_t id; - ngx_pool_t *pool; - ngx_log_t *log; - ngx_proxy_wasm_ctx_t *pwctx; - ngx_proxy_wasm_exec_t *pwexec; - ngx_proxy_wasm_filter_t *filter; - ngx_proxy_wasm_instance_t *ictx; - ngx_proxy_wasm_store_t *pwstore = NULL; + size_t i; + ngx_uint_t id; + ngx_proxy_wasm_ctx_t *pwctx; + ngx_proxy_wasm_filter_t *filter; + ngx_proxy_wasm_exec_t *pwexec = NULL; pwctx = subsys->get_context(data); if (pwctx == NULL) { @@ -292,115 +236,120 @@ ngx_proxy_wasm_ctx(ngx_uint_t *filter_ids, size_t nfilters, for (i = 0; i < nfilters; i++) { id = filter_ids[i]; - filter = ngx_proxy_wasm_filter_lookup(id); + filter = ngx_proxy_wasm_lookup_filter(id); if (filter == NULL) { /* TODO: log error */ ngx_wasm_assert(0); return NULL; } - pool = pwctx->pool; - log = pwctx->log; - - switch (pwctx->isolation) { - case NGX_PROXY_WASM_ISOLATION_NONE: - pwstore = filter->store; - break; - case NGX_PROXY_WASM_ISOLATION_STREAM: - pwstore = &pwctx->store; - break; - case NGX_PROXY_WASM_ISOLATION_FILTER: - break; - default: - ngx_proxy_wasm_log_error(NGX_LOG_WASM_NYI, pwctx->log, 0, - "NYI - instance isolation: %d", - pwctx->isolation); - return NULL; - } - - pwexec = ngx_array_push(&pwctx->pwexecs); + (void) ngx_proxy_wasm_create_context(filter, pwctx, + next_id++, NULL, &pwexec); if (pwexec == NULL) { return NULL; } - ngx_memzero(pwexec, sizeof(ngx_proxy_wasm_exec_t)); + } /* for () */ - pwexec->index = i; - pwexec->pool = pool; - pwexec->filter = filter; - pwexec->parent = pwctx; - pwexec->root_id = filter->id; + pwctx->ready = 1; - pwexec->log = ngx_pcalloc(pwexec->pool, sizeof(ngx_log_t)); - if (pwexec->log == NULL) { - return NULL; - } + } /* !ready */ - pwexec->log->file = log->file; - pwexec->log->next = log->next; - pwexec->log->writer = log->writer; - pwexec->log->wdata = log->wdata; - pwexec->log->log_level = log->log_level; - pwexec->log->connection = log->connection; - pwexec->log->handler = ngx_proxy_wasm_log_error_handler; - pwexec->log->data = &pwexec->log_ctx; + return pwctx; +} - pwexec->log_ctx.pwexec = pwexec; - pwexec->log_ctx.orig_log = log; - ictx = ngx_proxy_wasm_get_instance(filter, pwstore, pwexec, log); - if (ictx == NULL) { - return NULL; - } +static void +destroy_pwexec(ngx_proxy_wasm_exec_t *pwexec) +{ + pwexec->ictx = NULL; + pwexec->started = 0; - pwexec->ictx = ictx; + if (pwexec->ev) { + ngx_del_timer(pwexec->ev); + ngx_free(pwexec->ev); + pwexec->ev = NULL; + } - ngx_wasm_assert(pwexec->index + 1 == pwctx->pwexecs.nelts); + if (pwexec->log) { + if (pwexec->log_ctx.log_prefix.data) { + ngx_pfree(pwexec->pool, pwexec->log_ctx.log_prefix.data); + } - } /* for () */ + ngx_pfree(pwexec->pool, pwexec->log); + pwexec->log = NULL; + } - pwctx->ready = 1; + if (pwexec->parent) { + if (pwexec->log_ctx.log_prefix.data) { + ngx_pfree(pwexec->pool, pwexec->log_ctx.log_prefix.data); + pwexec->log_ctx.log_prefix.data = NULL; + } - } /* !ready */ + if (pwexec->root_id == NGX_PROXY_WASM_ROOT_CTX_ID) { + ngx_pfree(pwexec->pool, pwexec->parent); + pwexec->parent = NULL; - return pwctx; + } else if (pwexec->parent->isolation + == NGX_PROXY_WASM_ISOLATION_FILTER + && pwexec->store) + { + /* store specifically allocated for the pwexec */ + ngx_pfree(pwexec->parent->pool, pwexec->store); + pwexec->store = NULL; + } + } } void ngx_proxy_wasm_ctx_destroy(ngx_proxy_wasm_ctx_t *pwctx) { - size_t i; - ngx_proxy_wasm_exec_t *pwexec, *pwexecs; - ngx_proxy_wasm_instance_t *ictx; + size_t i; + ngx_proxy_wasm_exec_t *pwexec, *pwexecs; + + dd("enter (pwctx: %p)", pwctx); + + if (pwctx->ready + && pwctx->isolation == NGX_PROXY_WASM_ISOLATION_STREAM) + { + ngx_proxy_wasm_store_destroy(&pwctx->store); + } pwexecs = (ngx_proxy_wasm_exec_t *) pwctx->pwexecs.elts; for (i = 0; i < pwctx->pwexecs.nelts; i++) { pwexec = &pwexecs[i]; - ictx = pwexec->ictx; ngx_wasm_assert(pwexec->root_id != NGX_PROXY_WASM_ROOT_CTX_ID); - ngx_proxy_wasm_log_error(NGX_LOG_DEBUG, pwexec->log, 0, + ngx_proxy_wasm_log_error(NGX_LOG_DEBUG, pwctx->log, 0, "\"%V\" filter freeing context #%d " "(%l/%l)", pwexec->filter->name, pwexec->id, pwexec->index + 1, pwctx->nfilters); - if (pwexec->log) { - if (pwexec->log_ctx.log_prefix.data) { - ngx_pfree(pwexec->pool, pwexec->log_ctx.log_prefix.data); + + if (pwexec->ictx) { + if (pwexec->node.key) { + ngx_rbtree_delete(&pwexec->ictx->tree_ctxs, &pwexec->node); } - ngx_pfree(pwexec->pool, pwexec->log); + if (pwctx->isolation == NGX_PROXY_WASM_ISOLATION_NONE) { + /* sweep if an instance has trapped */ + ngx_proxy_wasm_store_sweep(pwexec->ictx->store); + + } else if (pwctx->isolation == NGX_PROXY_WASM_ISOLATION_FILTER) { + /* destroy filter context store */ + ngx_proxy_wasm_store_destroy(pwexec->store); + } } - ngx_proxy_wasm_release_instance(ictx, 0); + destroy_pwexec(pwexec); } if (pwctx->ready) { - ngx_proxy_wasm_store_destroy(&pwctx->store); + ngx_array_destroy(&pwctx->pwexecs); } #if 0 @@ -456,7 +405,7 @@ ngx_proxy_wasm_ctx_destroy(ngx_proxy_wasm_ctx_t *pwctx) static ngx_int_t -ngx_proxy_wasm_action2rc(ngx_proxy_wasm_ctx_t *pwctx, +action2rc(ngx_proxy_wasm_ctx_t *pwctx, ngx_proxy_wasm_exec_t *pwexec) { ngx_int_t rc = NGX_ERROR; @@ -482,7 +431,7 @@ ngx_proxy_wasm_action2rc(ngx_proxy_wasm_ctx_t *pwctx, #if (NGX_DEBUG) else { if (pwexec->root_id == NGX_PROXY_WASM_ROOT_CTX_ID) { - ngx_proxy_wasm_log_error(NGX_LOG_DEBUG, pwexec->log, + ngx_proxy_wasm_log_error(NGX_LOG_DEBUG, pwctx->log, pwexec->ecode, "root context skipping \"%V\" " "step in \"%V\" phase", @@ -490,7 +439,7 @@ ngx_proxy_wasm_action2rc(ngx_proxy_wasm_ctx_t *pwctx, &pwctx->phase->name); } else { - ngx_proxy_wasm_log_error(NGX_LOG_DEBUG, pwexec->log, + ngx_proxy_wasm_log_error(NGX_LOG_DEBUG, pwctx->log, pwexec->ecode, "filter %l/%l skipping \"%V\" " "step in \"%V\" phase", @@ -518,6 +467,7 @@ ngx_proxy_wasm_action2rc(ngx_proxy_wasm_ctx_t *pwctx, /* determine current action rc */ switch (action) { + case NGX_PROXY_WASM_ACTION_DONE: ngx_log_debug0(NGX_LOG_DEBUG_WASM, pwctx->log, 0, "proxy_wasm action " "\"DONE\" -> \"CONTINUE\" to resume later phases"); @@ -535,17 +485,16 @@ ngx_proxy_wasm_action2rc(ngx_proxy_wasm_ctx_t *pwctx, case NGX_HTTP_REWRITE_PHASE: case NGX_HTTP_ACCESS_PHASE: case NGX_HTTP_CONTENT_PHASE: - ngx_log_debug7(NGX_LOG_DEBUG_WASM, pwctx->log, 0, + ngx_log_debug6(NGX_LOG_DEBUG_WASM, pwctx->log, 0, "proxy_wasm pausing in \"%V\" phase " - "(root: %d, filter: %l/%l, step: %d, action: %d, " + "(filter: %l/%l, step: %d, action: %d, " "pwctx: %p)", &pwctx->phase->name, - pwexec->id == NGX_PROXY_WASM_ROOT_CTX_ID, pwexec->index + 1, pwctx->nfilters, pwctx->step, action, pwctx); goto yield; #endif default: - ngx_proxy_wasm_log_error(NGX_LOG_ERR, pwexec->log, pwexec->ecode, + ngx_proxy_wasm_log_error(NGX_LOG_ERR, pwctx->log, pwexec->ecode, "bad \"%V\" return action: \"PAUSE\"", ngx_proxy_wasm_step_name(pwctx->step)); @@ -597,128 +546,13 @@ ngx_proxy_wasm_action2rc(ngx_proxy_wasm_ctx_t *pwctx, } -ngx_proxy_wasm_err_e -ngx_proxy_wasm_run_step(ngx_proxy_wasm_exec_t *pwexec, - ngx_proxy_wasm_instance_t *ictx, ngx_proxy_wasm_step_e step) -{ - ngx_int_t rc; - ngx_proxy_wasm_action_e action = NGX_PROXY_WASM_ACTION_CONTINUE; - ngx_proxy_wasm_ctx_t *pwctx = pwexec->parent; - ngx_proxy_wasm_filter_t *filter = pwexec->filter; - ngx_wavm_instance_t *instance = ictx->instance; -#if (NGX_DEBUG) - ngx_proxy_wasm_action_e old_action = pwctx->action; -#endif - - ngx_wasm_assert(ictx->module == filter->module); - ngx_wasm_assert(pwctx->phase); - - ictx->pwexec = pwexec; /* set instance current pwexec */ - pwexec->ictx = ictx; /* link pwexec to instance */ - pwctx->step = step; - - /* - * update instance log - * (instance->data = ictx already set by instance_new) - */ - ngx_wavm_instance_set_data(instance, ictx, - pwexec ? pwexec->log : filter->log); - - if (pwexec->root_id == NGX_PROXY_WASM_ROOT_CTX_ID) { - ngx_proxy_wasm_log_error(NGX_LOG_DEBUG, pwexec->log, 0, - "root context resuming \"%V\" step " - "in \"%V\" phase", - ngx_proxy_wasm_step_name(step), - &pwctx->phase->name); - - } else { - ngx_proxy_wasm_log_error(NGX_LOG_DEBUG, pwexec->log, 0, - "filter %l/%l resuming \"%V\" step " - "in \"%V\" phase", - pwexec->index + 1, pwctx->nfilters, - ngx_proxy_wasm_step_name(step), - &pwctx->phase->name); - } - - switch (step) { - case NGX_PROXY_WASM_STEP_REQ_HEADERS: - case NGX_PROXY_WASM_STEP_REQ_BODY: - case NGX_PROXY_WASM_STEP_RESP_HEADERS: - case NGX_PROXY_WASM_STEP_RESP_BODY: -#ifdef NGX_WASM_RESPONSE_TRAILERS - case NGX_PROXY_WASM_STEP_RESP_TRAILERS: -#endif - rc = filter->subsystem->resume(pwexec, step, &action); - break; - case NGX_PROXY_WASM_STEP_LOG: - ngx_proxy_wasm_on_log(pwexec); - rc = NGX_OK; - break; - case NGX_PROXY_WASM_STEP_DONE: - ngx_proxy_wasm_on_done(pwexec); - rc = NGX_OK; - break; - case NGX_PROXY_WASM_STEP_DISPATCH_RESPONSE: - rc = filter->subsystem->resume(pwexec, step, &action); - break; - case NGX_PROXY_WASM_STEP_TICK: - rc = ngx_proxy_wasm_on_tick(pwexec); - break; - default: - ngx_proxy_wasm_log_error(NGX_LOG_WASM_NYI, pwctx->log, 0, - "NYI - proxy_wasm step: %d", step); - rc = NGX_ERROR; - break; - } - - dd("rc: %ld, old_action: %d, pwctx->action: %d, ret action: %d", - rc, old_action, pwctx->action, action); - - /* pwctx->action writes in host calls overwrite action return value */ - - if (pwctx->action != action) { - switch (pwctx->action) { - case NGX_PROXY_WASM_ACTION_DONE: - /* e.g. proxy_send_local_response() */ - ngx_wasm_assert(pwctx->action != old_action); - goto done; - default: - ngx_proxy_wasm_ctx_set_next_action(pwctx, action); - break; - } - } - - ngx_wasm_assert(rc == NGX_OK - || rc == NGX_ABORT - || rc == NGX_ERROR); - - if (rc == NGX_OK) { - pwexec->ecode = NGX_PROXY_WASM_ERR_NONE; - - } else if (rc == NGX_ABORT) { - pwexec->ecode = NGX_PROXY_WASM_ERR_INSTANCE_TRAPPED; - - } else if (rc == NGX_ERROR) { - pwexec->ecode = NGX_PROXY_WASM_ERR_UNKNOWN; - } - -done: - - ictx->pwexec = NULL; - - return pwexec->ecode; -} - - ngx_int_t ngx_proxy_wasm_resume(ngx_proxy_wasm_ctx_t *pwctx, ngx_wasm_phase_t *phase, ngx_proxy_wasm_step_e step) { - size_t i; - ngx_int_t rc = NGX_OK; - ngx_proxy_wasm_filter_t *filter; - ngx_proxy_wasm_instance_t *ictx; - ngx_proxy_wasm_exec_t *pwexec, *pwexecs; + size_t i; + ngx_int_t rc = NGX_OK; + ngx_proxy_wasm_exec_t *pwexec, *pwexecs; dd("enter"); @@ -749,41 +583,44 @@ ngx_proxy_wasm_resume(ngx_proxy_wasm_ctx_t *pwctx, pwexecs = (ngx_proxy_wasm_exec_t *) pwctx->pwexecs.elts; + dd("pwctx->exec_index: %ld, nelts: %ld", + pwctx->exec_index, pwctx->pwexecs.nelts); + for (i = pwctx->exec_index; i < pwctx->pwexecs.nelts; i++) { dd("exec_index: %ld", i); pwexec = &pwexecs[i]; - filter = pwexec->filter; - ictx = pwexec->ictx; ngx_wasm_assert(pwexec->root_id != NGX_PROXY_WASM_ROOT_CTX_ID); - /* check for trap */ - - if (ictx->instance->trapped && !pwexec->ecode) { - pwexec->ecode = NGX_PROXY_WASM_ERR_INSTANCE_TRAPPED; - } - /* check for yielded state */ - rc = ngx_proxy_wasm_action2rc(pwctx, pwexec); + rc = action2rc(pwctx, pwexec); if (rc != NGX_OK) { goto ret; } + if (step == NGX_PROXY_WASM_STEP_DONE + && (pwexec->ictx == NULL || pwexec->ictx->instance->trapped)) + { + dd("no instance, skip done"); + rc = NGX_OK; + goto ret; + } + /* run step */ - pwexec->ecode = ngx_proxy_wasm_run_step(pwexec, ictx, step); + pwexec->ecode = ngx_proxy_wasm_run_step(pwexec, step); dd("pwexec->ecode: %d, pwctx->action: %d (pwctx: %p)", pwexec->ecode, pwctx->action, pwctx); if (pwexec->ecode != NGX_PROXY_WASM_ERR_NONE) { - rc = filter->subsystem->ecode(pwexec->ecode); + rc = pwexec->filter->subsystem->ecode(pwexec->ecode); goto ret; } /* check for yield/done */ - rc = ngx_proxy_wasm_action2rc(pwctx, pwexec); + rc = action2rc(pwctx, pwexec); if (rc != NGX_OK) { if (rc == NGX_AGAIN && pwctx->exec_index + 1 <= pwctx->nfilters) @@ -823,68 +660,706 @@ ngx_proxy_wasm_resume(ngx_proxy_wasm_ctx_t *pwctx, } -ngx_wavm_ptr_t -ngx_proxy_wasm_alloc(ngx_proxy_wasm_exec_t *pwexec, size_t size) +ngx_proxy_wasm_err_e +ngx_proxy_wasm_run_step(ngx_proxy_wasm_exec_t *pwexec, + ngx_proxy_wasm_step_e step) { - ngx_wavm_ptr_t p; ngx_int_t rc; - wasm_val_vec_t *rets; + ngx_proxy_wasm_err_e ecode; + ngx_proxy_wasm_action_e action = NGX_PROXY_WASM_ACTION_CONTINUE; + ngx_proxy_wasm_ctx_t *pwctx = pwexec->parent; ngx_proxy_wasm_filter_t *filter = pwexec->filter; - ngx_wavm_instance_t *instance = ngx_proxy_wasm_pwexec2instance(pwexec); +#if (NGX_DEBUG) + ngx_proxy_wasm_action_e old_action = pwctx->action; +#endif - rc = ngx_wavm_instance_call_funcref(instance, - filter->proxy_on_memory_allocate, - &rets, size); - if (rc != NGX_OK) { - ngx_proxy_wasm_log_error(NGX_LOG_CRIT, pwexec->log, 0, - "proxy_wasm_alloc(%uz) failed", size); + ngx_wasm_assert(pwctx->phase); + + dd("enter (pwexec: %p, ictx: %p, trapped: %d)", + pwexec, pwexec->ictx, + pwexec->ictx ? pwexec->ictx->instance->trapped : 0); + +#if 0 + /* possible optimization, commented for linter */ + if (pwexec->ictx->instance->trapped) { +#endif + ecode = ngx_proxy_wasm_create_context(filter, pwctx, pwexec->id, + pwexec, NULL); + if (ecode != NGX_PROXY_WASM_ERR_NONE) { + return ecode; + } +#if 0 + } +#endif + + ngx_wasm_assert(!pwexec->ictx->instance->trapped); + ngx_wasm_assert(pwexec->ictx->module == filter->module); + + pwctx->step = step; + + ngx_proxy_wasm_instance_update(pwexec->ictx, pwexec); + + if (pwexec->root_id == NGX_PROXY_WASM_ROOT_CTX_ID) { + ngx_proxy_wasm_log_error(NGX_LOG_DEBUG, pwexec->log, 0, + "root context resuming \"%V\" step " + "in \"%V\" phase", + ngx_proxy_wasm_step_name(step), + &pwctx->phase->name); + + } else { + ngx_proxy_wasm_log_error(NGX_LOG_DEBUG, pwexec->log, 0, + "filter %l/%l resuming \"%V\" step " + "in \"%V\" phase", + pwexec->index + 1, pwctx->nfilters, + ngx_proxy_wasm_step_name(step), + &pwctx->phase->name); + } + + switch (step) { + case NGX_PROXY_WASM_STEP_REQ_HEADERS: + case NGX_PROXY_WASM_STEP_REQ_BODY: + case NGX_PROXY_WASM_STEP_RESP_HEADERS: + case NGX_PROXY_WASM_STEP_RESP_BODY: +#ifdef NGX_WASM_RESPONSE_TRAILERS + case NGX_PROXY_WASM_STEP_RESP_TRAILERS: +#endif + rc = filter->subsystem->resume(pwexec, step, &action); + break; + case NGX_PROXY_WASM_STEP_LOG: + ngx_proxy_wasm_on_log(pwexec); + rc = NGX_OK; + break; + case NGX_PROXY_WASM_STEP_DONE: + ngx_proxy_wasm_on_done(pwexec); + rc = NGX_OK; + break; + case NGX_PROXY_WASM_STEP_DISPATCH_RESPONSE: + rc = filter->subsystem->resume(pwexec, step, &action); + break; + case NGX_PROXY_WASM_STEP_TICK: + pwexec->in_tick = 1; + rc = ngx_proxy_wasm_on_tick(pwexec); + pwexec->in_tick = 0; + break; + default: + ngx_proxy_wasm_log_error(NGX_LOG_WASM_NYI, pwctx->log, 0, + "NYI - proxy_wasm step: %d", step); + rc = NGX_ERROR; + break; + } + + dd("rc: %ld, old_action: %d, pwctx->action: %d, ret action: %d, ictx: %p", + rc, old_action, pwctx->action, action, pwexec->ictx); + + /* pwctx->action writes in host calls overwrite action return value */ + + if (pwctx->action != action) { + switch (pwctx->action) { + case NGX_PROXY_WASM_ACTION_DONE: + /* e.g. proxy_send_local_response() */ + ngx_wasm_assert(pwctx->action != old_action); + goto done; + default: + ngx_proxy_wasm_ctx_set_next_action(pwctx, action); + break; + } + } + + ngx_wasm_assert(rc == NGX_OK + || rc == NGX_ABORT + || rc == NGX_ERROR); + + if (rc == NGX_OK) { + pwexec->ecode = NGX_PROXY_WASM_ERR_NONE; + + } else if (rc == NGX_ABORT) { + pwexec->ecode = NGX_PROXY_WASM_ERR_INSTANCE_TRAPPED; + + } else if (rc == NGX_ERROR) { + pwexec->ecode = NGX_PROXY_WASM_ERR_UNKNOWN; + } + +done: + + return pwexec->ecode; +} + + +/* host handlers */ + + +ngx_wavm_ptr_t +ngx_proxy_wasm_alloc(ngx_proxy_wasm_exec_t *pwexec, size_t size) +{ + ngx_wavm_ptr_t p; + ngx_int_t rc; + wasm_val_vec_t *rets; + ngx_proxy_wasm_filter_t *filter = pwexec->filter; + ngx_wavm_instance_t *instance = ngx_proxy_wasm_pwexec2instance(pwexec); + + rc = ngx_wavm_instance_call_funcref(instance, + filter->proxy_on_memory_allocate, + &rets, size); + if (rc != NGX_OK) { + ngx_proxy_wasm_log_error(NGX_LOG_CRIT, pwexec->log, 0, + "proxy_wasm_alloc(%uz) failed", size); return 0; } - p = rets->data[0].of.i32; + p = rets->data[0].of.i32; + + ngx_log_debug3(NGX_LOG_DEBUG_WASM, pwexec->log, 0, + "proxy_wasm_alloc: %uz:%uz:%uz", + ngx_wavm_memory_data_size(instance->memory), p, size); + + return p; +} + + +static ngx_proxy_wasm_instance_t * +get_instance(ngx_proxy_wasm_filter_t *filter, + ngx_proxy_wasm_store_t *store, ngx_log_t *log) +{ + ngx_queue_t *q; + ngx_wavm_module_t *module = filter->module; + ngx_proxy_wasm_instance_t *ictx; + + dd("get instance in store: %p", store); + + for (q = ngx_queue_head(&store->busy); + q != ngx_queue_sentinel(&store->busy); + q = ngx_queue_next(q)) + { + ictx = ngx_queue_data(q, ngx_proxy_wasm_instance_t, q); + + if (ictx->instance->trapped) { + q = ngx_queue_next(&ictx->q); + ngx_proxy_wasm_log_error(NGX_LOG_DEBUG, log, 0, + "\"%V\" filter invalidating trapped " + "instance (ictx: %p, store: %p)", + filter->name, ictx, store); + ngx_proxy_wasm_instance_invalidate(ictx); + continue; + } + + if (ictx->module == module) { + dd("reuse busy instance"); + goto reuse; + } + } + + for (q = ngx_queue_head(&store->free); + q != ngx_queue_sentinel(&store->free); + q = ngx_queue_next(q)) + { + ictx = ngx_queue_data(q, ngx_proxy_wasm_instance_t, q); + + ngx_wasm_assert(!ictx->instance->trapped); + + if (ictx->module == module) { + dd("reuse free instance, going to busy"); + ngx_queue_remove(&ictx->q); + ngx_queue_insert_tail(&store->busy, &ictx->q); + goto reuse; + } + } + + dd("create instance in store: %p", store); + + ictx = ngx_pcalloc(store->pool, sizeof(ngx_proxy_wasm_instance_t)); + if (ictx == NULL) { + goto error; + } + + ictx->pool = store->pool; + ictx->log = log; + ictx->store = store; + ictx->module = module; + + ngx_rbtree_init(&ictx->root_ctxs, &ictx->sentinel_root_ctxs, + ngx_rbtree_insert_value); + + ngx_rbtree_init(&ictx->tree_ctxs, &ictx->sentinel_ctxs, + ngx_rbtree_insert_value); + + ictx->instance = ngx_wavm_instance_create(ictx->module, ictx->pool, + ictx->log, ictx); + if (ictx->instance == NULL) { + ngx_pfree(store->pool, ictx); + goto error; + } + + ngx_proxy_wasm_log_error(NGX_LOG_DEBUG, log, 0, + "\"%V\" filter new instance (ictx: %p, store: %p)", + filter->name, ictx, store); + + ngx_queue_insert_tail(&store->busy, &ictx->q); + + goto done; + +reuse: + + ngx_proxy_wasm_log_error(NGX_LOG_DEBUG, log, 0, + "\"%V\" filter reusing instance " + "(ictx: %p, store: %p)", + filter->name, ictx, store); + +done: + + return ictx; + +error: + + return NULL; +} + + +static ngx_proxy_wasm_err_e +ngx_proxy_wasm_create_context(ngx_proxy_wasm_filter_t *filter, + ngx_proxy_wasm_ctx_t *pwctx, ngx_uint_t id, ngx_proxy_wasm_exec_t *in, + ngx_proxy_wasm_exec_t **out) +{ + ngx_int_t rc; + ngx_log_t *log; + wasm_val_vec_t *rets; + ngx_proxy_wasm_instance_t *ictx; + ngx_proxy_wasm_store_t *store; + ngx_proxy_wasm_exec_t *rexec = NULL, *pwexec = NULL; + ngx_proxy_wasm_err_e ecode = NGX_PROXY_WASM_ERR_UNKNOWN; + + dd("enter (filter: \"%.*s\", id: %ld)", + (int) filter->name->len, filter->name->data, id); + + if (id == NGX_PROXY_WASM_ROOT_CTX_ID + || (in && in->root_id == NGX_PROXY_WASM_ROOT_CTX_ID)) + { + /* root context */ + log = filter->log; + store = filter->store; + + } else { + /* filter context */ + log = pwctx->log; + + switch (pwctx->isolation) { + case NGX_PROXY_WASM_ISOLATION_NONE: + store = filter->store; + break; + case NGX_PROXY_WASM_ISOLATION_STREAM: + store = &pwctx->store; + + if (store->pool == NULL) { + ngx_proxy_wasm_store_init(&pwctx->store, pwctx->pool); + } + + break; + case NGX_PROXY_WASM_ISOLATION_FILTER: + store = ngx_palloc(pwctx->pool, sizeof(ngx_proxy_wasm_store_t)); + if (store == NULL) { + goto error; + } + + ngx_proxy_wasm_store_init(store, pwctx->pool); + break; + default: + ngx_proxy_wasm_log_error(NGX_LOG_WASM_NYI, pwctx->log, 0, + "NYI - instance isolation: %d", + pwctx->isolation); + goto error; + } + } + + /* get instance */ + + if (in && in->ictx && !in->ictx->instance->trapped) { + ictx = in->ictx; + + } else { + ictx = get_instance(filter, store, log); + if (ictx == NULL) { + goto error; + } + } + + /* create root context */ + + rexec = ngx_proxy_wasm_lookup_root_ctx(ictx, filter->id); + dd("rexec for id %ld: %p (in: %p)", filter->id, rexec, in); + if (rexec == NULL) { + if (in == NULL || (in && in->root_id != NGX_PROXY_WASM_ROOT_CTX_ID)) { + rexec = ngx_pcalloc(filter->pool, sizeof(ngx_proxy_wasm_exec_t)); + if (rexec == NULL) { + ecode = NGX_PROXY_WASM_ERR_START_FAILED; + goto error; + } + + rexec->root_id = NGX_PROXY_WASM_ROOT_CTX_ID; + rexec->id = filter->id; + rexec->pool = filter->pool; + rexec->log = filter->log; + rexec->filter = filter; + rexec->ictx = ictx; + + log = filter->log; + + rexec->log = ngx_pcalloc(rexec->pool, sizeof(ngx_log_t)); + if (rexec->log == NULL) { + ecode = NGX_PROXY_WASM_ERR_START_FAILED; + goto error; + } + + rexec->log->file = log->file; + rexec->log->next = log->next; + rexec->log->writer = log->writer; + rexec->log->wdata = log->wdata; + rexec->log->log_level = log->log_level; + rexec->log->handler = ngx_proxy_wasm_log_error_handler; + rexec->log->data = &rexec->log_ctx; + + rexec->log_ctx.pwexec = rexec; + rexec->log_ctx.orig_log = log; + + rexec->parent = ngx_pcalloc(rexec->pool, + sizeof(ngx_proxy_wasm_ctx_t)); + if (rexec->parent == NULL) { + ecode = NGX_PROXY_WASM_ERR_START_FAILED; + goto error; + } + + rexec->parent->id = NGX_PROXY_WASM_ROOT_CTX_ID; + rexec->parent->pool = rexec->pool; + rexec->parent->log = rexec->log; + rexec->parent->isolation = NGX_PROXY_WASM_ISOLATION_STREAM; + + } else { + if (in->ictx != ictx) { + dd("replace pwexec instance"); + ngx_wasm_assert(in->root_id == NGX_PROXY_WASM_ROOT_CTX_ID); + + in->ictx = ictx; + in->started = 0; + in->tick_period = 0; + } + + rexec = in; + } + } + + /* start root context */ + + if (!rexec->started) { + dd("start root exec ctx (rexec: %p, root_id: %ld, id: %ld, ictx: %p)", + rexec, rexec->root_id, rexec->id, ictx); + + ngx_proxy_wasm_instance_update(ictx, rexec); + + rc = ngx_wavm_instance_call_funcref(ictx->instance, + filter->proxy_on_context_create, + NULL, + rexec->id, rexec->root_id); + if (rc != NGX_OK) { + ecode = NGX_PROXY_WASM_ERR_START_FAILED; + goto error; + } + + if (id == NGX_PROXY_WASM_ROOT_CTX_ID) { + rc = ngx_wavm_instance_call_funcref(ictx->instance, + filter->proxy_on_vm_start, + &rets, + rexec->id, rexec->root_id); + if (rc != NGX_OK || !rets->data[0].of.i32) { + ecode = NGX_PROXY_WASM_ERR_VM_START_FAILED; + goto error; + } + } + + rc = ngx_wavm_instance_call_funcref(ictx->instance, + filter->proxy_on_plugin_start, + &rets, + rexec->id, filter->config.len); + if (rc != NGX_OK || !rets->data[0].of.i32) { + ecode = NGX_PROXY_WASM_ERR_CONFIGURE_FAILED; + goto error; + } + + rexec->node.key = rexec->id; + ngx_rbtree_insert(&ictx->root_ctxs, &rexec->node); + rexec->started = 1; + } + + /* start filter context */ + + if (id && (in == NULL || in->root_id != NGX_PROXY_WASM_ROOT_CTX_ID)) { + pwexec = ngx_proxy_wasm_lookup_ctx(ictx, id); + dd("pwexec for id %ld: %p (in: %p)", id, pwexec, in); + if (pwexec == NULL) { + + if (in == NULL) { + pwexec = ngx_array_push(&pwctx->pwexecs); + if (pwexec == NULL) { + ecode = NGX_PROXY_WASM_ERR_START_FAILED; + goto error; + } + + ngx_memzero(pwexec, sizeof(ngx_proxy_wasm_exec_t)); + + pwexec->id = id; + pwexec->root_id = filter->id; + pwexec->index = pwctx->pwexecs.nelts - 1; + pwexec->pool = pwctx->pool; + pwexec->filter = filter; + pwexec->parent = pwctx; + pwexec->ictx = ictx; + pwexec->store = ictx->store; + + } else { + if (in->ictx != ictx) { + dd("replace pwexec instance"); + + in->ictx = ictx; + in->started = 0; + } + + pwexec = in; + } + + if (pwexec->log == NULL) { + log = pwctx->log; + + pwexec->log = ngx_pcalloc(pwexec->pool, sizeof(ngx_log_t)); + if (pwexec->log == NULL) { + ecode = NGX_PROXY_WASM_ERR_START_FAILED; + goto error; + } + + pwexec->log->file = log->file; + pwexec->log->next = log->next; + pwexec->log->writer = log->writer; + pwexec->log->wdata = log->wdata; + pwexec->log->log_level = log->log_level; + pwexec->log->connection = log->connection; + pwexec->log->handler = ngx_proxy_wasm_log_error_handler; + pwexec->log->data = &pwexec->log_ctx; + + pwexec->log_ctx.pwexec = pwexec; + pwexec->log_ctx.orig_log = log; + } + } +#if (NGX_DEBUG) + else { + ngx_wasm_assert(pwexec->id == id); + dd("pwexec #%ld found in instance %p", pwexec->id, ictx); + } +#endif + + if (!pwexec->started) { + dd("start exec ctx (pwexec: %p, id: %ld, ictx: %p)", + pwexec, id, ictx); + + ngx_proxy_wasm_instance_update(ictx, pwexec); + + rc = ngx_wavm_instance_call_funcref(ictx->instance, + filter->proxy_on_context_create, + NULL, + id, filter->id); + if (rc != NGX_OK) { + ecode = NGX_PROXY_WASM_ERR_START_FAILED; + goto error; + } + + pwexec->node.key = pwexec->id; + ngx_rbtree_insert(&ictx->tree_ctxs, &pwexec->node); + + pwexec->started = 1; + } + } + + if (out) { + *out = pwexec; + } + + return NGX_PROXY_WASM_ERR_NONE; + +error: + + if (ecode != NGX_PROXY_WASM_ERR_NONE) { + if (pwexec) { + pwexec->ecode = ecode; + + } else { + filter->ecode = ecode; + } + } + + return ecode; +} + + +static void +ngx_proxy_wasm_on_log(ngx_proxy_wasm_exec_t *pwexec) +{ + ngx_proxy_wasm_filter_t *filter = pwexec->filter; + ngx_wavm_instance_t *instance = ngx_proxy_wasm_pwexec2instance(pwexec); + + if (filter->abi_version < NGX_PROXY_WASM_VNEXT) { + /* 0.1.0 - 0.2.1 */ + (void) ngx_wavm_instance_call_funcref(instance, filter->proxy_on_done, + NULL, pwexec->id); + } + + (void) ngx_wavm_instance_call_funcref(instance, filter->proxy_on_log, + NULL, pwexec->id); +} + + +static void +ngx_proxy_wasm_on_done(ngx_proxy_wasm_exec_t *pwexec) +{ + ngx_wavm_instance_t *instance; + ngx_proxy_wasm_filter_t *filter = pwexec->filter; +#ifdef NGX_WASM_HTTP + ngx_http_proxy_wasm_dispatch_t *call; +#endif + + instance = ngx_proxy_wasm_pwexec2instance(pwexec); + + ngx_proxy_wasm_log_error(NGX_LOG_DEBUG, pwexec->log, 0, + "filter %l/%l finalizing context", + pwexec->index + 1, pwexec->parent->nfilters); + +#ifdef NGX_WASM_HTTP + call = pwexec->call; + if (call) { + ngx_log_debug3(NGX_LOG_DEBUG_WASM, pwexec->log, 0, + "proxy_wasm \"%V\" filter (%l/%l) " + "cancelling HTTP dispatch", + pwexec->filter->name, pwexec->index + 1, + pwexec->parent->nfilters); + + ngx_http_proxy_wasm_dispatch_destroy(call); + + pwexec->call = NULL; + } +#endif + + (void) ngx_wavm_instance_call_funcref(instance, + filter->proxy_on_context_finalize, + NULL, pwexec->id); - ngx_log_debug3(NGX_LOG_DEBUG_WASM, pwexec->log, 0, - "proxy_wasm_alloc: %uz:%uz:%uz", - ngx_wavm_memory_data_size(instance->memory), p, size); + if (pwexec->node.key) { + ngx_rbtree_delete(&pwexec->ictx->tree_ctxs, &pwexec->node); + } +} - return p; + +static ngx_int_t +ngx_proxy_wasm_on_tick(ngx_proxy_wasm_exec_t *pwexec) +{ + ngx_int_t rc; + wasm_val_vec_t args; + ngx_proxy_wasm_filter_t *filter = pwexec->filter; + + ngx_wasm_assert(pwexec->root_id == NGX_PROXY_WASM_ROOT_CTX_ID); + + wasm_val_vec_new_uninitialized(&args, 1); + ngx_wasm_vec_set_i32(&args, 0, pwexec->id); + + rc = ngx_wavm_instance_call_funcref_vec(pwexec->ictx->instance, + filter->proxy_on_timer_ready, + NULL, &args); + + wasm_val_vec_delete(&args); + + return rc; } -void -ngx_proxy_wasm_store_destroy(ngx_proxy_wasm_store_t *store) +/* utils */ + + +static ngx_proxy_wasm_filter_t * +ngx_proxy_wasm_lookup_filter(ngx_uint_t id) { - ngx_queue_t *q; - ngx_proxy_wasm_instance_t *ictx; + ngx_rbtree_t *rbtree; + ngx_rbtree_node_t *node, *sentinel; + ngx_proxy_wasm_filter_t *filter; - dd("enter"); + rbtree = &ngx_proxy_wasm_filters_rbtree; + node = rbtree->root; + sentinel = rbtree->sentinel; - while (!ngx_queue_empty(&store->busy)) { - dd("remove busy"); - q = ngx_queue_head(&store->busy); - ictx = ngx_queue_data(q, ngx_proxy_wasm_instance_t, q); + while (node != sentinel) { - ngx_queue_remove(&ictx->q); - ngx_queue_insert_tail(&store->free, &ictx->q); + if (id != node->key) { + node = (id < node->key) ? node->left : node->right; + continue; + } + + filter = ngx_rbtree_data(node, ngx_proxy_wasm_filter_t, node); + + return filter; } - while (!ngx_queue_empty(&store->free)) { - q = ngx_queue_head(&store->free); - ictx = ngx_queue_data(q, ngx_proxy_wasm_instance_t, q); + return NULL; +} - dd("remove free"); - ngx_proxy_wasm_release_instance(ictx, 1); + +static ngx_proxy_wasm_exec_t * +ngx_proxy_wasm_lookup_root_ctx(ngx_proxy_wasm_instance_t *ictx, ngx_uint_t id) +{ + ngx_rbtree_t *rbtree; + ngx_rbtree_node_t *node, *sentinel; + ngx_proxy_wasm_exec_t *pwexec; + + rbtree = &ictx->root_ctxs; + node = rbtree->root; + sentinel = rbtree->sentinel; + + while (node != sentinel) { + + if (id != node->key) { + node = (id < node->key) ? node->left : node->right; + continue; + } + + pwexec = ngx_rbtree_data(node, ngx_proxy_wasm_exec_t, node); + + return pwexec; } - dd("exit"); + return NULL; } -/* static */ +static ngx_proxy_wasm_exec_t * +ngx_proxy_wasm_lookup_ctx(ngx_proxy_wasm_instance_t *ictx, ngx_uint_t id) +{ + ngx_rbtree_t *rbtree; + ngx_rbtree_node_t *node, *sentinel; + ngx_proxy_wasm_exec_t *pwexec; + + rbtree = &ictx->tree_ctxs; + node = rbtree->root; + sentinel = rbtree->sentinel; + + while (node != sentinel) { + + if (id != node->key) { + node = (id < node->key) ? node->left : node->right; + continue; + } + + pwexec = ngx_rbtree_data(node, ngx_proxy_wasm_exec_t, node); + + return pwexec; + } + + return NULL; +} -static ngx_inline ngx_wavm_funcref_t * -ngx_proxy_wasm_lookup_func(ngx_proxy_wasm_filter_t *filter, const char *n) +static ngx_wavm_funcref_t * +get_func(ngx_proxy_wasm_filter_t *filter, const char *n) { ngx_str_t name; @@ -896,7 +1371,7 @@ ngx_proxy_wasm_lookup_func(ngx_proxy_wasm_filter_t *filter, const char *n) static ngx_proxy_wasm_abi_version_e -ngx_proxy_wasm_abi_version(ngx_proxy_wasm_filter_t *filter) +get_abi_version(ngx_proxy_wasm_filter_t *filter) { size_t i; ngx_wavm_module_t *module = filter->module; @@ -939,14 +1414,14 @@ ngx_proxy_wasm_abi_version(ngx_proxy_wasm_filter_t *filter) static ngx_int_t -ngx_proxy_wasm_init_abi(ngx_proxy_wasm_filter_t *filter) +ngx_proxy_wasm_filter_init_abi(ngx_proxy_wasm_filter_t *filter) { ngx_log_debug4(NGX_LOG_DEBUG_WASM, filter->log, 0, "proxy_wasm initializing \"%V\" filter " "(config size: %d, filter: %p, filter->id: %ui)", filter->name, filter->config.len, filter, filter->id); - filter->abi_version = ngx_proxy_wasm_abi_version(filter); + filter->abi_version = get_abi_version(filter); switch (filter->abi_version) { case NGX_PROXY_WASM_0_1_0: @@ -970,12 +1445,11 @@ ngx_proxy_wasm_init_abi(ngx_proxy_wasm_filter_t *filter) /* malloc */ - filter->proxy_on_memory_allocate = - ngx_proxy_wasm_lookup_func(filter, "malloc"); + filter->proxy_on_memory_allocate = get_func(filter, "malloc"); if (filter->proxy_on_memory_allocate == NULL) { filter->proxy_on_memory_allocate = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_memory_allocate"); + get_func(filter, "proxy_on_memory_allocate"); if (filter->proxy_on_memory_allocate == NULL) { filter->ecode = NGX_PROXY_WASM_ERR_BAD_MODULE_INTERFACE; @@ -990,407 +1464,250 @@ ngx_proxy_wasm_init_abi(ngx_proxy_wasm_filter_t *filter) /* context */ filter->proxy_on_context_create = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_context_create"); + get_func(filter, "proxy_on_context_create"); filter->proxy_on_context_finalize = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_context_finalize"); + get_func(filter, "proxy_on_context_finalize"); if (filter->abi_version < NGX_PROXY_WASM_VNEXT) { /* 0.1.0 - 0.2.1 */ filter->proxy_on_done = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_done"); + get_func(filter, "proxy_on_done"); filter->proxy_on_log = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_log"); + get_func(filter, "proxy_on_log"); filter->proxy_on_context_finalize = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_delete"); + get_func(filter, "proxy_on_delete"); } /* configuration */ filter->proxy_on_vm_start = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_vm_start"); + get_func(filter, "proxy_on_vm_start"); filter->proxy_on_plugin_start = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_plugin_start"); + get_func(filter, "proxy_on_plugin_start"); if (filter->abi_version < NGX_PROXY_WASM_VNEXT) { /* 0.1.0 - 0.2.1 */ filter->proxy_on_plugin_start = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_configure"); + get_func(filter, "proxy_on_configure"); } /* stream */ filter->proxy_on_new_connection = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_new_connection"); + get_func(filter, "proxy_on_new_connection"); filter->proxy_on_downstream_data = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_downstream_data"); + get_func(filter, "proxy_on_downstream_data"); filter->proxy_on_upstream_data = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_upstream_data"); + get_func(filter, "proxy_on_upstream_data"); filter->proxy_on_downstream_close = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_downstream_close"); + get_func(filter, "proxy_on_downstream_close"); filter->proxy_on_upstream_close = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_upstream_close"); + get_func(filter, "proxy_on_upstream_close"); if (filter->abi_version < NGX_PROXY_WASM_VNEXT) { /* 0.1.0 - 0.2.1 */ filter->proxy_on_downstream_close = - ngx_proxy_wasm_lookup_func( - filter, "proxy_on_downstream_connection_close"); + get_func(filter, "proxy_on_downstream_connection_close"); filter->proxy_on_upstream_close = - ngx_proxy_wasm_lookup_func( - filter, "proxy_on_upstream_connection_close"); + get_func(filter, "proxy_on_upstream_connection_close"); } /* http */ filter->proxy_on_http_request_headers = - ngx_proxy_wasm_lookup_func(filter, - "proxy_on_http_request_headers"); + get_func(filter, "proxy_on_http_request_headers"); filter->proxy_on_http_request_body = - ngx_proxy_wasm_lookup_func(filter, - "proxy_on_http_request_body"); + get_func(filter, "proxy_on_http_request_body"); filter->proxy_on_http_request_trailers = - ngx_proxy_wasm_lookup_func(filter, - "proxy_on_http_request_trailers"); + get_func(filter, "proxy_on_http_request_trailers"); filter->proxy_on_http_request_metadata = - ngx_proxy_wasm_lookup_func(filter, - "proxy_on_http_request_metadata"); + get_func(filter, "proxy_on_http_request_metadata"); filter->proxy_on_http_response_headers = - ngx_proxy_wasm_lookup_func(filter, - "proxy_on_http_response_headers"); + get_func(filter, "proxy_on_http_response_headers"); filter->proxy_on_http_response_body = - ngx_proxy_wasm_lookup_func(filter, - "proxy_on_http_response_body"); + get_func(filter, "proxy_on_http_response_body"); filter->proxy_on_http_response_trailers = - ngx_proxy_wasm_lookup_func(filter, - "proxy_on_http_response_trailers"); + get_func(filter, "proxy_on_http_response_trailers"); filter->proxy_on_http_response_metadata = - ngx_proxy_wasm_lookup_func(filter, - "proxy_on_http_response_metadata"); + get_func(filter, "proxy_on_http_response_metadata"); if (filter->abi_version < NGX_PROXY_WASM_VNEXT) { /* 0.1.0 - 0.2.1 */ filter->proxy_on_http_request_headers = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_request_headers"); + get_func(filter, "proxy_on_request_headers"); filter->proxy_on_http_request_body = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_request_body"); + get_func(filter, "proxy_on_request_body"); filter->proxy_on_http_request_trailers = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_request_trailers"); + get_func(filter, "proxy_on_request_trailers"); filter->proxy_on_http_request_metadata = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_request_metadata"); + get_func(filter, "proxy_on_request_metadata"); filter->proxy_on_http_response_headers = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_response_headers"); + get_func(filter, "proxy_on_response_headers"); filter->proxy_on_http_response_body = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_response_body"); + get_func(filter, "proxy_on_response_body"); filter->proxy_on_http_response_trailers = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_response_trailers"); + get_func(filter, "proxy_on_response_trailers"); filter->proxy_on_http_response_metadata = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_response_metadata"); + get_func(filter, "proxy_on_response_metadata"); } /* shared queue */ filter->proxy_on_queue_ready = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_queue_ready"); + get_func(filter, "proxy_on_queue_ready"); /* timers */ filter->proxy_create_timer = - ngx_proxy_wasm_lookup_func(filter, "proxy_create_timer"); + get_func(filter, "proxy_create_timer"); filter->proxy_delete_timer = - ngx_proxy_wasm_lookup_func(filter, "proxy_delete_timer"); + get_func(filter, "proxy_delete_timer"); filter->proxy_on_timer_ready = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_timer_ready"); + get_func(filter, "proxy_on_timer_ready"); if (filter->abi_version < NGX_PROXY_WASM_VNEXT) { /* 0.1.0 - 0.2.1 */ - filter->proxy_on_timer_ready = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_tick"); - } - - /* http callouts */ - - filter->proxy_on_http_call_response = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_http_call_response"); - - /* grpc callouts */ - - filter->proxy_on_grpc_call_response_header_metadata = - ngx_proxy_wasm_lookup_func( - filter, "proxy_on_grpc_call_response_header_metadata"); - filter->proxy_on_grpc_call_response_message = - ngx_proxy_wasm_lookup_func( - filter, "proxy_on_grpc_call_response_message"); - filter->proxy_on_grpc_call_response_trailer_metadata = - ngx_proxy_wasm_lookup_func( - filter, "proxy_on_grpc_call_response_trailer_metadata"); - filter->proxy_on_grpc_call_close = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_grpc_call_close"); - - /* custom extensions */ - - filter->proxy_on_custom_callback = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_custom_callback"); - - if (filter->abi_version < NGX_PROXY_WASM_VNEXT) { - /* 0.2.0 - 0.2.1 */ - filter->proxy_on_custom_callback = - ngx_proxy_wasm_lookup_func(filter, "proxy_on_foreign_function"); - } - - /* validate */ - - if (filter->proxy_on_context_create == NULL - || filter->proxy_on_vm_start == NULL - || filter->proxy_on_plugin_start == NULL) - { - filter->ecode = NGX_PROXY_WASM_ERR_BAD_MODULE_INTERFACE; - - ngx_proxy_wasm_log_error(NGX_LOG_EMERG, filter->log, filter->ecode, - "\"%V\" filter missing one of: " - "on_context_create, on_vm_start, " - "on_plugin_start", filter->name); - return NGX_ERROR; - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_proxy_wasm_start_filter(ngx_proxy_wasm_filter_t *filter) -{ - ngx_proxy_wasm_instance_t *ictx; - - ngx_wasm_assert(filter->loaded); - - if (filter->ecode) { - return NGX_ERROR; - } - - if (filter->started) { - return NGX_OK; - } - - ictx = ngx_proxy_wasm_get_instance(filter, filter->store, NULL, - filter->log); - if (ictx == NULL) { - return NGX_ERROR; - } - - filter->started = 1; - - return NGX_OK; -} - - -ngx_proxy_wasm_instance_t * -ngx_proxy_wasm_get_instance(ngx_proxy_wasm_filter_t *filter, - ngx_proxy_wasm_store_t *store, ngx_proxy_wasm_exec_t *pwexec, - ngx_log_t *log) -{ - ngx_queue_t *q; - ngx_pool_t *pool; - ngx_wavm_module_t *module = filter->module; - ngx_proxy_wasm_instance_t *ictx; - ngx_proxy_wasm_err_e ecode; - - dd("enter (pwexec: %p)", pwexec); - - if (store == NULL) { - dd("no store, jump to create"); - pool = filter->pool; - goto create; - } - - pool = store->pool; - - dd("lookup instance in store: %p", store); - - for (q = ngx_queue_head(&store->busy); - q != ngx_queue_sentinel(&store->busy); - q = ngx_queue_next(q)) - { - ictx = ngx_queue_data(q, ngx_proxy_wasm_instance_t, q); - - if (ictx->instance->trapped) { - ngx_proxy_wasm_log_error(NGX_LOG_DEBUG, log, 0, - "\"%V\" filter freeing trapped instance " - "(ictx: %p, store: %p)", - filter->name, ictx, store); - q = ngx_queue_next(&ictx->q); - ngx_proxy_wasm_release_instance(ictx, 1); - continue; - } - - if (ictx->module == filter->module) { - dd("reuse busy instance"); - ngx_wasm_assert(ictx->nrefs); - goto reuse; - } - } - - for (q = ngx_queue_head(&store->free); - q != ngx_queue_sentinel(&store->free); - q = ngx_queue_next(q)) - { - ictx = ngx_queue_data(q, ngx_proxy_wasm_instance_t, q); - - if (ictx->instance->trapped) { - ngx_proxy_wasm_log_error(NGX_LOG_DEBUG, log, 0, - "\"%V\" filter freeing trapped instance " - "(ictx: %p, store: %p)", - filter->name, ictx, store); - - q = ngx_queue_next(&ictx->q); - ngx_proxy_wasm_release_instance(ictx, 1); - continue; - } - - if (ictx->module == filter->module) { - dd("reuse free instance"); - ngx_wasm_assert(ictx->nrefs == 0); - ngx_queue_remove(&ictx->q); - goto reuse; - } + filter->proxy_on_timer_ready = + get_func(filter, "proxy_on_tick"); } -create: + /* http callouts */ - dd("create instance in store: %p", store); + filter->proxy_on_http_call_response = + get_func(filter, "proxy_on_http_call_response"); - ictx = ngx_pcalloc(pool, sizeof(ngx_proxy_wasm_instance_t)); - if (ictx == NULL) { - goto error; - } + /* grpc callouts */ - ictx->next_id = 1; - ictx->pool = pool; - ictx->log = log; - ictx->store = store; - ictx->module = module; + filter->proxy_on_grpc_call_response_header_metadata = + get_func(filter, "proxy_on_grpc_call_response_header_metadata"); + filter->proxy_on_grpc_call_response_message = + get_func(filter, "proxy_on_grpc_call_response_message"); + filter->proxy_on_grpc_call_response_trailer_metadata = + get_func(filter, "proxy_on_grpc_call_response_trailer_metadata"); + filter->proxy_on_grpc_call_close = + get_func(filter, "proxy_on_grpc_call_close"); - ngx_rbtree_init(&ictx->root_ctxs, &ictx->sentinel_root_ctxs, - ngx_rbtree_insert_value); + /* custom extensions */ - ngx_rbtree_init(&ictx->tree_ctxs, &ictx->sentinel_ctxs, - ngx_rbtree_insert_value); + filter->proxy_on_custom_callback = + get_func(filter, "proxy_on_custom_callback"); - ictx->instance = ngx_wavm_instance_create(module, pool, log, ictx); - if (ictx->instance == NULL) { - ngx_pfree(pool, ictx); - goto error; + if (filter->abi_version < NGX_PROXY_WASM_VNEXT) { + /* 0.2.0 - 0.2.1 */ + filter->proxy_on_custom_callback = + get_func(filter, "proxy_on_foreign_function"); } - ngx_proxy_wasm_log_error(NGX_LOG_DEBUG, log, 0, - "\"%V\" filter new instance (ictx: %p, store: %p)", - filter->name, ictx, store); + /* validate */ - goto done; + if (filter->proxy_on_context_create == NULL + || filter->proxy_on_vm_start == NULL + || filter->proxy_on_plugin_start == NULL) + { + filter->ecode = NGX_PROXY_WASM_ERR_BAD_MODULE_INTERFACE; -reuse: + ngx_proxy_wasm_log_error(NGX_LOG_EMERG, filter->log, filter->ecode, + "\"%V\" filter missing one of: " + "on_context_create, on_vm_start, " + "on_plugin_start", filter->name); + return NGX_ERROR; + } - ngx_proxy_wasm_log_error(NGX_LOG_DEBUG, log, 0, - "\"%V\" filter reusing instance " - "(ictx: %p, nrefs: %d, store: %p)", - filter->name, ictx, ictx->nrefs + 1, store); + return NGX_OK; +} - goto done; -done: +static ngx_int_t +ngx_proxy_wasm_filter_start(ngx_proxy_wasm_filter_t *filter) +{ + ngx_proxy_wasm_err_e ecode; + + ngx_wasm_assert(filter->loaded); - if (store && !ictx->nrefs) { - ngx_queue_insert_tail(&store->busy, &ictx->q); + if (filter->ecode) { + return NGX_ERROR; } - if (pwexec) { - if (pwexec->root_id != NGX_PROXY_WASM_ROOT_CTX_ID) { - ngx_wasm_assert(pwexec->id == 0); - pwexec->id = ictx->next_id++; - } + if (filter->started) { + return NGX_OK; + } - if (pwexec->ecode) { - /* recycled instance */ - pwexec->ecode = NGX_PROXY_WASM_ERR_NONE; - pwexec->ecode_logged = 0; - } + ecode = ngx_proxy_wasm_create_context(filter, NULL, 0, NULL, NULL); + if (ecode != NGX_PROXY_WASM_ERR_NONE) { + return NGX_ERROR; } - ictx->nrefs++; - ictx->pwexec = pwexec; + filter->started = 1; + + return NGX_OK; +} + +static void +ngx_proxy_wasm_instance_update(ngx_proxy_wasm_instance_t *ictx, + ngx_proxy_wasm_exec_t *pwexec) +{ /** - * update instance log + * Update instance * FFI-injected filters have a valid log while the instance's * might be outdated. */ - ngx_wavm_instance_set_data(ictx->instance, ictx, log); + ictx->pwexec = pwexec; - /* create wasm context (root/http) */ + if (pwexec) { + ngx_wavm_instance_set_data(ictx->instance, ictx, pwexec->log); + } +} - ecode = ngx_proxy_wasm_on_start(ictx, filter, pwexec == NULL); - if (ecode != NGX_PROXY_WASM_ERR_NONE) { - if (pwexec) { - pwexec->ecode = ecode; - } else { - filter->ecode = ecode; - } +static void +ngx_proxy_wasm_instance_invalidate(ngx_proxy_wasm_instance_t *ictx) +{ + ngx_rbtree_node_t **root, **sentinel, *s, *n; + ngx_proxy_wasm_exec_t *pwexec; - goto error; - } + dd("enter (ictx: %p)", ictx); - return ictx; + /* root context */ -error: + root = &ictx->root_ctxs.root; + s = &ictx->sentinel_root_ctxs; + sentinel = &s; - return NULL; -} + while (*root != *sentinel) { + n = ngx_rbtree_min(*root, *sentinel); +#if (DDEBUG) + pwexec = ngx_rbtree_data(n, ngx_proxy_wasm_exec_t, node); + dd("invalidate root ctx #%ld instance (pwexec: %p)", + pwexec->id, pwexec); +#endif -void -ngx_proxy_wasm_release_instance(ngx_proxy_wasm_instance_t *ictx, - unsigned sweep) -{ - ngx_queue_t *q; + ngx_rbtree_delete(&ictx->root_ctxs, n); + } - if (sweep) { - ictx->nrefs = 0; + /* stream context */ - } else if (ictx->nrefs) { - ictx->nrefs--; - } + root = &ictx->tree_ctxs.root; + s = &ictx->sentinel_ctxs; + sentinel = &s; - dd("ictx: %p (nrefs: %ld, sweep: %d, trapped: %d)", - ictx, ictx->nrefs, sweep, ictx->instance->trapped); + while (*root != *sentinel) { + n = ngx_rbtree_min(*root, *sentinel); + pwexec = ngx_rbtree_data(n, ngx_proxy_wasm_exec_t, node); - if (ictx->nrefs == 0) { - if (ictx->store) { - dd("remove from busy"); - ngx_queue_remove(&ictx->q); /* remove from busy/free */ + dd("invalidate ctx #%ld instance (pwexec: %p)", pwexec->id, pwexec); - if (sweep || ictx->instance->trapped) { - dd("insert in sweep"); - ngx_queue_insert_tail(&ictx->store->sweep, &ictx->q); + ngx_rbtree_delete(&ictx->tree_ctxs, n); - } else { - dd("insert in free"); - ngx_queue_insert_tail(&ictx->store->free, &ictx->q); - } + destroy_pwexec(pwexec); + } - while (!ngx_queue_empty(&ictx->store->sweep)) { - dd("sweep (destroy)"); - q = ngx_queue_head(&ictx->store->sweep); - ictx = ngx_queue_data(q, ngx_proxy_wasm_instance_t, q); + /* remove from busy/free, schedule for sweeping */ - ngx_queue_remove(&ictx->q); - ngx_proxy_wasm_instance_destroy(ictx); - } + ngx_queue_remove(&ictx->q); - } else { - dd("destroy"); - ngx_proxy_wasm_instance_destroy(ictx); - } - } + ngx_queue_insert_tail(&ictx->store->sweep, &ictx->q); dd("exit"); } @@ -1412,28 +1729,24 @@ ngx_proxy_wasm_instance_destroy(ngx_proxy_wasm_instance_t *ictx) n = ngx_rbtree_min(*root, *sentinel); rexec = ngx_rbtree_data(n, ngx_proxy_wasm_exec_t, node); - if (rexec->ev) { - ngx_del_timer(rexec->ev); - ngx_free(rexec->ev); + rexec->ictx = NULL; - rexec->ev = NULL; - } + ngx_rbtree_delete(&ictx->root_ctxs, n); + } - if (rexec->log) { - ngx_pfree(rexec->pool, rexec->log); - } + root = &ictx->tree_ctxs.root; + s = &ictx->sentinel_ctxs; + sentinel = &s; - if (rexec->parent) { - if (rexec->log_ctx.log_prefix.data) { - ngx_pfree(rexec->pool, rexec->log_ctx.log_prefix.data); - } + while (*root != *sentinel) { + n = ngx_rbtree_min(*root, *sentinel); + rexec = ngx_rbtree_data(n, ngx_proxy_wasm_exec_t, node); - ngx_pfree(rexec->pool, rexec->parent); - } + ngx_wasm_assert(rexec->ev == NULL); - ngx_rbtree_delete(&ictx->root_ctxs, n); + rexec->ictx = NULL; - ngx_pfree(rexec->pool, rexec); + ngx_rbtree_delete(&ictx->tree_ctxs, n); } ngx_wavm_instance_destroy(ictx->instance); @@ -1444,198 +1757,80 @@ ngx_proxy_wasm_instance_destroy(ngx_proxy_wasm_instance_t *ictx) } -static ngx_proxy_wasm_err_e -ngx_proxy_wasm_on_start(ngx_proxy_wasm_instance_t *ictx, - ngx_proxy_wasm_filter_t *filter, unsigned start) +static void +ngx_proxy_wasm_store_destroy(ngx_proxy_wasm_store_t *store) { - ngx_int_t rc; - ngx_log_t *log; - ngx_proxy_wasm_exec_t *rexec, *pwexec = ictx->pwexec; - ngx_wavm_instance_t *instance = ictx->instance; - wasm_val_vec_t *rets; - - dd("enter (pwexec: %p, ictx: %p)", pwexec, ictx); - - rexec = ngx_proxy_wasm_root_lookup(ictx, filter->id); - if (rexec == NULL) { - rexec = ngx_pcalloc(ictx->pool, sizeof(ngx_proxy_wasm_exec_t)); - if (rexec == NULL) { - return NGX_PROXY_WASM_ERR_START_FAILED; - } - - rexec->root_id = NGX_PROXY_WASM_ROOT_CTX_ID; - rexec->id = filter->id; - rexec->pool = ictx->pool; - rexec->log = filter->log; - rexec->filter = filter; - rexec->ictx = ictx; - - log = filter->log; - - rexec->log = ngx_pcalloc(rexec->pool, sizeof(ngx_log_t)); - if (rexec->log == NULL) { - return NGX_PROXY_WASM_ERR_START_FAILED; - } - - rexec->log->file = log->file; - rexec->log->next = log->next; - rexec->log->writer = log->writer; - rexec->log->wdata = log->wdata; - rexec->log->log_level = log->log_level; - rexec->log->handler = ngx_proxy_wasm_log_error_handler; - rexec->log->data = &rexec->log_ctx; - - rexec->log_ctx.pwexec = rexec; - rexec->log_ctx.orig_log = log; + ngx_queue_t *q; + ngx_proxy_wasm_instance_t *ictx; - rexec->parent = ngx_pcalloc(rexec->pool, sizeof(ngx_proxy_wasm_ctx_t)); - if (rexec->parent == NULL) { - return NGX_PROXY_WASM_ERR_START_FAILED; - } + dd("enter"); - rexec->parent->id = NGX_PROXY_WASM_ROOT_CTX_ID; - rexec->parent->pool = rexec->pool; - rexec->parent->log = rexec->log; + while (!ngx_queue_empty(&store->busy)) { + dd("remove busy"); + q = ngx_queue_head(&store->busy); + ictx = ngx_queue_data(q, ngx_proxy_wasm_instance_t, q); - rexec->node.key = rexec->id; - ngx_rbtree_insert(&ictx->root_ctxs, &rexec->node); + ngx_queue_remove(&ictx->q); + ngx_queue_insert_tail(&store->free, &ictx->q); } - ictx->pwexec = rexec; /* set instance current pwexec */ - - if (!rexec->started) { - dd("start root exec ctx (rexec: %p, root_id: %ld, id: %ld, ictx: %p)", - rexec, rexec->root_id, rexec->id, ictx); - - rc = ngx_wavm_instance_call_funcref(instance, - filter->proxy_on_context_create, - NULL, - rexec->id, rexec->root_id); - if (rc != NGX_OK) { - return NGX_PROXY_WASM_ERR_START_FAILED; - } - - if (start) { - rc = ngx_wavm_instance_call_funcref(instance, - filter->proxy_on_vm_start, - &rets, - rexec->id, 0); - if (rc != NGX_OK || !rets->data[0].of.i32) { - return NGX_PROXY_WASM_ERR_VM_START_FAILED; - } - } - - rc = ngx_wavm_instance_call_funcref(instance, - filter->proxy_on_plugin_start, - &rets, - rexec->id, filter->config.len); - if (rc != NGX_OK || !rets->data[0].of.i32) { - return NGX_PROXY_WASM_ERR_CONFIGURE_FAILED; - } + while (!ngx_queue_empty(&store->free)) { + dd("remove free"); + q = ngx_queue_head(&store->free); + ictx = ngx_queue_data(q, ngx_proxy_wasm_instance_t, q); - rexec->started = 1; + ngx_queue_remove(&ictx->q); + ngx_queue_insert_tail(&store->sweep, &ictx->q); } - ictx->pwexec = pwexec; /* set instance current pwexec */ - - if (pwexec && pwexec->root_id != NGX_PROXY_WASM_ROOT_CTX_ID - && ngx_proxy_wasm_ctx_lookup(ictx, pwexec->id) == NULL) - { - dd("start exec ctx (pwexec: %p, root_id: %ld, id: %ld, ictx: %p)", - pwexec, pwexec->root_id, pwexec->id, ictx); - - rc = ngx_wavm_instance_call_funcref(instance, - filter->proxy_on_context_create, - NULL, - pwexec->id, pwexec->root_id); - if (rc != NGX_OK) { - return NGX_PROXY_WASM_ERR_START_FAILED; - } - - pwexec->node.key = pwexec->id; - ngx_rbtree_insert(&ictx->tree_ctxs, &pwexec->node); - } + ngx_proxy_wasm_store_sweep(store); - return NGX_PROXY_WASM_ERR_NONE; + dd("exit"); } static void -ngx_proxy_wasm_on_log(ngx_proxy_wasm_exec_t *pwexec) +ngx_proxy_wasm_store_sweep(ngx_proxy_wasm_store_t *store) { - ngx_proxy_wasm_filter_t *filter = pwexec->filter; - ngx_wavm_instance_t *instance = ngx_proxy_wasm_pwexec2instance(pwexec); + ngx_queue_t *q; + ngx_proxy_wasm_instance_t *ictx; - if (filter->abi_version < NGX_PROXY_WASM_VNEXT) { - /* 0.1.0 - 0.2.1 */ - (void) ngx_wavm_instance_call_funcref(instance, filter->proxy_on_done, - NULL, pwexec->id); - } + while (!ngx_queue_empty(&store->sweep)) { + q = ngx_queue_head(&store->sweep); + ictx = ngx_queue_data(q, ngx_proxy_wasm_instance_t, q); - (void) ngx_wavm_instance_call_funcref(instance, filter->proxy_on_log, - NULL, pwexec->id); + dd("sweep (ictx: %p)", ictx); + + ngx_queue_remove(&ictx->q); + ngx_proxy_wasm_instance_destroy(ictx); + } } +#if 0 static void -ngx_proxy_wasm_on_done(ngx_proxy_wasm_exec_t *pwexec) +ngx_proxy_wasm_store_schedule_sweep_handler(ngx_event_t *ev) { - ngx_wavm_instance_t *instance; - ngx_proxy_wasm_filter_t *filter = pwexec->filter; -#if 1 -#ifdef NGX_WASM_HTTP - ngx_http_proxy_wasm_dispatch_t *call; -#endif -#endif - - instance = ngx_proxy_wasm_pwexec2instance(pwexec); - - ngx_proxy_wasm_log_error(NGX_LOG_DEBUG, pwexec->log, 0, - "filter %l/%l finalizing context", - pwexec->index + 1, pwexec->parent->nfilters); - -#if 1 -#ifdef NGX_WASM_HTTP - call = pwexec->call; - if (call) { - ngx_log_debug3(NGX_LOG_DEBUG_WASM, pwexec->log, 0, - "proxy_wasm \"%V\" filter (%l/%l) " - "cancelling HTTP dispatch", - pwexec->filter->name, pwexec->index + 1, - pwexec->parent->nfilters); - - ngx_http_proxy_wasm_dispatch_destroy(call); - - pwexec->call = NULL; - } -#endif -#endif - - (void) ngx_wavm_instance_call_funcref(instance, - filter->proxy_on_context_finalize, - NULL, pwexec->id); + ngx_proxy_wasm_store_t *store = ev->data; - ngx_rbtree_delete(&pwexec->ictx->tree_ctxs, &pwexec->node); + ngx_proxy_wasm_store_sweep(store); } -static ngx_int_t -ngx_proxy_wasm_on_tick(ngx_proxy_wasm_exec_t *pwexec) +static void +ngx_proxy_wasm_store_schedule_sweep(ngx_proxy_wasm_store_t *store) { - ngx_int_t rc; - wasm_val_vec_t args; - ngx_proxy_wasm_filter_t *filter = pwexec->filter; - - ngx_wasm_assert(pwexec->root_id == NGX_PROXY_WASM_ROOT_CTX_ID); - - wasm_val_vec_new_uninitialized(&args, 1); - ngx_wasm_vec_set_i32(&args, 0, pwexec->id); + ngx_event_t *ev; - rc = ngx_wavm_instance_call_funcref_vec(pwexec->ictx->instance, - filter->proxy_on_timer_ready, - NULL, &args); + ev = ngx_calloc(sizeof(ngx_event_t), store->pool->log); + if (ev == NULL) { + return; + } - wasm_val_vec_delete(&args); + ev->handler = ngx_proxy_wasm_store_schedule_sweep_handler; + ev->data = store; + ev->log = store->pool->log; - return rc; + ngx_post_event(ev, &ngx_posted_events); } +#endif diff --git a/src/common/proxy_wasm/ngx_proxy_wasm.h b/src/common/proxy_wasm/ngx_proxy_wasm.h index 90adf8675..6dbce7237 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm.h +++ b/src/common/proxy_wasm/ngx_proxy_wasm.h @@ -8,12 +8,6 @@ #define NGX_PROXY_WASM_ROOT_CTX_ID 0 -#define ngx_proxy_wasm_store_init(s, p) \ - (s)->pool = (p); \ - ngx_queue_init(&(s)->sweep); \ - ngx_queue_init(&(s)->free); \ - ngx_queue_init(&(s)->busy) - typedef enum { NGX_PROXY_WASM_0_1_0 = 0, @@ -195,6 +189,7 @@ struct ngx_proxy_wasm_exec_s { ngx_proxy_wasm_ctx_t *parent; ngx_proxy_wasm_filter_t *filter; ngx_proxy_wasm_instance_t *ictx; + ngx_proxy_wasm_store_t *store; ngx_event_t *ev; #ifdef NGX_WASM_HTTP ngx_http_proxy_wasm_dispatch_t *call; @@ -203,8 +198,8 @@ struct ngx_proxy_wasm_exec_s { /* flags */ unsigned started:1; - unsigned ecode_logged:1; unsigned in_tick:1; + unsigned ecode_logged:1; }; @@ -259,9 +254,7 @@ struct ngx_proxy_wasm_ctx_s { struct ngx_proxy_wasm_instance_s { - ngx_uint_t next_id; - ngx_uint_t nrefs; - ngx_queue_t q; + ngx_queue_t q; /* store busy/free/sweep */ ngx_rbtree_t tree_ctxs; ngx_rbtree_t root_ctxs; ngx_rbtree_node_t sentinel_ctxs; @@ -274,7 +267,7 @@ struct ngx_proxy_wasm_instance_s { /* swap */ - ngx_proxy_wasm_exec_t *pwexec; + ngx_proxy_wasm_exec_t *pwexec; /* current pwexec */ }; @@ -379,16 +372,14 @@ struct ngx_proxy_wasm_filter_s { }; -/* root */ -void ngx_proxy_wasm_init(ngx_conf_t *cf); -void ngx_proxy_wasm_exit(); -ngx_uint_t ngx_proxy_wasm_id(ngx_str_t *name, ngx_str_t *config, - uintptr_t data); +/* root context */ +void ngx_proxy_wasm_init(ngx_conf_t *cf, ngx_proxy_wasm_store_t *gstore); +void ngx_proxy_wasm_exit(ngx_proxy_wasm_store_t *gstore); ngx_int_t ngx_proxy_wasm_load(ngx_proxy_wasm_filter_t *filter, ngx_log_t *log); ngx_int_t ngx_proxy_wasm_start(ngx_cycle_t *cycle); -/* ctx/store */ +/* stream context */ ngx_proxy_wasm_ctx_t *ngx_proxy_wasm_ctx_alloc(ngx_pool_t *pool); ngx_proxy_wasm_ctx_t *ngx_proxy_wasm_ctx(ngx_uint_t *filter_ids, size_t nfilters, ngx_uint_t isolation, ngx_proxy_wasm_subsystem_t *subsys, @@ -396,13 +387,12 @@ ngx_proxy_wasm_ctx_t *ngx_proxy_wasm_ctx(ngx_uint_t *filter_ids, void ngx_proxy_wasm_ctx_destroy(ngx_proxy_wasm_ctx_t *pwctx); ngx_int_t ngx_proxy_wasm_resume(ngx_proxy_wasm_ctx_t *pwctx, ngx_wasm_phase_t *phase, ngx_proxy_wasm_step_e step); +ngx_proxy_wasm_err_e ngx_proxy_wasm_run_step(ngx_proxy_wasm_exec_t *pwexec, + ngx_proxy_wasm_step_e step); + + +/* host handlers */ ngx_wavm_ptr_t ngx_proxy_wasm_alloc(ngx_proxy_wasm_exec_t *pwexec, size_t size); -void ngx_proxy_wasm_store_destroy(ngx_proxy_wasm_store_t *store); -ngx_proxy_wasm_instance_t *ngx_proxy_wasm_get_instance( - ngx_proxy_wasm_filter_t *filter, ngx_proxy_wasm_store_t *store, - ngx_proxy_wasm_exec_t *pwexec, ngx_log_t *log); -void ngx_proxy_wasm_release_instance(ngx_proxy_wasm_instance_t *ictx, - unsigned sweep); /* utils */ @@ -418,8 +408,6 @@ ngx_int_t ngx_proxy_wasm_pairs_unmarshal(ngx_proxy_wasm_exec_t *pwexec, unsigned ngx_proxy_wasm_marshal(ngx_proxy_wasm_exec_t *pwexec, ngx_list_t *list, ngx_array_t *extras, ngx_wavm_ptr_t *out, uint32_t *out_size, ngx_uint_t *truncated); -ngx_proxy_wasm_err_e ngx_proxy_wasm_run_step(ngx_proxy_wasm_exec_t *pwexec, - ngx_proxy_wasm_instance_t *ictx, ngx_proxy_wasm_step_e step); static ngx_inline void diff --git a/src/common/proxy_wasm/ngx_proxy_wasm_host.c b/src/common/proxy_wasm/ngx_proxy_wasm_host.c index 2c8dbb15c..a5be0a1a3 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm_host.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm_host.c @@ -205,26 +205,26 @@ ngx_proxy_wasm_hfuncs_set_tick_period(ngx_wavm_instance_t *instance, { uint32_t period = args[0].of.i32; ngx_event_t *ev; - ngx_proxy_wasm_exec_t *pwexec = ngx_proxy_wasm_instance2pwexec(instance); + ngx_proxy_wasm_exec_t *rexec = ngx_proxy_wasm_instance2pwexec(instance); - ngx_wasm_assert(pwexec->root_id == NGX_PROXY_WASM_ROOT_CTX_ID); + ngx_wasm_assert(rexec->root_id == NGX_PROXY_WASM_ROOT_CTX_ID); - if (pwexec->root_id != NGX_PROXY_WASM_ROOT_CTX_ID) { + if (rexec->root_id != NGX_PROXY_WASM_ROOT_CTX_ID) { /* ignore */ return ngx_proxy_wasm_result_ok(rets); } if (ngx_exiting) { - return ngx_proxy_wasm_result_trap(pwexec, "process exiting", rets, - NGX_WAVM_OK); + return ngx_proxy_wasm_result_trap(rexec, "process exiting", + rets, NGX_WAVM_OK); } - if (pwexec->tick_period) { - return ngx_proxy_wasm_result_trap(pwexec, "tick_period already set", + if (rexec->tick_period) { + return ngx_proxy_wasm_result_trap(rexec, "tick_period already set", rets, NGX_WAVM_OK); } - pwexec->tick_period = period; + rexec->tick_period = period; ev = ngx_calloc(sizeof(ngx_event_t), instance->log); if (ev == NULL) { @@ -232,17 +232,16 @@ ngx_proxy_wasm_hfuncs_set_tick_period(ngx_wavm_instance_t *instance, } ev->handler = ngx_proxy_wasm_filter_tick_handler; - ev->data = pwexec; - ev->log = pwexec->log; + ev->data = rexec; + ev->log = rexec->log; - ngx_add_timer(ev, pwexec->tick_period); + ngx_add_timer(ev, rexec->tick_period); return ngx_proxy_wasm_result_ok(rets); nomem: - return ngx_proxy_wasm_result_trap(pwexec, "no memory", - rets, NGX_WAVM_ERROR); + return ngx_proxy_wasm_result_trap(rexec, "no memory", rets, NGX_WAVM_ERROR); } diff --git a/src/common/proxy_wasm/ngx_proxy_wasm_util.c b/src/common/proxy_wasm/ngx_proxy_wasm_util.c index 361793192..1a8358a25 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm_util.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm_util.c @@ -193,65 +193,49 @@ ngx_proxy_wasm_log_error(ngx_uint_t level, ngx_log_t *log, void ngx_proxy_wasm_filter_tick_handler(ngx_event_t *ev) { - ngx_log_t *log = ev->log; - ngx_proxy_wasm_exec_t *pwexec = ev->data; + ngx_proxy_wasm_err_e ecode; + ngx_log_t *log = ev->log; + ngx_proxy_wasm_exec_t *rexec = ev->data; + ngx_proxy_wasm_filter_t *filter = rexec->filter; #ifdef NGX_WASM_HTTP - ngx_proxy_wasm_ctx_t *pwctx = pwexec->parent; + ngx_proxy_wasm_ctx_t *pwctx = rexec->parent; #endif - ngx_proxy_wasm_filter_t *filter = pwexec->filter; - ngx_proxy_wasm_instance_t *ictx; - ngx_proxy_wasm_err_e ecode; dd("enter"); - ngx_wasm_assert(pwexec->root_id == NGX_PROXY_WASM_ROOT_CTX_ID); + ngx_wasm_assert(rexec->root_id == NGX_PROXY_WASM_ROOT_CTX_ID); ngx_free(ev); - pwexec->ev = NULL; + rexec->ev = NULL; if (ngx_exiting || !filter->proxy_on_timer_ready) { return; } - ictx = ngx_proxy_wasm_get_instance(filter, filter->store, pwexec, - filter->log); - if (ictx == NULL) { - ngx_wasm_log_error(NGX_LOG_ERR, log, 0, - "tick_handler: no instance"); - return; - } - #ifdef NGX_WASM_HTTP pwctx->phase = ngx_wasm_phase_lookup(&ngx_http_wasm_subsystem, NGX_WASM_BACKGROUND_PHASE); #endif - pwexec->in_tick = 1; - - ecode = ngx_proxy_wasm_run_step(pwexec, ictx, NGX_PROXY_WASM_STEP_TICK); - - ngx_proxy_wasm_release_instance(ictx, 0); + ecode = ngx_proxy_wasm_run_step(rexec, NGX_PROXY_WASM_STEP_TICK); if (ecode != NGX_PROXY_WASM_ERR_NONE) { - pwexec->ecode = ecode; return; } - pwexec->in_tick = 0; - if (!ngx_exiting) { - pwexec->ev = ngx_calloc(sizeof(ngx_event_t), log); - if (pwexec->ev == NULL) { + rexec->ev = ngx_calloc(sizeof(ngx_event_t), log); + if (rexec->ev == NULL) { goto nomem; } - pwexec->ev->handler = ngx_proxy_wasm_filter_tick_handler; - pwexec->ev->data = pwexec; - pwexec->ev->log = log; + rexec->ev->handler = ngx_proxy_wasm_filter_tick_handler; + rexec->ev->data = rexec; + rexec->ev->log = log; - dd("scheduling next tick in %ld", pwexec->tick_period); + dd("scheduling next tick in %ld", rexec->tick_period); - ngx_add_timer(pwexec->ev, pwexec->tick_period); + ngx_add_timer(rexec->ev, rexec->tick_period); } return; diff --git a/src/http/ngx_http_wasm_module.c b/src/http/ngx_http_wasm_module.c index fbe4b3938..43ff937db 100644 --- a/src/http/ngx_http_wasm_module.c +++ b/src/http/ngx_http_wasm_module.c @@ -265,6 +265,7 @@ ngx_http_wasm_create_main_conf(ngx_conf_t *cf) mcf->vm = ngx_wasm_main_vm(cf->cycle); ngx_queue_init(&mcf->plans); + ngx_proxy_wasm_init(cf, &mcf->store); return mcf; } @@ -281,9 +282,6 @@ ngx_http_wasm_init_main_conf(ngx_conf_t *cf, void *conf) return NGX_CONF_ERROR; } - ngx_proxy_wasm_init(cf); - ngx_proxy_wasm_store_init(&mcf->store, cf->pool); - return NGX_CONF_OK; } @@ -445,8 +443,7 @@ ngx_http_wasm_exit_process(ngx_cycle_t *cycle) mcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_wasm_module); if (mcf) { - ngx_proxy_wasm_exit(); - ngx_proxy_wasm_store_destroy(&mcf->store); + ngx_proxy_wasm_exit(&mcf->store); ngx_wasm_ops_destroy(mcf->ops); } diff --git a/src/http/ngx_http_wasm_util.c b/src/http/ngx_http_wasm_util.c index 15123c374..c3841f4bc 100644 --- a/src/http/ngx_http_wasm_util.c +++ b/src/http/ngx_http_wasm_util.c @@ -411,8 +411,8 @@ ngx_http_wasm_ops_add_filter(ngx_wasm_ops_plan_t *plan, goto error; } - filter->pool = plan->pool; filter->log = vm->log; + filter->pool = store->pool; filter->store = store; if (config) { diff --git a/src/http/proxy_wasm/ngx_http_proxy_wasm.h b/src/http/proxy_wasm/ngx_http_proxy_wasm.h index 3392a93ad..37a9a052f 100644 --- a/src/http/proxy_wasm/ngx_http_proxy_wasm.h +++ b/src/http/proxy_wasm/ngx_http_proxy_wasm.h @@ -19,7 +19,7 @@ ngx_http_proxy_wasm_get_rctx(ngx_wavm_instance_t *instance) pwexec = ngx_proxy_wasm_instance2pwexec(instance); pwctx = pwexec->parent; - if (!pwctx) { + if (pwctx == NULL) { return NULL; } diff --git a/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c b/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c index 004a0201f..6b5c37243 100644 --- a/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c +++ b/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c @@ -825,7 +825,7 @@ ngx_http_proxy_wasm_dispatch_resume_handler(ngx_wasm_socket_tcp_t *sock) /* save step */ step = pwexec->parent->step; - ecode = ngx_proxy_wasm_run_step(pwexec, pwexec->ictx, + ecode = ngx_proxy_wasm_run_step(pwexec, NGX_PROXY_WASM_STEP_DISPATCH_RESPONSE); if (ecode != NGX_PROXY_WASM_ERR_NONE) { goto error; diff --git a/src/wasm/vm/ngx_wavm.c b/src/wasm/vm/ngx_wavm.c index ade694c87..643b7ea24 100644 --- a/src/wasm/vm/ngx_wavm.c +++ b/src/wasm/vm/ngx_wavm.c @@ -1345,12 +1345,12 @@ ngx_wavm_instance_destroy(ngx_wavm_instance_t *instance) ngx_wavm_func_t *func; ngx_wavm_module_t *module = instance->module; - ngx_log_debug5(NGX_LOG_DEBUG_WASM, + ngx_log_debug6(NGX_LOG_DEBUG_WASM, instance->log ? instance->log : ngx_cycle->log, 0, "wasm freeing \"%V\" instance in \"%V\" vm" - " (vm: %p, module: %p, instance: %p)", + " (vm: %p, module: %p, instance: %p, trapped: %d)", &module->name, module->vm->name, - module->vm, module, instance); + module->vm, module, instance, instance->trapped); if (instance->funcs.nelts) { for (i = 0; i < instance->funcs.nelts; i++) { diff --git a/t/03-proxy_wasm/003-on_tick.t b/t/03-proxy_wasm/003-on_tick.t index e4b6268e5..beb207a28 100644 --- a/t/03-proxy_wasm/003-on_tick.t +++ b/t/03-proxy_wasm/003-on_tick.t @@ -166,14 +166,14 @@ Should not prevent http context/instance from starting return 200; } --- response_body ---- grep_error_log eval: qr/\[(info|crit)].*?on_tick.*/ +--- grep_error_log eval: qr/(\[crit\]|\[info].*?on_tick).*/ --- grep_error_log_out eval qr/.*? \[info\] .*? on_tick 200.* -\[crit\] .*? panicked at 'on_tick trap'.* +\[crit\] .*? panicked at.* .*? \[info\] .*? on_tick 200.* -\[crit\] .*? panicked at 'on_tick trap'.*/ +\[crit\] .*? panicked at.*/ --- error_log filter 1/1 resuming "on_request_headers" step filter 1/1 resuming "on_response_headers" step diff --git a/t/03-proxy_wasm/007-on_http_instance_isolation.t b/t/03-proxy_wasm/007-on_http_instance_isolation.t index 7ac729bd6..5c4b9d133 100644 --- a/t/03-proxy_wasm/007-on_http_instance_isolation.t +++ b/t/03-proxy_wasm/007-on_http_instance_isolation.t @@ -94,10 +94,8 @@ Should recycle the global instance when trapped. (.*?(Uncaught RuntimeError: )?unreachable|\s*wasm trap: wasm `unreachable` instruction executed)[^#*]* \*\d+ .*? filter chain failed resuming: previous error \(instance trapped\)[^#*]* \*\d+ .*? filter freeing context #\d+ \(1\/2\)[^#*]* -\*\d+ .*? filter freeing context #\d+ \(2\/2\)\Z/, -qr/\A\*\d+ .*? filter freeing trapped instance[^#*]* -\*\d+ wasm freeing "hostcalls" instance in "main" vm[^#*]* -\*\d+ .*? filter new instance[^#*]* +\*\d+ .*? filter freeing context #\d+ \(2\/2\)[^#*]*\Z/, +qr/\A\*\d+ .*? filter new instance[^#*]* \*\d+ .*? filter reusing instance[^#*]* \*\d+ .*? filter 1\/2 resuming "on_request_headers" step in "rewrite" phase[^#*]* \*\d+ .*? filter 1\/2 resuming "on_response_headers" step in "header_filter" phase[^#*]* @@ -110,6 +108,7 @@ qr/\A\*\d+ .*? filter freeing trapped instance[^#*]* \*\d+ .*? filter 2\/2 resuming "on_done" step in "done" phase[^#*]* \*\d+ .*? filter 2\/2 finalizing context[^#*]* \*\d+ .*? filter freeing context #\d+ \(1\/2\)[^#*]* +\*\d+ wasm freeing "hostcalls" instance in "main" vm[^#*]* \*\d+ .*? filter freeing context #\d+ \(2\/2\)\Z/] --- no_error_log [emerg] @@ -153,9 +152,9 @@ should use an instance per stream \*\d+ .*? filter 1\/2 finalizing context[^#*]* \*\d+ .*? filter 2\/2 resuming "on_done" step in "done" phase[^#*]* \*\d+ .*? filter 2\/2 finalizing context[^#*]* +\*\d+ .*? freeing "hostcalls" instance in "main" vm[^#*]* \*\d+ .*? filter freeing context #\d+ \(1\/2\)[^#*]* -\*\d+ .*? filter freeing context #\d+ \(2\/2\)[^#*]* -\*\d+ .*? freeing "hostcalls" instance in "main" vm[^#*]*\Z/, +\*\d+ .*? filter freeing context #\d+ \(2\/2\)[^#*]*\Z/, qr/\A\*\d+ .*? filter new instance[^#*]* #0 on_configure[^#*]* \*\d+ .*? filter reusing instance[^#*]* @@ -172,9 +171,9 @@ qr/\A\*\d+ .*? filter new instance[^#*]* \*\d+ .*? filter 1\/2 finalizing context[^#*]* \*\d+ .*? filter 2\/2 resuming "on_done" step in "done" phase[^#*]* \*\d+ .*? filter 2\/2 finalizing context[^#*]* +\*\d+ .*? freeing "hostcalls" instance in "main" vm[^#*]* \*\d+ .*? filter freeing context #\d+ \(1\/2\)[^#*]* -\*\d+ .*? filter freeing context #\d+ \(2\/2\)[^#*]* -\*\d+ .*? freeing "hostcalls" instance in "main" vm[^#*]*\Z/] +\*\d+ .*? filter freeing context #\d+ \(2\/2\)[^#*]*\Z/] --- no_error_log [error] [crit] @@ -204,9 +203,9 @@ qr/\A\*\d+ .*? filter new instance[^#*]* \*\d+ .*? filter 1\/2 resuming "on_request_headers" step in "rewrite" phase[^#*]* (.*?(Uncaught RuntimeError: )?unreachable|\s*wasm trap: wasm `unreachable` instruction executed)[^#*]* \*\d+ .*? filter chain failed resuming: previous error \(instance trapped\)[^#*]* +\*\d+ .*? freeing "hostcalls" instance in "main" vm[^#*]* \*\d+ .*? filter freeing context #\d+ \(1\/2\)[^#*]* -\*\d+ .*? filter freeing context #\d+ \(2\/2\)[^#*]* -\*\d+ .*? freeing "hostcalls" instance in "main" vm[^#*]*\Z/, +\*\d+ .*? filter freeing context #\d+ \(2\/2\)[^#*]*\Z/, qr/\A\*\d+ .*? filter new instance[^#*]* \*\d+ .*? filter reusing instance[^#*]* \*\d+ .*? filter 1\/2 resuming "on_request_headers" step in "rewrite" phase[^#*]* @@ -219,9 +218,9 @@ qr/\A\*\d+ .*? filter new instance[^#*]* \*\d+ .*? filter 1\/2 finalizing context[^#*]* \*\d+ .*? filter 2\/2 resuming "on_done" step in "done" phase[^#*]* \*\d+ .*? filter 2\/2 finalizing context[^#*]* +\*\d+ .*? freeing "hostcalls" instance in "main" vm[^#*]* \*\d+ .*? filter freeing context #\d+ \(1\/2\)[^#*]* -\*\d+ .*? filter freeing context #\d+ \(2\/2\)[^#*]* -\*\d+ .*? freeing "hostcalls" instance in "main" vm[^#*]*\Z/] +\*\d+ .*? filter freeing context #\d+ \(2\/2\)[^#*]*\Z/] --- no_error_log [emerg] [alert] diff --git a/t/03-proxy_wasm/hfuncs/114-proxy_set_http_request_body.t b/t/03-proxy_wasm/hfuncs/114-proxy_set_http_request_body.t index bf147dcf2..1c31f21b1 100644 --- a/t/03-proxy_wasm/hfuncs/114-proxy_set_http_request_body.t +++ b/t/03-proxy_wasm/hfuncs/114-proxy_set_http_request_body.t @@ -235,7 +235,7 @@ HelloWorld } location /log { - # cannot set request body + # not executed (subrequest) proxy_wasm hostcalls 'on=log \ test=/t/set_request_body'; echo $request_body; @@ -258,7 +258,6 @@ from_request_body --- grep_error_log_out eval qr/.*?host trap \(bad usage\): cannot set request body.* \[info\] .*? \*\d+ .*? filter chain failed resuming: previous error \(instance trapped\).*? subrequest: "\/response_headers".* -\[info\] .*? \*\d+ .*? filter chain failed resuming: previous error \(instance trapped\).*? request: "GET \/t HTTP\/1\.1".* \z/ --- no_error_log [alert] diff --git a/t/03-proxy_wasm/hfuncs/119-proxy_properties_get_ngx.t b/t/03-proxy_wasm/hfuncs/119-proxy_properties_get_ngx.t index 28b520b3c..c5225b345 100644 --- a/t/03-proxy_wasm/hfuncs/119-proxy_properties_get_ngx.t +++ b/t/03-proxy_wasm/hfuncs/119-proxy_properties_get_ngx.t @@ -131,13 +131,8 @@ qr/\[info\] .*? property not found: n,/ === TEST 5: proxy_wasm - get_property() ngx.* - not available on: tick (isolation: global) - on_tick runs on the root context, so it does not have access to ngx_http_* calls. - -HTTP 500 since instance recycling happens on next request, and isolation -is global (single instance for root/request). - --- wasm_modules: hostcalls --- load_nginx_modules: ngx_http_echo_module --- config @@ -146,7 +141,6 @@ is global (single instance for root/request). echo_sleep 0.150; echo ok; } ---- error_code: 500 --- ignore_response_body --- error_log eval [ diff --git a/t/03-proxy_wasm/hfuncs/120-proxy_properties_get_host.t b/t/03-proxy_wasm/hfuncs/120-proxy_properties_get_host.t index 705c2fa3b..aadd5a76c 100644 --- a/t/03-proxy_wasm/hfuncs/120-proxy_properties_get_host.t +++ b/t/03-proxy_wasm/hfuncs/120-proxy_properties_get_host.t @@ -97,7 +97,8 @@ TODO: is this behavior correct? name=wasmx.nonexistent_property'; echo ok; } ---- ignore_response_body +--- response_body +ok --- error_log eval qr/\[info\] .*? property not found: wasmx.nonexistent_property,/ --- no_error_log @@ -129,10 +130,6 @@ qr/\[info\] .*? property not found: was,/ === TEST 4: proxy_wasm - get_property() wasmx - not available on: tick (isolation: global) - -HTTP 500 since instance recycling happens on next request, and isolation -is global (single instance for root/request). - --- wasm_modules: hostcalls --- load_nginx_modules: ngx_http_echo_module --- config @@ -143,7 +140,6 @@ is global (single instance for root/request). echo_sleep 0.150; echo ok; } ---- error_code: 500 --- ignore_response_body --- error_log eval [ @@ -152,15 +148,10 @@ is global (single instance for root/request). qr/\[crit\] .*? panicked at/, qr/unexpected status: 10/, ] ---- no_error_log -[emerg] === TEST 5: proxy_wasm - get_property() wasmx - not available on: tick (isolation: stream) - -HTTP 200 since the root and request instances are different. - --- wasm_modules: hostcalls --- load_nginx_modules: ngx_http_echo_module --- config diff --git a/t/03-proxy_wasm/hfuncs/122-proxy_properties_set_host.t b/t/03-proxy_wasm/hfuncs/122-proxy_properties_set_host.t index abe7b0aa0..bfc35f836 100644 --- a/t/03-proxy_wasm/hfuncs/122-proxy_properties_set_host.t +++ b/t/03-proxy_wasm/hfuncs/122-proxy_properties_set_host.t @@ -139,10 +139,8 @@ Does not fail when the property is not found. === TEST 5: proxy_wasm - set_property() wasmx - not available on: tick (isolation: global) - -HTTP 500 since instance recycling happens on next request, and -isolation is global (single instance for root/request). - +on_tick runs on the root context, so it does not have access to +ngx_http_* calls. --- wasm_modules: hostcalls --- load_nginx_modules: ngx_http_echo_module --- config @@ -157,7 +155,6 @@ isolation is global (single instance for root/request). echo_sleep 0.150; echo ok; } ---- error_code: 500 --- ignore_response_body --- error_log eval [ @@ -172,12 +169,8 @@ isolation is global (single instance for root/request). === TEST 6: proxy_wasm - set_property() wasmx - not available on: tick (isolation: stream) - -HTTP 200 since the root and request instances are different. - on_tick runs on the root context, so it does not have access to ngx_http_* calls. - --- wasm_modules: hostcalls --- load_nginx_modules: ngx_http_echo_module --- config diff --git a/t/03-proxy_wasm/hfuncs/123-proxy_properties_set_ngx.t b/t/03-proxy_wasm/hfuncs/123-proxy_properties_set_ngx.t index 370854afe..efd40ff02 100644 --- a/t/03-proxy_wasm/hfuncs/123-proxy_properties_set_ngx.t +++ b/t/03-proxy_wasm/hfuncs/123-proxy_properties_set_ngx.t @@ -194,9 +194,7 @@ forward the NotFound status back to the caller. on_tick runs on the root context, so it does not have access to ngx_http_* calls. -HTTP 500 since instance recycling happens on next -request, and isolation is global (single instance for root/request) - +--- skip_eval: 5: $ENV{TEST_NGINX_USE_HUP} == 1 --- wasm_modules: hostcalls --- load_nginx_modules: ngx_http_echo_module --- config @@ -211,7 +209,6 @@ request, and isolation is global (single instance for root/request) echo_sleep 0.150; echo ok; } ---- error_code: 500 --- ignore_response_body --- error_log eval [ @@ -230,6 +227,7 @@ ngx_http_* calls. HTTP 200 since the root and request instances are different. +--- skip_eval: 5: $ENV{TEST_NGINX_USE_HUP} == 1 --- wasm_modules: hostcalls --- load_nginx_modules: ngx_http_echo_module --- config diff --git a/t/04-openresty/ffi/103-proxy_wasm_attach.t b/t/04-openresty/ffi/103-proxy_wasm_attach.t index bf8c8b480..85a2e5125 100644 --- a/t/04-openresty/ffi/103-proxy_wasm_attach.t +++ b/t/04-openresty/ffi/103-proxy_wasm_attach.t @@ -527,8 +527,8 @@ qr/\A[^#]*#0 on_vm_start[^#*]* \*\d+ .*? filter 1\/1 resuming "on_log" step in "log" phase[^#*]* \*\d+ .*? filter 1\/1 resuming "on_done" step in "done" phase[^#*]* \*\d+ .*? filter 1\/1 finalizing context[^#*]* -\*\d+ .*? filter freeing context #\d+ \(1\/1\)[^#*]* -\*\d+ wasm freeing "hostcalls" instance[^#*]*\Z/, +\*\d+ wasm freeing "hostcalls" instance[^#*]* +\*\d+ .*? filter freeing context #\d+ \(1\/1\)[^#*]*\Z/, qr/\A\*\d+ proxy_wasm initializing filter chain \(nfilters: 1, isolation: 2\)[^#*]* \*\d+ .*? "hostcalls" filter new instance[^#*]* #0 on_configure[^#*]* @@ -539,8 +539,8 @@ qr/\A\*\d+ proxy_wasm initializing filter chain \(nfilters: 1, isolation: 2\)[^# \*\d+ .*? filter 1\/1 resuming "on_log" step in "log" phase[^#*]* \*\d+ .*? filter 1\/1 resuming "on_done" step in "done" phase[^#*]* \*\d+ .*? filter 1\/1 finalizing context[^#*]* -\*\d+ .*? filter freeing context #\d+ \(1\/1\)[^#*]* -\*\d+ wasm freeing "hostcalls" instance[^#*]*\Z/, +\*\d+ wasm freeing "hostcalls" instance[^#*]* +\*\d+ .*? filter freeing context #\d+ \(1\/1\)[^#*]*\Z/, ]