[njs] Modules: fixed size() and keys() methods of a shared dictionary.
Dmitry Volyntsev
xeioex at nginx.com
Thu Aug 31 04:01:40 UTC 2023
details: https://hg.nginx.org/njs/rev/3fe16507f80a
branches:
changeset: 2187:3fe16507f80a
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Wed Aug 30 18:59:28 2023 -0700
description:
Modules: fixed size() and keys() methods of a shared dictionary.
Previously, these methods did not take into the account exprired
entries. The expired entries appear in js_shared_dict_zone when timeout
directive is specified as the expired elements are not removed at the
moment they become stale right away.
This closes #665 issue on Github.
diffstat:
nginx/ngx_js_shared_dict.c | 16 +++++++++++++
nginx/t/js_shared_dict.t | 54 ++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 64 insertions(+), 6 deletions(-)
diffs (149 lines):
diff -r c7d2a7846b0b -r 3fe16507f80a nginx/ngx_js_shared_dict.c
--- a/nginx/ngx_js_shared_dict.c Wed Aug 30 12:06:12 2023 -0700
+++ b/nginx/ngx_js_shared_dict.c Wed Aug 30 18:59:28 2023 -0700
@@ -599,6 +599,8 @@ njs_js_ext_shared_dict_keys(njs_vm_t *vm
{
njs_int_t rc;
ngx_int_t max_count;
+ ngx_msec_t now;
+ ngx_time_t *tp;
njs_value_t *value;
ngx_rbtree_t *rbtree;
ngx_js_dict_t *dict;
@@ -630,6 +632,12 @@ njs_js_ext_shared_dict_keys(njs_vm_t *vm
ngx_rwlock_rlock(&dict->sh->rwlock);
+ if (dict->timeout) {
+ tp = ngx_timeofday();
+ now = tp->sec * 1000 + tp->msec;
+ ngx_js_dict_expire(dict, now);
+ }
+
rbtree = &dict->sh->rbtree;
if (rbtree->root == rbtree->sentinel) {
@@ -835,6 +843,8 @@ njs_js_ext_shared_dict_size(njs_vm_t *vm
njs_index_t unused, njs_value_t *retval)
{
njs_int_t items;
+ ngx_msec_t now;
+ ngx_time_t *tp;
ngx_rbtree_t *rbtree;
ngx_js_dict_t *dict;
ngx_shm_zone_t *shm_zone;
@@ -851,6 +861,12 @@ njs_js_ext_shared_dict_size(njs_vm_t *vm
ngx_rwlock_rlock(&dict->sh->rwlock);
+ if (dict->timeout) {
+ tp = ngx_timeofday();
+ now = tp->sec * 1000 + tp->msec;
+ ngx_js_dict_expire(dict, now);
+ }
+
rbtree = &dict->sh->rbtree;
if (rbtree->root == rbtree->sentinel) {
diff -r c7d2a7846b0b -r 3fe16507f80a nginx/t/js_shared_dict.t
--- a/nginx/t/js_shared_dict.t Wed Aug 30 12:06:12 2023 -0700
+++ b/nginx/t/js_shared_dict.t Wed Aug 30 18:59:28 2023 -0700
@@ -46,6 +46,10 @@ http {
listen 127.0.0.1:8080;
server_name localhost;
+ location /njs {
+ js_content test.njs;
+ }
+
location /add {
js_content test.add;
}
@@ -115,6 +119,10 @@ http {
EOF
$t->write_file('test.js', <<'EOF');
+ function test_njs(r) {
+ r.return(200, njs.version);
+ }
+
function convertToValue(dict, v) {
if (dict.type == 'number') {
return parseInt(v);
@@ -197,7 +205,7 @@ EOF
ks = ngx.shared[r.args.dict].keys();
}
- r.return(200, ks.toSorted());
+ r.return(200, `[${ks.toSorted()}]`);
}
function name(r) {
@@ -239,10 +247,11 @@ EOF
}
export default { add, capacity, chain, clear, del, free_space, get, has,
- incr, keys, name, pop, replace, set, size, zones };
+ incr, keys, name, njs: test_njs, pop, replace, set, size,
+ zones };
EOF
-$t->try_run('no js_shared_dict_zone')->plan(38);
+$t->try_run('no js_shared_dict_zone')->plan(41);
###############################################################################
@@ -274,8 +283,9 @@ like(http_get('/has?dict=waka&key=FOO'),
$t->reload();
-like(http_get('/keys?dict=foo'), qr/FOO\,FOO2\,FOO3/, 'foo keys');
-like(http_get('/keys?dict=foo&max=2'), qr/FOO\,FOO3/, 'foo keys max 2');
+like(http_get('/keys?dict=foo'), qr/\[FOO\,FOO2\,FOO3]/, 'foo keys');
+like(http_get('/keys?dict=foo&max=2'), qr/\[FOO\,FOO3]/, 'foo keys max 2');
+like(http_get('/size?dict=foo'), qr/size: 3/, 'no of items in foo');
like(http_get('/get?dict=foo&key=FOO2'), qr/yyy/, 'get foo.FOO2');
like(http_get('/get?dict=bar&key=FOO'), qr/zzz/, 'get bar.FOO');
like(http_get('/get?dict=foo&key=FOO'), qr/xxx/, 'get foo.FOO');
@@ -292,8 +302,40 @@ select undef, undef, undef, 2.1;
like(http_get('/get?dict=foo&key=FOO'), qr/undefined/, 'get expired foo.FOO');
like(http_get('/pop?dict=foo&key=FOO'), qr/undefined/, 'pop expired foo.FOO');
-like(http_get('/size?dict=foo'), qr/size: 2/, 'no of items in foo');
+
+TODO: {
+local $TODO = 'not yet' unless has_version('0.8.1');
+
+like(http_get('/keys?dict=foo'), qr/\[]/, 'foo keys after expire');
+like(http_get('/keys?dict=bar'), qr/\[FOO\,FOO2]/, 'bar keys after a delay');
+like(http_get('/size?dict=foo'), qr/size: 0/,
+ 'no of items in foo after expire');
+
+}
+
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');
like(http_get('/clear?dict=foo'), qr/undefined/, 'clear foo');
like(http_get('/size?dict=foo'), qr/size: 0/, 'no of items in foo after clear');
+
+###############################################################################
+
+sub has_version {
+ my $need = shift;
+
+ http_get('/njs') =~ /^([.0-9]+)$/m;
+
+ my @v = split(/\./, $1);
+ my ($n, $v);
+
+ for $n (split(/\./, $need)) {
+ $v = shift @v || 0;
+ return 0 if $n > $v;
+ return 1 if $v > $n;
+ }
+
+ return 1;
+}
+
+###############################################################################
More information about the nginx-devel
mailing list