]> git.kaiwu.me - njs.git/commitdiff
Modules: implemented items() method of a shared dictionary.
authorDmitry Volyntsev <xeioex@nginx.com>
Thu, 7 Sep 2023 23:12:40 +0000 (16:12 -0700)
committerDmitry Volyntsev <xeioex@nginx.com>
Thu, 7 Sep 2023 23:12:40 +0000 (16:12 -0700)
nginx/ngx_js_shared_dict.c
nginx/t/js_shared_dict.t

index 7a5c5c8c5cce4897daa56dc5765ede1c6124c541..c36a585b7598be4352c5d3aed84cb0f7e4d2f75a 100644 (file)
@@ -64,6 +64,8 @@ static njs_int_t njs_js_ext_shared_dict_keys(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs, njs_index_t unused, njs_value_t *retval);
 static njs_int_t njs_js_ext_shared_dict_incr(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs, njs_index_t unused, njs_value_t *retval);
+static njs_int_t njs_js_ext_shared_dict_items(njs_vm_t *vm, njs_value_t *args,
+    njs_uint_t nargs, njs_index_t unused, njs_value_t *retval);
 static njs_int_t njs_js_ext_shared_dict_name(njs_vm_t *vm,
     njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
     njs_value_t *retval);
@@ -184,6 +186,17 @@ static njs_external_t  ngx_js_ext_shared_dict[] = {
         }
     },
 
+    {
+        .flags = NJS_EXTERN_METHOD,
+        .name.string = njs_str("items"),
+        .writable = 1,
+        .configurable = 1,
+        .enumerable = 1,
+        .u.method = {
+            .native = njs_js_ext_shared_dict_items,
+        }
+    },
+
     {
         .flags = NJS_EXTERN_METHOD,
         .name.string = njs_str("get"),
@@ -738,6 +751,113 @@ njs_js_ext_shared_dict_incr(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 }
 
 
+static njs_int_t
+njs_js_ext_shared_dict_items(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+    njs_index_t unused, njs_value_t *retval)
+{
+    njs_int_t            rc;
+    ngx_int_t            max_count;
+    ngx_msec_t           now;
+    ngx_time_t          *tp;
+    njs_value_t         *value, *kv;
+    ngx_rbtree_t        *rbtree;
+    ngx_js_dict_t       *dict;
+    ngx_shm_zone_t      *shm_zone;
+    ngx_rbtree_node_t   *rn;
+    ngx_js_dict_node_t  *node;
+
+    shm_zone = njs_vm_external(vm, ngx_js_shared_dict_proto_id,
+                               njs_argument(args, 0));
+    if (shm_zone == NULL) {
+        njs_vm_type_error(vm, "\"this\" is not a shared dict");
+        return NJS_ERROR;
+    }
+
+    dict = shm_zone->data;
+
+    max_count = 1024;
+
+    if (nargs > 1) {
+        if (ngx_js_integer(vm, njs_arg(args, nargs, 1), &max_count) != NGX_OK) {
+            return NJS_ERROR;
+        }
+    }
+
+    rc = njs_vm_array_alloc(vm, retval, 8);
+    if (rc != NJS_OK) {
+        return NJS_ERROR;
+    }
+
+    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) {
+        goto done;
+    }
+
+    for (rn = ngx_rbtree_min(rbtree->root, rbtree->sentinel);
+         rn != NULL;
+         rn = ngx_rbtree_next(rbtree, rn))
+    {
+        if (max_count-- == 0) {
+            break;
+        }
+
+        node = (ngx_js_dict_node_t *) rn;
+
+        kv = njs_vm_array_push(vm, retval);
+        if (kv == NULL) {
+            goto fail;
+        }
+
+        rc = njs_vm_array_alloc(vm, kv, 2);
+        if (rc != NJS_OK) {
+            return NJS_ERROR;
+        }
+
+        value = njs_vm_array_push(vm, kv);
+        if (value == NULL) {
+            goto fail;
+        }
+
+        rc = njs_vm_value_string_set(vm, value, node->sn.str.data,
+                                     node->sn.str.len);
+        if (rc != NJS_OK) {
+            goto fail;
+        }
+
+        value = njs_vm_array_push(vm, kv);
+        if (value == NULL) {
+            goto fail;
+        }
+
+        rc = ngx_js_dict_copy_value_locked(vm, dict, node, value);
+        if (rc != NJS_OK) {
+            goto fail;
+        }
+    }
+
+done:
+
+    ngx_rwlock_unlock(&dict->sh->rwlock);
+
+    return NJS_OK;
+
+fail:
+
+    ngx_rwlock_unlock(&dict->sh->rwlock);
+
+    return NJS_ERROR;
+}
+
+
 static njs_int_t
 njs_js_ext_shared_dict_name(njs_vm_t *vm, njs_object_prop_t *prop,
     njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
index d43a13be0058ff7d34411a80ecb8ad85cbdb3842..1cf794ce093903a120bc17ac7a21a1e98db77f21 100644 (file)
@@ -86,6 +86,10 @@ http {
             js_content test.incr;
         }
 
+        location /items {
+            js_content test.items;
+        }
+
         location /keys {
             js_content test.keys;
         }
@@ -208,6 +212,19 @@ $t->write_file('test.js', <<'EOF');
         r.return(200, `[${ks.toSorted()}]`);
     }
 
+    function items(r) {
+        var kvs;
+
+        if (r.args.max) {
+            kvs = ngx.shared[r.args.dict].items(parseInt(r.args.max));
+
+        } else {
+            kvs = ngx.shared[r.args.dict].items();
+        }
+
+        r.return(200, njs.dump(kvs.toSorted()));
+    }
+
     function name(r) {
         r.return(200, ngx.shared[r.args.dict].name);
     }
@@ -247,11 +264,11 @@ $t->write_file('test.js', <<'EOF');
     }
 
     export default { add, capacity, chain, clear, del, free_space, get, has,
-                     incr, keys, name, njs: test_njs, pop, replace, set, size,
-                     zones };
+                     incr, items, keys, name, njs: test_njs, pop, replace, set,
+                     size, zones };
 EOF
 
-$t->try_run('no js_shared_dict_zone')->plan(41);
+$t->try_run('no js_shared_dict_zone')->plan(43);
 
 ###############################################################################
 
@@ -311,6 +328,10 @@ 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('/items?dict=bar'), qr/\[\['FOO','zzz'],\['FOO2','aaa']]/,
+       'bar items');
+like(http_get('/items?dict=waka'),
+       qr/\[\['FOO',47],\['FOO2',7779],\['FOO3',3338]]/, 'waka items');
 
 }