Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

feature: added the "get_keys" method for the shared dictionaries for …

…fetching all the (or the specified number of) keys (default to 1024 keys). thanks Brian Akins for the patch in pull \#170.
  • Loading branch information...
commit f928feae8d3b4de4d5790cab06f27e4ca34698f8 1 parent e607b63
@agentzh agentzh authored
Showing with 299 additions and 2 deletions.
  1. +103 −1 src/ngx_http_lua_shdict.c
  2. +195 −0 t/043-shdict.t
  3. +1 −1  t/062-count.t
View
104 src/ngx_http_lua_shdict.c
@@ -24,6 +24,7 @@ static int ngx_http_lua_shdict_incr(lua_State *L);
static int ngx_http_lua_shdict_delete(lua_State *L);
static int ngx_http_lua_shdict_flush_all(lua_State *L);
static int ngx_http_lua_shdict_flush_expired(lua_State *L);
+static int ngx_http_lua_shdict_get_keys(lua_State *L);
#define NGX_HTTP_LUA_SHDICT_ADD 0x0001
@@ -282,7 +283,7 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L)
lua_createtable(L, 0, lmcf->shm_zones->nelts /* nrec */);
/* ngx.shared */
- lua_createtable(L, 0 /* narr */, 9 /* nrec */); /* shared mt */
+ lua_createtable(L, 0 /* narr */, 10 /* nrec */); /* shared mt */
lua_pushcfunction(L, ngx_http_lua_shdict_get);
lua_setfield(L, -2, "get");
@@ -308,6 +309,9 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L)
lua_pushcfunction(L, ngx_http_lua_shdict_flush_expired);
lua_setfield(L, -2, "flush_expired");
+ lua_pushcfunction(L, ngx_http_lua_shdict_get_keys);
+ lua_setfield(L, -2, "get_keys");
+
lua_pushvalue(L, -1); /* shared mt mt */
lua_setfield(L, -2, "__index"); /* shared mt */
@@ -617,6 +621,104 @@ ngx_http_lua_shdict_flush_expired(lua_State *L)
}
+/*
+ * This trades CPU for memory. This is potentially slow. O(2n)
+ */
+
+static int
+ngx_http_lua_shdict_get_keys(lua_State *L)
+{
+ ngx_queue_t *q, *prev;
+ ngx_http_lua_shdict_node_t *sd;
+ ngx_http_lua_shdict_ctx_t *ctx;
+ ngx_shm_zone_t *zone;
+ ngx_time_t *tp;
+ int total = 0;
+ int attempts = 1024;
+ uint64_t now;
+ int n;
+
+ n = lua_gettop(L);
+
+ if (n != 1 && n != 2) {
+ return luaL_error(L, "expecting 1 or 2 argument(s), "
+ "but saw %d", n);
+ }
+
+ luaL_checktype(L, 1, LUA_TLIGHTUSERDATA);
+
+ zone = lua_touserdata(L, 1);
+ if (zone == NULL) {
+ return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer");
+ }
+
+ if (n == 2) {
+ attempts = luaL_checknumber(L, 2);
+ }
+
+ ctx = zone->data;
+
+ ngx_shmtx_lock(&ctx->shpool->mutex);
+
+ if (ngx_queue_empty(&ctx->sh->queue)) {
+ ngx_shmtx_unlock(&ctx->shpool->mutex);
+ lua_createtable(L, 0, 0);
+ return 1;
+ }
+
+ tp = ngx_timeofday();
+
+ now = (uint64_t) tp->sec * 1000 + tp->msec;
+
+ /* first run through: get total number of elements we need to allocate */
+
+ q = ngx_queue_last(&ctx->sh->queue);
+
+ while (q != ngx_queue_sentinel(&ctx->sh->queue)) {
+ prev = ngx_queue_prev(q);
+
+ sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue);
+
+ if (sd->expires == 0 || sd->expires > now) {
+ total++;
+ if (attempts && total == attempts) {
+ break;
+ }
+ }
+
+ q = prev;
+ }
+
+ lua_createtable(L, total, 0);
+
+ /* second run through: add keys to table */
+
+ total = 0;
+ q = ngx_queue_last(&ctx->sh->queue);
+
+ while (q != ngx_queue_sentinel(&ctx->sh->queue)) {
+ prev = ngx_queue_prev(q);
+
+ sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue);
+
+ if (sd->expires == 0 || sd->expires > now) {
+ lua_pushlstring(L, (char *) sd->data, sd->key_len);
+ lua_rawseti(L, -2, ++total);
+ if (attempts && total == attempts) {
+ break;
+ }
+ }
+
+ q = prev;
+ }
+
+ ngx_shmtx_unlock(&ctx->shpool->mutex);
+
+ /* table is at top of stack */
+ return 1;
+}
+
+
static int
ngx_http_lua_shdict_add(lua_State *L)
{
View
195 t/043-shdict.t
@@ -1172,3 +1172,198 @@ GET /t
--- response_body
0
+
+
+=== TEST 49: list all keys in a shdict
+--- http_config
+ lua_shared_dict dogs 1m;
+--- config
+ location = /t {
+ content_by_lua '
+ local dogs = ngx.shared.dogs
+
+ dogs:set("bah", "y", 0)
+ dogs:set("bar", "z", 0)
+ local keys = dogs:get_keys()
+ ngx.say(#keys)
+ table.sort(keys)
+ for _,k in ipairs(keys) do
+ ngx.say(k)
+ end
+ ';
+ }
+--- request
+GET /t
+--- response_body
+2
+bah
+bar
+
+
+
+=== TEST 50: list keys in a shdict with limit
+--- http_config
+ lua_shared_dict dogs 1m;
+--- config
+ location = /t {
+ content_by_lua '
+ local dogs = ngx.shared.dogs
+
+ dogs:set("bah", "y", 0)
+ dogs:set("bar", "z", 0)
+ local keys = dogs:get_keys(1)
+ ngx.say(#keys)
+ ';
+ }
+--- request
+GET /t
+--- response_body
+1
+
+
+
+=== TEST 51: list all keys in a shdict with expires
+--- http_config
+ lua_shared_dict dogs 1m;
+--- config
+ location = /t {
+ content_by_lua '
+ local dogs = ngx.shared.dogs
+ dogs:set("foo", "x", 1)
+ dogs:set("bah", "y", 0)
+ dogs:set("bar", "z", 100)
+
+ ngx.sleep(1.5)
+
+ local keys = dogs:get_keys()
+ ngx.say(#keys)
+ ';
+ }
+--- request
+GET /t
+--- response_body
+2
+
+
+
+=== TEST 52: list keys in a shdict with limit larger than number of keys
+--- http_config
+ lua_shared_dict dogs 1m;
+--- config
+ location = /t {
+ content_by_lua '
+ local dogs = ngx.shared.dogs
+
+ dogs:set("bah", "y", 0)
+ dogs:set("bar", "z", 0)
+ local keys = dogs:get_keys(3)
+ ngx.say(#keys)
+ ';
+ }
+--- request
+GET /t
+--- response_body
+2
+
+
+
+=== TEST 53: list keys in an empty shdict
+--- http_config
+ lua_shared_dict dogs 1m;
+--- config
+ location = /t {
+ content_by_lua '
+ local dogs = ngx.shared.dogs
+ local keys = dogs:get_keys()
+ ngx.say(#keys)
+ ';
+ }
+--- request
+GET /t
+--- response_body
+0
+
+
+
+=== TEST 54: list keys in an empty shdict with a limit
+--- http_config
+ lua_shared_dict dogs 1m;
+--- config
+ location = /t {
+ content_by_lua '
+ local dogs = ngx.shared.dogs
+ local keys = dogs:get_keys(4)
+ ngx.say(#keys)
+ ';
+ }
+--- request
+GET /t
+--- response_body
+0
+
+
+
+=== TEST 55: list all keys in a shdict with all keys expired
+--- http_config
+ lua_shared_dict dogs 1m;
+--- config
+ location = /t {
+ content_by_lua '
+ local dogs = ngx.shared.dogs
+ dogs:set("foo", "x", 1)
+ dogs:set("bah", "y", 1)
+ dogs:set("bar", "z", 1)
+
+ ngx.sleep(1.5)
+
+ local keys = dogs:get_keys()
+ ngx.say(#keys)
+ ';
+ }
+--- request
+GET /t
+--- response_body
+0
+
+
+
+=== TEST 56: list all keys in a shdict with more than 1024 keys with no limit set
+--- http_config
+ lua_shared_dict dogs 1m;
+--- config
+ location = /t {
+ content_by_lua '
+ local dogs = ngx.shared.dogs
+ for i=1,2048 do
+ dogs:set(tostring(i), i)
+ end
+ local keys = dogs:get_keys()
+ ngx.say(#keys)
+ ';
+ }
+--- request
+GET /t
+--- response_body
+1024
+
+
+
+=== TEST 57: list all keys in a shdict with more than 1024 keys with 0 limit set
+--- http_config
+ lua_shared_dict dogs 1m;
+--- config
+ location = /t {
+ content_by_lua '
+ local dogs = ngx.shared.dogs
+ for i=1,2048 do
+ dogs:set(tostring(i), i)
+ end
+ local keys = dogs:get_keys(0)
+ ngx.say(#keys)
+ ';
+ }
+--- request
+GET /t
+--- response_body
+2048
+
View
2  t/062-count.t
@@ -279,7 +279,7 @@ n = 4
--- request
GET /test
--- response_body
-n = 9
+n = 10
--- no_error_log
[error]
Please sign in to comment.
Something went wrong with that request. Please try again.