@@ -24,6 +24,7 @@ static int ngx_http_lua_shdict_incr(lua_State *L);
2424static int ngx_http_lua_shdict_delete (lua_State * L );
2525static int ngx_http_lua_shdict_flush_all (lua_State * L );
2626static 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+
620722static int
621723ngx_http_lua_shdict_add (lua_State * L )
622724{
0 commit comments