Skip to content

Commit f928fea

Browse files
committed
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 \openresty#170.
1 parent e607b63 commit f928fea

File tree

3 files changed

+299
-2
lines changed

3 files changed

+299
-2
lines changed

src/ngx_http_lua_shdict.c

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ static int ngx_http_lua_shdict_incr(lua_State *L);
2424
static int ngx_http_lua_shdict_delete(lua_State *L);
2525
static int ngx_http_lua_shdict_flush_all(lua_State *L);
2626
static int ngx_http_lua_shdict_flush_expired(lua_State *L);
27+
static int ngx_http_lua_shdict_get_keys(lua_State *L);
2728

2829

2930
#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)
282283
lua_createtable(L, 0, lmcf->shm_zones->nelts /* nrec */);
283284
/* ngx.shared */
284285

285-
lua_createtable(L, 0 /* narr */, 9 /* nrec */); /* shared mt */
286+
lua_createtable(L, 0 /* narr */, 10 /* nrec */); /* shared mt */
286287

287288
lua_pushcfunction(L, ngx_http_lua_shdict_get);
288289
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)
308309
lua_pushcfunction(L, ngx_http_lua_shdict_flush_expired);
309310
lua_setfield(L, -2, "flush_expired");
310311

312+
lua_pushcfunction(L, ngx_http_lua_shdict_get_keys);
313+
lua_setfield(L, -2, "get_keys");
314+
311315
lua_pushvalue(L, -1); /* shared mt mt */
312316
lua_setfield(L, -2, "__index"); /* shared mt */
313317

@@ -617,6 +621,104 @@ ngx_http_lua_shdict_flush_expired(lua_State *L)
617621
}
618622

619623

624+
/*
625+
* This trades CPU for memory. This is potentially slow. O(2n)
626+
*/
627+
628+
static int
629+
ngx_http_lua_shdict_get_keys(lua_State *L)
630+
{
631+
ngx_queue_t *q, *prev;
632+
ngx_http_lua_shdict_node_t *sd;
633+
ngx_http_lua_shdict_ctx_t *ctx;
634+
ngx_shm_zone_t *zone;
635+
ngx_time_t *tp;
636+
int total = 0;
637+
int attempts = 1024;
638+
uint64_t now;
639+
int n;
640+
641+
n = lua_gettop(L);
642+
643+
if (n != 1 && n != 2) {
644+
return luaL_error(L, "expecting 1 or 2 argument(s), "
645+
"but saw %d", n);
646+
}
647+
648+
luaL_checktype(L, 1, LUA_TLIGHTUSERDATA);
649+
650+
zone = lua_touserdata(L, 1);
651+
if (zone == NULL) {
652+
return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer");
653+
}
654+
655+
if (n == 2) {
656+
attempts = luaL_checknumber(L, 2);
657+
}
658+
659+
ctx = zone->data;
660+
661+
ngx_shmtx_lock(&ctx->shpool->mutex);
662+
663+
if (ngx_queue_empty(&ctx->sh->queue)) {
664+
ngx_shmtx_unlock(&ctx->shpool->mutex);
665+
lua_createtable(L, 0, 0);
666+
return 1;
667+
}
668+
669+
tp = ngx_timeofday();
670+
671+
now = (uint64_t) tp->sec * 1000 + tp->msec;
672+
673+
/* first run through: get total number of elements we need to allocate */
674+
675+
q = ngx_queue_last(&ctx->sh->queue);
676+
677+
while (q != ngx_queue_sentinel(&ctx->sh->queue)) {
678+
prev = ngx_queue_prev(q);
679+
680+
sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue);
681+
682+
if (sd->expires == 0 || sd->expires > now) {
683+
total++;
684+
if (attempts && total == attempts) {
685+
break;
686+
}
687+
}
688+
689+
q = prev;
690+
}
691+
692+
lua_createtable(L, total, 0);
693+
694+
/* second run through: add keys to table */
695+
696+
total = 0;
697+
q = ngx_queue_last(&ctx->sh->queue);
698+
699+
while (q != ngx_queue_sentinel(&ctx->sh->queue)) {
700+
prev = ngx_queue_prev(q);
701+
702+
sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue);
703+
704+
if (sd->expires == 0 || sd->expires > now) {
705+
lua_pushlstring(L, (char *) sd->data, sd->key_len);
706+
lua_rawseti(L, -2, ++total);
707+
if (attempts && total == attempts) {
708+
break;
709+
}
710+
}
711+
712+
q = prev;
713+
}
714+
715+
ngx_shmtx_unlock(&ctx->shpool->mutex);
716+
717+
/* table is at top of stack */
718+
return 1;
719+
}
720+
721+
620722
static int
621723
ngx_http_lua_shdict_add(lua_State *L)
622724
{

t/043-shdict.t

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,3 +1172,198 @@ GET /t
11721172
--- response_body
11731173
0
11741174

1175+
1176+
1177+
=== TEST 49: list all keys in a shdict
1178+
--- http_config
1179+
lua_shared_dict dogs 1m;
1180+
--- config
1181+
location = /t {
1182+
content_by_lua '
1183+
local dogs = ngx.shared.dogs
1184+
1185+
dogs:set("bah", "y", 0)
1186+
dogs:set("bar", "z", 0)
1187+
local keys = dogs:get_keys()
1188+
ngx.say(#keys)
1189+
table.sort(keys)
1190+
for _,k in ipairs(keys) do
1191+
ngx.say(k)
1192+
end
1193+
';
1194+
}
1195+
--- request
1196+
GET /t
1197+
--- response_body
1198+
2
1199+
bah
1200+
bar
1201+
1202+
1203+
1204+
=== TEST 50: list keys in a shdict with limit
1205+
--- http_config
1206+
lua_shared_dict dogs 1m;
1207+
--- config
1208+
location = /t {
1209+
content_by_lua '
1210+
local dogs = ngx.shared.dogs
1211+
1212+
dogs:set("bah", "y", 0)
1213+
dogs:set("bar", "z", 0)
1214+
local keys = dogs:get_keys(1)
1215+
ngx.say(#keys)
1216+
';
1217+
}
1218+
--- request
1219+
GET /t
1220+
--- response_body
1221+
1
1222+
1223+
1224+
1225+
=== TEST 51: list all keys in a shdict with expires
1226+
--- http_config
1227+
lua_shared_dict dogs 1m;
1228+
--- config
1229+
location = /t {
1230+
content_by_lua '
1231+
local dogs = ngx.shared.dogs
1232+
dogs:set("foo", "x", 1)
1233+
dogs:set("bah", "y", 0)
1234+
dogs:set("bar", "z", 100)
1235+
1236+
ngx.sleep(1.5)
1237+
1238+
local keys = dogs:get_keys()
1239+
ngx.say(#keys)
1240+
';
1241+
}
1242+
--- request
1243+
GET /t
1244+
--- response_body
1245+
2
1246+
1247+
1248+
1249+
=== TEST 52: list keys in a shdict with limit larger than number of keys
1250+
--- http_config
1251+
lua_shared_dict dogs 1m;
1252+
--- config
1253+
location = /t {
1254+
content_by_lua '
1255+
local dogs = ngx.shared.dogs
1256+
1257+
dogs:set("bah", "y", 0)
1258+
dogs:set("bar", "z", 0)
1259+
local keys = dogs:get_keys(3)
1260+
ngx.say(#keys)
1261+
';
1262+
}
1263+
--- request
1264+
GET /t
1265+
--- response_body
1266+
2
1267+
1268+
1269+
1270+
=== TEST 53: list keys in an empty shdict
1271+
--- http_config
1272+
lua_shared_dict dogs 1m;
1273+
--- config
1274+
location = /t {
1275+
content_by_lua '
1276+
local dogs = ngx.shared.dogs
1277+
local keys = dogs:get_keys()
1278+
ngx.say(#keys)
1279+
';
1280+
}
1281+
--- request
1282+
GET /t
1283+
--- response_body
1284+
0
1285+
1286+
1287+
1288+
=== TEST 54: list keys in an empty shdict with a limit
1289+
--- http_config
1290+
lua_shared_dict dogs 1m;
1291+
--- config
1292+
location = /t {
1293+
content_by_lua '
1294+
local dogs = ngx.shared.dogs
1295+
local keys = dogs:get_keys(4)
1296+
ngx.say(#keys)
1297+
';
1298+
}
1299+
--- request
1300+
GET /t
1301+
--- response_body
1302+
0
1303+
1304+
1305+
1306+
=== TEST 55: list all keys in a shdict with all keys expired
1307+
--- http_config
1308+
lua_shared_dict dogs 1m;
1309+
--- config
1310+
location = /t {
1311+
content_by_lua '
1312+
local dogs = ngx.shared.dogs
1313+
dogs:set("foo", "x", 1)
1314+
dogs:set("bah", "y", 1)
1315+
dogs:set("bar", "z", 1)
1316+
1317+
ngx.sleep(1.5)
1318+
1319+
local keys = dogs:get_keys()
1320+
ngx.say(#keys)
1321+
';
1322+
}
1323+
--- request
1324+
GET /t
1325+
--- response_body
1326+
0
1327+
1328+
1329+
1330+
=== TEST 56: list all keys in a shdict with more than 1024 keys with no limit set
1331+
--- http_config
1332+
lua_shared_dict dogs 1m;
1333+
--- config
1334+
location = /t {
1335+
content_by_lua '
1336+
local dogs = ngx.shared.dogs
1337+
for i=1,2048 do
1338+
dogs:set(tostring(i), i)
1339+
end
1340+
local keys = dogs:get_keys()
1341+
ngx.say(#keys)
1342+
';
1343+
}
1344+
--- request
1345+
GET /t
1346+
--- response_body
1347+
1024
1348+
1349+
1350+
1351+
=== TEST 57: list all keys in a shdict with more than 1024 keys with 0 limit set
1352+
--- http_config
1353+
lua_shared_dict dogs 1m;
1354+
--- config
1355+
location = /t {
1356+
content_by_lua '
1357+
local dogs = ngx.shared.dogs
1358+
for i=1,2048 do
1359+
dogs:set(tostring(i), i)
1360+
end
1361+
local keys = dogs:get_keys(0)
1362+
ngx.say(#keys)
1363+
';
1364+
}
1365+
--- request
1366+
GET /t
1367+
--- response_body
1368+
2048
1369+

t/062-count.t

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ n = 4
279279
--- request
280280
GET /test
281281
--- response_body
282-
n = 9
282+
n = 10
283283
--- no_error_log
284284
[error]
285285

0 commit comments

Comments
 (0)