From 7543fe86ad808bcc6ca3e151822a0fea9b5e47c7 Mon Sep 17 00:00:00 2001 From: Caio Ramos Casimiro Date: Tue, 2 Apr 2024 16:48:53 +0100 Subject: [PATCH] refactor(shm/kv) retrieve items by key hash The change is motivated by the upcoming proxy-wasm metrics support, which will be built atop `ngx_wasm_shm_kv`. Proxy-Wasm filter developers are expected to define metrics before using them. When a metric is defined the host returns an id to the filter which is later used for updating or retrieving that metric's value. As such, now `ngx_wasm_shm_kv_get_locked` expects either a key (ngx_str_t *) or its hash (uint32_t *). If both are provided, the hash is used and the key is ignored. A new function `ngx_wasm_shm_rbtree_lookup` is also introduced allowing item retrieval using only key hash. --- src/common/proxy_wasm/ngx_proxy_wasm_host.c | 2 +- src/common/shm/ngx_wasm_shm_kv.c | 44 ++++++++++++++++++--- src/common/shm/ngx_wasm_shm_kv.h | 2 +- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/common/proxy_wasm/ngx_proxy_wasm_host.c b/src/common/proxy_wasm/ngx_proxy_wasm_host.c index d3d48ee26..b933fae29 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm_host.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm_host.c @@ -1283,7 +1283,7 @@ ngx_proxy_wasm_hfuncs_get_shared_data(ngx_wavm_instance_t *instance, ngx_wasm_shm_lock(resolved.shm); - rc = ngx_wasm_shm_kv_get_locked(resolved.shm, &key, &value, cas); + rc = ngx_wasm_shm_kv_get_locked(resolved.shm, &key, NULL, &value, cas); ngx_wasm_shm_unlock(resolved.shm); diff --git a/src/common/shm/ngx_wasm_shm_kv.c b/src/common/shm/ngx_wasm_shm_kv.c index 475ce3699..265023d83 100644 --- a/src/common/shm/ngx_wasm_shm_kv.c +++ b/src/common/shm/ngx_wasm_shm_kv.c @@ -133,14 +133,45 @@ queue_for_node(ngx_wasm_shm_t *shm, ngx_wasm_shm_kv_node_t *n) } +static ngx_wasm_shm_kv_node_t * +ngx_wasm_shm_rbtree_lookup(ngx_rbtree_t *rbtree, uint32_t key_hash) +{ + ngx_wasm_shm_kv_node_t *n; + ngx_rbtree_node_t *node, *sentinel; + + node = rbtree->root; + sentinel = rbtree->sentinel; + + while (node != sentinel) { + + n = (ngx_wasm_shm_kv_node_t *) node; + + if (key_hash != node->key) { + node = (key_hash < node->key) ? node->left : node->right; + continue; + } + + return n; + } + + return NULL; +} + + ngx_int_t ngx_wasm_shm_kv_get_locked(ngx_wasm_shm_t *shm, ngx_str_t *key, - ngx_str_t **value_out, uint32_t *cas) + uint32_t *key_hash, ngx_str_t **value_out, uint32_t *cas) { - ngx_wasm_shm_kv_node_t *n; ngx_wasm_shm_kv_t *kv = ngx_wasm_shm_get_kv(shm); + ngx_wasm_shm_kv_node_t *n; - n = (ngx_wasm_shm_kv_node_t *) ngx_str_rbtree_lookup(&kv->rbtree, key, 0); + if (key_hash) { + n = ngx_wasm_shm_rbtree_lookup(&kv->rbtree, *key_hash); + + } else { + n = ngx_wasm_shm_rbtree_lookup(&kv->rbtree, + ngx_crc32_long(key->data, key->len)); + } if (n == NULL) { return NGX_DECLINED; @@ -251,11 +282,13 @@ ngx_wasm_shm_kv_set_locked(ngx_wasm_shm_t *shm, ngx_str_t *key, ngx_str_t *value, uint32_t cas, ngx_int_t *written) { size_t size; - ngx_wasm_shm_kv_node_t *n, *old; + uint32_t key_hash = ngx_crc32_long(key->data, key->len); ngx_wasm_shm_kv_t *kv = ngx_wasm_shm_get_kv(shm); + ngx_wasm_shm_kv_node_t *n, *old; old = NULL; - n = (ngx_wasm_shm_kv_node_t *) ngx_str_rbtree_lookup(&kv->rbtree, key, 0); + n = (ngx_wasm_shm_kv_node_t *) ngx_wasm_shm_rbtree_lookup(&kv->rbtree, + key_hash); if (cas != (n == NULL ? 0 : n->cas)) { *written = 0; @@ -318,6 +351,7 @@ ngx_wasm_shm_kv_set_locked(ngx_wasm_shm_t *shm, ngx_str_t *key, n->key.str.data = (u_char *) n + sizeof(ngx_wasm_shm_kv_node_t); n->key.str.len = key->len; + n->key.node.key = ngx_crc32_long(key->data, key->len); n->value.data = n->key.str.data + key->len; n->value.len = value->len; diff --git a/src/common/shm/ngx_wasm_shm_kv.h b/src/common/shm/ngx_wasm_shm_kv.h index eec3998ff..fe280034f 100644 --- a/src/common/shm/ngx_wasm_shm_kv.h +++ b/src/common/shm/ngx_wasm_shm_kv.h @@ -15,7 +15,7 @@ typedef struct { ngx_int_t ngx_wasm_shm_kv_init(ngx_wasm_shm_t *shm); ngx_int_t ngx_wasm_shm_kv_get_locked(ngx_wasm_shm_t *shm, - ngx_str_t *key, ngx_str_t **value_out, uint32_t *cas); + ngx_str_t *key, uint32_t *key_hash, ngx_str_t **value_out, uint32_t *cas); ngx_int_t ngx_wasm_shm_kv_set_locked(ngx_wasm_shm_t *shm, ngx_str_t *key, ngx_str_t *value, uint32_t cas, ngx_int_t *written); ngx_int_t ngx_wasm_shm_kv_resolve_key(ngx_str_t *key,