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.

This commit is contained in:
agentzh (Yichun Zhang) 2012-10-29 18:09:31 -07:00
Родитель e607b639be
Коммит f928feae8d
3 изменённых файлов: 299 добавлений и 2 удалений

Просмотреть файл

@ -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)
{

Просмотреть файл

@ -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

Просмотреть файл

@ -279,7 +279,7 @@ n = 4
--- request
GET /test
--- response_body
n = 9
n = 10
--- no_error_log
[error]