details: https://hg.nginx.org/njs/rev/a5da85a3d309 branches: changeset: 2356:a5da85a3d309 user: jo-carter <104033676+jo-car...@users.noreply.github.com> date: Sun Jun 02 09:11:13 2024 +0100 description: Modules: shared dictionary add, set, incr methods timeout argument.
The optional timeout argument overrides the timeout specified with the shared_dict_zone directive for the effected key and operation only. The timeout is specified in milliseconds. This is useful when the majority of keys are expected to require unique timeouts. diffstat: nginx/ngx_js_shared_dict.c | 85 ++++++++++++++++++++++++++++++++++++--------- nginx/t/js_shared_dict.t | 55 ++++++++++++++++++++++++++--- 2 files changed, 116 insertions(+), 24 deletions(-) diffs (298 lines): diff -r ae4f50f7b7b3 -r a5da85a3d309 nginx/ngx_js_shared_dict.c --- a/nginx/ngx_js_shared_dict.c Fri Jun 07 22:58:53 2024 -0700 +++ b/nginx/ngx_js_shared_dict.c Sun Jun 02 09:11:13 2024 +0100 @@ -85,15 +85,16 @@ static ngx_js_dict_node_t *ngx_js_dict_l #define NGX_JS_DICT_FLAG_MUST_NOT_EXIST 2 static ngx_int_t ngx_js_dict_set(njs_vm_t *vm, ngx_js_dict_t *dict, - njs_str_t *key, njs_value_t *value, unsigned flags); + njs_str_t *key, njs_value_t *value, ngx_msec_t timeout, unsigned flags); static ngx_int_t ngx_js_dict_add(ngx_js_dict_t *dict, njs_str_t *key, - njs_value_t *value, ngx_msec_t now); + njs_value_t *value, ngx_msec_t timeout, ngx_msec_t now); static ngx_int_t ngx_js_dict_update(ngx_js_dict_t *dict, - ngx_js_dict_node_t *node, njs_value_t *value, ngx_msec_t now); + ngx_js_dict_node_t *node, njs_value_t *value, ngx_msec_t timeout, + ngx_msec_t now); static ngx_int_t ngx_js_dict_get(njs_vm_t *vm, ngx_js_dict_t *dict, njs_str_t *key, njs_value_t *retval); static ngx_int_t ngx_js_dict_incr(ngx_js_dict_t *dict, njs_str_t *key, - njs_value_t *delta, njs_value_t *init, double *value); + njs_value_t *delta, njs_value_t *init, double *value, ngx_msec_t timeout); static ngx_int_t ngx_js_dict_delete(njs_vm_t *vm, ngx_js_dict_t *dict, njs_str_t *key, njs_value_t *retval); static ngx_int_t ngx_js_dict_copy_value_locked(njs_vm_t *vm, @@ -726,7 +727,8 @@ njs_js_ext_shared_dict_incr(njs_vm_t *vm double value; ngx_int_t rc; njs_str_t key; - njs_value_t *delta, *init; + ngx_msec_t timeout; + njs_value_t *delta, *init, *timeo; ngx_js_dict_t *dict; ngx_shm_zone_t *shm_zone; njs_opaque_value_t lvalue; @@ -765,7 +767,30 @@ njs_js_ext_shared_dict_incr(njs_vm_t *vm njs_value_number_set(init, 0); } - rc = ngx_js_dict_incr(shm_zone->data, &key, delta, init, &value); + timeo = njs_arg(args, nargs, 4); + if (!njs_value_is_undefined(timeo)) { + if (!njs_value_is_number(timeo)) { + njs_vm_type_error(vm, "timeout is not a number"); + return NJS_ERROR; + } + + if (!dict->timeout) { + njs_vm_type_error(vm, "shared dict must be declared with timeout"); + return NJS_ERROR; + } + + timeout = (ngx_msec_t) njs_value_number(timeo); + + if (timeout < 1) { + njs_vm_type_error(vm, "timeout must be greater than or equal to 1"); + return NJS_ERROR; + } + + } else { + timeout = dict->timeout; + } + + rc = ngx_js_dict_incr(shm_zone->data, &key, delta, init, &value, timeout); if (rc == NGX_ERROR) { njs_vm_error(vm, "failed to increment value in shared dict"); return NJS_ERROR; @@ -936,7 +961,8 @@ njs_js_ext_shared_dict_set(njs_vm_t *vm, { njs_str_t key; ngx_int_t rc; - njs_value_t *value; + ngx_msec_t timeout; + njs_value_t *value, *timeo; ngx_js_dict_t *dict; ngx_shm_zone_t *shm_zone; @@ -967,7 +993,30 @@ njs_js_ext_shared_dict_set(njs_vm_t *vm, } } - rc = ngx_js_dict_set(vm, shm_zone->data, &key, value, flags); + timeo = njs_arg(args, nargs, 3); + if (!njs_value_is_undefined(timeo)) { + if (!njs_value_is_number(timeo)) { + njs_vm_type_error(vm, "timeout is not a number"); + return NJS_ERROR; + } + + if (!dict->timeout) { + njs_vm_type_error(vm, "shared dict must be declared with timeout"); + return NJS_ERROR; + } + + timeout = (ngx_msec_t) njs_value_number(timeo); + + if (timeout < 1) { + njs_vm_type_error(vm, "timeout must be greater than or equal to 1"); + return NJS_ERROR; + } + + } else { + timeout = dict->timeout; + } + + rc = ngx_js_dict_set(vm, shm_zone->data, &key, value, timeout, flags); if (rc == NGX_ERROR) { return NJS_ERROR; } @@ -1118,7 +1167,7 @@ ngx_js_dict_node_free(ngx_js_dict_t *dic static ngx_int_t ngx_js_dict_set(njs_vm_t *vm, ngx_js_dict_t *dict, njs_str_t *key, - njs_value_t *value, unsigned flags) + njs_value_t *value, ngx_msec_t timeout, unsigned flags) { ngx_msec_t now; ngx_time_t *tp; @@ -1137,7 +1186,7 @@ ngx_js_dict_set(njs_vm_t *vm, ngx_js_dic return NGX_DECLINED; } - if (ngx_js_dict_add(dict, key, value, now) != NGX_OK) { + if (ngx_js_dict_add(dict, key, value, timeout, now) != NGX_OK) { goto memory_error; } @@ -1149,7 +1198,7 @@ ngx_js_dict_set(njs_vm_t *vm, ngx_js_dic } } - if (ngx_js_dict_update(dict, node, value, now) != NGX_OK) { + if (ngx_js_dict_update(dict, node, value, timeout, now) != NGX_OK) { goto memory_error; } } @@ -1170,7 +1219,7 @@ memory_error: static ngx_int_t ngx_js_dict_add(ngx_js_dict_t *dict, njs_str_t *key, njs_value_t *value, - ngx_msec_t now) + ngx_msec_t timeout, ngx_msec_t now) { size_t n; uint32_t hash; @@ -1214,7 +1263,7 @@ ngx_js_dict_add(ngx_js_dict_t *dict, njs ngx_rbtree_insert(&dict->sh->rbtree, &node->sn.node); if (dict->timeout) { - node->expire.key = now + dict->timeout; + node->expire.key = now + timeout; ngx_rbtree_insert(&dict->sh->rbtree_expire, &node->expire); } @@ -1224,7 +1273,7 @@ ngx_js_dict_add(ngx_js_dict_t *dict, njs static ngx_int_t ngx_js_dict_update(ngx_js_dict_t *dict, ngx_js_dict_node_t *node, - njs_value_t *value, ngx_msec_t now) + njs_value_t *value, ngx_msec_t timeout, ngx_msec_t now) { u_char *p; njs_str_t string; @@ -1249,7 +1298,7 @@ ngx_js_dict_update(ngx_js_dict_t *dict, if (dict->timeout) { ngx_rbtree_delete(&dict->sh->rbtree_expire, &node->expire); - node->expire.key = now + dict->timeout; + node->expire.key = now + timeout; ngx_rbtree_insert(&dict->sh->rbtree_expire, &node->expire); } @@ -1306,7 +1355,7 @@ ngx_js_dict_delete(njs_vm_t *vm, ngx_js_ static ngx_int_t ngx_js_dict_incr(ngx_js_dict_t *dict, njs_str_t *key, njs_value_t *delta, - njs_value_t *init, double *value) + njs_value_t *init, double *value, ngx_msec_t timeout) { ngx_msec_t now; ngx_time_t *tp; @@ -1322,7 +1371,7 @@ ngx_js_dict_incr(ngx_js_dict_t *dict, nj if (node == NULL) { njs_value_number_set(init, njs_value_number(init) + njs_value_number(delta)); - if (ngx_js_dict_add(dict, key, init, now) != NGX_OK) { + if (ngx_js_dict_add(dict, key, init, timeout, now) != NGX_OK) { ngx_rwlock_unlock(&dict->sh->rwlock); return NGX_ERROR; } @@ -1335,7 +1384,7 @@ ngx_js_dict_incr(ngx_js_dict_t *dict, nj if (dict->timeout) { ngx_rbtree_delete(&dict->sh->rbtree_expire, &node->expire); - node->expire.key = now + dict->timeout; + node->expire.key = now + timeout; ngx_rbtree_insert(&dict->sh->rbtree_expire, &node->expire); } } diff -r ae4f50f7b7b3 -r a5da85a3d309 nginx/t/js_shared_dict.t --- a/nginx/t/js_shared_dict.t Fri Jun 07 22:58:53 2024 -0700 +++ b/nginx/t/js_shared_dict.t Sun Jun 02 09:11:13 2024 +0100 @@ -40,7 +40,7 @@ http { js_shared_dict_zone zone=foo:32k timeout=2s evict; js_shared_dict_zone zone=bar:64k type=string; - js_shared_dict_zone zone=waka:32k type=number; + js_shared_dict_zone zone=waka:32k timeout=1000s type=number; js_shared_dict_zone zone=no_timeout:32k; server { @@ -146,7 +146,14 @@ EOF function add(r) { var dict = ngx.shared[r.args.dict]; var value = convertToValue(dict, r.args.value); - r.return(200, dict.add(r.args.key, value)); + + if (r.args.timeout) { + var timeout = Number(r.args.timeout); + r.return(200, dict.add(r.args.key, value, timeout)); + + } else { + r.return(200, dict.add(r.args.key, value)); + } } function capacity(r) { @@ -200,8 +207,16 @@ EOF function incr(r) { var dict = ngx.shared[r.args.dict]; var def = r.args.def ? parseInt(r.args.def) : 0; - var val = dict.incr(r.args.key, parseInt(r.args.by), def); - r.return(200, val); + + if (r.args.timeout) { + var timeout = Number(r.args.timeout); + var val = dict.incr(r.args.key, parseInt(r.args.by), def, timeout); + r.return(200, val); + + } else { + var val = dict.incr(r.args.key, parseInt(r.args.by), def); + r.return(200, val); + } } function keys(r) { @@ -256,7 +271,14 @@ EOF function set(r) { var dict = ngx.shared[r.args.dict]; var value = convertToValue(dict, r.args.value); - r.return(200, dict.set(r.args.key, value) === dict); + + if (r.args.timeout) { + var timeout = Number(r.args.timeout); + r.return(200, dict.set(r.args.key, value, timeout) === dict); + + } else { + r.return(200, dict.set(r.args.key, value) === dict); + } } function size(r) { @@ -283,7 +305,7 @@ EOF set_clear, size, zones }; EOF -$t->try_run('no js_shared_dict_zone')->plan(44); +$t->try_run('no js_shared_dict_zone')->plan(51); ############################################################################### @@ -350,6 +372,27 @@ like(http_get('/items?dict=waka'), } +TODO: { +local $TODO = 'not yet' unless has_version('0.8.5'); + +http_get('/clear?dict=waka'); +like(http_get('/set?dict=waka&key=BAR&value=1&timeout=1'), qr/true/, + 'set waka.BAR'); +like(http_get('/add?dict=waka&key=BAR2&value=1&timeout=1'), qr/true/, + 'add waka.BAR2'); +like(http_get('/incr?dict=waka&key=BAR3&by=42&timeout=1'), qr/42/, + 'incr waka.BAR3'); +like(http_get('/set?dict=waka&key=FOO&value=42&timeout=1000'), qr/true/, + 'set waka.FOO'); +like(http_get('/add?dict=waka&key=FOO2&value=42&timeout=1000'), qr/true/, + 'add waka.FOO2'); +like(http_get('/incr?dict=waka&key=FOO3&by=42&timeout=1000'), qr/42/, + 'incr waka.FOO3'); + +like(http_get('/keys?dict=waka'), qr/\[FOO\,FOO2\,FOO3]/, 'waka keys'); + +} + like(http_get('/pop?dict=bar&key=FOO'), qr/zzz/, 'pop bar.FOO'); like(http_get('/pop?dict=bar&key=FOO'), qr/undefined/, 'pop deleted bar.FOO'); http_get('/set?dict=foo&key=BAR&value=xxx'); _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org https://mailman.nginx.org/mailman/listinfo/nginx-devel