[njs] Modules: shared dictionary add, set, incr methods timeout argument.
noreply at nginx.com
noreply at nginx.com
Mon Jun 10 23:05:04 UTC 2024
details: https://hg.nginx.org/njs/rev/a5da85a3d309
branches:
changeset: 2356:a5da85a3d309
user: jo-carter <104033676+jo-carter at 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');
More information about the nginx-devel
mailing list