diff --git a/patch/1.19.9/lua-resty-core-shared_shdict.patch b/patch/1.19.9/lua-resty-core-shared_shdict.patch new file mode 100644 index 0000000..e2b9b7b --- /dev/null +++ b/patch/1.19.9/lua-resty-core-shared_shdict.patch @@ -0,0 +1,157 @@ +diff --git lib/resty/core/shdict.lua lib/resty/core/shdict.lua +index dedf12c..7644b77 100644 +--- lib/resty/core/shdict.lua ++++ lib/resty/core/shdict.lua +@@ -28,7 +28,6 @@ local type = type + local error = error + local getmetatable = getmetatable + local FFI_DECLINED = base.FFI_DECLINED +-local subsystem = ngx.config.subsystem + + + local ngx_lua_ffi_shdict_get +@@ -42,117 +41,56 @@ local ngx_lua_ffi_shdict_free_space + local ngx_lua_ffi_shdict_udata_to_zone + + +-if subsystem == 'http' then +- ffi.cdef[[ +-int ngx_http_lua_ffi_shdict_get(void *zone, const unsigned char *key, ++ffi.cdef[[ ++int ngx_meta_lua_ffi_shdict_get(void *zone, const unsigned char *key, + size_t key_len, int *value_type, unsigned char **str_value_buf, + size_t *str_value_len, double *num_value, int *user_flags, + int get_stale, int *is_stale, char **errmsg); + +-int ngx_http_lua_ffi_shdict_incr(void *zone, const unsigned char *key, ++int ngx_meta_lua_ffi_shdict_incr(void *zone, const unsigned char *key, + size_t key_len, double *value, char **err, int has_init, + double init, long init_ttl, int *forcible); + +-int ngx_http_lua_ffi_shdict_store(void *zone, int op, ++int ngx_meta_lua_ffi_shdict_store(void *zone, int op, + const unsigned char *key, size_t key_len, int value_type, + const unsigned char *str_value_buf, size_t str_value_len, + double num_value, long exptime, int user_flags, char **errmsg, + int *forcible); + +-int ngx_http_lua_ffi_shdict_flush_all(void *zone); ++int ngx_meta_lua_ffi_shdict_flush_all(void *zone); + +-long ngx_http_lua_ffi_shdict_get_ttl(void *zone, ++long ngx_meta_lua_ffi_shdict_get_ttl(void *zone, + const unsigned char *key, size_t key_len); + +-int ngx_http_lua_ffi_shdict_set_expire(void *zone, ++int ngx_meta_lua_ffi_shdict_set_expire(void *zone, + const unsigned char *key, size_t key_len, long exptime); + +-size_t ngx_http_lua_ffi_shdict_capacity(void *zone); +- +-void *ngx_http_lua_ffi_shdict_udata_to_zone(void *zone_udata); +- ]] +- +- ngx_lua_ffi_shdict_get = C.ngx_http_lua_ffi_shdict_get +- ngx_lua_ffi_shdict_incr = C.ngx_http_lua_ffi_shdict_incr +- ngx_lua_ffi_shdict_store = C.ngx_http_lua_ffi_shdict_store +- ngx_lua_ffi_shdict_flush_all = C.ngx_http_lua_ffi_shdict_flush_all +- ngx_lua_ffi_shdict_get_ttl = C.ngx_http_lua_ffi_shdict_get_ttl +- ngx_lua_ffi_shdict_set_expire = C.ngx_http_lua_ffi_shdict_set_expire +- ngx_lua_ffi_shdict_capacity = C.ngx_http_lua_ffi_shdict_capacity +- ngx_lua_ffi_shdict_udata_to_zone = +- C.ngx_http_lua_ffi_shdict_udata_to_zone +- +- if not pcall(function () +- return C.ngx_http_lua_ffi_shdict_free_space +- end) +- then +- ffi.cdef[[ +-size_t ngx_http_lua_ffi_shdict_free_space(void *zone); +- ]] +- end +- +- pcall(function () +- ngx_lua_ffi_shdict_free_space = C.ngx_http_lua_ffi_shdict_free_space +- end) ++size_t ngx_meta_lua_ffi_shdict_capacity(void *zone); + +-elseif subsystem == 'stream' then ++void *ngx_meta_lua_ffi_shdict_udata_to_zone(void *zone_udata); ++]] + ++if not pcall(function () ++ return C.ngx_meta_lua_ffi_shdict_free_space ++end) ++then + ffi.cdef[[ +-int ngx_stream_lua_ffi_shdict_get(void *zone, const unsigned char *key, +- size_t key_len, int *value_type, unsigned char **str_value_buf, +- size_t *str_value_len, double *num_value, int *user_flags, +- int get_stale, int *is_stale, char **errmsg); +- +-int ngx_stream_lua_ffi_shdict_incr(void *zone, const unsigned char *key, +- size_t key_len, double *value, char **err, int has_init, +- double init, long init_ttl, int *forcible); +- +-int ngx_stream_lua_ffi_shdict_store(void *zone, int op, +- const unsigned char *key, size_t key_len, int value_type, +- const unsigned char *str_value_buf, size_t str_value_len, +- double num_value, long exptime, int user_flags, char **errmsg, +- int *forcible); +- +-int ngx_stream_lua_ffi_shdict_flush_all(void *zone); +- +-long ngx_stream_lua_ffi_shdict_get_ttl(void *zone, +- const unsigned char *key, size_t key_len); +- +-int ngx_stream_lua_ffi_shdict_set_expire(void *zone, +- const unsigned char *key, size_t key_len, long exptime); +- +-size_t ngx_stream_lua_ffi_shdict_capacity(void *zone); +- +-void *ngx_stream_lua_ffi_shdict_udata_to_zone(void *zone_udata); ++size_t ngx_meta_lua_ffi_shdict_free_space(void *zone); + ]] +- +- ngx_lua_ffi_shdict_get = C.ngx_stream_lua_ffi_shdict_get +- ngx_lua_ffi_shdict_incr = C.ngx_stream_lua_ffi_shdict_incr +- ngx_lua_ffi_shdict_store = C.ngx_stream_lua_ffi_shdict_store +- ngx_lua_ffi_shdict_flush_all = C.ngx_stream_lua_ffi_shdict_flush_all +- ngx_lua_ffi_shdict_get_ttl = C.ngx_stream_lua_ffi_shdict_get_ttl +- ngx_lua_ffi_shdict_set_expire = C.ngx_stream_lua_ffi_shdict_set_expire +- ngx_lua_ffi_shdict_capacity = C.ngx_stream_lua_ffi_shdict_capacity +- ngx_lua_ffi_shdict_udata_to_zone = +- C.ngx_stream_lua_ffi_shdict_udata_to_zone +- +- if not pcall(function () +- return C.ngx_stream_lua_ffi_shdict_free_space +- end) +- then +- ffi.cdef[[ +-size_t ngx_stream_lua_ffi_shdict_free_space(void *zone); +- ]] +- end +- +- -- ngx_stream_lua is only compatible with NGINX >= 1.13.6, meaning it +- -- cannot lack support for ngx_stream_lua_ffi_shdict_free_space. +- ngx_lua_ffi_shdict_free_space = C.ngx_stream_lua_ffi_shdict_free_space +- +-else +- error("unknown subsystem: " .. subsystem) + end + ++pcall(function () ++ ngx_lua_ffi_shdict_get = C.ngx_meta_lua_ffi_shdict_get ++ ngx_lua_ffi_shdict_incr = C.ngx_meta_lua_ffi_shdict_incr ++ ngx_lua_ffi_shdict_store = C.ngx_meta_lua_ffi_shdict_store ++ ngx_lua_ffi_shdict_flush_all = C.ngx_meta_lua_ffi_shdict_flush_all ++ ngx_lua_ffi_shdict_get_ttl = C.ngx_meta_lua_ffi_shdict_get_ttl ++ ngx_lua_ffi_shdict_set_expire = C.ngx_meta_lua_ffi_shdict_set_expire ++ ngx_lua_ffi_shdict_capacity = C.ngx_meta_lua_ffi_shdict_capacity ++ ngx_lua_ffi_shdict_free_space = C.ngx_meta_lua_ffi_shdict_free_space ++ ngx_lua_ffi_shdict_udata_to_zone = C.ngx_meta_lua_ffi_shdict_udata_to_zone ++end) ++ + if not pcall(function () return C.free end) then + ffi.cdef[[ + void free(void *ptr); diff --git a/patch/1.19.9/ngx_lua-shared_shdict.patch b/patch/1.19.9/ngx_lua-shared_shdict.patch new file mode 100644 index 0000000..0af5ce4 --- /dev/null +++ b/patch/1.19.9/ngx_lua-shared_shdict.patch @@ -0,0 +1,2997 @@ +diff --git config config +index 4b32d383..06ec0da0 100644 +--- config ++++ config +@@ -268,7 +268,6 @@ HTTP_LUA_SRCS=" \ + $ngx_addon_dir/src/ngx_http_lua_clfactory.c \ + $ngx_addon_dir/src/ngx_http_lua_pcrefix.c \ + $ngx_addon_dir/src/ngx_http_lua_headerfilterby.c \ +- $ngx_addon_dir/src/ngx_http_lua_shdict.c \ + $ngx_addon_dir/src/ngx_http_lua_socket_tcp.c \ + $ngx_addon_dir/src/ngx_http_lua_api.c \ + $ngx_addon_dir/src/ngx_http_lua_logby.c \ +@@ -330,7 +329,6 @@ HTTP_LUA_DEPS=" \ + $ngx_addon_dir/src/ngx_http_lua_clfactory.h \ + $ngx_addon_dir/src/ngx_http_lua_pcrefix.h \ + $ngx_addon_dir/src/ngx_http_lua_headerfilterby.h \ +- $ngx_addon_dir/src/ngx_http_lua_shdict.h \ + $ngx_addon_dir/src/ngx_http_lua_socket_tcp.h \ + $ngx_addon_dir/src/api/ngx_http_lua_api.h \ + $ngx_addon_dir/src/ngx_http_lua_logby.h \ +diff --git src/api/ngx_http_lua_api.h src/api/ngx_http_lua_api.h +index 43f90bd0..7530add0 100644 +--- src/api/ngx_http_lua_api.h ++++ src/api/ngx_http_lua_api.h +@@ -48,14 +48,6 @@ ngx_http_request_t *ngx_http_lua_get_request(lua_State *L); + ngx_int_t ngx_http_lua_add_package_preload(ngx_conf_t *cf, const char *package, + lua_CFunction func); + +-ngx_int_t ngx_http_lua_shared_dict_get(ngx_shm_zone_t *shm_zone, +- u_char *key_data, size_t key_len, ngx_http_lua_value_t *value); +- +-ngx_shm_zone_t *ngx_http_lua_find_zone(u_char *name_data, size_t name_len); +- +-ngx_shm_zone_t *ngx_http_lua_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, +- size_t size, void *tag); +- + + #endif /* _NGX_HTTP_LUA_API_H_INCLUDED_ */ + +diff --git src/ngx_http_lua_api.c src/ngx_http_lua_api.c +index b69d627d..691b3212 100644 +--- src/ngx_http_lua_api.c ++++ src/ngx_http_lua_api.c +@@ -12,7 +12,6 @@ + + #include "ngx_http_lua_common.h" + #include "api/ngx_http_lua_api.h" +-#include "ngx_http_lua_shdict.h" + #include "ngx_http_lua_util.h" + + +@@ -34,10 +33,6 @@ ngx_http_lua_get_request(lua_State *L) + } + + +-static ngx_int_t ngx_http_lua_shared_memory_init(ngx_shm_zone_t *shm_zone, +- void *data); +- +- + ngx_int_t + ngx_http_lua_add_package_preload(ngx_conf_t *cf, const char *package, + lua_CFunction func) +@@ -83,134 +78,4 @@ ngx_http_lua_add_package_preload(ngx_conf_t *cf, const char *package, + } + + +-ngx_shm_zone_t * +-ngx_http_lua_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, +- void *tag) +-{ +- ngx_http_lua_main_conf_t *lmcf; +- ngx_shm_zone_t **zp; +- ngx_shm_zone_t *zone; +- ngx_http_lua_shm_zone_ctx_t *ctx; +- ngx_int_t n; +- +- lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); +- if (lmcf == NULL) { +- return NULL; +- } +- +- if (lmcf->shm_zones == NULL) { +- lmcf->shm_zones = ngx_palloc(cf->pool, sizeof(ngx_array_t)); +- if (lmcf->shm_zones == NULL) { +- return NULL; +- } +- +- if (ngx_array_init(lmcf->shm_zones, cf->pool, 2, +- sizeof(ngx_shm_zone_t *)) +- != NGX_OK) +- { +- return NULL; +- } +- } +- +- zone = ngx_shared_memory_add(cf, name, (size_t) size, tag); +- if (zone == NULL) { +- return NULL; +- } +- +- if (zone->data) { +- ctx = (ngx_http_lua_shm_zone_ctx_t *) zone->data; +- return &ctx->zone; +- } +- +- n = sizeof(ngx_http_lua_shm_zone_ctx_t); +- +- ctx = ngx_pcalloc(cf->pool, n); +- if (ctx == NULL) { +- return NULL; +- } +- +- ctx->lmcf = lmcf; +- ctx->log = &cf->cycle->new_log; +- ctx->cycle = cf->cycle; +- +- ngx_memcpy(&ctx->zone, zone, sizeof(ngx_shm_zone_t)); +- +- zp = ngx_array_push(lmcf->shm_zones); +- if (zp == NULL) { +- return NULL; +- } +- +- *zp = zone; +- +- /* set zone init */ +- zone->init = ngx_http_lua_shared_memory_init; +- zone->data = ctx; +- +- lmcf->requires_shm = 1; +- +- return &ctx->zone; +-} +- +- +-static ngx_int_t +-ngx_http_lua_shared_memory_init(ngx_shm_zone_t *shm_zone, void *data) +-{ +- ngx_http_lua_shm_zone_ctx_t *octx = data; +- ngx_shm_zone_t *ozone; +- void *odata; +- +- ngx_int_t rc; +- volatile ngx_cycle_t *saved_cycle; +- ngx_http_lua_main_conf_t *lmcf; +- ngx_http_lua_shm_zone_ctx_t *ctx; +- ngx_shm_zone_t *zone; +- +- ctx = (ngx_http_lua_shm_zone_ctx_t *) shm_zone->data; +- zone = &ctx->zone; +- +- odata = NULL; +- if (octx) { +- ozone = &octx->zone; +- odata = ozone->data; +- } +- +- zone->shm = shm_zone->shm; +-#if (nginx_version >= 1009000) +- zone->noreuse = shm_zone->noreuse; +-#endif +- +- if (zone->init(zone, odata) != NGX_OK) { +- return NGX_ERROR; +- } +- +- dd("get lmcf"); +- +- lmcf = ctx->lmcf; +- if (lmcf == NULL) { +- return NGX_ERROR; +- } +- +- dd("lmcf->lua: %p", lmcf->lua); +- +- lmcf->shm_zones_inited++; +- +- if (lmcf->shm_zones_inited == lmcf->shm_zones->nelts +- && lmcf->init_handler && !ngx_test_config) +- { +- saved_cycle = ngx_cycle; +- ngx_cycle = ctx->cycle; +- +- rc = lmcf->init_handler(ctx->log, lmcf, lmcf->lua); +- +- ngx_cycle = saved_cycle; +- +- if (rc != NGX_OK) { +- /* an error happened */ +- return NGX_ERROR; +- } +- } +- +- return NGX_OK; +-} +- + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ +diff --git src/ngx_http_lua_common.h src/ngx_http_lua_common.h +index 0751a112..1e2e4fe1 100644 +--- src/ngx_http_lua_common.h ++++ src/ngx_http_lua_common.h +@@ -23,6 +23,8 @@ + #include + #include + ++#include "ngx_meta_lua_api.h" ++ + + #if defined(NDK) && NDK + #include +@@ -67,6 +69,10 @@ typedef struct { + # error at least nginx 1.6.0 is required but found an older version + #endif + ++#if !defined(ngx_meta_lua_version) || ngx_meta_lua_version < 00001 ++# error ngx_meta_lua_module 0.0.1 or above is required ++#endif ++ + #if LUA_VERSION_NUM != 501 + # error unsupported Lua language version + #endif +@@ -169,9 +175,6 @@ typedef struct ngx_http_lua_posted_thread_s ngx_http_lua_posted_thread_t; + typedef struct ngx_http_lua_balancer_peer_data_s + ngx_http_lua_balancer_peer_data_t; + +-typedef ngx_int_t (*ngx_http_lua_main_conf_handler_pt)(ngx_log_t *log, +- ngx_http_lua_main_conf_t *lmcf, lua_State *L); +- + typedef ngx_int_t (*ngx_http_lua_srv_conf_handler_pt)(ngx_http_request_t *r, + ngx_http_lua_srv_conf_t *lscf, lua_State *L); + +@@ -221,22 +224,18 @@ struct ngx_http_lua_main_conf_s { + # endif + #endif + +- ngx_array_t *shm_zones; /* of ngx_shm_zone_t* */ +- +- ngx_array_t *shdict_zones; /* shm zones of "shdict" */ +- + ngx_array_t *preload_hooks; /* of ngx_http_lua_preload_hook_t */ + + ngx_flag_t postponed_to_rewrite_phase_end; + ngx_flag_t postponed_to_access_phase_end; + +- ngx_http_lua_main_conf_handler_pt init_handler; ++ ngx_meta_lua_main_conf_handler_pt init_handler; + ngx_str_t init_src; + +- ngx_http_lua_main_conf_handler_pt init_worker_handler; ++ ngx_meta_lua_main_conf_handler_pt init_worker_handler; + ngx_str_t init_worker_src; + +- ngx_http_lua_main_conf_handler_pt exit_worker_handler; ++ ngx_meta_lua_main_conf_handler_pt exit_worker_handler; + ngx_str_t exit_worker_src; + + ngx_http_lua_balancer_peer_data_t *balancer_peer_data; +@@ -267,8 +266,6 @@ struct ngx_http_lua_main_conf_s { + * main conf. + */ + +- ngx_uint_t shm_zones_inited; +- + ngx_http_lua_sema_mm_t *sema_mm; + + ngx_uint_t malloc_trim_cycle; /* a cycle is defined as the number +@@ -294,7 +291,6 @@ struct ngx_http_lua_main_conf_s { + unsigned requires_rewrite:1; + unsigned requires_access:1; + unsigned requires_log:1; +- unsigned requires_shm:1; + unsigned requires_capture_log:1; + }; + +diff --git src/ngx_http_lua_directive.c src/ngx_http_lua_directive.c +index 1ec641e0..6d4329a1 100644 +--- src/ngx_http_lua_directive.c ++++ src/ngx_http_lua_directive.c +@@ -24,7 +24,6 @@ + #include "ngx_http_lua_initby.h" + #include "ngx_http_lua_initworkerby.h" + #include "ngx_http_lua_exitworkerby.h" +-#include "ngx_http_lua_shdict.h" + #include "ngx_http_lua_ssl_certby.h" + #include "ngx_http_lua_lex.h" + #include "api/ngx_http_lua_api.h" +@@ -71,91 +70,6 @@ enum { + }; + + +-char * +-ngx_http_lua_shared_dict(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +-{ +- ngx_http_lua_main_conf_t *lmcf = conf; +- +- ngx_str_t *value, name; +- ngx_shm_zone_t *zone; +- ngx_shm_zone_t **zp; +- ngx_http_lua_shdict_ctx_t *ctx; +- ssize_t size; +- +- if (lmcf->shdict_zones == NULL) { +- lmcf->shdict_zones = ngx_palloc(cf->pool, sizeof(ngx_array_t)); +- if (lmcf->shdict_zones == NULL) { +- return NGX_CONF_ERROR; +- } +- +- if (ngx_array_init(lmcf->shdict_zones, cf->pool, 2, +- sizeof(ngx_shm_zone_t *)) +- != NGX_OK) +- { +- return NGX_CONF_ERROR; +- } +- } +- +- value = cf->args->elts; +- +- ctx = NULL; +- +- if (value[1].len == 0) { +- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, +- "invalid lua shared dict name \"%V\"", &value[1]); +- return NGX_CONF_ERROR; +- } +- +- name = value[1]; +- +- size = ngx_parse_size(&value[2]); +- +- if (size <= 8191) { +- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, +- "invalid lua shared dict size \"%V\"", &value[2]); +- return NGX_CONF_ERROR; +- } +- +- ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_lua_shdict_ctx_t)); +- if (ctx == NULL) { +- return NGX_CONF_ERROR; +- } +- +- ctx->name = name; +- ctx->main_conf = lmcf; +- ctx->log = &cf->cycle->new_log; +- +- zone = ngx_http_lua_shared_memory_add(cf, &name, (size_t) size, +- &ngx_http_lua_module); +- if (zone == NULL) { +- return NGX_CONF_ERROR; +- } +- +- if (zone->data) { +- ctx = zone->data; +- +- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, +- "lua_shared_dict \"%V\" is already defined as " +- "\"%V\"", &name, &ctx->name); +- return NGX_CONF_ERROR; +- } +- +- zone->init = ngx_http_lua_shdict_init_zone; +- zone->data = ctx; +- +- zp = ngx_array_push(lmcf->shdict_zones); +- if (zp == NULL) { +- return NGX_CONF_ERROR; +- } +- +- *zp = zone; +- +- lmcf->requires_shm = 1; +- +- return NGX_CONF_OK; +-} +- +- + char * + ngx_http_lua_code_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) + { +@@ -191,6 +105,15 @@ ngx_http_lua_load_resty_core(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) + } + + ++char * ++ngx_http_lua_shdict_directive(ngx_conf_t *cf, ngx_command_t *cmd, ++ void *conf) ++{ ++ return ngx_meta_lua_shdict_directive_helper(cf, ++ &ngx_http_lua_module); ++} ++ ++ + char * + ngx_http_lua_package_cpath(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) + { +@@ -1121,7 +1044,7 @@ ngx_http_lua_init_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + return NGX_CONF_ERROR; + } + +- lmcf->init_handler = (ngx_http_lua_main_conf_handler_pt) cmd->post; ++ lmcf->init_handler = (ngx_meta_lua_main_conf_handler_pt) cmd->post; + + if (cmd->post == ngx_http_lua_init_by_file) { + name = ngx_http_lua_rebase_path(cf->pool, value[1].data, +@@ -1181,7 +1104,7 @@ ngx_http_lua_init_worker_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + + value = cf->args->elts; + +- lmcf->init_worker_handler = (ngx_http_lua_main_conf_handler_pt) cmd->post; ++ lmcf->init_worker_handler = (ngx_meta_lua_main_conf_handler_pt) cmd->post; + + if (cmd->post == ngx_http_lua_init_worker_by_file) { + name = ngx_http_lua_rebase_path(cf->pool, value[1].data, +@@ -1239,7 +1162,7 @@ ngx_http_lua_exit_worker_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + + value = cf->args->elts; + +- lmcf->exit_worker_handler = (ngx_http_lua_main_conf_handler_pt) cmd->post; ++ lmcf->exit_worker_handler = (ngx_meta_lua_main_conf_handler_pt) cmd->post; + + if (cmd->post == ngx_http_lua_exit_worker_by_file) { + name = ngx_http_lua_rebase_path(cf->pool, value[1].data, +diff --git src/ngx_http_lua_directive.h src/ngx_http_lua_directive.h +index adfba127..83d082ee 100644 +--- src/ngx_http_lua_directive.h ++++ src/ngx_http_lua_directive.h +@@ -12,7 +12,7 @@ + #include "ngx_http_lua_common.h" + + +-char *ngx_http_lua_shared_dict(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); ++char *ngx_http_lua_shdict_directive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + char *ngx_http_lua_package_cpath(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + char *ngx_http_lua_package_path(ngx_conf_t *cf, ngx_command_t *cmd, +diff --git src/ngx_http_lua_exitworkerby.c src/ngx_http_lua_exitworkerby.c +index cd59dc4b..9765c218 100644 +--- src/ngx_http_lua_exitworkerby.c ++++ src/ngx_http_lua_exitworkerby.c +@@ -67,7 +67,8 @@ ngx_http_lua_exit_worker(ngx_cycle_t *cycle) + + ngx_http_lua_set_req(lmcf->lua, r); + +- (void) lmcf->exit_worker_handler(cycle->log, lmcf, lmcf->lua); ++ (void) lmcf->exit_worker_handler(cycle->log, lmcf->exit_worker_src, ++ lmcf->lua); + + ngx_destroy_pool(c->pool); + return; +@@ -84,12 +85,12 @@ failed: + + ngx_int_t + ngx_http_lua_exit_worker_by_inline(ngx_log_t *log, +- ngx_http_lua_main_conf_t *lmcf, lua_State *L) ++ ngx_str_t init_src, lua_State *L) + { + int status; + +- status = luaL_loadbuffer(L, (char *) lmcf->exit_worker_src.data, +- lmcf->exit_worker_src.len, "=exit_worker_by_lua") ++ status = luaL_loadbuffer(L, (char *) init_src.data, init_src.len, ++ "=exit_worker_by_lua") + || ngx_http_lua_do_call(log, L); + + return ngx_http_lua_report(log, L, status, "exit_worker_by_lua"); +@@ -97,12 +98,12 @@ ngx_http_lua_exit_worker_by_inline(ngx_log_t *log, + + + ngx_int_t +-ngx_http_lua_exit_worker_by_file(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, ++ngx_http_lua_exit_worker_by_file(ngx_log_t *log, ngx_str_t init_src, + lua_State *L) + { + int status; + +- status = luaL_loadfile(L, (char *) lmcf->exit_worker_src.data) ++ status = luaL_loadfile(L, (char *) init_src.data) + || ngx_http_lua_do_call(log, L); + + return ngx_http_lua_report(log, L, status, "exit_worker_by_lua_file"); +diff --git src/ngx_http_lua_exitworkerby.h src/ngx_http_lua_exitworkerby.h +index 3a4274c0..ad8f63b6 100644 +--- src/ngx_http_lua_exitworkerby.h ++++ src/ngx_http_lua_exitworkerby.h +@@ -12,10 +12,10 @@ + + + ngx_int_t ngx_http_lua_exit_worker_by_inline(ngx_log_t *log, +- ngx_http_lua_main_conf_t *lmcf, lua_State *L); ++ ngx_str_t init_src, lua_State *L); + + ngx_int_t ngx_http_lua_exit_worker_by_file(ngx_log_t *log, +- ngx_http_lua_main_conf_t *lmcf, lua_State *L); ++ ngx_str_t init_src, lua_State *L); + + void ngx_http_lua_exit_worker(ngx_cycle_t *cycle); + +diff --git src/ngx_http_lua_headerfilterby.c src/ngx_http_lua_headerfilterby.c +index 4741c722..ed0c3a6c 100644 +--- src/ngx_http_lua_headerfilterby.c ++++ src/ngx_http_lua_headerfilterby.c +@@ -19,7 +19,6 @@ + #include "ngx_http_lua_string.h" + #include "ngx_http_lua_misc.h" + #include "ngx_http_lua_consts.h" +-#include "ngx_http_lua_shdict.h" + + + static ngx_http_output_header_filter_pt ngx_http_next_header_filter; +diff --git src/ngx_http_lua_initby.c src/ngx_http_lua_initby.c +index e8941da6..4e8d898f 100644 +--- src/ngx_http_lua_initby.c ++++ src/ngx_http_lua_initby.c +@@ -14,13 +14,13 @@ + + + ngx_int_t +-ngx_http_lua_init_by_inline(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, ++ngx_http_lua_init_by_inline(ngx_log_t *log, ngx_str_t init_src, + lua_State *L) + { + int status; + +- status = luaL_loadbuffer(L, (char *) lmcf->init_src.data, +- lmcf->init_src.len, "=init_by_lua") ++ status = luaL_loadbuffer(L, (char *) init_src.data, init_src.len, ++ "=init_by_lua") + || ngx_http_lua_do_call(log, L); + + return ngx_http_lua_report(log, L, status, "init_by_lua"); +@@ -28,12 +28,12 @@ ngx_http_lua_init_by_inline(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, + + + ngx_int_t +-ngx_http_lua_init_by_file(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, ++ngx_http_lua_init_by_file(ngx_log_t *log, ngx_str_t init_src, + lua_State *L) + { + int status; + +- status = luaL_loadfile(L, (char *) lmcf->init_src.data) ++ status = luaL_loadfile(L, (char *) init_src.data) + || ngx_http_lua_do_call(log, L); + + return ngx_http_lua_report(log, L, status, "init_by_lua_file"); +diff --git src/ngx_http_lua_initby.h src/ngx_http_lua_initby.h +index 67ac0b6c..cbd439aa 100644 +--- src/ngx_http_lua_initby.h ++++ src/ngx_http_lua_initby.h +@@ -12,10 +12,10 @@ + + + ngx_int_t ngx_http_lua_init_by_inline(ngx_log_t *log, +- ngx_http_lua_main_conf_t *lmcf, lua_State *L); ++ ngx_str_t init_src, lua_State *L); + + ngx_int_t ngx_http_lua_init_by_file(ngx_log_t *log, +- ngx_http_lua_main_conf_t *lmcf, lua_State *L); ++ ngx_str_t init_src, lua_State *L); + + + #endif /* _NGX_HTTP_LUA_INITBY_H_INCLUDED_ */ +diff --git src/ngx_http_lua_initworkerby.c src/ngx_http_lua_initworkerby.c +index 94de796a..bba63c5b 100644 +--- src/ngx_http_lua_initworkerby.c ++++ src/ngx_http_lua_initworkerby.c +@@ -293,7 +293,8 @@ ngx_http_lua_init_worker(ngx_cycle_t *cycle) + + ngx_http_lua_set_req(lmcf->lua, r); + +- (void) lmcf->init_worker_handler(cycle->log, lmcf, lmcf->lua); ++ (void) lmcf->init_worker_handler(cycle->log, lmcf->init_worker_src, ++ lmcf->lua); + + ngx_destroy_pool(c->pool); + return NGX_OK; +@@ -314,12 +315,12 @@ failed: + + ngx_int_t + ngx_http_lua_init_worker_by_inline(ngx_log_t *log, +- ngx_http_lua_main_conf_t *lmcf, lua_State *L) ++ ngx_str_t init_worker_src, lua_State *L) + { + int status; + +- status = luaL_loadbuffer(L, (char *) lmcf->init_worker_src.data, +- lmcf->init_worker_src.len, "=init_worker_by_lua") ++ status = luaL_loadbuffer(L, (char *) init_worker_src.data, ++ init_worker_src.len, "=init_worker_by_lua") + || ngx_http_lua_do_call(log, L); + + return ngx_http_lua_report(log, L, status, "init_worker_by_lua"); +@@ -327,12 +328,12 @@ ngx_http_lua_init_worker_by_inline(ngx_log_t *log, + + + ngx_int_t +-ngx_http_lua_init_worker_by_file(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, +- lua_State *L) ++ngx_http_lua_init_worker_by_file(ngx_log_t *log, ++ ngx_str_t init_worker_src, lua_State *L) + { + int status; + +- status = luaL_loadfile(L, (char *) lmcf->init_worker_src.data) ++ status = luaL_loadfile(L, (char *) init_worker_src.data) + || ngx_http_lua_do_call(log, L); + + return ngx_http_lua_report(log, L, status, "init_worker_by_lua_file"); +diff --git src/ngx_http_lua_initworkerby.h src/ngx_http_lua_initworkerby.h +index 40b2db0e..d4c399cf 100644 +--- src/ngx_http_lua_initworkerby.h ++++ src/ngx_http_lua_initworkerby.h +@@ -12,10 +12,10 @@ + + + ngx_int_t ngx_http_lua_init_worker_by_inline(ngx_log_t *log, +- ngx_http_lua_main_conf_t *lmcf, lua_State *L); ++ ngx_str_t init_worker_src, lua_State *L); + + ngx_int_t ngx_http_lua_init_worker_by_file(ngx_log_t *log, +- ngx_http_lua_main_conf_t *lmcf, lua_State *L); ++ ngx_str_t init_worker_src, lua_State *L); + + ngx_int_t ngx_http_lua_init_worker(ngx_cycle_t *cycle); + +diff --git src/ngx_http_lua_logby.c src/ngx_http_lua_logby.c +index b47058be..a31d424b 100644 +--- src/ngx_http_lua_logby.c ++++ src/ngx_http_lua_logby.c +@@ -21,7 +21,6 @@ + #include "ngx_http_lua_string.h" + #include "ngx_http_lua_misc.h" + #include "ngx_http_lua_consts.h" +-#include "ngx_http_lua_shdict.h" + #if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM) + #include + #endif +diff --git src/ngx_http_lua_module.c src/ngx_http_lua_module.c +index 7358a956..857deb45 100644 +--- src/ngx_http_lua_module.c ++++ src/ngx_http_lua_module.c +@@ -11,6 +11,7 @@ + #include "ddebug.h" + + ++#include "ngx_meta_lua_api.h" + #include "ngx_http_lua_directive.h" + #include "ngx_http_lua_capturefilter.h" + #include "ngx_http_lua_contentby.h" +@@ -108,7 +109,7 @@ static ngx_command_t ngx_http_lua_cmds[] = { + + { ngx_string("lua_shared_dict"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE2, +- ngx_http_lua_shared_dict, ++ ngx_http_lua_shdict_directive, + 0, + 0, + NULL }, +@@ -671,7 +672,6 @@ ngx_http_lua_init(ngx_conf_t *cf) + ngx_int_t rc; + ngx_array_t *arr; + ngx_http_handler_pt *h; +- volatile ngx_cycle_t *saved_cycle; + ngx_http_core_main_conf_t *cmcf; + ngx_http_lua_main_conf_t *lmcf; + ngx_pool_cleanup_t *cln; +@@ -850,18 +850,11 @@ ngx_http_lua_init(ngx_conf_t *cf) + + ngx_http_lua_assert(lmcf->lua != NULL); + +- if (!lmcf->requires_shm && lmcf->init_handler) { +- saved_cycle = ngx_cycle; +- ngx_cycle = cf->cycle; +- +- rc = lmcf->init_handler(cf->log, lmcf, lmcf->lua); +- +- ngx_cycle = saved_cycle; +- +- if (rc != NGX_OK) { +- /* an error happened */ +- return NGX_ERROR; +- } ++ if (ngx_meta_lua_post_init_handler(cf, lmcf->init_handler, ++ lmcf->init_src, lmcf->lua) ++ != NGX_OK) ++ { ++ return NGX_ERROR; + } + + dd("Lua VM initialized!"); +@@ -921,11 +914,8 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) + * lmcf->watcher = NULL; + * lmcf->regex_cache_entries = 0; + * lmcf->jit_stack = NULL; +- * lmcf->shm_zones = NULL; + * lmcf->init_handler = NULL; + * lmcf->init_src = { 0, NULL }; +- * lmcf->shm_zones_inited = 0; +- * lmcf->shdict_zones = NULL; + * lmcf->preload_hooks = NULL; + * lmcf->requires_header_filter = 0; + * lmcf->requires_body_filter = 0; +@@ -933,7 +923,6 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) + * lmcf->requires_rewrite = 0; + * lmcf->requires_access = 0; + * lmcf->requires_log = 0; +- * lmcf->requires_shm = 0; + */ + + lmcf->pool = cf->pool; +diff --git src/ngx_http_lua_setby.c src/ngx_http_lua_setby.c +index f00468c9..c6ef36f4 100644 +--- src/ngx_http_lua_setby.c ++++ src/ngx_http_lua_setby.c +@@ -19,7 +19,6 @@ + #include "ngx_http_lua_string.h" + #include "ngx_http_lua_misc.h" + #include "ngx_http_lua_consts.h" +-#include "ngx_http_lua_shdict.h" + #include "ngx_http_lua_util.h" + + +diff --git src/ngx_http_lua_shdict.c src/ngx_http_lua_shdict.c +deleted file mode 100644 +index 07effa88..00000000 +--- src/ngx_http_lua_shdict.c ++++ /dev/null +@@ -1,2100 +0,0 @@ +- +-/* +- * Copyright (C) Yichun Zhang (agentzh) +- */ +- +- +-#ifndef DDEBUG +-#define DDEBUG 0 +-#endif +-#include "ddebug.h" +- +- +-#include "ngx_http_lua_shdict.h" +-#include "ngx_http_lua_util.h" +-#include "ngx_http_lua_api.h" +- +- +-static int ngx_http_lua_shdict_expire(ngx_http_lua_shdict_ctx_t *ctx, +- ngx_uint_t n); +-static ngx_int_t ngx_http_lua_shdict_lookup(ngx_shm_zone_t *shm_zone, +- ngx_uint_t hash, u_char *kdata, size_t klen, +- ngx_http_lua_shdict_node_t **sdp); +-static int ngx_http_lua_shdict_flush_expired(lua_State *L); +-static int ngx_http_lua_shdict_get_keys(lua_State *L); +-static int ngx_http_lua_shdict_lpush(lua_State *L); +-static int ngx_http_lua_shdict_rpush(lua_State *L); +-static int ngx_http_lua_shdict_push_helper(lua_State *L, int flags); +-static int ngx_http_lua_shdict_lpop(lua_State *L); +-static int ngx_http_lua_shdict_rpop(lua_State *L); +-static int ngx_http_lua_shdict_pop_helper(lua_State *L, int flags); +-static int ngx_http_lua_shdict_llen(lua_State *L); +- +- +-static ngx_inline ngx_shm_zone_t *ngx_http_lua_shdict_get_zone(lua_State *L, +- int index); +- +- +-#define NGX_HTTP_LUA_SHDICT_ADD 0x0001 +-#define NGX_HTTP_LUA_SHDICT_REPLACE 0x0002 +-#define NGX_HTTP_LUA_SHDICT_SAFE_STORE 0x0004 +- +- +-#define NGX_HTTP_LUA_SHDICT_LEFT 0x0001 +-#define NGX_HTTP_LUA_SHDICT_RIGHT 0x0002 +- +- +-enum { +- SHDICT_USERDATA_INDEX = 1, +-}; +- +- +-enum { +- SHDICT_TNIL = 0, /* same as LUA_TNIL */ +- SHDICT_TBOOLEAN = 1, /* same as LUA_TBOOLEAN */ +- SHDICT_TNUMBER = 3, /* same as LUA_TNUMBER */ +- SHDICT_TSTRING = 4, /* same as LUA_TSTRING */ +- SHDICT_TLIST = 5, +-}; +- +- +-static ngx_inline ngx_queue_t * +-ngx_http_lua_shdict_get_list_head(ngx_http_lua_shdict_node_t *sd, size_t len) +-{ +- return (ngx_queue_t *) ngx_align_ptr(((u_char *) &sd->data + len), +- NGX_ALIGNMENT); +-} +- +- +-ngx_int_t +-ngx_http_lua_shdict_init_zone(ngx_shm_zone_t *shm_zone, void *data) +-{ +- ngx_http_lua_shdict_ctx_t *octx = data; +- +- size_t len; +- ngx_http_lua_shdict_ctx_t *ctx; +- +- dd("init zone"); +- +- ctx = shm_zone->data; +- +- if (octx) { +- ctx->sh = octx->sh; +- ctx->shpool = octx->shpool; +- +- return NGX_OK; +- } +- +- ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; +- +- if (shm_zone->shm.exists) { +- ctx->sh = ctx->shpool->data; +- +- return NGX_OK; +- } +- +- ctx->sh = ngx_slab_alloc(ctx->shpool, sizeof(ngx_http_lua_shdict_shctx_t)); +- if (ctx->sh == NULL) { +- return NGX_ERROR; +- } +- +- ctx->shpool->data = ctx->sh; +- +- ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel, +- ngx_http_lua_shdict_rbtree_insert_value); +- +- ngx_queue_init(&ctx->sh->lru_queue); +- +- len = sizeof(" in lua_shared_dict zone \"\"") + shm_zone->shm.name.len; +- +- ctx->shpool->log_ctx = ngx_slab_alloc(ctx->shpool, len); +- if (ctx->shpool->log_ctx == NULL) { +- return NGX_ERROR; +- } +- +- ngx_sprintf(ctx->shpool->log_ctx, " in lua_shared_dict zone \"%V\"%Z", +- &shm_zone->shm.name); +- +- ctx->shpool->log_nomem = 0; +- +- return NGX_OK; +-} +- +- +-void +-ngx_http_lua_shdict_rbtree_insert_value(ngx_rbtree_node_t *temp, +- ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) +-{ +- ngx_rbtree_node_t **p; +- ngx_http_lua_shdict_node_t *sdn, *sdnt; +- +- for ( ;; ) { +- +- if (node->key < temp->key) { +- +- p = &temp->left; +- +- } else if (node->key > temp->key) { +- +- p = &temp->right; +- +- } else { /* node->key == temp->key */ +- +- sdn = (ngx_http_lua_shdict_node_t *) &node->color; +- sdnt = (ngx_http_lua_shdict_node_t *) &temp->color; +- +- p = ngx_memn2cmp(sdn->data, sdnt->data, sdn->key_len, +- sdnt->key_len) < 0 ? &temp->left : &temp->right; +- } +- +- if (*p == sentinel) { +- break; +- } +- +- temp = *p; +- } +- +- *p = node; +- node->parent = temp; +- node->left = sentinel; +- node->right = sentinel; +- ngx_rbt_red(node); +-} +- +- +-static ngx_int_t +-ngx_http_lua_shdict_lookup(ngx_shm_zone_t *shm_zone, ngx_uint_t hash, +- u_char *kdata, size_t klen, ngx_http_lua_shdict_node_t **sdp) +-{ +- ngx_int_t rc; +- ngx_time_t *tp; +- uint64_t now; +- int64_t ms; +- ngx_rbtree_node_t *node, *sentinel; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_http_lua_shdict_node_t *sd; +- +- ctx = shm_zone->data; +- +- node = ctx->sh->rbtree.root; +- sentinel = ctx->sh->rbtree.sentinel; +- +- while (node != sentinel) { +- +- if (hash < node->key) { +- node = node->left; +- continue; +- } +- +- if (hash > node->key) { +- node = node->right; +- continue; +- } +- +- /* hash == node->key */ +- +- sd = (ngx_http_lua_shdict_node_t *) &node->color; +- +- rc = ngx_memn2cmp(kdata, sd->data, klen, (size_t) sd->key_len); +- +- if (rc == 0) { +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- *sdp = sd; +- +- dd("node expires: %lld", (long long) sd->expires); +- +- if (sd->expires != 0) { +- tp = ngx_timeofday(); +- +- now = (uint64_t) tp->sec * 1000 + tp->msec; +- ms = sd->expires - now; +- +- dd("time to live: %lld", (long long) ms); +- +- if (ms < 0) { +- dd("node already expired"); +- return NGX_DONE; +- } +- } +- +- return NGX_OK; +- } +- +- node = (rc < 0) ? node->left : node->right; +- } +- +- *sdp = NULL; +- +- return NGX_DECLINED; +-} +- +- +-static int +-ngx_http_lua_shdict_expire(ngx_http_lua_shdict_ctx_t *ctx, ngx_uint_t n) +-{ +- ngx_time_t *tp; +- uint64_t now; +- ngx_queue_t *q, *list_queue, *lq; +- int64_t ms; +- ngx_rbtree_node_t *node; +- ngx_http_lua_shdict_node_t *sd; +- int freed = 0; +- ngx_http_lua_shdict_list_node_t *lnode; +- +- tp = ngx_timeofday(); +- +- now = (uint64_t) tp->sec * 1000 + tp->msec; +- +- /* +- * n == 1 deletes one or two expired entries +- * n == 0 deletes oldest entry by force +- * and one or two zero rate entries +- */ +- +- while (n < 3) { +- +- if (ngx_queue_empty(&ctx->sh->lru_queue)) { +- return freed; +- } +- +- q = ngx_queue_last(&ctx->sh->lru_queue); +- +- sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue); +- +- if (n++ != 0) { +- +- if (sd->expires == 0) { +- return freed; +- } +- +- ms = sd->expires - now; +- if (ms > 0) { +- return freed; +- } +- } +- +- if (sd->value_type == SHDICT_TLIST) { +- list_queue = ngx_http_lua_shdict_get_list_head(sd, sd->key_len); +- +- for (lq = ngx_queue_head(list_queue); +- lq != ngx_queue_sentinel(list_queue); +- lq = ngx_queue_next(lq)) +- { +- lnode = ngx_queue_data(lq, ngx_http_lua_shdict_list_node_t, +- queue); +- +- ngx_slab_free_locked(ctx->shpool, lnode); +- } +- } +- +- ngx_queue_remove(q); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- +- ngx_slab_free_locked(ctx->shpool, node); +- +- freed++; +- } +- +- return freed; +-} +- +- +-void +-ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L) +-{ +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_uint_t i; +- ngx_shm_zone_t **zone; +- ngx_shm_zone_t **zone_udata; +- +- if (lmcf->shdict_zones != NULL) { +- lua_createtable(L, 0, lmcf->shdict_zones->nelts /* nrec */); +- /* ngx.shared */ +- +- lua_createtable(L, 0 /* narr */, 22 /* nrec */); /* shared mt */ +- +- lua_pushcfunction(L, ngx_http_lua_shdict_lpush); +- lua_setfield(L, -2, "lpush"); +- +- lua_pushcfunction(L, ngx_http_lua_shdict_rpush); +- lua_setfield(L, -2, "rpush"); +- +- lua_pushcfunction(L, ngx_http_lua_shdict_lpop); +- lua_setfield(L, -2, "lpop"); +- +- lua_pushcfunction(L, ngx_http_lua_shdict_rpop); +- lua_setfield(L, -2, "rpop"); +- +- lua_pushcfunction(L, ngx_http_lua_shdict_llen); +- lua_setfield(L, -2, "llen"); +- +- 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 */ +- +- zone = lmcf->shdict_zones->elts; +- +- for (i = 0; i < lmcf->shdict_zones->nelts; i++) { +- ctx = zone[i]->data; +- +- lua_pushlstring(L, (char *) ctx->name.data, ctx->name.len); +- /* shared mt key */ +- +- lua_createtable(L, 1 /* narr */, 0 /* nrec */); +- /* table of zone[i] */ +- zone_udata = lua_newuserdata(L, sizeof(ngx_shm_zone_t *)); +- /* shared mt key ud */ +- *zone_udata = zone[i]; +- lua_rawseti(L, -2, SHDICT_USERDATA_INDEX); /* {zone[i]} */ +- lua_pushvalue(L, -3); /* shared mt key ud mt */ +- lua_setmetatable(L, -2); /* shared mt key ud */ +- lua_rawset(L, -4); /* shared mt */ +- } +- +- lua_pop(L, 1); /* shared */ +- +- } else { +- lua_newtable(L); /* ngx.shared */ +- } +- +- lua_setfield(L, -2, "shared"); +-} +- +- +-static ngx_inline ngx_shm_zone_t * +-ngx_http_lua_shdict_get_zone(lua_State *L, int index) +-{ +- ngx_shm_zone_t *zone; +- ngx_shm_zone_t **zone_udata; +- +- lua_rawgeti(L, index, SHDICT_USERDATA_INDEX); +- zone_udata = lua_touserdata(L, -1); +- lua_pop(L, 1); +- +- if (zone_udata == NULL) { +- return NULL; +- } +- +- zone = *zone_udata; +- return zone; +-} +- +- +-static int +-ngx_http_lua_shdict_flush_expired(lua_State *L) +-{ +- ngx_queue_t *q, *prev, *list_queue, *lq; +- ngx_http_lua_shdict_node_t *sd; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_shm_zone_t *zone; +- ngx_time_t *tp; +- int freed = 0; +- int attempts = 0; +- ngx_rbtree_node_t *node; +- uint64_t now; +- int n; +- ngx_http_lua_shdict_list_node_t *lnode; +- +- 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_TTABLE); +- +- zone = ngx_http_lua_shdict_get_zone(L, 1); +- if (zone == NULL) { +- return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer"); +- } +- +- if (n == 2) { +- attempts = luaL_checkint(L, 2); +- } +- +- ctx = zone->data; +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +- if (ngx_queue_empty(&ctx->sh->lru_queue)) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- lua_pushnumber(L, 0); +- return 1; +- } +- +- tp = ngx_timeofday(); +- +- now = (uint64_t) tp->sec * 1000 + tp->msec; +- +- q = ngx_queue_last(&ctx->sh->lru_queue); +- +- while (q != ngx_queue_sentinel(&ctx->sh->lru_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) { +- +- if (sd->value_type == SHDICT_TLIST) { +- list_queue = ngx_http_lua_shdict_get_list_head(sd, sd->key_len); +- +- for (lq = ngx_queue_head(list_queue); +- lq != ngx_queue_sentinel(list_queue); +- lq = ngx_queue_next(lq)) +- { +- lnode = ngx_queue_data(lq, ngx_http_lua_shdict_list_node_t, +- queue); +- +- ngx_slab_free_locked(ctx->shpool, lnode); +- } +- } +- +- ngx_queue_remove(q); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- ngx_slab_free_locked(ctx->shpool, node); +- freed++; +- +- if (attempts && freed == attempts) { +- break; +- } +- } +- +- q = prev; +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnumber(L, freed); +- return 1; +-} +- +- +-/* +- * 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_TTABLE); +- +- zone = ngx_http_lua_shdict_get_zone(L, 1); +- if (zone == NULL) { +- return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer"); +- } +- +- if (n == 2) { +- attempts = luaL_checkint(L, 2); +- } +- +- ctx = zone->data; +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +- if (ngx_queue_empty(&ctx->sh->lru_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->lru_queue); +- +- while (q != ngx_queue_sentinel(&ctx->sh->lru_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->lru_queue); +- +- while (q != ngx_queue_sentinel(&ctx->sh->lru_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; +-} +- +- +-ngx_int_t +-ngx_http_lua_shared_dict_get(ngx_shm_zone_t *zone, u_char *key_data, +- size_t key_len, ngx_http_lua_value_t *value) +-{ +- u_char *data; +- size_t len; +- uint32_t hash; +- ngx_int_t rc; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_http_lua_shdict_node_t *sd; +- +- if (zone == NULL) { +- return NGX_ERROR; +- } +- +- hash = ngx_crc32_short(key_data, key_len); +- +- ctx = zone->data; +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +- rc = ngx_http_lua_shdict_lookup(zone, hash, key_data, key_len, &sd); +- +- dd("shdict lookup returned %d", (int) rc); +- +- if (rc == NGX_DECLINED || rc == NGX_DONE) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return rc; +- } +- +- /* rc == NGX_OK */ +- +- value->type = sd->value_type; +- +- dd("type: %d", (int) value->type); +- +- data = sd->data + sd->key_len; +- len = (size_t) sd->value_len; +- +- switch (value->type) { +- +- case SHDICT_TSTRING: +- +- if (value->value.s.data == NULL || value->value.s.len == 0) { +- ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "no string buffer " +- "initialized"); +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- return NGX_ERROR; +- } +- +- if (len > value->value.s.len) { +- len = value->value.s.len; +- +- } else { +- value->value.s.len = len; +- } +- +- ngx_memcpy(value->value.s.data, data, len); +- break; +- +- case SHDICT_TNUMBER: +- +- if (len != sizeof(double)) { +- ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "bad lua number " +- "value size found for key %*s: %lu", key_len, +- key_data, (unsigned long) len); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- return NGX_ERROR; +- } +- +- ngx_memcpy(&value->value.b, data, len); +- break; +- +- case SHDICT_TBOOLEAN: +- +- if (len != sizeof(u_char)) { +- ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "bad lua boolean " +- "value size found for key %*s: %lu", key_len, +- key_data, (unsigned long) len); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- return NGX_ERROR; +- } +- +- value->value.b = *data; +- break; +- +- default: +- ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "bad lua value type " +- "found for key %*s: %d", key_len, key_data, +- (int) value->type); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- return NGX_ERROR; +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- return NGX_OK; +-} +- +- +-static int +-ngx_http_lua_shdict_lpush(lua_State *L) +-{ +- return ngx_http_lua_shdict_push_helper(L, NGX_HTTP_LUA_SHDICT_LEFT); +-} +- +- +-static int +-ngx_http_lua_shdict_rpush(lua_State *L) +-{ +- return ngx_http_lua_shdict_push_helper(L, NGX_HTTP_LUA_SHDICT_RIGHT); +-} +- +- +-static int +-ngx_http_lua_shdict_push_helper(lua_State *L, int flags) +-{ +- int n; +- ngx_str_t key; +- uint32_t hash; +- ngx_int_t rc; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_http_lua_shdict_node_t *sd; +- ngx_str_t value; +- int value_type; +- double num; +- ngx_rbtree_node_t *node; +- ngx_shm_zone_t *zone; +- ngx_queue_t *queue, *q; +- ngx_http_lua_shdict_list_node_t *lnode; +- +- n = lua_gettop(L); +- +- if (n != 3) { +- return luaL_error(L, "expecting 3 arguments, " +- "but only seen %d", n); +- } +- +- if (lua_type(L, 1) != LUA_TTABLE) { +- return luaL_error(L, "bad \"zone\" argument"); +- } +- +- zone = ngx_http_lua_shdict_get_zone(L, 1); +- if (zone == NULL) { +- return luaL_error(L, "bad \"zone\" argument"); +- } +- +- ctx = zone->data; +- +- if (lua_isnil(L, 2)) { +- lua_pushnil(L); +- lua_pushliteral(L, "nil key"); +- return 2; +- } +- +- key.data = (u_char *) luaL_checklstring(L, 2, &key.len); +- +- if (key.len == 0) { +- lua_pushnil(L); +- lua_pushliteral(L, "empty key"); +- return 2; +- } +- +- if (key.len > 65535) { +- lua_pushnil(L); +- lua_pushliteral(L, "key too long"); +- return 2; +- } +- +- hash = ngx_crc32_short(key.data, key.len); +- +- value_type = lua_type(L, 3); +- +- switch (value_type) { +- +- case SHDICT_TSTRING: +- value.data = (u_char *) lua_tolstring(L, 3, &value.len); +- break; +- +- case SHDICT_TNUMBER: +- value.len = sizeof(double); +- num = lua_tonumber(L, 3); +- value.data = (u_char *) # +- break; +- +- default: +- lua_pushnil(L); +- lua_pushliteral(L, "bad value type"); +- return 2; +- } +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +-#if 1 +- ngx_http_lua_shdict_expire(ctx, 1); +-#endif +- +- rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); +- +- dd("shdict lookup returned %d", (int) rc); +- +- /* exists but expired */ +- +- if (rc == NGX_DONE) { +- +- if (sd->value_type != SHDICT_TLIST) { +- /* TODO: reuse when length matched */ +- +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict push: found old entry and value " +- "type not matched, remove it first"); +- +- ngx_queue_remove(&sd->queue); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- +- ngx_slab_free_locked(ctx->shpool, node); +- +- dd("go to init_list"); +- goto init_list; +- } +- +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict push: found old entry and value " +- "type matched, reusing it"); +- +- sd->expires = 0; +- +- /* free list nodes */ +- +- queue = ngx_http_lua_shdict_get_list_head(sd, key.len); +- +- for (q = ngx_queue_head(queue); +- q != ngx_queue_sentinel(queue); +- q = ngx_queue_next(q)) +- { +- /* TODO: reuse matched size list node */ +- lnode = ngx_queue_data(q, ngx_http_lua_shdict_list_node_t, queue); +- ngx_slab_free_locked(ctx->shpool, lnode); +- } +- +- ngx_queue_init(queue); +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- dd("go to push_node"); +- goto push_node; +- } +- +- /* exists and not expired */ +- +- if (rc == NGX_OK) { +- +- if (sd->value_type != SHDICT_TLIST) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnil(L); +- lua_pushliteral(L, "value not a list"); +- return 2; +- } +- +- queue = ngx_http_lua_shdict_get_list_head(sd, key.len); +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- dd("go to push_node"); +- goto push_node; +- } +- +- /* rc == NGX_DECLINED, not found */ +- +-init_list: +- +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict list: creating a new entry"); +- +- /* NOTICE: we assume the begin point aligned in slab, be careful */ +- n = offsetof(ngx_rbtree_node_t, color) +- + offsetof(ngx_http_lua_shdict_node_t, data) +- + key.len +- + sizeof(ngx_queue_t); +- +- dd("length before aligned: %d", n); +- +- n = (int) (uintptr_t) ngx_align_ptr(n, NGX_ALIGNMENT); +- +- dd("length after aligned: %d", n); +- +- node = ngx_slab_alloc_locked(ctx->shpool, n); +- +- if (node == NULL) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushboolean(L, 0); +- lua_pushliteral(L, "no memory"); +- return 2; +- } +- +- sd = (ngx_http_lua_shdict_node_t *) &node->color; +- +- queue = ngx_http_lua_shdict_get_list_head(sd, key.len); +- +- node->key = hash; +- sd->key_len = (u_short) key.len; +- +- sd->expires = 0; +- +- sd->value_len = 0; +- +- dd("setting value type to %d", (int) SHDICT_TLIST); +- +- sd->value_type = (uint8_t) SHDICT_TLIST; +- +- ngx_memcpy(sd->data, key.data, key.len); +- +- ngx_queue_init(queue); +- +- ngx_rbtree_insert(&ctx->sh->rbtree, node); +- +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +-push_node: +- +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict list: creating a new list node"); +- +- n = offsetof(ngx_http_lua_shdict_list_node_t, data) +- + value.len; +- +- dd("list node length: %d", n); +- +- lnode = ngx_slab_alloc_locked(ctx->shpool, n); +- +- if (lnode == NULL) { +- +- if (sd->value_len == 0) { +- +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict list: no memory for create" +- " list node and list empty, remove it"); +- +- ngx_queue_remove(&sd->queue); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- +- ngx_slab_free_locked(ctx->shpool, node); +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushboolean(L, 0); +- lua_pushliteral(L, "no memory"); +- return 2; +- } +- +- dd("setting list length to %d", sd->value_len + 1); +- +- sd->value_len = sd->value_len + 1; +- +- dd("setting list node value length to %d", (int) value.len); +- +- lnode->value_len = (uint32_t) value.len; +- +- dd("setting list node value type to %d", value_type); +- +- lnode->value_type = (uint8_t) value_type; +- +- ngx_memcpy(lnode->data, value.data, value.len); +- +- if (flags == NGX_HTTP_LUA_SHDICT_LEFT) { +- ngx_queue_insert_head(queue, &lnode->queue); +- +- } else { +- ngx_queue_insert_tail(queue, &lnode->queue); +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnumber(L, sd->value_len); +- return 1; +-} +- +- +-static int +-ngx_http_lua_shdict_lpop(lua_State *L) +-{ +- return ngx_http_lua_shdict_pop_helper(L, NGX_HTTP_LUA_SHDICT_LEFT); +-} +- +- +-static int +-ngx_http_lua_shdict_rpop(lua_State *L) +-{ +- return ngx_http_lua_shdict_pop_helper(L, NGX_HTTP_LUA_SHDICT_RIGHT); +-} +- +- +-static int +-ngx_http_lua_shdict_pop_helper(lua_State *L, int flags) +-{ +- int n; +- ngx_str_t name; +- ngx_str_t key; +- uint32_t hash; +- ngx_int_t rc; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_http_lua_shdict_node_t *sd; +- ngx_str_t value; +- int value_type; +- double num; +- ngx_rbtree_node_t *node; +- ngx_shm_zone_t *zone; +- ngx_queue_t *queue; +- ngx_http_lua_shdict_list_node_t *lnode; +- +- n = lua_gettop(L); +- +- if (n != 2) { +- return luaL_error(L, "expecting 2 arguments, " +- "but only seen %d", n); +- } +- +- if (lua_type(L, 1) != LUA_TTABLE) { +- return luaL_error(L, "bad \"zone\" argument"); +- } +- +- zone = ngx_http_lua_shdict_get_zone(L, 1); +- if (zone == NULL) { +- return luaL_error(L, "bad \"zone\" argument"); +- } +- +- ctx = zone->data; +- name = ctx->name; +- +- if (lua_isnil(L, 2)) { +- lua_pushnil(L); +- lua_pushliteral(L, "nil key"); +- return 2; +- } +- +- key.data = (u_char *) luaL_checklstring(L, 2, &key.len); +- +- if (key.len == 0) { +- lua_pushnil(L); +- lua_pushliteral(L, "empty key"); +- return 2; +- } +- +- if (key.len > 65535) { +- lua_pushnil(L); +- lua_pushliteral(L, "key too long"); +- return 2; +- } +- +- hash = ngx_crc32_short(key.data, key.len); +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +-#if 1 +- ngx_http_lua_shdict_expire(ctx, 1); +-#endif +- +- rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); +- +- dd("shdict lookup returned %d", (int) rc); +- +- if (rc == NGX_DECLINED || rc == NGX_DONE) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- lua_pushnil(L); +- return 1; +- } +- +- /* rc == NGX_OK */ +- +- if (sd->value_type != SHDICT_TLIST) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnil(L); +- lua_pushliteral(L, "value not a list"); +- return 2; +- } +- +- if (sd->value_len <= 0) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return luaL_error(L, "bad lua list length found for key %s " +- "in shared_dict %s: %lu", key.data, name.data, +- (unsigned long) sd->value_len); +- } +- +- queue = ngx_http_lua_shdict_get_list_head(sd, key.len); +- +- if (flags == NGX_HTTP_LUA_SHDICT_LEFT) { +- queue = ngx_queue_head(queue); +- +- } else { +- queue = ngx_queue_last(queue); +- } +- +- lnode = ngx_queue_data(queue, ngx_http_lua_shdict_list_node_t, queue); +- +- value_type = lnode->value_type; +- +- dd("data: %p", lnode->data); +- dd("value len: %d", (int) sd->value_len); +- +- value.data = lnode->data; +- value.len = (size_t) lnode->value_len; +- +- switch (value_type) { +- +- case SHDICT_TSTRING: +- +- lua_pushlstring(L, (char *) value.data, value.len); +- break; +- +- case SHDICT_TNUMBER: +- +- if (value.len != sizeof(double)) { +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return luaL_error(L, "bad lua list node number value size found " +- "for key %s in shared_dict %s: %lu", key.data, +- name.data, (unsigned long) value.len); +- } +- +- ngx_memcpy(&num, value.data, sizeof(double)); +- +- lua_pushnumber(L, num); +- break; +- +- default: +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return luaL_error(L, "bad list node value type found for key %s in " +- "shared_dict %s: %d", key.data, name.data, +- value_type); +- } +- +- ngx_queue_remove(queue); +- +- ngx_slab_free_locked(ctx->shpool, lnode); +- +- if (sd->value_len == 1) { +- +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict list: empty node after pop, " +- "remove it"); +- +- ngx_queue_remove(&sd->queue); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- +- ngx_slab_free_locked(ctx->shpool, node); +- +- } else { +- sd->value_len = sd->value_len - 1; +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return 1; +-} +- +- +-static int +-ngx_http_lua_shdict_llen(lua_State *L) +-{ +- int n; +- ngx_str_t key; +- uint32_t hash; +- ngx_int_t rc; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_http_lua_shdict_node_t *sd; +- ngx_shm_zone_t *zone; +- +- n = lua_gettop(L); +- +- if (n != 2) { +- return luaL_error(L, "expecting 2 arguments, " +- "but only seen %d", n); +- } +- +- if (lua_type(L, 1) != LUA_TTABLE) { +- return luaL_error(L, "bad \"zone\" argument"); +- } +- +- zone = ngx_http_lua_shdict_get_zone(L, 1); +- if (zone == NULL) { +- return luaL_error(L, "bad \"zone\" argument"); +- } +- +- ctx = zone->data; +- +- if (lua_isnil(L, 2)) { +- lua_pushnil(L); +- lua_pushliteral(L, "nil key"); +- return 2; +- } +- +- key.data = (u_char *) luaL_checklstring(L, 2, &key.len); +- +- if (key.len == 0) { +- lua_pushnil(L); +- lua_pushliteral(L, "empty key"); +- return 2; +- } +- +- if (key.len > 65535) { +- lua_pushnil(L); +- lua_pushliteral(L, "key too long"); +- return 2; +- } +- +- hash = ngx_crc32_short(key.data, key.len); +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +-#if 1 +- ngx_http_lua_shdict_expire(ctx, 1); +-#endif +- +- rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); +- +- dd("shdict lookup returned %d", (int) rc); +- +- if (rc == NGX_OK) { +- +- if (sd->value_type != SHDICT_TLIST) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnil(L); +- lua_pushliteral(L, "value not a list"); +- return 2; +- } +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnumber(L, (lua_Number) sd->value_len); +- return 1; +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnumber(L, 0); +- return 1; +-} +- +- +-ngx_shm_zone_t * +-ngx_http_lua_find_zone(u_char *name_data, size_t name_len) +-{ +- ngx_str_t *name; +- ngx_uint_t i; +- ngx_shm_zone_t *zone; +- ngx_http_lua_shm_zone_ctx_t *ctx; +- volatile ngx_list_part_t *part; +- +- part = &ngx_cycle->shared_memory.part; +- zone = part->elts; +- +- for (i = 0; /* void */ ; i++) { +- +- if (i >= part->nelts) { +- if (part->next == NULL) { +- break; +- } +- +- part = part->next; +- zone = part->elts; +- i = 0; +- } +- +- name = &zone[i].shm.name; +- +- dd("name: [%.*s] %d", (int) name->len, name->data, (int) name->len); +- dd("name2: [%.*s] %d", (int) name_len, name_data, (int) name_len); +- +- if (name->len == name_len +- && ngx_strncmp(name->data, name_data, name_len) == 0) +- { +- ctx = (ngx_http_lua_shm_zone_ctx_t *) zone[i].data; +- return &ctx->zone; +- } +- } +- +- return NULL; +-} +- +- +-ngx_shm_zone_t * +-ngx_http_lua_ffi_shdict_udata_to_zone(void *zone_udata) +-{ +- if (zone_udata == NULL) { +- return NULL; +- } +- +- return *(ngx_shm_zone_t **) zone_udata; +-} +- +- +-int +-ngx_http_lua_ffi_shdict_store(ngx_shm_zone_t *zone, int op, u_char *key, +- size_t key_len, int value_type, u_char *str_value_buf, +- size_t str_value_len, double num_value, long exptime, int user_flags, +- char **errmsg, int *forcible) +-{ +- int i, n; +- u_char c, *p; +- uint32_t hash; +- ngx_int_t rc; +- ngx_time_t *tp; +- ngx_queue_t *queue, *q; +- ngx_rbtree_node_t *node; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_http_lua_shdict_node_t *sd; +- +- dd("exptime: %ld", exptime); +- +- ctx = zone->data; +- +- *forcible = 0; +- +- hash = ngx_crc32_short(key, key_len); +- +- switch (value_type) { +- +- case SHDICT_TSTRING: +- /* do nothing */ +- break; +- +- case SHDICT_TNUMBER: +- dd("num value: %lf", num_value); +- str_value_buf = (u_char *) &num_value; +- str_value_len = sizeof(double); +- break; +- +- case SHDICT_TBOOLEAN: +- c = num_value ? 1 : 0; +- str_value_buf = &c; +- str_value_len = sizeof(u_char); +- break; +- +- case LUA_TNIL: +- if (op & (NGX_HTTP_LUA_SHDICT_ADD|NGX_HTTP_LUA_SHDICT_REPLACE)) { +- *errmsg = "attempt to add or replace nil values"; +- return NGX_ERROR; +- } +- +- str_value_buf = NULL; +- str_value_len = 0; +- break; +- +- default: +- *errmsg = "unsupported value type"; +- return NGX_ERROR; +- } +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +-#if 1 +- ngx_http_lua_shdict_expire(ctx, 1); +-#endif +- +- rc = ngx_http_lua_shdict_lookup(zone, hash, key, key_len, &sd); +- +- dd("lookup returns %d", (int) rc); +- +- if (op & NGX_HTTP_LUA_SHDICT_REPLACE) { +- +- if (rc == NGX_DECLINED || rc == NGX_DONE) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- *errmsg = "not found"; +- return NGX_DECLINED; +- } +- +- /* rc == NGX_OK */ +- +- goto replace; +- } +- +- if (op & NGX_HTTP_LUA_SHDICT_ADD) { +- +- if (rc == NGX_OK) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- *errmsg = "exists"; +- return NGX_DECLINED; +- } +- +- if (rc == NGX_DONE) { +- /* exists but expired */ +- +- dd("go to replace"); +- goto replace; +- } +- +- /* rc == NGX_DECLINED */ +- +- dd("go to insert"); +- goto insert; +- } +- +- if (rc == NGX_OK || rc == NGX_DONE) { +- +- if (value_type == LUA_TNIL) { +- goto remove; +- } +- +-replace: +- +- if (str_value_buf +- && str_value_len == (size_t) sd->value_len +- && sd->value_type != SHDICT_TLIST) +- { +- +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict set: found old entry and value " +- "size matched, reusing it"); +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- sd->key_len = (u_short) key_len; +- +- if (exptime > 0) { +- tp = ngx_timeofday(); +- sd->expires = (uint64_t) tp->sec * 1000 + tp->msec +- + (uint64_t) exptime; +- +- } else { +- sd->expires = 0; +- } +- +- sd->user_flags = user_flags; +- +- sd->value_len = (uint32_t) str_value_len; +- +- dd("setting value type to %d", value_type); +- +- sd->value_type = (uint8_t) value_type; +- +- p = ngx_copy(sd->data, key, key_len); +- ngx_memcpy(p, str_value_buf, str_value_len); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return NGX_OK; +- } +- +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict set: found old entry but value size " +- "NOT matched, removing it first"); +- +-remove: +- +- if (sd->value_type == SHDICT_TLIST) { +- queue = ngx_http_lua_shdict_get_list_head(sd, key_len); +- +- for (q = ngx_queue_head(queue); +- q != ngx_queue_sentinel(queue); +- q = ngx_queue_next(q)) +- { +- p = (u_char *) ngx_queue_data(q, +- ngx_http_lua_shdict_list_node_t, +- queue); +- +- ngx_slab_free_locked(ctx->shpool, p); +- } +- } +- +- ngx_queue_remove(&sd->queue); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- +- ngx_slab_free_locked(ctx->shpool, node); +- +- } +- +-insert: +- +- /* rc == NGX_DECLINED or value size unmatch */ +- +- if (str_value_buf == NULL) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- return NGX_OK; +- } +- +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict set: creating a new entry"); +- +- n = offsetof(ngx_rbtree_node_t, color) +- + offsetof(ngx_http_lua_shdict_node_t, data) +- + key_len +- + str_value_len; +- +- node = ngx_slab_alloc_locked(ctx->shpool, n); +- +- if (node == NULL) { +- +- if (op & NGX_HTTP_LUA_SHDICT_SAFE_STORE) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- *errmsg = "no memory"; +- return NGX_ERROR; +- } +- +- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict set: overriding non-expired items " +- "due to memory shortage for entry \"%*s\"", key_len, +- key); +- +- for (i = 0; i < 30; i++) { +- if (ngx_http_lua_shdict_expire(ctx, 0) == 0) { +- break; +- } +- +- *forcible = 1; +- +- node = ngx_slab_alloc_locked(ctx->shpool, n); +- if (node != NULL) { +- goto allocated; +- } +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- *errmsg = "no memory"; +- return NGX_ERROR; +- } +- +-allocated: +- +- sd = (ngx_http_lua_shdict_node_t *) &node->color; +- +- node->key = hash; +- sd->key_len = (u_short) key_len; +- +- if (exptime > 0) { +- tp = ngx_timeofday(); +- sd->expires = (uint64_t) tp->sec * 1000 + tp->msec +- + (uint64_t) exptime; +- +- } else { +- sd->expires = 0; +- } +- +- sd->user_flags = user_flags; +- sd->value_len = (uint32_t) str_value_len; +- dd("setting value type to %d", value_type); +- sd->value_type = (uint8_t) value_type; +- +- p = ngx_copy(sd->data, key, key_len); +- ngx_memcpy(p, str_value_buf, str_value_len); +- +- ngx_rbtree_insert(&ctx->sh->rbtree, node); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return NGX_OK; +-} +- +- +-int +-ngx_http_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, +- size_t key_len, int *value_type, u_char **str_value_buf, +- size_t *str_value_len, double *num_value, int *user_flags, +- int get_stale, int *is_stale, char **err) +-{ +- ngx_str_t name; +- uint32_t hash; +- ngx_int_t rc; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_http_lua_shdict_node_t *sd; +- ngx_str_t value; +- +- *err = NULL; +- +- ctx = zone->data; +- name = ctx->name; +- +- hash = ngx_crc32_short(key, key_len); +- +-#if (NGX_DEBUG) +- ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "fetching key \"%*s\" in shared dict \"%V\"", key_len, +- key, &name); +-#endif /* NGX_DEBUG */ +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +-#if 1 +- if (!get_stale) { +- ngx_http_lua_shdict_expire(ctx, 1); +- } +-#endif +- +- rc = ngx_http_lua_shdict_lookup(zone, hash, key, key_len, &sd); +- +- dd("shdict lookup returns %d", (int) rc); +- +- if (rc == NGX_DECLINED || (rc == NGX_DONE && !get_stale)) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- *value_type = LUA_TNIL; +- return NGX_OK; +- } +- +- /* rc == NGX_OK || (rc == NGX_DONE && get_stale) */ +- +- *value_type = sd->value_type; +- +- dd("data: %p", sd->data); +- dd("key len: %d", (int) sd->key_len); +- +- value.data = sd->data + sd->key_len; +- value.len = (size_t) sd->value_len; +- +- if (*str_value_len < (size_t) value.len) { +- if (*value_type == SHDICT_TBOOLEAN) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- return NGX_ERROR; +- } +- +- if (*value_type == SHDICT_TSTRING) { +- *str_value_buf = malloc(value.len); +- if (*str_value_buf == NULL) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- return NGX_ERROR; +- } +- } +- } +- +- switch (*value_type) { +- +- case SHDICT_TSTRING: +- *str_value_len = value.len; +- ngx_memcpy(*str_value_buf, value.data, value.len); +- break; +- +- case SHDICT_TNUMBER: +- +- if (value.len != sizeof(double)) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, +- "bad lua number value size found for key %*s " +- "in shared_dict %V: %z", key_len, key, +- &name, value.len); +- return NGX_ERROR; +- } +- +- *str_value_len = value.len; +- ngx_memcpy(num_value, value.data, sizeof(double)); +- break; +- +- case SHDICT_TBOOLEAN: +- +- if (value.len != sizeof(u_char)) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, +- "bad lua boolean value size found for key %*s " +- "in shared_dict %V: %z", key_len, key, &name, +- value.len); +- return NGX_ERROR; +- } +- +- ngx_memcpy(*str_value_buf, value.data, value.len); +- break; +- +- case SHDICT_TLIST: +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- *err = "value is a list"; +- return NGX_ERROR; +- +- default: +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, +- "bad value type found for key %*s in " +- "shared_dict %V: %d", key_len, key, &name, +- *value_type); +- return NGX_ERROR; +- } +- +- *user_flags = sd->user_flags; +- dd("user flags: %d", *user_flags); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- if (get_stale) { +- +- /* always return value, flags, stale */ +- +- *is_stale = (rc == NGX_DONE); +- return NGX_OK; +- } +- +- return NGX_OK; +-} +- +- +-int +-ngx_http_lua_ffi_shdict_incr(ngx_shm_zone_t *zone, u_char *key, +- size_t key_len, double *value, char **err, int has_init, double init, +- long init_ttl, int *forcible) +-{ +- int i, n; +- uint32_t hash; +- ngx_int_t rc; +- ngx_time_t *tp = NULL; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_http_lua_shdict_node_t *sd; +- double num; +- ngx_rbtree_node_t *node; +- u_char *p; +- ngx_queue_t *queue, *q; +- +- if (init_ttl > 0) { +- tp = ngx_timeofday(); +- } +- +- ctx = zone->data; +- +- *forcible = 0; +- +- hash = ngx_crc32_short(key, key_len); +- +- dd("looking up key %.*s in shared dict %.*s", (int) key_len, key, +- (int) ctx->name.len, ctx->name.data); +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +-#if 1 +- ngx_http_lua_shdict_expire(ctx, 1); +-#endif +- rc = ngx_http_lua_shdict_lookup(zone, hash, key, key_len, &sd); +- +- dd("shdict lookup returned %d", (int) rc); +- +- if (rc == NGX_DECLINED || rc == NGX_DONE) { +- if (!has_init) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- *err = "not found"; +- return NGX_ERROR; +- } +- +- /* add value */ +- num = *value + init; +- +- if (rc == NGX_DONE) { +- +- /* found an expired item */ +- +- if ((size_t) sd->value_len == sizeof(double) +- && sd->value_type != SHDICT_TLIST) +- { +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict incr: found old entry and " +- "value size matched, reusing it"); +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- dd("go to setvalue"); +- goto setvalue; +- } +- +- dd("go to remove"); +- goto remove; +- } +- +- dd("go to insert"); +- goto insert; +- } +- +- /* rc == NGX_OK */ +- +- if (sd->value_type != SHDICT_TNUMBER || sd->value_len != sizeof(double)) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- *err = "not a number"; +- return NGX_ERROR; +- } +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- dd("setting value type to %d", (int) sd->value_type); +- +- p = sd->data + key_len; +- +- ngx_memcpy(&num, p, sizeof(double)); +- num += *value; +- +- ngx_memcpy(p, (double *) &num, sizeof(double)); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- *value = num; +- return NGX_OK; +- +-remove: +- +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict incr: found old entry but value size " +- "NOT matched, removing it first"); +- +- if (sd->value_type == SHDICT_TLIST) { +- queue = ngx_http_lua_shdict_get_list_head(sd, key_len); +- +- for (q = ngx_queue_head(queue); +- q != ngx_queue_sentinel(queue); +- q = ngx_queue_next(q)) +- { +- p = (u_char *) ngx_queue_data(q, ngx_http_lua_shdict_list_node_t, +- queue); +- +- ngx_slab_free_locked(ctx->shpool, p); +- } +- } +- +- ngx_queue_remove(&sd->queue); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- +- ngx_slab_free_locked(ctx->shpool, node); +- +-insert: +- +- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict incr: creating a new entry"); +- +- n = offsetof(ngx_rbtree_node_t, color) +- + offsetof(ngx_http_lua_shdict_node_t, data) +- + key_len +- + sizeof(double); +- +- node = ngx_slab_alloc_locked(ctx->shpool, n); +- +- if (node == NULL) { +- +- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ctx->log, 0, +- "lua shared dict incr: overriding non-expired items " +- "due to memory shortage for entry \"%*s\"", key_len, +- key); +- +- for (i = 0; i < 30; i++) { +- if (ngx_http_lua_shdict_expire(ctx, 0) == 0) { +- break; +- } +- +- *forcible = 1; +- +- node = ngx_slab_alloc_locked(ctx->shpool, n); +- if (node != NULL) { +- goto allocated; +- } +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- *err = "no memory"; +- return NGX_ERROR; +- } +- +-allocated: +- +- sd = (ngx_http_lua_shdict_node_t *) &node->color; +- +- node->key = hash; +- +- sd->key_len = (u_short) key_len; +- +- sd->value_len = (uint32_t) sizeof(double); +- +- ngx_rbtree_insert(&ctx->sh->rbtree, node); +- +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +-setvalue: +- +- sd->user_flags = 0; +- +- if (init_ttl > 0) { +- sd->expires = (uint64_t) tp->sec * 1000 + tp->msec +- + (uint64_t) init_ttl; +- +- } else { +- sd->expires = 0; +- } +- +- dd("setting value type to %d", LUA_TNUMBER); +- +- sd->value_type = (uint8_t) LUA_TNUMBER; +- +- p = ngx_copy(sd->data, key, key_len); +- ngx_memcpy(p, (double *) &num, sizeof(double)); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- *value = num; +- return NGX_OK; +-} +- +- +-int +-ngx_http_lua_ffi_shdict_flush_all(ngx_shm_zone_t *zone) +-{ +- ngx_queue_t *q; +- ngx_http_lua_shdict_node_t *sd; +- ngx_http_lua_shdict_ctx_t *ctx; +- +- ctx = zone->data; +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +- for (q = ngx_queue_head(&ctx->sh->lru_queue); +- q != ngx_queue_sentinel(&ctx->sh->lru_queue); +- q = ngx_queue_next(q)) +- { +- sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue); +- sd->expires = 1; +- } +- +- ngx_http_lua_shdict_expire(ctx, 0); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return NGX_OK; +-} +- +- +-static ngx_int_t +-ngx_http_lua_shdict_peek(ngx_shm_zone_t *shm_zone, ngx_uint_t hash, +- u_char *kdata, size_t klen, ngx_http_lua_shdict_node_t **sdp) +-{ +- ngx_int_t rc; +- ngx_rbtree_node_t *node, *sentinel; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_http_lua_shdict_node_t *sd; +- +- ctx = shm_zone->data; +- +- node = ctx->sh->rbtree.root; +- sentinel = ctx->sh->rbtree.sentinel; +- +- while (node != sentinel) { +- +- if (hash < node->key) { +- node = node->left; +- continue; +- } +- +- if (hash > node->key) { +- node = node->right; +- continue; +- } +- +- /* hash == node->key */ +- +- sd = (ngx_http_lua_shdict_node_t *) &node->color; +- +- rc = ngx_memn2cmp(kdata, sd->data, klen, (size_t) sd->key_len); +- +- if (rc == 0) { +- *sdp = sd; +- +- return NGX_OK; +- } +- +- node = (rc < 0) ? node->left : node->right; +- } +- +- *sdp = NULL; +- +- return NGX_DECLINED; +-} +- +- +-long +-ngx_http_lua_ffi_shdict_get_ttl(ngx_shm_zone_t *zone, u_char *key, +- size_t key_len) +-{ +- uint32_t hash; +- uint64_t now; +- uint64_t expires; +- ngx_int_t rc; +- ngx_time_t *tp; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_http_lua_shdict_node_t *sd; +- +- ctx = zone->data; +- hash = ngx_crc32_short(key, key_len); +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +- rc = ngx_http_lua_shdict_peek(zone, hash, key, key_len, &sd); +- +- if (rc == NGX_DECLINED) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return NGX_DECLINED; +- } +- +- /* rc == NGX_OK */ +- +- expires = sd->expires; +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- if (expires == 0) { +- return 0; +- } +- +- tp = ngx_timeofday(); +- now = (uint64_t) tp->sec * 1000 + tp->msec; +- +- return expires - now; +-} +- +- +-int +-ngx_http_lua_ffi_shdict_set_expire(ngx_shm_zone_t *zone, u_char *key, +- size_t key_len, long exptime) +-{ +- uint32_t hash; +- ngx_int_t rc; +- ngx_time_t *tp = NULL; +- ngx_http_lua_shdict_ctx_t *ctx; +- ngx_http_lua_shdict_node_t *sd; +- +- if (exptime > 0) { +- tp = ngx_timeofday(); +- } +- +- ctx = zone->data; +- hash = ngx_crc32_short(key, key_len); +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +- rc = ngx_http_lua_shdict_peek(zone, hash, key, key_len, &sd); +- +- if (rc == NGX_DECLINED) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return NGX_DECLINED; +- } +- +- /* rc == NGX_OK */ +- +- if (exptime > 0) { +- sd->expires = (uint64_t) tp->sec * 1000 + tp->msec +- + (uint64_t) exptime; +- +- } else { +- sd->expires = 0; +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return NGX_OK; +-} +- +- +-size_t +-ngx_http_lua_ffi_shdict_capacity(ngx_shm_zone_t *zone) +-{ +- return zone->shm.size; +-} +- +- +-#if (nginx_version >= 1011007) +-size_t +-ngx_http_lua_ffi_shdict_free_space(ngx_shm_zone_t *zone) +-{ +- size_t bytes; +- ngx_http_lua_shdict_ctx_t *ctx; +- +- ctx = zone->data; +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- bytes = ctx->shpool->pfree * ngx_pagesize; +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return bytes; +-} +-#endif +- +- +-/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ +diff --git src/ngx_http_lua_shdict.h src/ngx_http_lua_shdict.h +deleted file mode 100644 +index 90a0099f..00000000 +--- src/ngx_http_lua_shdict.h ++++ /dev/null +@@ -1,67 +0,0 @@ +- +-/* +- * Copyright (C) Yichun Zhang (agentzh) +- */ +- +- +-#ifndef _NGX_HTTP_LUA_SHDICT_H_INCLUDED_ +-#define _NGX_HTTP_LUA_SHDICT_H_INCLUDED_ +- +- +-#include "ngx_http_lua_common.h" +- +- +-typedef struct { +- u_char color; +- uint8_t value_type; +- u_short key_len; +- uint32_t value_len; +- uint64_t expires; +- ngx_queue_t queue; +- uint32_t user_flags; +- u_char data[1]; +-} ngx_http_lua_shdict_node_t; +- +- +-typedef struct { +- ngx_queue_t queue; +- uint32_t value_len; +- uint8_t value_type; +- u_char data[1]; +-} ngx_http_lua_shdict_list_node_t; +- +- +-typedef struct { +- ngx_rbtree_t rbtree; +- ngx_rbtree_node_t sentinel; +- ngx_queue_t lru_queue; +-} ngx_http_lua_shdict_shctx_t; +- +- +-typedef struct { +- ngx_http_lua_shdict_shctx_t *sh; +- ngx_slab_pool_t *shpool; +- ngx_str_t name; +- ngx_http_lua_main_conf_t *main_conf; +- ngx_log_t *log; +-} ngx_http_lua_shdict_ctx_t; +- +- +-typedef struct { +- ngx_log_t *log; +- ngx_http_lua_main_conf_t *lmcf; +- ngx_cycle_t *cycle; +- ngx_shm_zone_t zone; +-} ngx_http_lua_shm_zone_ctx_t; +- +- +-ngx_int_t ngx_http_lua_shdict_init_zone(ngx_shm_zone_t *shm_zone, void *data); +-void ngx_http_lua_shdict_rbtree_insert_value(ngx_rbtree_node_t *temp, +- ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); +-void ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, +- lua_State *L); +- +- +-#endif /* _NGX_HTTP_LUA_SHDICT_H_INCLUDED_ */ +- +-/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ +diff --git src/ngx_http_lua_util.c src/ngx_http_lua_util.c +index 5fe9b506..33d6a657 100644 +--- src/ngx_http_lua_util.c ++++ src/ngx_http_lua_util.c +@@ -12,6 +12,7 @@ + + + #include "nginx.h" ++#include "ngx_meta_lua_api.h" + #include "ngx_http_lua_directive.h" + #include "ngx_http_lua_util.h" + #include "ngx_http_lua_exception.h" +@@ -28,7 +29,6 @@ + #include "ngx_http_lua_string.h" + #include "ngx_http_lua_misc.h" + #include "ngx_http_lua_consts.h" +-#include "ngx_http_lua_shdict.h" + #include "ngx_http_lua_coroutine.h" + #include "ngx_http_lua_socket_tcp.h" + #include "ngx_http_lua_socket_udp.h" +@@ -114,7 +114,7 @@ static ngx_int_t ngx_http_lua_handle_rewrite_jump(lua_State *L, + static int ngx_http_lua_thread_traceback(lua_State *L, lua_State *co, + ngx_http_lua_co_ctx_t *coctx); + static void ngx_http_lua_inject_ngx_api(lua_State *L, +- ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log); ++ ngx_cycle_t *cycle, ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log); + static void ngx_http_lua_inject_arg_api(lua_State *L); + static int ngx_http_lua_param_get(lua_State *L); + static int ngx_http_lua_param_set(lua_State *L); +@@ -808,13 +808,13 @@ ngx_http_lua_init_globals(lua_State *L, ngx_cycle_t *cycle, + ngx_http_lua_inject_ndk_api(L); + #endif /* defined(NDK) && NDK */ + +- ngx_http_lua_inject_ngx_api(L, lmcf, log); ++ ngx_http_lua_inject_ngx_api(L, cycle, lmcf, log); + } + + + static void +-ngx_http_lua_inject_ngx_api(lua_State *L, ngx_http_lua_main_conf_t *lmcf, +- ngx_log_t *log) ++ngx_http_lua_inject_ngx_api(lua_State *L, ngx_cycle_t *cycle, ++ ngx_http_lua_main_conf_t *lmcf, ngx_log_t *log) + { + lua_createtable(L, 0 /* narr */, 113 /* nrec */); /* ngx.* */ + +@@ -836,7 +836,7 @@ ngx_http_lua_inject_ngx_api(lua_State *L, ngx_http_lua_main_conf_t *lmcf, + ngx_http_lua_inject_req_api(log, L); + ngx_http_lua_inject_resp_header_api(L); + ngx_http_lua_create_headers_metatable(log, L); +- ngx_http_lua_inject_shdict_api(lmcf, L); ++ ngx_meta_lua_inject_shdict_api(L, cycle, &ngx_http_lua_module); + ngx_http_lua_inject_socket_tcp_api(log, L); + ngx_http_lua_inject_socket_udp_api(log, L); + ngx_http_lua_inject_uthread_api(log, L); +@@ -2204,7 +2204,7 @@ ngx_http_lua_util_hex2int(char xdigit) + if (xdigit <= 'f' && xdigit >= 'a') { + return xdigit - 'a' + 10; + } +- ++ + return -1; + } + +@@ -2235,7 +2235,7 @@ ngx_http_lua_unescape_uri(u_char **dst, u_char **src, size_t size, + /* we can be sure here they must be hex digits */ + ch = ngx_http_lua_util_hex2int(s[0]) * 16 + + ngx_http_lua_util_hex2int(s[1]); +- ++ + if ((isuri || isredirect) && ch == '?') { + *d++ = ch; + break; +@@ -2255,7 +2255,7 @@ ngx_http_lua_unescape_uri(u_char **dst, u_char **src, size_t size, + *d++ = curr; + } + } +- ++ + /* a safe guard if dst need to be null-terminated */ + if (d != de) { + *d = '\0'; +diff --git src/ngx_http_lua_util.h src/ngx_http_lua_util.h +index 1768e5e2..9c5d26de 100644 +--- src/ngx_http_lua_util.h ++++ src/ngx_http_lua_util.h +@@ -327,7 +327,9 @@ ngx_http_lua_create_ctx(ngx_http_request_t *r) + ngx_http_lua_assert(L != NULL); + + if (lmcf->init_handler) { +- if (lmcf->init_handler(r->connection->log, lmcf, L) != NGX_OK) { ++ if (lmcf->init_handler(r->connection->log, lmcf->init_src, L) ++ != NGX_OK) ++ { + /* an error happened */ + return NULL; + } diff --git a/patch/1.19.9/ngx_stream_lua-shared_shdict.patch b/patch/1.19.9/ngx_stream_lua-shared_shdict.patch new file mode 100644 index 0000000..84cd486 --- /dev/null +++ b/patch/1.19.9/ngx_stream_lua-shared_shdict.patch @@ -0,0 +1,2790 @@ +diff --git config config +index 07240ea..536b66b 100644 +--- config ++++ config +@@ -260,7 +260,6 @@ STREAM_LUA_SRCS=" \ + $ngx_addon_dir/src/ngx_stream_lua_ctx.c \ + $ngx_addon_dir/src/ngx_stream_lua_regex.c \ + $ngx_addon_dir/src/ngx_stream_lua_script.c \ +- $ngx_addon_dir/src/ngx_stream_lua_shdict.c \ + $ngx_addon_dir/src/ngx_stream_lua_variable.c \ + $ngx_addon_dir/src/ngx_stream_lua_timer.c \ + $ngx_addon_dir/src/ngx_stream_lua_config.c \ +@@ -304,7 +303,6 @@ STREAM_LUA_DEPS=" \ + $ngx_addon_dir/src/ngx_stream_lua_phase.h \ + $ngx_addon_dir/src/ngx_stream_lua_ctx.h \ + $ngx_addon_dir/src/ngx_stream_lua_script.h \ +- $ngx_addon_dir/src/ngx_stream_lua_shdict.h \ + $ngx_addon_dir/src/ngx_stream_lua_timer.h \ + $ngx_addon_dir/src/ngx_stream_lua_config.h \ + $ngx_addon_dir/src/api/ngx_stream_lua_api.h \ +diff --git src/api/ngx_stream_lua_api.h src/api/ngx_stream_lua_api.h +index 92f933d..e722580 100644 +--- src/api/ngx_stream_lua_api.h ++++ src/api/ngx_stream_lua_api.h +@@ -57,15 +57,6 @@ lua_State *ngx_stream_lua_get_global_state(ngx_conf_t *cf); + ngx_int_t ngx_stream_lua_add_package_preload(ngx_conf_t *cf, + const char *package, lua_CFunction func); + +-ngx_int_t ngx_stream_lua_shared_dict_get(ngx_shm_zone_t *shm_zone, +- u_char *key_data, size_t key_len, ngx_stream_lua_value_t *value); +- +-ngx_shm_zone_t *ngx_stream_lua_find_zone(u_char *name_data, +- size_t name_len); +- +-ngx_shm_zone_t *ngx_stream_lua_shared_memory_add(ngx_conf_t *cf, +- ngx_str_t *name, size_t size, void *tag); +- + + #endif /* _NGX_STREAM_LUA_API_H_INCLUDED_ */ + +diff --git src/ngx_stream_lua_api.c src/ngx_stream_lua_api.c +index cf01b36..fcc685c 100644 +--- src/ngx_stream_lua_api.c ++++ src/ngx_stream_lua_api.c +@@ -20,7 +20,6 @@ + + #include "ngx_stream_lua_common.h" + #include "api/ngx_stream_lua_api.h" +-#include "ngx_stream_lua_shdict.h" + #include "ngx_stream_lua_util.h" + + +@@ -35,12 +34,6 @@ ngx_stream_lua_get_global_state(ngx_conf_t *cf) + } + + +- +- +-static ngx_int_t ngx_stream_lua_shared_memory_init(ngx_shm_zone_t *shm_zone, +- void *data); +- +- + ngx_int_t + ngx_stream_lua_add_package_preload(ngx_conf_t *cf, const char *package, + lua_CFunction func) +@@ -86,136 +79,4 @@ ngx_stream_lua_add_package_preload(ngx_conf_t *cf, const char *package, + return NGX_OK; + } + +- +-ngx_shm_zone_t * +-ngx_stream_lua_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, +- size_t size, void *tag) +-{ +- ngx_stream_lua_main_conf_t *lmcf; +- ngx_stream_lua_shm_zone_ctx_t *ctx; +- +- ngx_shm_zone_t **zp; +- ngx_shm_zone_t *zone; +- ngx_int_t n; +- +- lmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_lua_module); +- if (lmcf == NULL) { +- return NULL; +- } +- +- if (lmcf->shm_zones == NULL) { +- lmcf->shm_zones = ngx_palloc(cf->pool, sizeof(ngx_array_t)); +- if (lmcf->shm_zones == NULL) { +- return NULL; +- } +- +- if (ngx_array_init(lmcf->shm_zones, cf->pool, 2, +- sizeof(ngx_shm_zone_t *)) +- != NGX_OK) +- { +- return NULL; +- } +- } +- +- zone = ngx_shared_memory_add(cf, name, (size_t) size, tag); +- if (zone == NULL) { +- return NULL; +- } +- +- if (zone->data) { +- ctx = (ngx_stream_lua_shm_zone_ctx_t *) zone->data; +- return &ctx->zone; +- } +- +- n = sizeof(ngx_stream_lua_shm_zone_ctx_t); +- +- ctx = ngx_pcalloc(cf->pool, n); +- if (ctx == NULL) { +- return NULL; +- } +- +- ctx->lmcf = lmcf; +- ctx->log = &cf->cycle->new_log; +- ctx->cycle = cf->cycle; +- +- ngx_memcpy(&ctx->zone, zone, sizeof(ngx_shm_zone_t)); +- +- zp = ngx_array_push(lmcf->shm_zones); +- if (zp == NULL) { +- return NULL; +- } +- +- *zp = zone; +- +- /* set zone init */ +- zone->init = ngx_stream_lua_shared_memory_init; +- zone->data = ctx; +- +- lmcf->requires_shm = 1; +- +- return &ctx->zone; +-} +- +- +-static ngx_int_t +-ngx_stream_lua_shared_memory_init(ngx_shm_zone_t *shm_zone, void *data) +-{ +- ngx_stream_lua_shm_zone_ctx_t *octx = data; +- ngx_stream_lua_main_conf_t *lmcf; +- ngx_stream_lua_shm_zone_ctx_t *ctx; +- +- ngx_shm_zone_t *ozone; +- void *odata; +- ngx_int_t rc; +- volatile ngx_cycle_t *saved_cycle; +- ngx_shm_zone_t *zone; +- +- ctx = (ngx_stream_lua_shm_zone_ctx_t *) shm_zone->data; +- zone = &ctx->zone; +- +- odata = NULL; +- if (octx) { +- ozone = &octx->zone; +- odata = ozone->data; +- } +- +- zone->shm = shm_zone->shm; +-#if defined(nginx_version) && nginx_version >= 1009000 +- zone->noreuse = shm_zone->noreuse; +-#endif +- +- if (zone->init(zone, odata) != NGX_OK) { +- return NGX_ERROR; +- } +- +- dd("get lmcf"); +- +- lmcf = ctx->lmcf; +- if (lmcf == NULL) { +- return NGX_ERROR; +- } +- +- dd("lmcf->lua: %p", lmcf->lua); +- +- lmcf->shm_zones_inited++; +- +- if (lmcf->shm_zones_inited == lmcf->shm_zones->nelts +- && lmcf->init_handler && !ngx_test_config) +- { +- saved_cycle = ngx_cycle; +- ngx_cycle = ctx->cycle; +- +- rc = lmcf->init_handler(ctx->log, lmcf, lmcf->lua); +- +- ngx_cycle = saved_cycle; +- +- if (rc != NGX_OK) { +- /* an error happened */ +- return NGX_ERROR; +- } +- } +- +- return NGX_OK; +-} +- + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ +diff --git src/ngx_stream_lua_common.h src/ngx_stream_lua_common.h +index 0aa0a5e..28ef2d1 100644 +--- src/ngx_stream_lua_common.h ++++ src/ngx_stream_lua_common.h +@@ -31,6 +31,8 @@ + #include + #include + ++#include "ngx_meta_lua_api.h" ++ + + #include "ngx_stream_lua_request.h" + +@@ -53,6 +55,11 @@ + #endif + + ++#if !defined(ngx_meta_lua_version) || ngx_meta_lua_version < 00001 ++# error ngx_meta_lua_module 0.0.1 or above is required ++#endif ++ ++ + + + #if LUA_VERSION_NUM != 501 +@@ -158,8 +165,6 @@ typedef struct ngx_stream_lua_balancer_peer_data_s + typedef struct ngx_stream_lua_sema_mm_s ngx_stream_lua_sema_mm_t; + + +-typedef ngx_int_t (*ngx_stream_lua_main_conf_handler_pt)(ngx_log_t *log, +- ngx_stream_lua_main_conf_t *lmcf, lua_State *L); + typedef ngx_int_t (*ngx_stream_lua_srv_conf_handler_pt)( + ngx_stream_lua_request_t *r, ngx_stream_lua_srv_conf_t *lscf, lua_State *L); + +@@ -207,10 +212,10 @@ struct ngx_stream_lua_main_conf_s { + + ngx_flag_t postponed_to_preread_phase_end; + +- ngx_stream_lua_main_conf_handler_pt init_handler; ++ ngx_meta_lua_main_conf_handler_pt init_handler; + ngx_str_t init_src; + +- ngx_stream_lua_main_conf_handler_pt init_worker_handler; ++ ngx_meta_lua_main_conf_handler_pt init_worker_handler; + ngx_str_t init_worker_src; + + ngx_stream_lua_balancer_peer_data_t *balancer_peer_data; +@@ -220,8 +225,6 @@ struct ngx_stream_lua_main_conf_s { + * data pointer in the main conf. + */ + +- ngx_uint_t shm_zones_inited; +- + ngx_stream_lua_sema_mm_t *sema_mm; + + ngx_uint_t malloc_trim_cycle; /* a cycle is defined as the number +@@ -234,7 +237,6 @@ struct ngx_stream_lua_main_conf_s { + unsigned requires_preread:1; + + unsigned requires_log:1; +- unsigned requires_shm:1; + unsigned requires_capture_log:1; + }; + +diff --git src/ngx_stream_lua_directive.c src/ngx_stream_lua_directive.c +index 5580106..04fed32 100644 +--- src/ngx_stream_lua_directive.c ++++ src/ngx_stream_lua_directive.c +@@ -27,7 +27,6 @@ + #include "ngx_stream_lua_logby.h" + #include "ngx_stream_lua_initby.h" + #include "ngx_stream_lua_initworkerby.h" +-#include "ngx_stream_lua_shdict.h" + #include "ngx_stream_lua_lex.h" + #include "ngx_stream_lua_log.h" + #include "ngx_stream_lua_log_ringbuf.h" +@@ -69,90 +68,6 @@ enum { + }; + + +-char * +-ngx_stream_lua_shared_dict(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +-{ +- ngx_stream_lua_main_conf_t *lmcf = conf; +- ngx_str_t *value, name; +- ngx_shm_zone_t *zone; +- ngx_shm_zone_t **zp; +- ngx_stream_lua_shdict_ctx_t *ctx; +- ssize_t size; +- +- if (lmcf->shdict_zones == NULL) { +- lmcf->shdict_zones = ngx_palloc(cf->pool, sizeof(ngx_array_t)); +- if (lmcf->shdict_zones == NULL) { +- return NGX_CONF_ERROR; +- } +- +- if (ngx_array_init(lmcf->shdict_zones, cf->pool, 2, +- sizeof(ngx_shm_zone_t *)) +- != NGX_OK) +- { +- return NGX_CONF_ERROR; +- } +- } +- +- value = cf->args->elts; +- +- ctx = NULL; +- +- if (value[1].len == 0) { +- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, +- "invalid lua shared dict name \"%V\"", &value[1]); +- return NGX_CONF_ERROR; +- } +- +- name = value[1]; +- +- size = ngx_parse_size(&value[2]); +- +- if (size <= 8191) { +- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, +- "invalid lua shared dict size \"%V\"", &value[2]); +- return NGX_CONF_ERROR; +- } +- +- ctx = ngx_pcalloc(cf->pool, sizeof(ngx_stream_lua_shdict_ctx_t)); +- if (ctx == NULL) { +- return NGX_CONF_ERROR; +- } +- +- ctx->name = name; +- ctx->main_conf = lmcf; +- ctx->log = &cf->cycle->new_log; +- +- zone = ngx_stream_lua_shared_memory_add(cf, &name, (size_t) size, +- &ngx_stream_lua_module); +- if (zone == NULL) { +- return NGX_CONF_ERROR; +- } +- +- if (zone->data) { +- ctx = zone->data; +- +- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, +- "lua_shared_dict \"%V\" is already defined as " +- "\"%V\"", &name, &ctx->name); +- return NGX_CONF_ERROR; +- } +- +- zone->init = ngx_stream_lua_shdict_init_zone; +- zone->data = ctx; +- +- zp = ngx_array_push(lmcf->shdict_zones); +- if (zp == NULL) { +- return NGX_CONF_ERROR; +- } +- +- *zp = zone; +- +- lmcf->requires_shm = 1; +- +- return NGX_CONF_OK; +-} +- +- + char * + ngx_stream_lua_code_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) + { +@@ -190,6 +105,15 @@ ngx_stream_lua_load_resty_core(ngx_conf_t *cf, ngx_command_t *cmd, + } + + ++char * ++ngx_stream_lua_shdict_directive(ngx_conf_t *cf, ngx_command_t *cmd, ++ void *conf) ++{ ++ return ngx_meta_lua_shdict_directive_helper(cf, ++ &ngx_stream_lua_module); ++} ++ ++ + char * + ngx_stream_lua_package_cpath(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) + { +@@ -646,7 +570,7 @@ ngx_stream_lua_init_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + return NGX_CONF_ERROR; + } + +- lmcf->init_handler = (ngx_stream_lua_main_conf_handler_pt) cmd->post; ++ lmcf->init_handler = (ngx_meta_lua_main_conf_handler_pt) cmd->post; + + if (cmd->post == ngx_stream_lua_init_by_file) { + name = ngx_stream_lua_rebase_path(cf->pool, value[1].data, +@@ -707,7 +631,7 @@ ngx_stream_lua_init_worker_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + + value = cf->args->elts; + +- lmcf->init_worker_handler = (ngx_stream_lua_main_conf_handler_pt) cmd->post; ++ lmcf->init_worker_handler = (ngx_meta_lua_main_conf_handler_pt) cmd->post; + + if (cmd->post == ngx_stream_lua_init_worker_by_file) { + name = ngx_stream_lua_rebase_path(cf->pool, value[1].data, +diff --git src/ngx_stream_lua_directive.h src/ngx_stream_lua_directive.h +index 6b36bb1..fa469b6 100644 +--- src/ngx_stream_lua_directive.h ++++ src/ngx_stream_lua_directive.h +@@ -20,7 +20,7 @@ + #include "ngx_stream_lua_common.h" + + +-char *ngx_stream_lua_shared_dict(ngx_conf_t *cf, ngx_command_t *cmd, ++char *ngx_stream_lua_shdict_directive(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + char *ngx_stream_lua_package_cpath(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +diff --git src/ngx_stream_lua_initby.c src/ngx_stream_lua_initby.c +index c6bbf0d..98e3c6f 100644 +--- src/ngx_stream_lua_initby.c ++++ src/ngx_stream_lua_initby.c +@@ -22,13 +22,13 @@ + + + ngx_int_t +-ngx_stream_lua_init_by_inline(ngx_log_t *log, ngx_stream_lua_main_conf_t *lmcf, ++ngx_stream_lua_init_by_inline(ngx_log_t *log, ngx_str_t init_src, + lua_State *L) + { + int status; + +- status = luaL_loadbuffer(L, (char *) lmcf->init_src.data, +- lmcf->init_src.len, "=init_by_lua") ++ status = luaL_loadbuffer(L, (char *) init_src.data, init_src.len, ++ "=init_by_lua") + || ngx_stream_lua_do_call(log, L); + + return ngx_stream_lua_report(log, L, status, "init_by_lua"); +@@ -36,12 +36,12 @@ ngx_stream_lua_init_by_inline(ngx_log_t *log, ngx_stream_lua_main_conf_t *lmcf, + + + ngx_int_t +-ngx_stream_lua_init_by_file(ngx_log_t *log, ngx_stream_lua_main_conf_t *lmcf, ++ngx_stream_lua_init_by_file(ngx_log_t *log, ngx_str_t init_src, + lua_State *L) + { + int status; + +- status = luaL_loadfile(L, (char *) lmcf->init_src.data) ++ status = luaL_loadfile(L, (char *) init_src.data) + || ngx_stream_lua_do_call(log, L); + + return ngx_stream_lua_report(log, L, status, "init_by_lua_file"); +diff --git src/ngx_stream_lua_initby.h src/ngx_stream_lua_initby.h +index f2e2c40..060ee41 100644 +--- src/ngx_stream_lua_initby.h ++++ src/ngx_stream_lua_initby.h +@@ -20,10 +20,10 @@ + + + ngx_int_t ngx_stream_lua_init_by_inline(ngx_log_t *log, +- ngx_stream_lua_main_conf_t *lmcf, lua_State *L); ++ ngx_str_t init_src, lua_State *L); + + ngx_int_t ngx_stream_lua_init_by_file(ngx_log_t *log, +- ngx_stream_lua_main_conf_t *lmcf, lua_State *L); ++ ngx_str_t init_src, lua_State *L); + + + #endif /* _NGX_STREAM_LUA_INITBY_H_INCLUDED_ */ +diff --git src/ngx_stream_lua_initworkerby.c src/ngx_stream_lua_initworkerby.c +index 0c329a5..151cf19 100644 +--- src/ngx_stream_lua_initworkerby.c ++++ src/ngx_stream_lua_initworkerby.c +@@ -297,7 +297,8 @@ ngx_stream_lua_init_worker(ngx_cycle_t *cycle) + + ngx_stream_lua_set_req(lmcf->lua, r); + +- (void) lmcf->init_worker_handler(cycle->log, lmcf, lmcf->lua); ++ (void) lmcf->init_worker_handler(cycle->log, lmcf->init_worker_src, ++ lmcf->lua); + + ngx_destroy_pool(c->pool); + return NGX_OK; +@@ -318,12 +319,12 @@ failed: + + ngx_int_t + ngx_stream_lua_init_worker_by_inline(ngx_log_t *log, +- ngx_stream_lua_main_conf_t *lmcf, lua_State *L) ++ ngx_str_t init_worker_src, lua_State *L) + { + int status; + +- status = luaL_loadbuffer(L, (char *) lmcf->init_worker_src.data, +- lmcf->init_worker_src.len, "=init_worker_by_lua") ++ status = luaL_loadbuffer(L, (char *) init_worker_src.data, ++ init_worker_src.len, "=init_worker_by_lua") + || ngx_stream_lua_do_call(log, L); + + return ngx_stream_lua_report(log, L, status, "init_worker_by_lua"); +@@ -332,11 +333,11 @@ ngx_stream_lua_init_worker_by_inline(ngx_log_t *log, + + ngx_int_t + ngx_stream_lua_init_worker_by_file(ngx_log_t *log, +- ngx_stream_lua_main_conf_t *lmcf, lua_State *L) ++ ngx_str_t init_worker_src, lua_State *L) + { + int status; + +- status = luaL_loadfile(L, (char *) lmcf->init_worker_src.data) ++ status = luaL_loadfile(L, (char *) init_worker_src.data) + || ngx_stream_lua_do_call(log, L); + + return ngx_stream_lua_report(log, L, status, "init_worker_by_lua_file"); +diff --git src/ngx_stream_lua_initworkerby.h src/ngx_stream_lua_initworkerby.h +index 43f6de3..53a443a 100644 +--- src/ngx_stream_lua_initworkerby.h ++++ src/ngx_stream_lua_initworkerby.h +@@ -20,10 +20,10 @@ + + + ngx_int_t ngx_stream_lua_init_worker_by_inline(ngx_log_t *log, +- ngx_stream_lua_main_conf_t *lmcf, lua_State *L); ++ ngx_str_t init_worker_src, lua_State *L); + + ngx_int_t ngx_stream_lua_init_worker_by_file(ngx_log_t *log, +- ngx_stream_lua_main_conf_t *lmcf, lua_State *L); ++ ngx_str_t init_worker_src, lua_State *L); + + ngx_int_t ngx_stream_lua_init_worker(ngx_cycle_t *cycle); + +diff --git src/ngx_stream_lua_module.c src/ngx_stream_lua_module.c +index 6034add..45e3b89 100644 +--- src/ngx_stream_lua_module.c ++++ src/ngx_stream_lua_module.c +@@ -19,6 +19,7 @@ + #include "ddebug.h" + + ++#include "ngx_meta_lua_api.h" + #include "ngx_stream_lua_directive.h" + #include "ngx_stream_lua_contentby.h" + #include "ngx_stream_lua_util.h" +@@ -103,7 +104,7 @@ static ngx_command_t ngx_stream_lua_cmds[] = { + + { ngx_string("lua_shared_dict"), + NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE2, +- ngx_stream_lua_shared_dict, ++ ngx_stream_lua_shdict_directive, + 0, + 0, + NULL }, +@@ -465,7 +466,6 @@ static ngx_int_t + ngx_stream_lua_init(ngx_conf_t *cf) + { + ngx_int_t rc; +- volatile ngx_cycle_t *saved_cycle; + ngx_array_t *arr; + ngx_pool_cleanup_t *cln; + +@@ -577,18 +577,11 @@ ngx_stream_lua_init(ngx_conf_t *cf) + + ngx_stream_lua_assert(lmcf->lua != NULL); + +- if (!lmcf->requires_shm && lmcf->init_handler) { +- saved_cycle = ngx_cycle; +- ngx_cycle = cf->cycle; +- +- rc = lmcf->init_handler(cf->log, lmcf, lmcf->lua); +- +- ngx_cycle = saved_cycle; +- +- if (rc != NGX_OK) { +- /* an error happened */ +- return NGX_ERROR; +- } ++ if (ngx_meta_lua_post_init_handler(cf, lmcf->init_handler, ++ lmcf->init_src, lmcf->lua) ++ != NGX_OK) ++ { ++ return NGX_ERROR; + } + + dd("Lua VM initialized!"); +@@ -648,11 +641,8 @@ ngx_stream_lua_create_main_conf(ngx_conf_t *cf) + * lmcf->watcher = NULL; + * lmcf->regex_cache_entries = 0; + * lmcf->jit_stack = NULL; +- * lmcf->shm_zones = NULL; + * lmcf->init_handler = NULL; + * lmcf->init_src = { 0, NULL }; +- * lmcf->shm_zones_inited = 0; +- * lmcf->shdict_zones = NULL; + * lmcf->preload_hooks = NULL; + * lmcf->requires_header_filter = 0; + * lmcf->requires_body_filter = 0; +@@ -660,7 +650,6 @@ ngx_stream_lua_create_main_conf(ngx_conf_t *cf) + * lmcf->requires_rewrite = 0; + * lmcf->requires_access = 0; + * lmcf->requires_log = 0; +- * lmcf->requires_shm = 0; + */ + + lmcf->pool = cf->pool; +diff --git src/ngx_stream_lua_shdict.c src/ngx_stream_lua_shdict.c +deleted file mode 100644 +index 6b137f5..0000000 +--- src/ngx_stream_lua_shdict.c ++++ /dev/null +@@ -1,2030 +0,0 @@ +- +-/* +- * !!! DO NOT EDIT DIRECTLY !!! +- * This file was automatically generated from the following template: +- * +- * src/subsys/ngx_subsys_lua_shdict.c.tt2 +- */ +- +- +-/* +- * Copyright (C) Yichun Zhang (agentzh) +- */ +- +- +-#ifndef DDEBUG +-#define DDEBUG 0 +-#endif +-#include "ddebug.h" +- +- +-#include "ngx_stream_lua_shdict.h" +-#include "ngx_stream_lua_util.h" +-#include "ngx_stream_lua_api.h" +- +- +-static int ngx_stream_lua_shdict_expire(ngx_stream_lua_shdict_ctx_t *ctx, +- ngx_uint_t n); +-static ngx_int_t ngx_stream_lua_shdict_lookup(ngx_shm_zone_t *shm_zone, +- ngx_uint_t hash, u_char *kdata, size_t klen, +- ngx_stream_lua_shdict_node_t **sdp); +-static int ngx_stream_lua_shdict_flush_expired(lua_State *L); +-static int ngx_stream_lua_shdict_get_keys(lua_State *L); +-static int ngx_stream_lua_shdict_lpush(lua_State *L); +-static int ngx_stream_lua_shdict_rpush(lua_State *L); +-static int ngx_stream_lua_shdict_push_helper(lua_State *L, int flags); +-static int ngx_stream_lua_shdict_lpop(lua_State *L); +-static int ngx_stream_lua_shdict_rpop(lua_State *L); +-static int ngx_stream_lua_shdict_pop_helper(lua_State *L, int flags); +-static int ngx_stream_lua_shdict_llen(lua_State *L); +- +- +-static ngx_inline ngx_shm_zone_t *ngx_stream_lua_shdict_get_zone(lua_State *L, +- int index); +- +- +-#define NGX_STREAM_LUA_SHDICT_ADD 0x0001 +-#define NGX_STREAM_LUA_SHDICT_REPLACE 0x0002 +-#define NGX_STREAM_LUA_SHDICT_SAFE_STORE 0x0004 +- +- +-#define NGX_STREAM_LUA_SHDICT_LEFT 0x0001 +-#define NGX_STREAM_LUA_SHDICT_RIGHT 0x0002 +- +- +-enum { +- SHDICT_USERDATA_INDEX = 1, +-}; +- +- +-enum { +- SHDICT_TNIL = 0, /* same as LUA_TNIL */ +- SHDICT_TBOOLEAN = 1, /* same as LUA_TBOOLEAN */ +- SHDICT_TNUMBER = 3, /* same as LUA_TNUMBER */ +- SHDICT_TSTRING = 4, /* same as LUA_TSTRING */ +- SHDICT_TLIST = 5, +-}; +- +- +-static ngx_inline ngx_queue_t * +-ngx_stream_lua_shdict_get_list_head(ngx_stream_lua_shdict_node_t *sd, +- size_t len) +-{ +- return (ngx_queue_t *) ngx_align_ptr(((u_char *) &sd->data + len), +- NGX_ALIGNMENT); +-} +- +- +-ngx_int_t +-ngx_stream_lua_shdict_init_zone(ngx_shm_zone_t *shm_zone, void *data) +-{ +- ngx_stream_lua_shdict_ctx_t *octx = data; +- ngx_stream_lua_shdict_ctx_t *ctx; +- +- size_t len; +- +- dd("init zone"); +- +- ctx = shm_zone->data; +- +- if (octx) { +- ctx->sh = octx->sh; +- ctx->shpool = octx->shpool; +- +- return NGX_OK; +- } +- +- ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; +- +- if (shm_zone->shm.exists) { +- ctx->sh = ctx->shpool->data; +- +- return NGX_OK; +- } +- +- ctx->sh = ngx_slab_alloc(ctx->shpool, +- sizeof(ngx_stream_lua_shdict_shctx_t)); +- if (ctx->sh == NULL) { +- return NGX_ERROR; +- } +- +- ctx->shpool->data = ctx->sh; +- +- ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel, +- ngx_stream_lua_shdict_rbtree_insert_value); +- +- ngx_queue_init(&ctx->sh->lru_queue); +- +- len = sizeof(" in lua_shared_dict zone \"\"") + shm_zone->shm.name.len; +- +- ctx->shpool->log_ctx = ngx_slab_alloc(ctx->shpool, len); +- if (ctx->shpool->log_ctx == NULL) { +- return NGX_ERROR; +- } +- +- ngx_sprintf(ctx->shpool->log_ctx, " in lua_shared_dict zone \"%V\"%Z", +- &shm_zone->shm.name); +- +- ctx->shpool->log_nomem = 0; +- +- return NGX_OK; +-} +- +- +-void +-ngx_stream_lua_shdict_rbtree_insert_value(ngx_rbtree_node_t *temp, +- ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) +-{ +- ngx_rbtree_node_t **p; +- +- ngx_stream_lua_shdict_node_t *sdn, *sdnt; +- +- for ( ;; ) { +- +- if (node->key < temp->key) { +- +- p = &temp->left; +- +- } else if (node->key > temp->key) { +- +- p = &temp->right; +- +- } else { /* node->key == temp->key */ +- +- sdn = (ngx_stream_lua_shdict_node_t *) &node->color; +- sdnt = (ngx_stream_lua_shdict_node_t *) &temp->color; +- +- p = ngx_memn2cmp(sdn->data, sdnt->data, sdn->key_len, +- sdnt->key_len) < 0 ? &temp->left : &temp->right; +- } +- +- if (*p == sentinel) { +- break; +- } +- +- temp = *p; +- } +- +- *p = node; +- node->parent = temp; +- node->left = sentinel; +- node->right = sentinel; +- ngx_rbt_red(node); +-} +- +- +-static ngx_int_t +-ngx_stream_lua_shdict_lookup(ngx_shm_zone_t *shm_zone, ngx_uint_t hash, +- u_char *kdata, size_t klen, ngx_stream_lua_shdict_node_t **sdp) +-{ +- ngx_int_t rc; +- ngx_time_t *tp; +- uint64_t now; +- int64_t ms; +- ngx_rbtree_node_t *node, *sentinel; +- +- ngx_stream_lua_shdict_ctx_t *ctx; +- ngx_stream_lua_shdict_node_t *sd; +- +- ctx = shm_zone->data; +- +- node = ctx->sh->rbtree.root; +- sentinel = ctx->sh->rbtree.sentinel; +- +- while (node != sentinel) { +- +- if (hash < node->key) { +- node = node->left; +- continue; +- } +- +- if (hash > node->key) { +- node = node->right; +- continue; +- } +- +- /* hash == node->key */ +- +- sd = (ngx_stream_lua_shdict_node_t *) &node->color; +- +- rc = ngx_memn2cmp(kdata, sd->data, klen, (size_t) sd->key_len); +- +- if (rc == 0) { +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- *sdp = sd; +- +- dd("node expires: %lld", (long long) sd->expires); +- +- if (sd->expires != 0) { +- tp = ngx_timeofday(); +- +- now = (uint64_t) tp->sec * 1000 + tp->msec; +- ms = sd->expires - now; +- +- dd("time to live: %lld", (long long) ms); +- +- if (ms < 0) { +- dd("node already expired"); +- return NGX_DONE; +- } +- } +- +- return NGX_OK; +- } +- +- node = (rc < 0) ? node->left : node->right; +- } +- +- *sdp = NULL; +- +- return NGX_DECLINED; +-} +- +- +-static int +-ngx_stream_lua_shdict_expire(ngx_stream_lua_shdict_ctx_t *ctx, ngx_uint_t n) +-{ +- ngx_time_t *tp; +- uint64_t now; +- ngx_queue_t *q, *list_queue, *lq; +- int64_t ms; +- ngx_rbtree_node_t *node; +- int freed = 0; +- +- ngx_stream_lua_shdict_node_t *sd; +- ngx_stream_lua_shdict_list_node_t *lnode; +- +- tp = ngx_timeofday(); +- +- now = (uint64_t) tp->sec * 1000 + tp->msec; +- +- /* +- * n == 1 deletes one or two expired entries +- * n == 0 deletes oldest entry by force +- * and one or two zero rate entries +- */ +- +- while (n < 3) { +- +- if (ngx_queue_empty(&ctx->sh->lru_queue)) { +- return freed; +- } +- +- q = ngx_queue_last(&ctx->sh->lru_queue); +- +- sd = ngx_queue_data(q, ngx_stream_lua_shdict_node_t, queue); +- +- if (n++ != 0) { +- +- if (sd->expires == 0) { +- return freed; +- } +- +- ms = sd->expires - now; +- if (ms > 0) { +- return freed; +- } +- } +- +- if (sd->value_type == SHDICT_TLIST) { +- list_queue = ngx_stream_lua_shdict_get_list_head(sd, +- sd->key_len); +- +- for (lq = ngx_queue_head(list_queue); +- lq != ngx_queue_sentinel(list_queue); +- lq = ngx_queue_next(lq)) +- { +- lnode = ngx_queue_data(lq, ngx_stream_lua_shdict_list_node_t, +- queue); +- +- ngx_slab_free_locked(ctx->shpool, lnode); +- } +- } +- +- ngx_queue_remove(q); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- +- ngx_slab_free_locked(ctx->shpool, node); +- +- freed++; +- } +- +- return freed; +-} +- +- +-void +-ngx_stream_lua_inject_shdict_api(ngx_stream_lua_main_conf_t *lmcf, lua_State *L) +-{ +- ngx_stream_lua_shdict_ctx_t *ctx; +- +- ngx_uint_t i; +- ngx_shm_zone_t **zone; +- ngx_shm_zone_t **zone_udata; +- +- if (lmcf->shdict_zones != NULL) { +- lua_createtable(L, 0, lmcf->shdict_zones->nelts /* nrec */); +- /* ngx.shared */ +- +- lua_createtable(L, 0 /* narr */, 22 /* nrec */); /* shared mt */ +- +- lua_pushcfunction(L, ngx_stream_lua_shdict_lpush); +- lua_setfield(L, -2, "lpush"); +- +- lua_pushcfunction(L, ngx_stream_lua_shdict_rpush); +- lua_setfield(L, -2, "rpush"); +- +- lua_pushcfunction(L, ngx_stream_lua_shdict_lpop); +- lua_setfield(L, -2, "lpop"); +- +- lua_pushcfunction(L, ngx_stream_lua_shdict_rpop); +- lua_setfield(L, -2, "rpop"); +- +- lua_pushcfunction(L, ngx_stream_lua_shdict_llen); +- lua_setfield(L, -2, "llen"); +- +- lua_pushcfunction(L, ngx_stream_lua_shdict_flush_expired); +- lua_setfield(L, -2, "flush_expired"); +- +- lua_pushcfunction(L, ngx_stream_lua_shdict_get_keys); +- lua_setfield(L, -2, "get_keys"); +- +- lua_pushvalue(L, -1); /* shared mt mt */ +- lua_setfield(L, -2, "__index"); /* shared mt */ +- +- zone = lmcf->shdict_zones->elts; +- +- for (i = 0; i < lmcf->shdict_zones->nelts; i++) { +- ctx = zone[i]->data; +- +- lua_pushlstring(L, (char *) ctx->name.data, ctx->name.len); +- /* shared mt key */ +- +- lua_createtable(L, 1 /* narr */, 0 /* nrec */); +- /* table of zone[i] */ +- zone_udata = lua_newuserdata(L, sizeof(ngx_shm_zone_t *)); +- /* shared mt key ud */ +- *zone_udata = zone[i]; +- lua_rawseti(L, -2, SHDICT_USERDATA_INDEX); /* {zone[i]} */ +- lua_pushvalue(L, -3); /* shared mt key ud mt */ +- lua_setmetatable(L, -2); /* shared mt key ud */ +- lua_rawset(L, -4); /* shared mt */ +- } +- +- lua_pop(L, 1); /* shared */ +- +- } else { +- lua_newtable(L); /* ngx.shared */ +- } +- +- lua_setfield(L, -2, "shared"); +-} +- +- +-static ngx_inline ngx_shm_zone_t * +-ngx_stream_lua_shdict_get_zone(lua_State *L, int index) +-{ +- ngx_shm_zone_t *zone; +- ngx_shm_zone_t **zone_udata; +- +- lua_rawgeti(L, index, SHDICT_USERDATA_INDEX); +- zone_udata = lua_touserdata(L, -1); +- lua_pop(L, 1); +- +- if (zone_udata == NULL) { +- return NULL; +- } +- +- zone = *zone_udata; +- return zone; +-} +- +- +-static int +-ngx_stream_lua_shdict_flush_expired(lua_State *L) +-{ +- ngx_queue_t *q, *prev, *list_queue, *lq; +- ngx_shm_zone_t *zone; +- ngx_time_t *tp; +- int freed = 0; +- int attempts = 0; +- ngx_rbtree_node_t *node; +- uint64_t now; +- int n; +- +- ngx_stream_lua_shdict_node_t *sd; +- ngx_stream_lua_shdict_ctx_t *ctx; +- ngx_stream_lua_shdict_list_node_t *lnode; +- +- 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_TTABLE); +- +- zone = ngx_stream_lua_shdict_get_zone(L, 1); +- if (zone == NULL) { +- return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer"); +- } +- +- if (n == 2) { +- attempts = luaL_checkint(L, 2); +- } +- +- ctx = zone->data; +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +- if (ngx_queue_empty(&ctx->sh->lru_queue)) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- lua_pushnumber(L, 0); +- return 1; +- } +- +- tp = ngx_timeofday(); +- +- now = (uint64_t) tp->sec * 1000 + tp->msec; +- +- q = ngx_queue_last(&ctx->sh->lru_queue); +- +- while (q != ngx_queue_sentinel(&ctx->sh->lru_queue)) { +- prev = ngx_queue_prev(q); +- +- sd = ngx_queue_data(q, ngx_stream_lua_shdict_node_t, queue); +- +- if (sd->expires != 0 && sd->expires <= now) { +- +- if (sd->value_type == SHDICT_TLIST) { +- list_queue = ngx_stream_lua_shdict_get_list_head(sd, +- sd->key_len); +- +- for (lq = ngx_queue_head(list_queue); +- lq != ngx_queue_sentinel(list_queue); +- lq = ngx_queue_next(lq)) +- { +- lnode = ngx_queue_data(lq, +- ngx_stream_lua_shdict_list_node_t, +- queue); +- +- ngx_slab_free_locked(ctx->shpool, lnode); +- } +- } +- +- ngx_queue_remove(q); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- ngx_slab_free_locked(ctx->shpool, node); +- freed++; +- +- if (attempts && freed == attempts) { +- break; +- } +- } +- +- q = prev; +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnumber(L, freed); +- return 1; +-} +- +- +-/* +- * This trades CPU for memory. This is potentially slow. O(2n) +- */ +- +-static int +-ngx_stream_lua_shdict_get_keys(lua_State *L) +-{ +- ngx_queue_t *q, *prev; +- ngx_shm_zone_t *zone; +- ngx_time_t *tp; +- int total = 0; +- int attempts = 1024; +- uint64_t now; +- int n; +- +- ngx_stream_lua_shdict_node_t *sd; +- ngx_stream_lua_shdict_ctx_t *ctx; +- +- 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_TTABLE); +- +- zone = ngx_stream_lua_shdict_get_zone(L, 1); +- if (zone == NULL) { +- return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer"); +- } +- +- if (n == 2) { +- attempts = luaL_checkint(L, 2); +- } +- +- ctx = zone->data; +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +- if (ngx_queue_empty(&ctx->sh->lru_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->lru_queue); +- +- while (q != ngx_queue_sentinel(&ctx->sh->lru_queue)) { +- prev = ngx_queue_prev(q); +- +- sd = ngx_queue_data(q, ngx_stream_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->lru_queue); +- +- while (q != ngx_queue_sentinel(&ctx->sh->lru_queue)) { +- prev = ngx_queue_prev(q); +- +- sd = ngx_queue_data(q, ngx_stream_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_stream_lua_shdict_lpush(lua_State *L) +-{ +- return ngx_stream_lua_shdict_push_helper(L, NGX_STREAM_LUA_SHDICT_LEFT); +-} +- +- +-static int +-ngx_stream_lua_shdict_rpush(lua_State *L) +-{ +- return ngx_stream_lua_shdict_push_helper(L, NGX_STREAM_LUA_SHDICT_RIGHT); +-} +- +- +-static int +-ngx_stream_lua_shdict_push_helper(lua_State *L, int flags) +-{ +- int n; +- ngx_str_t key; +- uint32_t hash; +- ngx_int_t rc; +- ngx_str_t value; +- int value_type; +- double num; +- ngx_rbtree_node_t *node; +- ngx_shm_zone_t *zone; +- ngx_queue_t *queue, *q; +- +- ngx_stream_lua_shdict_ctx_t *ctx; +- ngx_stream_lua_shdict_node_t *sd; +- ngx_stream_lua_shdict_list_node_t *lnode; +- +- n = lua_gettop(L); +- +- if (n != 3) { +- return luaL_error(L, "expecting 3 arguments, " +- "but only seen %d", n); +- } +- +- if (lua_type(L, 1) != LUA_TTABLE) { +- return luaL_error(L, "bad \"zone\" argument"); +- } +- +- zone = ngx_stream_lua_shdict_get_zone(L, 1); +- if (zone == NULL) { +- return luaL_error(L, "bad \"zone\" argument"); +- } +- +- ctx = zone->data; +- +- if (lua_isnil(L, 2)) { +- lua_pushnil(L); +- lua_pushliteral(L, "nil key"); +- return 2; +- } +- +- key.data = (u_char *) luaL_checklstring(L, 2, &key.len); +- +- if (key.len == 0) { +- lua_pushnil(L); +- lua_pushliteral(L, "empty key"); +- return 2; +- } +- +- if (key.len > 65535) { +- lua_pushnil(L); +- lua_pushliteral(L, "key too long"); +- return 2; +- } +- +- hash = ngx_crc32_short(key.data, key.len); +- +- value_type = lua_type(L, 3); +- +- switch (value_type) { +- +- case SHDICT_TSTRING: +- value.data = (u_char *) lua_tolstring(L, 3, &value.len); +- break; +- +- case SHDICT_TNUMBER: +- value.len = sizeof(double); +- num = lua_tonumber(L, 3); +- value.data = (u_char *) # +- break; +- +- default: +- lua_pushnil(L); +- lua_pushliteral(L, "bad value type"); +- return 2; +- } +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +-#if 1 +- ngx_stream_lua_shdict_expire(ctx, 1); +-#endif +- +- rc = ngx_stream_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); +- +- dd("shdict lookup returned %d", (int) rc); +- +- /* exists but expired */ +- +- if (rc == NGX_DONE) { +- +- if (sd->value_type != SHDICT_TLIST) { +- /* TODO: reuse when length matched */ +- +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict push: found old entry and value " +- "type not matched, remove it first"); +- +- ngx_queue_remove(&sd->queue); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- +- ngx_slab_free_locked(ctx->shpool, node); +- +- dd("go to init_list"); +- goto init_list; +- } +- +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict push: found old entry and value " +- "type matched, reusing it"); +- +- sd->expires = 0; +- +- /* free list nodes */ +- +- queue = ngx_stream_lua_shdict_get_list_head(sd, key.len); +- +- for (q = ngx_queue_head(queue); +- q != ngx_queue_sentinel(queue); +- q = ngx_queue_next(q)) +- { +- /* TODO: reuse matched size list node */ +- lnode = ngx_queue_data(q, ngx_stream_lua_shdict_list_node_t, queue); +- ngx_slab_free_locked(ctx->shpool, lnode); +- } +- +- ngx_queue_init(queue); +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- dd("go to push_node"); +- goto push_node; +- } +- +- /* exists and not expired */ +- +- if (rc == NGX_OK) { +- +- if (sd->value_type != SHDICT_TLIST) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnil(L); +- lua_pushliteral(L, "value not a list"); +- return 2; +- } +- +- queue = ngx_stream_lua_shdict_get_list_head(sd, key.len); +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- dd("go to push_node"); +- goto push_node; +- } +- +- /* rc == NGX_DECLINED, not found */ +- +-init_list: +- +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict list: creating a new entry"); +- +- /* NOTICE: we assume the begin point aligned in slab, be careful */ +- n = offsetof(ngx_rbtree_node_t, color) +- + offsetof(ngx_stream_lua_shdict_node_t, data) +- + key.len +- + sizeof(ngx_queue_t); +- +- dd("length before aligned: %d", n); +- +- n = (int) (uintptr_t) ngx_align_ptr(n, NGX_ALIGNMENT); +- +- dd("length after aligned: %d", n); +- +- node = ngx_slab_alloc_locked(ctx->shpool, n); +- +- if (node == NULL) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushboolean(L, 0); +- lua_pushliteral(L, "no memory"); +- return 2; +- } +- +- sd = (ngx_stream_lua_shdict_node_t *) &node->color; +- +- queue = ngx_stream_lua_shdict_get_list_head(sd, key.len); +- +- node->key = hash; +- sd->key_len = (u_short) key.len; +- +- sd->expires = 0; +- +- sd->value_len = 0; +- +- dd("setting value type to %d", (int) SHDICT_TLIST); +- +- sd->value_type = (uint8_t) SHDICT_TLIST; +- +- ngx_memcpy(sd->data, key.data, key.len); +- +- ngx_queue_init(queue); +- +- ngx_rbtree_insert(&ctx->sh->rbtree, node); +- +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +-push_node: +- +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict list: creating a new list node"); +- +- n = offsetof(ngx_stream_lua_shdict_list_node_t, data) +- + value.len; +- +- dd("list node length: %d", n); +- +- lnode = ngx_slab_alloc_locked(ctx->shpool, n); +- +- if (lnode == NULL) { +- +- if (sd->value_len == 0) { +- +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict list: no memory for create" +- " list node and list empty, remove it"); +- +- ngx_queue_remove(&sd->queue); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- +- ngx_slab_free_locked(ctx->shpool, node); +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushboolean(L, 0); +- lua_pushliteral(L, "no memory"); +- return 2; +- } +- +- dd("setting list length to %d", sd->value_len + 1); +- +- sd->value_len = sd->value_len + 1; +- +- dd("setting list node value length to %d", (int) value.len); +- +- lnode->value_len = (uint32_t) value.len; +- +- dd("setting list node value type to %d", value_type); +- +- lnode->value_type = (uint8_t) value_type; +- +- ngx_memcpy(lnode->data, value.data, value.len); +- +- if (flags == NGX_STREAM_LUA_SHDICT_LEFT) { +- ngx_queue_insert_head(queue, &lnode->queue); +- +- } else { +- ngx_queue_insert_tail(queue, &lnode->queue); +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnumber(L, sd->value_len); +- return 1; +-} +- +- +-static int +-ngx_stream_lua_shdict_lpop(lua_State *L) +-{ +- return ngx_stream_lua_shdict_pop_helper(L, NGX_STREAM_LUA_SHDICT_LEFT); +-} +- +- +-static int +-ngx_stream_lua_shdict_rpop(lua_State *L) +-{ +- return ngx_stream_lua_shdict_pop_helper(L, NGX_STREAM_LUA_SHDICT_RIGHT); +-} +- +- +-static int +-ngx_stream_lua_shdict_pop_helper(lua_State *L, int flags) +-{ +- int n; +- ngx_str_t name; +- ngx_str_t key; +- uint32_t hash; +- ngx_int_t rc; +- ngx_str_t value; +- int value_type; +- double num; +- ngx_rbtree_node_t *node; +- ngx_shm_zone_t *zone; +- ngx_queue_t *queue; +- +- ngx_stream_lua_shdict_ctx_t *ctx; +- ngx_stream_lua_shdict_node_t *sd; +- ngx_stream_lua_shdict_list_node_t *lnode; +- +- n = lua_gettop(L); +- +- if (n != 2) { +- return luaL_error(L, "expecting 2 arguments, " +- "but only seen %d", n); +- } +- +- if (lua_type(L, 1) != LUA_TTABLE) { +- return luaL_error(L, "bad \"zone\" argument"); +- } +- +- zone = ngx_stream_lua_shdict_get_zone(L, 1); +- if (zone == NULL) { +- return luaL_error(L, "bad \"zone\" argument"); +- } +- +- ctx = zone->data; +- name = ctx->name; +- +- if (lua_isnil(L, 2)) { +- lua_pushnil(L); +- lua_pushliteral(L, "nil key"); +- return 2; +- } +- +- key.data = (u_char *) luaL_checklstring(L, 2, &key.len); +- +- if (key.len == 0) { +- lua_pushnil(L); +- lua_pushliteral(L, "empty key"); +- return 2; +- } +- +- if (key.len > 65535) { +- lua_pushnil(L); +- lua_pushliteral(L, "key too long"); +- return 2; +- } +- +- hash = ngx_crc32_short(key.data, key.len); +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +-#if 1 +- ngx_stream_lua_shdict_expire(ctx, 1); +-#endif +- +- rc = ngx_stream_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); +- +- dd("shdict lookup returned %d", (int) rc); +- +- if (rc == NGX_DECLINED || rc == NGX_DONE) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- lua_pushnil(L); +- return 1; +- } +- +- /* rc == NGX_OK */ +- +- if (sd->value_type != SHDICT_TLIST) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnil(L); +- lua_pushliteral(L, "value not a list"); +- return 2; +- } +- +- if (sd->value_len <= 0) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return luaL_error(L, "bad lua list length found for key %s " +- "in shared_dict %s: %lu", key.data, name.data, +- (unsigned long) sd->value_len); +- } +- +- queue = ngx_stream_lua_shdict_get_list_head(sd, key.len); +- +- if (flags == NGX_STREAM_LUA_SHDICT_LEFT) { +- queue = ngx_queue_head(queue); +- +- } else { +- queue = ngx_queue_last(queue); +- } +- +- lnode = ngx_queue_data(queue, ngx_stream_lua_shdict_list_node_t, queue); +- +- value_type = lnode->value_type; +- +- dd("data: %p", lnode->data); +- dd("value len: %d", (int) sd->value_len); +- +- value.data = lnode->data; +- value.len = (size_t) lnode->value_len; +- +- switch (value_type) { +- +- case SHDICT_TSTRING: +- +- lua_pushlstring(L, (char *) value.data, value.len); +- break; +- +- case SHDICT_TNUMBER: +- +- if (value.len != sizeof(double)) { +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return luaL_error(L, "bad lua list node number value size found " +- "for key %s in shared_dict %s: %lu", key.data, +- name.data, (unsigned long) value.len); +- } +- +- ngx_memcpy(&num, value.data, sizeof(double)); +- +- lua_pushnumber(L, num); +- break; +- +- default: +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return luaL_error(L, "bad list node value type found for key %s in " +- "shared_dict %s: %d", key.data, name.data, +- value_type); +- } +- +- ngx_queue_remove(queue); +- +- ngx_slab_free_locked(ctx->shpool, lnode); +- +- if (sd->value_len == 1) { +- +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict list: empty node after pop, " +- "remove it"); +- +- ngx_queue_remove(&sd->queue); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- +- ngx_slab_free_locked(ctx->shpool, node); +- +- } else { +- sd->value_len = sd->value_len - 1; +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return 1; +-} +- +- +-static int +-ngx_stream_lua_shdict_llen(lua_State *L) +-{ +- int n; +- ngx_str_t key; +- uint32_t hash; +- ngx_int_t rc; +- ngx_shm_zone_t *zone; +- +- ngx_stream_lua_shdict_ctx_t *ctx; +- ngx_stream_lua_shdict_node_t *sd; +- +- n = lua_gettop(L); +- +- if (n != 2) { +- return luaL_error(L, "expecting 2 arguments, " +- "but only seen %d", n); +- } +- +- if (lua_type(L, 1) != LUA_TTABLE) { +- return luaL_error(L, "bad \"zone\" argument"); +- } +- +- zone = ngx_stream_lua_shdict_get_zone(L, 1); +- if (zone == NULL) { +- return luaL_error(L, "bad \"zone\" argument"); +- } +- +- ctx = zone->data; +- +- if (lua_isnil(L, 2)) { +- lua_pushnil(L); +- lua_pushliteral(L, "nil key"); +- return 2; +- } +- +- key.data = (u_char *) luaL_checklstring(L, 2, &key.len); +- +- if (key.len == 0) { +- lua_pushnil(L); +- lua_pushliteral(L, "empty key"); +- return 2; +- } +- +- if (key.len > 65535) { +- lua_pushnil(L); +- lua_pushliteral(L, "key too long"); +- return 2; +- } +- +- hash = ngx_crc32_short(key.data, key.len); +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +-#if 1 +- ngx_stream_lua_shdict_expire(ctx, 1); +-#endif +- +- rc = ngx_stream_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); +- +- dd("shdict lookup returned %d", (int) rc); +- +- if (rc == NGX_OK) { +- +- if (sd->value_type != SHDICT_TLIST) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnil(L); +- lua_pushliteral(L, "value not a list"); +- return 2; +- } +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnumber(L, (lua_Number) sd->value_len); +- return 1; +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- lua_pushnumber(L, 0); +- return 1; +-} +- +- +-ngx_shm_zone_t * +-ngx_stream_lua_find_zone(u_char *name_data, size_t name_len) +-{ +- ngx_str_t *name; +- ngx_uint_t i; +- ngx_shm_zone_t *zone; +- volatile ngx_list_part_t *part; +- +- ngx_stream_lua_shm_zone_ctx_t *ctx; +- +- part = &ngx_cycle->shared_memory.part; +- zone = part->elts; +- +- for (i = 0; /* void */ ; i++) { +- +- if (i >= part->nelts) { +- if (part->next == NULL) { +- break; +- } +- +- part = part->next; +- zone = part->elts; +- i = 0; +- } +- +- name = &zone[i].shm.name; +- +- dd("name: [%.*s] %d", (int) name->len, name->data, (int) name->len); +- dd("name2: [%.*s] %d", (int) name_len, name_data, (int) name_len); +- +- if (name->len == name_len +- && ngx_strncmp(name->data, name_data, name_len) == 0) +- { +- ctx = (ngx_stream_lua_shm_zone_ctx_t *) zone[i].data; +- return &ctx->zone; +- } +- } +- +- return NULL; +-} +- +- +-ngx_shm_zone_t * +-ngx_stream_lua_ffi_shdict_udata_to_zone(void *zone_udata) +-{ +- if (zone_udata == NULL) { +- return NULL; +- } +- +- return *(ngx_shm_zone_t **) zone_udata; +-} +- +- +-int +-ngx_stream_lua_ffi_shdict_store(ngx_shm_zone_t *zone, int op, u_char *key, +- size_t key_len, int value_type, u_char *str_value_buf, +- size_t str_value_len, double num_value, long exptime, int user_flags, +- char **errmsg, int *forcible) +-{ +- int i, n; +- u_char c, *p; +- uint32_t hash; +- ngx_int_t rc; +- ngx_time_t *tp; +- ngx_queue_t *queue, *q; +- ngx_rbtree_node_t *node; +- +- ngx_stream_lua_shdict_ctx_t *ctx; +- ngx_stream_lua_shdict_node_t *sd; +- +- dd("exptime: %ld", exptime); +- +- ctx = zone->data; +- +- *forcible = 0; +- +- hash = ngx_crc32_short(key, key_len); +- +- switch (value_type) { +- +- case SHDICT_TSTRING: +- /* do nothing */ +- break; +- +- case SHDICT_TNUMBER: +- dd("num value: %lf", num_value); +- str_value_buf = (u_char *) &num_value; +- str_value_len = sizeof(double); +- break; +- +- case SHDICT_TBOOLEAN: +- c = num_value ? 1 : 0; +- str_value_buf = &c; +- str_value_len = sizeof(u_char); +- break; +- +- case LUA_TNIL: +- if (op & (NGX_STREAM_LUA_SHDICT_ADD|NGX_STREAM_LUA_SHDICT_REPLACE)) { +- *errmsg = "attempt to add or replace nil values"; +- return NGX_ERROR; +- } +- +- str_value_buf = NULL; +- str_value_len = 0; +- break; +- +- default: +- *errmsg = "unsupported value type"; +- return NGX_ERROR; +- } +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +-#if 1 +- ngx_stream_lua_shdict_expire(ctx, 1); +-#endif +- +- rc = ngx_stream_lua_shdict_lookup(zone, hash, key, key_len, &sd); +- +- dd("lookup returns %d", (int) rc); +- +- if (op & NGX_STREAM_LUA_SHDICT_REPLACE) { +- +- if (rc == NGX_DECLINED || rc == NGX_DONE) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- *errmsg = "not found"; +- return NGX_DECLINED; +- } +- +- /* rc == NGX_OK */ +- +- goto replace; +- } +- +- if (op & NGX_STREAM_LUA_SHDICT_ADD) { +- +- if (rc == NGX_OK) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- *errmsg = "exists"; +- return NGX_DECLINED; +- } +- +- if (rc == NGX_DONE) { +- /* exists but expired */ +- +- dd("go to replace"); +- goto replace; +- } +- +- /* rc == NGX_DECLINED */ +- +- dd("go to insert"); +- goto insert; +- } +- +- if (rc == NGX_OK || rc == NGX_DONE) { +- +- if (value_type == LUA_TNIL) { +- goto remove; +- } +- +-replace: +- +- if (str_value_buf +- && str_value_len == (size_t) sd->value_len +- && sd->value_type != SHDICT_TLIST) +- { +- +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict set: found old entry and value " +- "size matched, reusing it"); +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- sd->key_len = (u_short) key_len; +- +- if (exptime > 0) { +- tp = ngx_timeofday(); +- sd->expires = (uint64_t) tp->sec * 1000 + tp->msec +- + (uint64_t) exptime; +- +- } else { +- sd->expires = 0; +- } +- +- sd->user_flags = user_flags; +- +- sd->value_len = (uint32_t) str_value_len; +- +- dd("setting value type to %d", value_type); +- +- sd->value_type = (uint8_t) value_type; +- +- p = ngx_copy(sd->data, key, key_len); +- ngx_memcpy(p, str_value_buf, str_value_len); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return NGX_OK; +- } +- +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict set: found old entry but value size " +- "NOT matched, removing it first"); +- +-remove: +- +- if (sd->value_type == SHDICT_TLIST) { +- queue = ngx_stream_lua_shdict_get_list_head(sd, key_len); +- +- for (q = ngx_queue_head(queue); +- q != ngx_queue_sentinel(queue); +- q = ngx_queue_next(q)) +- { +- p = (u_char *) ngx_queue_data(q, +- ngx_stream_lua_shdict_list_node_t, +- queue); +- +- ngx_slab_free_locked(ctx->shpool, p); +- } +- } +- +- ngx_queue_remove(&sd->queue); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- +- ngx_slab_free_locked(ctx->shpool, node); +- +- } +- +-insert: +- +- /* rc == NGX_DECLINED or value size unmatch */ +- +- if (str_value_buf == NULL) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- return NGX_OK; +- } +- +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict set: creating a new entry"); +- +- n = offsetof(ngx_rbtree_node_t, color) +- + offsetof(ngx_stream_lua_shdict_node_t, data) +- + key_len +- + str_value_len; +- +- node = ngx_slab_alloc_locked(ctx->shpool, n); +- +- if (node == NULL) { +- +- if (op & NGX_STREAM_LUA_SHDICT_SAFE_STORE) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- *errmsg = "no memory"; +- return NGX_ERROR; +- } +- +- ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict set: overriding non-expired items " +- "due to memory shortage for entry \"%*s\"", key_len, +- key); +- +- for (i = 0; i < 30; i++) { +- if (ngx_stream_lua_shdict_expire(ctx, 0) == 0) { +- break; +- } +- +- *forcible = 1; +- +- node = ngx_slab_alloc_locked(ctx->shpool, n); +- if (node != NULL) { +- goto allocated; +- } +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- *errmsg = "no memory"; +- return NGX_ERROR; +- } +- +-allocated: +- +- sd = (ngx_stream_lua_shdict_node_t *) &node->color; +- +- node->key = hash; +- sd->key_len = (u_short) key_len; +- +- if (exptime > 0) { +- tp = ngx_timeofday(); +- sd->expires = (uint64_t) tp->sec * 1000 + tp->msec +- + (uint64_t) exptime; +- +- } else { +- sd->expires = 0; +- } +- +- sd->user_flags = user_flags; +- sd->value_len = (uint32_t) str_value_len; +- dd("setting value type to %d", value_type); +- sd->value_type = (uint8_t) value_type; +- +- p = ngx_copy(sd->data, key, key_len); +- ngx_memcpy(p, str_value_buf, str_value_len); +- +- ngx_rbtree_insert(&ctx->sh->rbtree, node); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return NGX_OK; +-} +- +- +-int +-ngx_stream_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, +- size_t key_len, int *value_type, u_char **str_value_buf, +- size_t *str_value_len, double *num_value, int *user_flags, +- int get_stale, int *is_stale, char **err) +-{ +- ngx_str_t name; +- uint32_t hash; +- ngx_int_t rc; +- ngx_str_t value; +- +- ngx_stream_lua_shdict_ctx_t *ctx; +- ngx_stream_lua_shdict_node_t *sd; +- +- *err = NULL; +- +- ctx = zone->data; +- name = ctx->name; +- +- hash = ngx_crc32_short(key, key_len); +- +-#if (NGX_DEBUG) +- ngx_log_debug3(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "fetching key \"%*s\" in shared dict \"%V\"", key_len, +- key, &name); +-#endif /* NGX_DEBUG */ +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +-#if 1 +- if (!get_stale) { +- ngx_stream_lua_shdict_expire(ctx, 1); +- } +-#endif +- +- rc = ngx_stream_lua_shdict_lookup(zone, hash, key, key_len, &sd); +- +- dd("shdict lookup returns %d", (int) rc); +- +- if (rc == NGX_DECLINED || (rc == NGX_DONE && !get_stale)) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- *value_type = LUA_TNIL; +- return NGX_OK; +- } +- +- /* rc == NGX_OK || (rc == NGX_DONE && get_stale) */ +- +- *value_type = sd->value_type; +- +- dd("data: %p", sd->data); +- dd("key len: %d", (int) sd->key_len); +- +- value.data = sd->data + sd->key_len; +- value.len = (size_t) sd->value_len; +- +- if (*str_value_len < (size_t) value.len) { +- if (*value_type == SHDICT_TBOOLEAN) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- return NGX_ERROR; +- } +- +- if (*value_type == SHDICT_TSTRING) { +- *str_value_buf = malloc(value.len); +- if (*str_value_buf == NULL) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- return NGX_ERROR; +- } +- } +- } +- +- switch (*value_type) { +- +- case SHDICT_TSTRING: +- *str_value_len = value.len; +- ngx_memcpy(*str_value_buf, value.data, value.len); +- break; +- +- case SHDICT_TNUMBER: +- +- if (value.len != sizeof(double)) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, +- "bad lua number value size found for key %*s " +- "in shared_dict %V: %z", key_len, key, +- &name, value.len); +- return NGX_ERROR; +- } +- +- *str_value_len = value.len; +- ngx_memcpy(num_value, value.data, sizeof(double)); +- break; +- +- case SHDICT_TBOOLEAN: +- +- if (value.len != sizeof(u_char)) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, +- "bad lua boolean value size found for key %*s " +- "in shared_dict %V: %z", key_len, key, &name, +- value.len); +- return NGX_ERROR; +- } +- +- ngx_memcpy(*str_value_buf, value.data, value.len); +- break; +- +- case SHDICT_TLIST: +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- *err = "value is a list"; +- return NGX_ERROR; +- +- default: +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, +- "bad value type found for key %*s in " +- "shared_dict %V: %d", key_len, key, &name, +- *value_type); +- return NGX_ERROR; +- } +- +- *user_flags = sd->user_flags; +- dd("user flags: %d", *user_flags); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- if (get_stale) { +- +- /* always return value, flags, stale */ +- +- *is_stale = (rc == NGX_DONE); +- return NGX_OK; +- } +- +- return NGX_OK; +-} +- +- +-int +-ngx_stream_lua_ffi_shdict_incr(ngx_shm_zone_t *zone, u_char *key, +- size_t key_len, double *value, char **err, int has_init, double init, +- long init_ttl, int *forcible) +-{ +- int i, n; +- uint32_t hash; +- ngx_int_t rc; +- ngx_time_t *tp = NULL; +- double num; +- ngx_rbtree_node_t *node; +- u_char *p; +- ngx_queue_t *queue, *q; +- +- ngx_stream_lua_shdict_ctx_t *ctx; +- ngx_stream_lua_shdict_node_t *sd; +- +- if (init_ttl > 0) { +- tp = ngx_timeofday(); +- } +- +- ctx = zone->data; +- +- *forcible = 0; +- +- hash = ngx_crc32_short(key, key_len); +- +- dd("looking up key %.*s in shared dict %.*s", (int) key_len, key, +- (int) ctx->name.len, ctx->name.data); +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +-#if 1 +- ngx_stream_lua_shdict_expire(ctx, 1); +-#endif +- rc = ngx_stream_lua_shdict_lookup(zone, hash, key, key_len, &sd); +- +- dd("shdict lookup returned %d", (int) rc); +- +- if (rc == NGX_DECLINED || rc == NGX_DONE) { +- if (!has_init) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- *err = "not found"; +- return NGX_ERROR; +- } +- +- /* add value */ +- num = *value + init; +- +- if (rc == NGX_DONE) { +- +- /* found an expired item */ +- +- if ((size_t) sd->value_len == sizeof(double) +- && sd->value_type != SHDICT_TLIST) +- { +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict incr: found old entry and " +- "value size matched, reusing it"); +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- dd("go to setvalue"); +- goto setvalue; +- } +- +- dd("go to remove"); +- goto remove; +- } +- +- dd("go to insert"); +- goto insert; +- } +- +- /* rc == NGX_OK */ +- +- if (sd->value_type != SHDICT_TNUMBER || sd->value_len != sizeof(double)) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- *err = "not a number"; +- return NGX_ERROR; +- } +- +- ngx_queue_remove(&sd->queue); +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +- dd("setting value type to %d", (int) sd->value_type); +- +- p = sd->data + key_len; +- +- ngx_memcpy(&num, p, sizeof(double)); +- num += *value; +- +- ngx_memcpy(p, (double *) &num, sizeof(double)); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- *value = num; +- return NGX_OK; +- +-remove: +- +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict incr: found old entry but value size " +- "NOT matched, removing it first"); +- +- if (sd->value_type == SHDICT_TLIST) { +- queue = ngx_stream_lua_shdict_get_list_head(sd, key_len); +- +- for (q = ngx_queue_head(queue); +- q != ngx_queue_sentinel(queue); +- q = ngx_queue_next(q)) +- { +- p = (u_char *) ngx_queue_data(q, ngx_stream_lua_shdict_list_node_t, +- queue); +- +- ngx_slab_free_locked(ctx->shpool, p); +- } +- } +- +- ngx_queue_remove(&sd->queue); +- +- node = (ngx_rbtree_node_t *) +- ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); +- +- ngx_rbtree_delete(&ctx->sh->rbtree, node); +- +- ngx_slab_free_locked(ctx->shpool, node); +- +-insert: +- +- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict incr: creating a new entry"); +- +- n = offsetof(ngx_rbtree_node_t, color) +- + offsetof(ngx_stream_lua_shdict_node_t, data) +- + key_len +- + sizeof(double); +- +- node = ngx_slab_alloc_locked(ctx->shpool, n); +- +- if (node == NULL) { +- +- ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ctx->log, 0, +- "lua shared dict incr: overriding non-expired items " +- "due to memory shortage for entry \"%*s\"", key_len, +- key); +- +- for (i = 0; i < 30; i++) { +- if (ngx_stream_lua_shdict_expire(ctx, 0) == 0) { +- break; +- } +- +- *forcible = 1; +- +- node = ngx_slab_alloc_locked(ctx->shpool, n); +- if (node != NULL) { +- goto allocated; +- } +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- *err = "no memory"; +- return NGX_ERROR; +- } +- +-allocated: +- +- sd = (ngx_stream_lua_shdict_node_t *) &node->color; +- +- node->key = hash; +- +- sd->key_len = (u_short) key_len; +- +- sd->value_len = (uint32_t) sizeof(double); +- +- ngx_rbtree_insert(&ctx->sh->rbtree, node); +- +- ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); +- +-setvalue: +- +- sd->user_flags = 0; +- +- if (init_ttl > 0) { +- sd->expires = (uint64_t) tp->sec * 1000 + tp->msec +- + (uint64_t) init_ttl; +- +- } else { +- sd->expires = 0; +- } +- +- dd("setting value type to %d", LUA_TNUMBER); +- +- sd->value_type = (uint8_t) LUA_TNUMBER; +- +- p = ngx_copy(sd->data, key, key_len); +- ngx_memcpy(p, (double *) &num, sizeof(double)); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- *value = num; +- return NGX_OK; +-} +- +- +-int +-ngx_stream_lua_ffi_shdict_flush_all(ngx_shm_zone_t *zone) +-{ +- ngx_queue_t *q; +- +- ngx_stream_lua_shdict_node_t *sd; +- ngx_stream_lua_shdict_ctx_t *ctx; +- +- ctx = zone->data; +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +- for (q = ngx_queue_head(&ctx->sh->lru_queue); +- q != ngx_queue_sentinel(&ctx->sh->lru_queue); +- q = ngx_queue_next(q)) +- { +- sd = ngx_queue_data(q, ngx_stream_lua_shdict_node_t, queue); +- sd->expires = 1; +- } +- +- ngx_stream_lua_shdict_expire(ctx, 0); +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return NGX_OK; +-} +- +- +-static ngx_int_t +-ngx_stream_lua_shdict_peek(ngx_shm_zone_t *shm_zone, ngx_uint_t hash, +- u_char *kdata, size_t klen, ngx_stream_lua_shdict_node_t **sdp) +-{ +- ngx_int_t rc; +- ngx_rbtree_node_t *node, *sentinel; +- +- ngx_stream_lua_shdict_ctx_t *ctx; +- ngx_stream_lua_shdict_node_t *sd; +- +- ctx = shm_zone->data; +- +- node = ctx->sh->rbtree.root; +- sentinel = ctx->sh->rbtree.sentinel; +- +- while (node != sentinel) { +- +- if (hash < node->key) { +- node = node->left; +- continue; +- } +- +- if (hash > node->key) { +- node = node->right; +- continue; +- } +- +- /* hash == node->key */ +- +- sd = (ngx_stream_lua_shdict_node_t *) &node->color; +- +- rc = ngx_memn2cmp(kdata, sd->data, klen, (size_t) sd->key_len); +- +- if (rc == 0) { +- *sdp = sd; +- +- return NGX_OK; +- } +- +- node = (rc < 0) ? node->left : node->right; +- } +- +- *sdp = NULL; +- +- return NGX_DECLINED; +-} +- +- +-long +-ngx_stream_lua_ffi_shdict_get_ttl(ngx_shm_zone_t *zone, u_char *key, +- size_t key_len) +-{ +- uint32_t hash; +- uint64_t now; +- uint64_t expires; +- ngx_int_t rc; +- ngx_time_t *tp; +- +- ngx_stream_lua_shdict_ctx_t *ctx; +- ngx_stream_lua_shdict_node_t *sd; +- +- ctx = zone->data; +- hash = ngx_crc32_short(key, key_len); +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +- rc = ngx_stream_lua_shdict_peek(zone, hash, key, key_len, &sd); +- +- if (rc == NGX_DECLINED) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return NGX_DECLINED; +- } +- +- /* rc == NGX_OK */ +- +- expires = sd->expires; +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- if (expires == 0) { +- return 0; +- } +- +- tp = ngx_timeofday(); +- now = (uint64_t) tp->sec * 1000 + tp->msec; +- +- return expires - now; +-} +- +- +-int +-ngx_stream_lua_ffi_shdict_set_expire(ngx_shm_zone_t *zone, u_char *key, +- size_t key_len, long exptime) +-{ +- uint32_t hash; +- ngx_int_t rc; +- ngx_time_t *tp = NULL; +- +- ngx_stream_lua_shdict_ctx_t *ctx; +- ngx_stream_lua_shdict_node_t *sd; +- +- if (exptime > 0) { +- tp = ngx_timeofday(); +- } +- +- ctx = zone->data; +- hash = ngx_crc32_short(key, key_len); +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- +- rc = ngx_stream_lua_shdict_peek(zone, hash, key, key_len, &sd); +- +- if (rc == NGX_DECLINED) { +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return NGX_DECLINED; +- } +- +- /* rc == NGX_OK */ +- +- if (exptime > 0) { +- sd->expires = (uint64_t) tp->sec * 1000 + tp->msec +- + (uint64_t) exptime; +- +- } else { +- sd->expires = 0; +- } +- +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return NGX_OK; +-} +- +- +-size_t +-ngx_stream_lua_ffi_shdict_capacity(ngx_shm_zone_t *zone) +-{ +- return zone->shm.size; +-} +- +- +-#if defined(nginx_version) && nginx_version >= 1011007 +-size_t +-ngx_stream_lua_ffi_shdict_free_space(ngx_shm_zone_t *zone) +-{ +- size_t bytes; +- +- ngx_stream_lua_shdict_ctx_t *ctx; +- +- ctx = zone->data; +- +- ngx_shmtx_lock(&ctx->shpool->mutex); +- bytes = ctx->shpool->pfree * ngx_pagesize; +- ngx_shmtx_unlock(&ctx->shpool->mutex); +- +- return bytes; +-} +-#endif +- +- +-/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ +diff --git src/ngx_stream_lua_shdict.h src/ngx_stream_lua_shdict.h +deleted file mode 100644 +index 630c5b6..0000000 +--- src/ngx_stream_lua_shdict.h ++++ /dev/null +@@ -1,75 +0,0 @@ +- +-/* +- * !!! DO NOT EDIT DIRECTLY !!! +- * This file was automatically generated from the following template: +- * +- * src/subsys/ngx_subsys_lua_shdict.h.tt2 +- */ +- +- +-/* +- * Copyright (C) Yichun Zhang (agentzh) +- */ +- +- +-#ifndef _NGX_STREAM_LUA_SHDICT_H_INCLUDED_ +-#define _NGX_STREAM_LUA_SHDICT_H_INCLUDED_ +- +- +-#include "ngx_stream_lua_common.h" +- +- +-typedef struct { +- u_char color; +- uint8_t value_type; +- u_short key_len; +- uint32_t value_len; +- uint64_t expires; +- ngx_queue_t queue; +- uint32_t user_flags; +- u_char data[1]; +-} ngx_stream_lua_shdict_node_t; +- +- +-typedef struct { +- ngx_queue_t queue; +- uint32_t value_len; +- uint8_t value_type; +- u_char data[1]; +-} ngx_stream_lua_shdict_list_node_t; +- +- +-typedef struct { +- ngx_rbtree_t rbtree; +- ngx_rbtree_node_t sentinel; +- ngx_queue_t lru_queue; +-} ngx_stream_lua_shdict_shctx_t; +- +- +-typedef struct { +- ngx_stream_lua_shdict_shctx_t *sh; +- ngx_slab_pool_t *shpool; +- ngx_str_t name; +- ngx_stream_lua_main_conf_t *main_conf; +- ngx_log_t *log; +-} ngx_stream_lua_shdict_ctx_t; +- +- +-typedef struct { +- ngx_log_t *log; +- ngx_stream_lua_main_conf_t *lmcf; +- ngx_cycle_t *cycle; +- ngx_shm_zone_t zone; +-} ngx_stream_lua_shm_zone_ctx_t; +- +- +-ngx_int_t ngx_stream_lua_shdict_init_zone(ngx_shm_zone_t *shm_zone, void *data); +-void ngx_stream_lua_shdict_rbtree_insert_value(ngx_rbtree_node_t *temp, +- ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); +-void ngx_stream_lua_inject_shdict_api(ngx_stream_lua_main_conf_t *lmcf, +- lua_State *L); +- +- +-#endif /* _NGX_STREAM_LUA_SHDICT_H_INCLUDED_ */ +- +-/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ +diff --git src/ngx_stream_lua_util.c src/ngx_stream_lua_util.c +index 58061b4..ab52d5a 100644 +--- src/ngx_stream_lua_util.c ++++ src/ngx_stream_lua_util.c +@@ -20,6 +20,7 @@ + + + #include "nginx.h" ++#include "ngx_meta_lua_api.h" + #include "ngx_stream_lua_directive.h" + #include "ngx_stream_lua_util.h" + #include "ngx_stream_lua_exception.h" +@@ -31,7 +32,6 @@ + #include "ngx_stream_lua_string.h" + #include "ngx_stream_lua_misc.h" + #include "ngx_stream_lua_consts.h" +-#include "ngx_stream_lua_shdict.h" + #include "ngx_stream_lua_coroutine.h" + #include "ngx_stream_lua_socket_tcp.h" + #include "ngx_stream_lua_socket_udp.h" +@@ -102,7 +102,7 @@ static ngx_int_t ngx_stream_lua_handle_exit(lua_State *L, + static int ngx_stream_lua_thread_traceback(lua_State *L, lua_State *co, + ngx_stream_lua_co_ctx_t *coctx); + static void ngx_stream_lua_inject_ngx_api(lua_State *L, +- ngx_stream_lua_main_conf_t *lmcf, ngx_log_t *log); ++ ngx_cycle_t *cycle, ngx_stream_lua_main_conf_t *lmcf, ngx_log_t *log); + static ngx_int_t ngx_stream_lua_output_filter(ngx_stream_lua_request_t *r, + ngx_chain_t *in); + static void ngx_stream_lua_finalize_threads(ngx_stream_lua_request_t *r, +@@ -501,13 +501,13 @@ ngx_stream_lua_init_globals(lua_State *L, ngx_cycle_t *cycle, + "lua initializing lua globals"); + + +- ngx_stream_lua_inject_ngx_api(L, lmcf, log); ++ ngx_stream_lua_inject_ngx_api(L, cycle, lmcf, log); + } + + + static void +-ngx_stream_lua_inject_ngx_api(lua_State *L, ngx_stream_lua_main_conf_t *lmcf, +- ngx_log_t *log) ++ngx_stream_lua_inject_ngx_api(lua_State *L, ngx_cycle_t *cycle, ++ ngx_stream_lua_main_conf_t *lmcf, ngx_log_t *log) + { + lua_createtable(L, 0 /* narr */, 113 /* nrec */); /* ngx.* */ + +@@ -529,7 +529,7 @@ ngx_stream_lua_inject_ngx_api(lua_State *L, ngx_stream_lua_main_conf_t *lmcf, + ngx_stream_lua_inject_req_api(log, L); + + +- ngx_stream_lua_inject_shdict_api(lmcf, L); ++ ngx_meta_lua_inject_shdict_api(L, cycle, &ngx_stream_lua_module); + ngx_stream_lua_inject_socket_tcp_api(log, L); + ngx_stream_lua_inject_socket_udp_api(log, L); + ngx_stream_lua_inject_uthread_api(log, L); +diff --git src/ngx_stream_lua_util.h src/ngx_stream_lua_util.h +index deb255f..e1c2f92 100644 +--- src/ngx_stream_lua_util.h ++++ src/ngx_stream_lua_util.h +@@ -344,7 +344,9 @@ ngx_stream_lua_create_ctx(ngx_stream_session_t *r) + ngx_stream_lua_assert(L != NULL); + + if (lmcf->init_handler) { +- if (lmcf->init_handler(r->connection->log, lmcf, L) != NGX_OK) { ++ if (lmcf->init_handler(r->connection->log, lmcf->init_src, L) ++ != NGX_OK) ++ { + /* an error happened */ + return NULL; + } diff --git a/patch/README.md b/patch/README.md index b58b637..1892a8e 100644 --- a/patch/README.md +++ b/patch/README.md @@ -13,4 +13,9 @@ The `*-ngx_pipe_environ_on_mac` patches support the environ argument of the ngx. The `*-enable_keepalive` patches originally come from: https://github.com/openresty/lua-nginx-module/pull/1600 -https://github.com/openresty/lua-resty-core/pull/276 \ No newline at end of file +https://github.com/openresty/lua-resty-core/pull/276 + +The `*-shared_shdict` patches, `src/meta/*` and `t/meta/*` originally come from: +https://github.com/openresty/meta-lua-nginx-module/pull/76 +https://github.com/thibaultcha/lua-resty-core/commit/8ad30813a3d8037f92aaaffaacd0a14bc7388edf +, which is under BSD license. diff --git a/src/meta/config b/src/meta/config new file mode 100644 index 0000000..599a853 --- /dev/null +++ b/src/meta/config @@ -0,0 +1,13 @@ +ngx_module_type=CORE +ngx_module_name=ngx_meta_lua_module +ngx_module_incs="$ngx_addon_dir" +ngx_module_deps="$ngx_addon_dir/ddebug.h \ + $ngx_addon_dir/ngx_meta_lua_api.h \ + $ngx_addon_dir/ngx_meta_lua_module.h \ + $ngx_addon_dir/ngx_meta_lua_shdict.h" +ngx_module_srcs="$ngx_addon_dir/ngx_meta_lua_module.c \ + $ngx_addon_dir/ngx_meta_lua_shdict.c" + +. auto/module + +ngx_addon_name=$ngx_module_name diff --git a/src/meta/ddebug.h b/src/meta/ddebug.h new file mode 100644 index 0000000..7bf22e9 --- /dev/null +++ b/src/meta/ddebug.h @@ -0,0 +1,85 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _DDEBUG_H_INCLUDED_ +#define _DDEBUG_H_INCLUDED_ + + +#include +#include +#include + + +#if defined(DDEBUG) && (DDEBUG) + +# if (NGX_HAVE_VARIADIC_MACROS) + +# define dd(...) fprintf(stderr, "lua *** %s: ", __func__); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, " at %s line %d.\n", __FILE__, __LINE__) + +# else + +#include +#include + +#include + +static ngx_inline void +dd(const char *fmt, ...) { +} + +# endif + +#else + +# if (NGX_HAVE_VARIADIC_MACROS) + +# define dd(...) + +# else + +#include + +static ngx_inline void +dd(const char *fmt, ...) { +} + +# endif + +#endif + +#if defined(DDEBUG) && (DDEBUG) + +#define dd_check_read_event_handler(r) \ + dd("r->read_event_handler = %s", \ + r->read_event_handler == ngx_http_block_reading ? \ + "ngx_http_block_reading" : \ + r->read_event_handler == ngx_http_test_reading ? \ + "ngx_http_test_reading" : \ + r->read_event_handler == ngx_http_request_empty_handler ? \ + "ngx_http_request_empty_handler" : "UNKNOWN") + +#define dd_check_write_event_handler(r) \ + dd("r->write_event_handler = %s", \ + r->write_event_handler == ngx_http_handler ? \ + "ngx_http_handler" : \ + r->write_event_handler == ngx_http_core_run_phases ? \ + "ngx_http_core_run_phases" : \ + r->write_event_handler == ngx_http_request_empty_handler ? \ + "ngx_http_request_empty_handler" : "UNKNOWN") + +#else + +#define dd_check_read_event_handler(r) +#define dd_check_write_event_handler(r) + +#endif + + +#endif /* _DDEBUG_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/meta/ngx_meta_lua_api.h b/src/meta/ngx_meta_lua_api.h new file mode 100644 index 0000000..5c8bddc --- /dev/null +++ b/src/meta/ngx_meta_lua_api.h @@ -0,0 +1,37 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_META_LUA_API_H_INCLUDED_ +#define _NGX_META_LUA_API_H_INCLUDED_ + + +#include +#include + +#include +#include +#include + + +#define ngx_meta_lua_version 00001 + + +typedef ngx_int_t (*ngx_meta_lua_main_conf_handler_pt)(ngx_log_t *log, + ngx_str_t init_src, lua_State *L); + + +ngx_int_t ngx_meta_lua_post_init_handler(ngx_conf_t *cf, + ngx_meta_lua_main_conf_handler_pt init_handler, ngx_str_t init_src, + lua_State *L); +char *ngx_meta_lua_shdict_directive_helper(ngx_conf_t *cf, void *tag); +void ngx_meta_lua_inject_shdict_api(lua_State *L, ngx_cycle_t *cycle, + void *tag); + + +#endif /* _NGX_META_LUA_API_H_INCLUDED_ */ + + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/meta/ngx_meta_lua_module.c b/src/meta/ngx_meta_lua_module.c new file mode 100644 index 0000000..691d48f --- /dev/null +++ b/src/meta/ngx_meta_lua_module.c @@ -0,0 +1,206 @@ +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + +#include + +#include "ngx_meta_lua_shdict.h" + + +static void *ngx_meta_lua_module_create_conf(ngx_cycle_t *cycle); +static char *ngx_meta_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static ngx_int_t ngx_meta_lua_run_init_handler(ngx_cycle_t *cycle, + ngx_log_t *log, ngx_meta_lua_init_handler_t *inh); + + +static ngx_command_t ngx_meta_lua_cmds[] = { + + { ngx_string("lua"), + NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, + ngx_meta_lua_block, + 0, + 0, + NULL }, + + { ngx_string("lua_shared_dict"), + NGX_META_LUA_CONF|NGX_CONF_TAKE2, + ngx_meta_lua_shdict_directive, + 0, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_core_module_t ngx_meta_lua_module_ctx = { + ngx_string("lua"), + ngx_meta_lua_module_create_conf, + NULL +}; + + +ngx_module_t ngx_meta_lua_module = { + NGX_MODULE_V1, + &ngx_meta_lua_module_ctx, /* module context */ + ngx_meta_lua_cmds, /* module directives */ + NGX_CORE_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static void * +ngx_meta_lua_module_create_conf(ngx_cycle_t *cycle) +{ + ngx_meta_lua_conf_t *mcf; + + mcf = ngx_pcalloc(cycle->pool, sizeof(ngx_meta_lua_conf_t)); + if (mcf == NULL) { + return NULL; + } + + mcf->shdict_zones = ngx_array_create(cycle->pool, 2, + sizeof(ngx_shm_zone_t *)); + if (mcf->shdict_zones == NULL) { + return NULL; + } + + mcf->init_handlers = ngx_array_create(cycle->pool, 2, + sizeof(ngx_meta_lua_init_handler_t *)); + if (mcf->init_handlers == NULL) { + return NULL; + } + + return mcf; +} + + +static char * +ngx_meta_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *rv; + ngx_conf_t pcf; + ngx_meta_lua_conf_t *mcf = *(ngx_meta_lua_conf_t **) conf; + + if (mcf->parsed_lua_block) { + return "is duplicate"; + } + + /* parse the lua{} block */ + + mcf->parsed_lua_block = 1; + + pcf = *cf; + + cf->ctx = mcf; + cf->module_type = NGX_CORE_MODULE; + cf->cmd_type = NGX_META_LUA_CONF; + + rv = ngx_conf_parse(cf, NULL); + + *cf = pcf; + + if (rv != NGX_CONF_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +ngx_int_t +ngx_meta_lua_post_init_handler(ngx_conf_t *cf, + ngx_meta_lua_main_conf_handler_pt init_handler, ngx_str_t init_src, + lua_State *L) +{ + ngx_meta_lua_conf_t *mcf; + ngx_meta_lua_init_handler_t **inhp, *inh, iinh; + + if (init_handler == NULL) { + return NGX_OK; + } + + mcf = ngx_meta_lua_conf_get_main_conf(cf); + + if (!mcf->delay_init_handlers) { + iinh.init_handler = init_handler; + iinh.init_src = init_src; + iinh.L = L; + + return ngx_meta_lua_run_init_handler(cf->cycle, cf->log, &iinh); + } + + inh = ngx_palloc(cf->pool, sizeof(ngx_meta_lua_init_handler_t)); + if (inh == NULL) { + return NGX_ERROR; + } + + inh->init_handler = init_handler; + inh->init_src = init_src; + inh->L = L; + + inhp = ngx_array_push(mcf->init_handlers); + if (inhp == NULL) { + return NGX_ERROR; + } + + *inhp = inh; + + return NGX_OK; +} + + +ngx_int_t +ngx_meta_lua_run_delayed_init_handlers(ngx_meta_lua_conf_t *mcf, + ngx_cycle_t *cycle, ngx_log_t *log) +{ + ngx_uint_t i; + ngx_meta_lua_init_handler_t **inhp; + + inhp = mcf->init_handlers->elts; + + /* respect order in which the modules were compiled */ + + for (i = 0; i < mcf->init_handlers->nelts; i++) { + ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, + "lua run delayed init_handler: %p", inhp[i]); + + if (ngx_meta_lua_run_init_handler(cycle, log, inhp[i]) != NGX_OK) { + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_meta_lua_run_init_handler(ngx_cycle_t *cycle, ngx_log_t *log, + ngx_meta_lua_init_handler_t *inh) +{ + volatile ngx_cycle_t *saved_cycle; + ngx_int_t rc; + + saved_cycle = ngx_cycle; + ngx_cycle = cycle; + + rc = inh->init_handler(log, inh->init_src, inh->L); + + ngx_cycle = saved_cycle; + + if (rc != NGX_OK) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/meta/ngx_meta_lua_module.h b/src/meta/ngx_meta_lua_module.h new file mode 100644 index 0000000..40598a0 --- /dev/null +++ b/src/meta/ngx_meta_lua_module.h @@ -0,0 +1,53 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_META_LUA_H_INCLUDED_ +#define _NGX_META_LUA_H_INCLUDED_ + + +#include "ngx_meta_lua_api.h" + + +#define NGX_META_LUA_MODULE 0x41554c4d /* "MLUA" */ +#define NGX_META_LUA_CONF 0x02000000 + + +#define ngx_meta_lua_conf_get_main_conf(cf) \ + ((ngx_meta_lua_conf_t *) ngx_get_conf(cf->cycle->conf_ctx, \ + ngx_meta_lua_module)) + +#define ngx_meta_lua_cycle_get_main_conf(cycle) \ + ((ngx_meta_lua_conf_t *) ngx_get_conf(cycle->conf_ctx, \ + ngx_meta_lua_module)) + + +typedef struct { + ngx_uint_t shm_zones_inited; + ngx_array_t *shdict_zones; + ngx_array_t *init_handlers; + unsigned delay_init_handlers:1; + unsigned parsed_lua_block:1; +} ngx_meta_lua_conf_t; + + +typedef struct { + ngx_meta_lua_main_conf_handler_pt init_handler; + ngx_str_t init_src; + lua_State *L; +} ngx_meta_lua_init_handler_t; + + +extern ngx_module_t ngx_meta_lua_module; + + +ngx_int_t ngx_meta_lua_run_delayed_init_handlers(ngx_meta_lua_conf_t *mcf, + ngx_cycle_t *cycle, ngx_log_t *log); + + +#endif /* _NGX_META_LUA_H_INCLUDED_ */ + + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/meta/ngx_meta_lua_shdict.c b/src/meta/ngx_meta_lua_shdict.c new file mode 100644 index 0000000..1b4f3e6 --- /dev/null +++ b/src/meta/ngx_meta_lua_shdict.c @@ -0,0 +1,2133 @@ +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_meta_lua_shdict.h" + + +char *ngx_meta_lua_shdict_directive_helper(ngx_conf_t *cf, void *tag); +static ngx_int_t ngx_meta_lua_shdict_init(ngx_shm_zone_t *shm_zone, + void *data); +static ngx_int_t ngx_meta_lua_shdict_init_zone(ngx_shm_zone_t *shm_zone, + void *data); +static void ngx_meta_lua_shdict_rbtree_insert_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); +static ngx_inline ngx_shm_zone_t *ngx_meta_lua_shdict_get_zone(lua_State *L, + int index); +static ngx_int_t ngx_meta_lua_shdict_lookup(ngx_shm_zone_t *shm_zone, + ngx_uint_t hash, u_char *kdata, size_t klen, + ngx_meta_lua_shdict_node_t **sdp); +static ngx_inline ngx_queue_t * + ngx_meta_lua_shdict_get_list_head(ngx_meta_lua_shdict_node_t *sd, + size_t len); +static int ngx_meta_lua_shdict_expire(ngx_meta_lua_shdict_ctx_t *ctx, + ngx_uint_t n); +#if (NGX_DEBUG) +static int ngx_meta_lua_shdict_get_info(lua_State *L); +#endif +static int ngx_meta_lua_shdict_push_helper(lua_State *L, int flags); +static int ngx_meta_lua_shdict_pop_helper(lua_State *L, int flags); +static int ngx_meta_lua_shdict_flush_expired(lua_State *L); +static int ngx_meta_lua_shdict_get_keys(lua_State *L); +static int ngx_meta_lua_shdict_lpush(lua_State *L); +static int ngx_meta_lua_shdict_rpush(lua_State *L); +static int ngx_meta_lua_shdict_lpop(lua_State *L); +static int ngx_meta_lua_shdict_rpop(lua_State *L); +static int ngx_meta_lua_shdict_llen(lua_State *L); + + +#define NGX_META_LUA_SHDICT_ADD 0x0001 +#define NGX_META_LUA_SHDICT_REPLACE 0x0002 +#define NGX_META_LUA_SHDICT_SAFE_STORE 0x0004 +#define NGX_META_LUA_SHDICT_LEFT 0x0001 +#define NGX_META_LUA_SHDICT_RIGHT 0x0002 + + +enum { + SHDICT_USERDATA_INDEX = 1, +}; + + +enum { + SHDICT_TNIL = 0, /* same as LUA_TNIL */ + SHDICT_TBOOLEAN = 1, /* same as LUA_TBOOLEAN */ + SHDICT_TNUMBER = 3, /* same as LUA_TNUMBER */ + SHDICT_TSTRING = 4, /* same as LUA_TSTRING */ + SHDICT_TLIST = 5, +}; + + +char * +ngx_meta_lua_shdict_directive(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + return ngx_meta_lua_shdict_directive_helper(cf, &ngx_meta_lua_module); +} + + +char * +ngx_meta_lua_shdict_directive_helper(ngx_conf_t *cf, void *tag) +{ + ngx_meta_lua_conf_t *mcf; + ngx_meta_lua_shdict_ctx_t *shdict_ctx; + ngx_meta_lua_shm_zone_ctx_t *shm_zone_ctx; + ngx_shm_zone_t *zone; + ngx_shm_zone_t **zp; + ngx_str_t name, *value; + ssize_t size; + + mcf = ngx_meta_lua_conf_get_main_conf(cf); + + /* args */ + + value = cf->args->elts; + name = value[1]; + size = ngx_parse_size(&value[2]); + + if (name.len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid lua shared dict name \"%V\"", &name); + return NGX_CONF_ERROR; + } + + if (size <= 8191) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid lua shared dict size \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } + + /* shm zone */ + + zone = ngx_shared_memory_add(cf, &name, size, tag); + if (zone == NULL) { + return NGX_CONF_ERROR; + } + + shm_zone_ctx = ngx_pcalloc(cf->pool, sizeof(ngx_meta_lua_shm_zone_ctx_t)); + if (shm_zone_ctx == NULL) { + return NGX_CONF_ERROR; + } + + if (zone->data) { + shdict_ctx = zone->data; + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "lua_shared_dict \"%V\" is already defined as " + "\"%V\"", &name, &name); + return NGX_CONF_ERROR; + } + + shm_zone_ctx->mcf = mcf; + shm_zone_ctx->log = &cf->cycle->new_log; + shm_zone_ctx->cycle = cf->cycle; + + ngx_memcpy(&shm_zone_ctx->zone, zone, sizeof(ngx_shm_zone_t)); + + zone->init = ngx_meta_lua_shdict_init; + zone->data = shm_zone_ctx; + + /* shdict */ + + shdict_ctx = ngx_pcalloc(cf->pool, sizeof(ngx_meta_lua_shdict_ctx_t)); + if (shdict_ctx == NULL) { + return NGX_CONF_ERROR; + } + + shdict_ctx->name = name; + shdict_ctx->mcf = mcf; + shdict_ctx->log = &cf->cycle->new_log; + + zone = &shm_zone_ctx->zone; + + zone->init = ngx_meta_lua_shdict_init_zone; + zone->data = shdict_ctx; + + zp = ngx_array_push(mcf->shdict_zones); + if (zp == NULL) { + return NGX_CONF_ERROR; + } + + *zp = &shm_zone_ctx->zone; + + mcf->delay_init_handlers = 1; + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_meta_lua_shdict_init(ngx_shm_zone_t *shm_zone, void *data) +{ + ngx_int_t rc; + ngx_shm_zone_t *zone, *ozone; + ngx_meta_lua_shm_zone_ctx_t *ctx, *octx = data; + ngx_meta_lua_conf_t *mcf; + void *odata = NULL; + + ctx = (ngx_meta_lua_shm_zone_ctx_t *) shm_zone->data; + zone = &ctx->zone; + + if (octx) { + ozone = &octx->zone; + odata = ozone->data; + } + + zone->shm = shm_zone->shm; +#if defined(nginx_version) && nginx_version >= 1009000 + zone->noreuse = shm_zone->noreuse; +#endif + + if (zone->init(zone, odata) != NGX_OK) { + return NGX_ERROR; + } + + mcf = ctx->mcf; + if (mcf == NULL) { + return NGX_ERROR; + } + + mcf->shm_zones_inited++; + + if (mcf->shm_zones_inited == mcf->shdict_zones->nelts && !ngx_test_config) { + rc = ngx_meta_lua_run_delayed_init_handlers(mcf, ctx->cycle, ctx->log); + if (rc != NGX_OK) { + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_meta_lua_shdict_init_zone(ngx_shm_zone_t *shm_zone, void *data) +{ + size_t len; + ngx_meta_lua_shdict_ctx_t *ctx, *octx = data; + + ctx = shm_zone->data; + +#if (NGX_DEBUG) + ctx->isinit = 1; +#endif + + if (octx) { + ctx->sh = octx->sh; + ctx->shpool = octx->shpool; +#if (NGX_DEBUG) + ctx->isold = 1; +#endif + + return NGX_OK; + } + + ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; + + if (shm_zone->shm.exists) { + ctx->sh = ctx->shpool->data; + + return NGX_OK; + } + + ctx->shpool->data = ctx->sh; + ctx->shpool->log_nomem = 0; + + ctx->sh = ngx_slab_alloc(ctx->shpool, sizeof(ngx_meta_lua_shdict_shctx_t)); + if (ctx->sh == NULL) { + return NGX_ERROR; + } + + ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel, + ngx_meta_lua_shdict_rbtree_insert_value); + + ngx_queue_init(&ctx->sh->lru_queue); + + len = sizeof(" in lua_shared_dict zone \"\"") + shm_zone->shm.name.len; + + ctx->shpool->log_ctx = ngx_slab_alloc(ctx->shpool, len); + if (ctx->shpool->log_ctx == NULL) { + return NGX_ERROR; + } + + ngx_sprintf(ctx->shpool->log_ctx, " in lua_shared_dict zone \"%V\"%Z", + &shm_zone->shm.name); + + return NGX_OK; +} + + +static void +ngx_meta_lua_shdict_rbtree_insert_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) +{ + ngx_rbtree_node_t **p; + ngx_meta_lua_shdict_node_t *sdn, *sdnt; + + for ( ;; ) { + + if (node->key < temp->key) { + + p = &temp->left; + + } else if (node->key > temp->key) { + + p = &temp->right; + + } else { /* node->key == temp->key */ + + sdn = (ngx_meta_lua_shdict_node_t *) &node->color; + sdnt = (ngx_meta_lua_shdict_node_t *) &temp->color; + + p = ngx_memn2cmp(sdn->data, sdnt->data, sdn->key_len, + sdnt->key_len) < 0 ? &temp->left : &temp->right; + } + + if (*p == sentinel) { + break; + } + + temp = *p; + } + + *p = node; + node->parent = temp; + node->left = sentinel; + node->right = sentinel; + ngx_rbt_red(node); +} + + +void +ngx_meta_lua_inject_shdict_api(lua_State *L, ngx_cycle_t *cycle, void *tag) +{ + int nrec; + ngx_uint_t i; + ngx_meta_lua_conf_t *mcf; + ngx_meta_lua_shdict_ctx_t *ctx; + ngx_shm_zone_t **zone; + ngx_shm_zone_t **zone_udata; + + mcf = ngx_meta_lua_cycle_get_main_conf(cycle); + + if (mcf->shdict_zones->nelts) { + nrec = 0; + zone = mcf->shdict_zones->elts; + + for (i = 0; i < mcf->shdict_zones->nelts; i++) { + if (zone[i]->tag == tag || zone[i]->tag == &ngx_meta_lua_module) { + nrec += 1; + } + } + + lua_createtable(L, 0, nrec); /* ngx.shared */ + + lua_createtable(L, 0 /* narr */, 22 /* nrec */); /* shared mt */ + + lua_pushcfunction(L, ngx_meta_lua_shdict_lpush); + lua_setfield(L, -2, "lpush"); + + lua_pushcfunction(L, ngx_meta_lua_shdict_rpush); + lua_setfield(L, -2, "rpush"); + + lua_pushcfunction(L, ngx_meta_lua_shdict_lpop); + lua_setfield(L, -2, "lpop"); + + lua_pushcfunction(L, ngx_meta_lua_shdict_rpop); + lua_setfield(L, -2, "rpop"); + + lua_pushcfunction(L, ngx_meta_lua_shdict_llen); + lua_setfield(L, -2, "llen"); + + lua_pushcfunction(L, ngx_meta_lua_shdict_flush_expired); + lua_setfield(L, -2, "flush_expired"); + + lua_pushcfunction(L, ngx_meta_lua_shdict_get_keys); + lua_setfield(L, -2, "get_keys"); + +#if (NGX_DEBUG) + lua_pushcfunction(L, ngx_meta_lua_shdict_get_info); + lua_setfield(L, -2, "get_info"); +#endif + + lua_pushvalue(L, -1); /* shared mt mt */ + lua_setfield(L, -2, "__index"); /* shared mt */ + + for (i = 0; i < mcf->shdict_zones->nelts; i++) { + if (zone[i]->tag == tag || zone[i]->tag == &ngx_meta_lua_module) { + ctx = zone[i]->data; + + lua_pushlstring(L, (char *) ctx->name.data, ctx->name.len); + /* shared mt key */ + lua_createtable(L, 1 /* narr */, 0 /* nrec */); + /* table of zone[i] */ + zone_udata = lua_newuserdata(L, sizeof(ngx_shm_zone_t *)); + /* shared mt key ud */ + *zone_udata = zone[i]; + lua_rawseti(L, -2, SHDICT_USERDATA_INDEX); /* {zone[i]} */ + lua_pushvalue(L, -3); /* shared mt key ud mt */ + lua_setmetatable(L, -2); /* shared mt key ud */ + lua_rawset(L, -4); /* shared mt */ + } + } + + lua_pop(L, 1); /* shared */ + + } else { + lua_newtable(L); /* ngx.shared */ + } + + lua_setfield(L, -2, "shared"); +} + + +static ngx_int_t +ngx_meta_lua_shdict_lookup(ngx_shm_zone_t *shm_zone, ngx_uint_t hash, + u_char *kdata, size_t klen, ngx_meta_lua_shdict_node_t **sdp) +{ + int64_t ms; + uint64_t now; + ngx_int_t rc; + ngx_time_t *tp; + ngx_rbtree_node_t *node, *sentinel; + ngx_meta_lua_shdict_ctx_t *ctx; + ngx_meta_lua_shdict_node_t *sd; + + ctx = shm_zone->data; + + node = ctx->sh->rbtree.root; + sentinel = ctx->sh->rbtree.sentinel; + + while (node != sentinel) { + + if (hash < node->key) { + node = node->left; + continue; + } + + if (hash > node->key) { + node = node->right; + continue; + } + + /* hash == node->key */ + + sd = (ngx_meta_lua_shdict_node_t *) &node->color; + + rc = ngx_memn2cmp(kdata, sd->data, klen, (size_t) sd->key_len); + + if (rc == 0) { + ngx_queue_remove(&sd->queue); + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); + + *sdp = sd; + + dd("node expires: %lld", (long long) sd->expires); + + if (sd->expires != 0) { + tp = ngx_timeofday(); + + now = (uint64_t) tp->sec * 1000 + tp->msec; + ms = sd->expires - now; + + dd("time to live: %lld", (long long) ms); + + if (ms < 0) { + dd("node already expired"); + return NGX_DONE; + } + } + + return NGX_OK; + } + + node = (rc < 0) ? node->left : node->right; + } + + *sdp = NULL; + + return NGX_DECLINED; +} + + +static int +ngx_meta_lua_shdict_expire(ngx_meta_lua_shdict_ctx_t *ctx, ngx_uint_t n) +{ + int freed = 0; + int64_t ms; + uint64_t now; + ngx_time_t *tp; + ngx_queue_t *q, *list_queue, *lq; + ngx_rbtree_node_t *node; + ngx_meta_lua_shdict_node_t *sd; + ngx_meta_lua_shdict_list_node_t *lnode; + + tp = ngx_timeofday(); + + now = (uint64_t) tp->sec * 1000 + tp->msec; + + /* + * n == 1 deletes one or two expired entries + * n == 0 deletes oldest entry by force + * and one or two zero rate entries + */ + + while (n < 3) { + + if (ngx_queue_empty(&ctx->sh->lru_queue)) { + return freed; + } + + q = ngx_queue_last(&ctx->sh->lru_queue); + + sd = ngx_queue_data(q, ngx_meta_lua_shdict_node_t, queue); + + if (n++ != 0) { + + if (sd->expires == 0) { + return freed; + } + + ms = sd->expires - now; + if (ms > 0) { + return freed; + } + } + + if (sd->value_type == SHDICT_TLIST) { + list_queue = ngx_meta_lua_shdict_get_list_head(sd, sd->key_len); + + for (lq = ngx_queue_head(list_queue); + lq != ngx_queue_sentinel(list_queue); + lq = ngx_queue_next(lq)) + { + lnode = ngx_queue_data(lq, ngx_meta_lua_shdict_list_node_t, + queue); + + ngx_slab_free_locked(ctx->shpool, lnode); + } + } + + ngx_queue_remove(q); + + node = (ngx_rbtree_node_t *) + ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); + + ngx_rbtree_delete(&ctx->sh->rbtree, node); + + ngx_slab_free_locked(ctx->shpool, node); + + freed++; + } + + return freed; +} + + +static ngx_inline ngx_shm_zone_t * +ngx_meta_lua_shdict_get_zone(lua_State *L, int index) +{ + ngx_shm_zone_t **zone_udata; + + lua_rawgeti(L, index, SHDICT_USERDATA_INDEX); + zone_udata = lua_touserdata(L, -1); + lua_pop(L, 1); + + if (zone_udata == NULL) { + return NULL; + } + + return *zone_udata; +} + + +static ngx_inline ngx_queue_t * +ngx_meta_lua_shdict_get_list_head(ngx_meta_lua_shdict_node_t *sd, size_t len) +{ + return (ngx_queue_t *) ngx_align_ptr(((u_char *) &sd->data + len), + NGX_ALIGNMENT); +} + + +static int +ngx_meta_lua_shdict_flush_expired(lua_State *L) +{ + uint64_t now; + int n; + int freed = 0, attempts = 0; + ngx_queue_t *q, *prev, *list_queue, *lq; + ngx_shm_zone_t *zone; + ngx_time_t *tp; + ngx_rbtree_node_t *node; + ngx_meta_lua_shdict_node_t *sd; + ngx_meta_lua_shdict_ctx_t *ctx; + ngx_meta_lua_shdict_list_node_t *lnode; + + 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_TTABLE); + + zone = ngx_meta_lua_shdict_get_zone(L, 1); + if (zone == NULL) { + return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer"); + } + + if (n == 2) { + attempts = luaL_checkint(L, 2); + } + + ctx = zone->data; + + ngx_shmtx_lock(&ctx->shpool->mutex); + + if (ngx_queue_empty(&ctx->sh->lru_queue)) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + lua_pushnumber(L, 0); + return 1; + } + + tp = ngx_timeofday(); + + now = (uint64_t) tp->sec * 1000 + tp->msec; + + q = ngx_queue_last(&ctx->sh->lru_queue); + + while (q != ngx_queue_sentinel(&ctx->sh->lru_queue)) { + prev = ngx_queue_prev(q); + + sd = ngx_queue_data(q, ngx_meta_lua_shdict_node_t, queue); + + if (sd->expires != 0 && sd->expires <= now) { + + if (sd->value_type == SHDICT_TLIST) { + list_queue = ngx_meta_lua_shdict_get_list_head(sd, sd->key_len); + + for (lq = ngx_queue_head(list_queue); + lq != ngx_queue_sentinel(list_queue); + lq = ngx_queue_next(lq)) + { + lnode = ngx_queue_data(lq, ngx_meta_lua_shdict_list_node_t, + queue); + + ngx_slab_free_locked(ctx->shpool, lnode); + } + } + + ngx_queue_remove(q); + + node = (ngx_rbtree_node_t *) + ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); + + ngx_rbtree_delete(&ctx->sh->rbtree, node); + ngx_slab_free_locked(ctx->shpool, node); + freed++; + + if (attempts && freed == attempts) { + break; + } + } + + q = prev; + } + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + lua_pushnumber(L, freed); + + return 1; +} + + +static int +ngx_meta_lua_shdict_get_keys(lua_State *L) +{ + int n, total = 0, attempts = 1024; + uint64_t now; + ngx_queue_t *q, *prev; + ngx_shm_zone_t *zone; + ngx_time_t *tp; + ngx_meta_lua_shdict_node_t *sd; + ngx_meta_lua_shdict_ctx_t *ctx; + + 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_TTABLE); + + zone = ngx_meta_lua_shdict_get_zone(L, 1); + if (zone == NULL) { + return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer"); + } + + if (n == 2) { + attempts = luaL_checkint(L, 2); + } + + ctx = zone->data; + + ngx_shmtx_lock(&ctx->shpool->mutex); + + if (ngx_queue_empty(&ctx->sh->lru_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->lru_queue); + + while (q != ngx_queue_sentinel(&ctx->sh->lru_queue)) { + prev = ngx_queue_prev(q); + + sd = ngx_queue_data(q, ngx_meta_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->lru_queue); + + while (q != ngx_queue_sentinel(&ctx->sh->lru_queue)) { + prev = ngx_queue_prev(q); + + sd = ngx_queue_data(q, ngx_meta_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_meta_lua_shdict_lpush(lua_State *L) +{ + return ngx_meta_lua_shdict_push_helper(L, NGX_META_LUA_SHDICT_LEFT); +} + + +static int +ngx_meta_lua_shdict_rpush(lua_State *L) +{ + return ngx_meta_lua_shdict_push_helper(L, NGX_META_LUA_SHDICT_RIGHT); +} + + +static int +ngx_meta_lua_shdict_lpop(lua_State *L) +{ + return ngx_meta_lua_shdict_pop_helper(L, NGX_META_LUA_SHDICT_LEFT); +} + + +static int +ngx_meta_lua_shdict_rpop(lua_State *L) +{ + return ngx_meta_lua_shdict_pop_helper(L, NGX_META_LUA_SHDICT_RIGHT); +} + + +static int +ngx_meta_lua_shdict_push_helper(lua_State *L, int flags) +{ + int n, value_type; + double num; + uint32_t hash; + ngx_str_t key, value; + ngx_int_t rc; + ngx_rbtree_node_t *node; + ngx_shm_zone_t *zone; + ngx_queue_t *queue, *q; + ngx_meta_lua_shdict_ctx_t *ctx; + ngx_meta_lua_shdict_node_t *sd; + ngx_meta_lua_shdict_list_node_t *lnode; + + n = lua_gettop(L); + + if (n != 3) { + return luaL_error(L, "expecting 3 arguments, " + "but only seen %d", n); + } + + if (lua_type(L, 1) != LUA_TTABLE) { + return luaL_error(L, "bad \"zone\" argument"); + } + + zone = ngx_meta_lua_shdict_get_zone(L, 1); + if (zone == NULL) { + return luaL_error(L, "bad \"zone\" argument"); + } + + ctx = zone->data; + + if (lua_isnil(L, 2)) { + lua_pushnil(L); + lua_pushliteral(L, "nil key"); + return 2; + } + + key.data = (u_char *) luaL_checklstring(L, 2, &key.len); + + if (key.len == 0) { + lua_pushnil(L); + lua_pushliteral(L, "empty key"); + return 2; + } + + if (key.len > 65535) { + lua_pushnil(L); + lua_pushliteral(L, "key too long"); + return 2; + } + + hash = ngx_crc32_short(key.data, key.len); + + value_type = lua_type(L, 3); + + switch (value_type) { + + case SHDICT_TSTRING: + value.data = (u_char *) lua_tolstring(L, 3, &value.len); + break; + + case SHDICT_TNUMBER: + value.len = sizeof(double); + num = lua_tonumber(L, 3); + value.data = (u_char *) # + break; + + default: + lua_pushnil(L); + lua_pushliteral(L, "bad value type"); + return 2; + } + + ngx_shmtx_lock(&ctx->shpool->mutex); + +#if 1 + ngx_meta_lua_shdict_expire(ctx, 1); +#endif + + rc = ngx_meta_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); + + dd("shdict lookup returned %d", (int) rc); + + /* exists but expired */ + + if (rc == NGX_DONE) { + + if (sd->value_type != SHDICT_TLIST) { + /* TODO: reuse when length matched */ + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, ctx->log, 0, + "lua shared dict push: found old entry and value " + "type not matched, remove it first"); + + ngx_queue_remove(&sd->queue); + + node = (ngx_rbtree_node_t *) + ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); + + ngx_rbtree_delete(&ctx->sh->rbtree, node); + + ngx_slab_free_locked(ctx->shpool, node); + + dd("go to init_list"); + goto init_list; + } + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, ctx->log, 0, + "lua shared dict push: found old entry and value " + "type matched, reusing it"); + + sd->expires = 0; + + /* free list nodes */ + + queue = ngx_meta_lua_shdict_get_list_head(sd, key.len); + + for (q = ngx_queue_head(queue); + q != ngx_queue_sentinel(queue); + q = ngx_queue_next(q)) + { + /* TODO: reuse matched size list node */ + lnode = ngx_queue_data(q, ngx_meta_lua_shdict_list_node_t, queue); + ngx_slab_free_locked(ctx->shpool, lnode); + } + + ngx_queue_init(queue); + + ngx_queue_remove(&sd->queue); + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); + + dd("go to push_node"); + goto push_node; + } + + /* exists and not expired */ + + if (rc == NGX_OK) { + + if (sd->value_type != SHDICT_TLIST) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + + lua_pushnil(L); + lua_pushliteral(L, "value not a list"); + return 2; + } + + queue = ngx_meta_lua_shdict_get_list_head(sd, key.len); + + ngx_queue_remove(&sd->queue); + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); + + dd("go to push_node"); + goto push_node; + } + + /* rc == NGX_DECLINED, not found */ + +init_list: + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, ctx->log, 0, + "lua shared dict list: creating a new entry"); + + /* NOTICE: we assume the begin point aligned in slab, be careful */ + n = offsetof(ngx_rbtree_node_t, color) + + offsetof(ngx_meta_lua_shdict_node_t, data) + + key.len + + sizeof(ngx_queue_t); + + dd("length before aligned: %d", n); + + n = (int) (uintptr_t) ngx_align_ptr(n, NGX_ALIGNMENT); + + dd("length after aligned: %d", n); + + node = ngx_slab_alloc_locked(ctx->shpool, n); + + if (node == NULL) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + + lua_pushboolean(L, 0); + lua_pushliteral(L, "no memory"); + return 2; + } + + sd = (ngx_meta_lua_shdict_node_t *) &node->color; + + queue = ngx_meta_lua_shdict_get_list_head(sd, key.len); + + node->key = hash; + + dd("setting value type to %d", (int) SHDICT_TLIST); + + sd->key_len = (u_short) key.len; + sd->expires = 0; + sd->value_len = 0; + sd->value_type = (uint8_t) SHDICT_TLIST; + + ngx_memcpy(sd->data, key.data, key.len); + + ngx_queue_init(queue); + + ngx_rbtree_insert(&ctx->sh->rbtree, node); + + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); + +push_node: + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, ctx->log, 0, + "lua shared dict list: creating a new list node"); + + n = offsetof(ngx_meta_lua_shdict_list_node_t, data) + + value.len; + + dd("list node length: %d", n); + + lnode = ngx_slab_alloc_locked(ctx->shpool, n); + + if (lnode == NULL) { + + if (sd->value_len == 0) { + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, ctx->log, 0, + "lua shared dict list: no memory for create" + " list node and list empty, remove it"); + + ngx_queue_remove(&sd->queue); + + node = (ngx_rbtree_node_t *) + ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); + + ngx_rbtree_delete(&ctx->sh->rbtree, node); + + ngx_slab_free_locked(ctx->shpool, node); + } + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + lua_pushboolean(L, 0); + lua_pushliteral(L, "no memory"); + return 2; + } + + dd("setting list length to %d", sd->value_len + 1); + dd("setting list node value length to %d", (int) value.len); + dd("setting list node value type to %d", value_type); + + sd->value_len = sd->value_len + 1; + + lnode->value_len = (uint32_t) value.len; + lnode->value_type = (uint8_t) value_type; + + ngx_memcpy(lnode->data, value.data, value.len); + + if (flags == NGX_META_LUA_SHDICT_LEFT) { + ngx_queue_insert_head(queue, &lnode->queue); + + } else { + ngx_queue_insert_tail(queue, &lnode->queue); + } + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + lua_pushnumber(L, sd->value_len); + return 1; +} + + +static int +ngx_meta_lua_shdict_pop_helper(lua_State *L, int flags) +{ + int n, value_type; + double num; + uint32_t hash; + ngx_str_t name, key, value; + ngx_int_t rc; + ngx_rbtree_node_t *node; + ngx_shm_zone_t *zone; + ngx_queue_t *queue; + ngx_meta_lua_shdict_ctx_t *ctx; + ngx_meta_lua_shdict_node_t *sd; + ngx_meta_lua_shdict_list_node_t *lnode; + + n = lua_gettop(L); + + if (n != 2) { + return luaL_error(L, "expecting 2 arguments, " + "but only seen %d", n); + } + + if (lua_type(L, 1) != LUA_TTABLE) { + return luaL_error(L, "bad \"zone\" argument"); + } + + zone = ngx_meta_lua_shdict_get_zone(L, 1); + if (zone == NULL) { + return luaL_error(L, "bad \"zone\" argument"); + } + + ctx = zone->data; + name = ctx->name; + + if (lua_isnil(L, 2)) { + lua_pushnil(L); + lua_pushliteral(L, "nil key"); + return 2; + } + + key.data = (u_char *) luaL_checklstring(L, 2, &key.len); + + if (key.len == 0) { + lua_pushnil(L); + lua_pushliteral(L, "empty key"); + return 2; + } + + if (key.len > 65535) { + lua_pushnil(L); + lua_pushliteral(L, "key too long"); + return 2; + } + + hash = ngx_crc32_short(key.data, key.len); + + ngx_shmtx_lock(&ctx->shpool->mutex); + +#if 1 + ngx_meta_lua_shdict_expire(ctx, 1); +#endif + + rc = ngx_meta_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); + + dd("shdict lookup returned %d", (int) rc); + + if (rc == NGX_DECLINED || rc == NGX_DONE) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + lua_pushnil(L); + return 1; + } + + /* rc == NGX_OK */ + + if (sd->value_type != SHDICT_TLIST) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + + lua_pushnil(L); + lua_pushliteral(L, "value not a list"); + return 2; + } + + if (sd->value_len <= 0) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return luaL_error(L, "bad lua list length found for key %s " + "in shared_dict %s: %lu", key.data, name.data, + (unsigned long) sd->value_len); + } + + queue = ngx_meta_lua_shdict_get_list_head(sd, key.len); + + if (flags == NGX_META_LUA_SHDICT_LEFT) { + queue = ngx_queue_head(queue); + + } else { + queue = ngx_queue_last(queue); + } + + lnode = ngx_queue_data(queue, ngx_meta_lua_shdict_list_node_t, queue); + + value_type = lnode->value_type; + + dd("data: %p", lnode->data); + dd("value len: %d", (int) sd->value_len); + + value.data = lnode->data; + value.len = (size_t) lnode->value_len; + + switch (value_type) { + + case SHDICT_TSTRING: + + lua_pushlstring(L, (char *) value.data, value.len); + break; + + case SHDICT_TNUMBER: + + if (value.len != sizeof(double)) { + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return luaL_error(L, "bad lua list node number value size found " + "for key %s in shared_dict %s: %lu", key.data, + name.data, (unsigned long) value.len); + } + + ngx_memcpy(&num, value.data, sizeof(double)); + + lua_pushnumber(L, num); + break; + + default: + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return luaL_error(L, "bad list node value type found for key %s in " + "shared_dict %s: %d", key.data, name.data, + value_type); + } + + ngx_queue_remove(queue); + + ngx_slab_free_locked(ctx->shpool, lnode); + + if (sd->value_len == 1) { + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, ctx->log, 0, + "lua shared dict list: empty node after pop, " + "remove it"); + + ngx_queue_remove(&sd->queue); + + node = (ngx_rbtree_node_t *) + ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); + + ngx_rbtree_delete(&ctx->sh->rbtree, node); + + ngx_slab_free_locked(ctx->shpool, node); + + } else { + sd->value_len = sd->value_len - 1; + + ngx_queue_remove(&sd->queue); + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); + } + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return 1; +} + + +static int +ngx_meta_lua_shdict_llen(lua_State *L) +{ + int n; + uint32_t hash; + ngx_str_t key; + ngx_int_t rc; + ngx_shm_zone_t *zone; + ngx_meta_lua_shdict_ctx_t *ctx; + ngx_meta_lua_shdict_node_t *sd; + + n = lua_gettop(L); + + if (n != 2) { + return luaL_error(L, "expecting 2 arguments, " + "but only seen %d", n); + } + + if (lua_type(L, 1) != LUA_TTABLE) { + return luaL_error(L, "bad \"zone\" argument"); + } + + zone = ngx_meta_lua_shdict_get_zone(L, 1); + if (zone == NULL) { + return luaL_error(L, "bad \"zone\" argument"); + } + + ctx = zone->data; + + if (lua_isnil(L, 2)) { + lua_pushnil(L); + lua_pushliteral(L, "nil key"); + return 2; + } + + key.data = (u_char *) luaL_checklstring(L, 2, &key.len); + + if (key.len == 0) { + lua_pushnil(L); + lua_pushliteral(L, "empty key"); + return 2; + } + + if (key.len > 65535) { + lua_pushnil(L); + lua_pushliteral(L, "key too long"); + return 2; + } + + hash = ngx_crc32_short(key.data, key.len); + + ngx_shmtx_lock(&ctx->shpool->mutex); + +#if 1 + ngx_meta_lua_shdict_expire(ctx, 1); +#endif + + rc = ngx_meta_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); + + dd("shdict lookup returned %d", (int) rc); + + if (rc == NGX_OK) { + + if (sd->value_type != SHDICT_TLIST) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + + lua_pushnil(L); + lua_pushliteral(L, "value not a list"); + return 2; + } + + ngx_queue_remove(&sd->queue); + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + lua_pushnumber(L, (lua_Number) sd->value_len); + return 1; + } + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + lua_pushnumber(L, 0); + return 1; +} + + +#if (NGX_DEBUG) +static int +ngx_meta_lua_shdict_get_info(lua_State *L) +{ + ngx_int_t n; + ngx_shm_zone_t *zone; + ngx_meta_lua_shdict_ctx_t *ctx; + + n = lua_gettop(L); + + if (n != 1) { + return luaL_error(L, "expecting exactly one argument, but seen %d", n); + } + + luaL_checktype(L, 1, LUA_TTABLE); + + zone = ngx_meta_lua_shdict_get_zone(L, 1); + if (zone == NULL) { + return luaL_error(L, "bad \"zone\" argument"); + } + + ctx = (ngx_meta_lua_shdict_ctx_t *) zone->data; + + lua_pushlstring(L, (char *) zone->shm.name.data, zone->shm.name.len); + lua_pushnumber(L, zone->shm.size); + lua_pushboolean(L, ctx->isinit); + lua_pushboolean(L, ctx->isold); + + return 4; +} +#endif + + +ngx_shm_zone_t * +ngx_meta_lua_ffi_shdict_udata_to_zone(void *zone_udata) +{ + if (zone_udata == NULL) { + return NULL; + } + + return *(ngx_shm_zone_t **) zone_udata; +} + + +int +ngx_meta_lua_ffi_shdict_store(ngx_shm_zone_t *zone, int op, u_char *key, + size_t key_len, int value_type, u_char *str_value_buf, + size_t str_value_len, double num_value, long exptime, int user_flags, + char **errmsg, int *forcible) +{ + int i, n; + uint32_t hash; + u_char c, *p; + ngx_int_t rc; + ngx_time_t *tp; + ngx_queue_t *queue, *q; + ngx_rbtree_node_t *node; + ngx_meta_lua_shdict_ctx_t *ctx; + ngx_meta_lua_shdict_node_t *sd; + + dd("exptime: %ld", exptime); + + ctx = zone->data; + + *forcible = 0; + + hash = ngx_crc32_short(key, key_len); + + switch (value_type) { + + case SHDICT_TSTRING: + /* do nothing */ + break; + + case SHDICT_TNUMBER: + dd("num value: %lf", num_value); + str_value_buf = (u_char *) &num_value; + str_value_len = sizeof(double); + break; + + case SHDICT_TBOOLEAN: + c = num_value ? 1 : 0; + str_value_buf = &c; + str_value_len = sizeof(u_char); + break; + + case LUA_TNIL: + if (op & (NGX_META_LUA_SHDICT_ADD|NGX_META_LUA_SHDICT_REPLACE)) { + *errmsg = "attempt to add or replace nil values"; + return NGX_ERROR; + } + + str_value_buf = NULL; + str_value_len = 0; + break; + + default: + *errmsg = "unsupported value type"; + return NGX_ERROR; + } + + ngx_shmtx_lock(&ctx->shpool->mutex); + +#if 1 + ngx_meta_lua_shdict_expire(ctx, 1); +#endif + + rc = ngx_meta_lua_shdict_lookup(zone, hash, key, key_len, &sd); + + dd("lookup returns %d", (int) rc); + + if (op & NGX_META_LUA_SHDICT_REPLACE) { + + if (rc == NGX_DECLINED || rc == NGX_DONE) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + *errmsg = "not found"; + return NGX_DECLINED; + } + + /* rc == NGX_OK */ + + goto replace; + } + + if (op & NGX_META_LUA_SHDICT_ADD) { + + if (rc == NGX_OK) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + *errmsg = "exists"; + return NGX_DECLINED; + } + + if (rc == NGX_DONE) { + /* exists but expired */ + + dd("go to replace"); + goto replace; + } + + /* rc == NGX_DECLINED */ + + dd("go to insert"); + goto insert; + } + + if (rc == NGX_OK || rc == NGX_DONE) { + + if (value_type == LUA_TNIL) { + goto remove; + } + +replace: + + if (str_value_buf + && str_value_len == (size_t) sd->value_len + && sd->value_type != SHDICT_TLIST) + { + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, ctx->log, 0, + "lua shared dict set: found old entry and value " + "size matched, reusing it"); + + ngx_queue_remove(&sd->queue); + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); + + sd->key_len = (u_short) key_len; + + if (exptime > 0) { + tp = ngx_timeofday(); + sd->expires = (uint64_t) tp->sec * 1000 + tp->msec + + (uint64_t) exptime; + + } else { + sd->expires = 0; + } + + dd("setting value type to %d", value_type); + + sd->user_flags = user_flags; + sd->value_len = (uint32_t) str_value_len; + sd->value_type = (uint8_t) value_type; + + p = ngx_copy(sd->data, key, key_len); + ngx_memcpy(p, str_value_buf, str_value_len); + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return NGX_OK; + } + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, ctx->log, 0, + "lua shared dict set: found old entry but value size " + "NOT matched, removing it first"); + +remove: + + if (sd->value_type == SHDICT_TLIST) { + queue = ngx_meta_lua_shdict_get_list_head(sd, key_len); + + for (q = ngx_queue_head(queue); + q != ngx_queue_sentinel(queue); + q = ngx_queue_next(q)) + { + p = (u_char *) ngx_queue_data(q, + ngx_meta_lua_shdict_list_node_t, + queue); + + ngx_slab_free_locked(ctx->shpool, p); + } + } + + ngx_queue_remove(&sd->queue); + + node = (ngx_rbtree_node_t *) + ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); + + ngx_rbtree_delete(&ctx->sh->rbtree, node); + + ngx_slab_free_locked(ctx->shpool, node); + + } + +insert: + + /* rc == NGX_DECLINED or value size unmatch */ + + if (str_value_buf == NULL) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + return NGX_OK; + } + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, ctx->log, 0, + "lua shared dict set: creating a new entry"); + + n = offsetof(ngx_rbtree_node_t, color) + + offsetof(ngx_meta_lua_shdict_node_t, data) + + key_len + + str_value_len; + + node = ngx_slab_alloc_locked(ctx->shpool, n); + + if (node == NULL) { + + if (op & NGX_META_LUA_SHDICT_SAFE_STORE) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + + *errmsg = "no memory"; + return NGX_ERROR; + } + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0, + "lua shared dict set: overriding non-expired items " + "due to memory shortage for entry \"%*s\"", key_len, + key); + + for (i = 0; i < 30; i++) { + if (ngx_meta_lua_shdict_expire(ctx, 0) == 0) { + break; + } + + *forcible = 1; + + node = ngx_slab_alloc_locked(ctx->shpool, n); + if (node != NULL) { + goto allocated; + } + } + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + *errmsg = "no memory"; + return NGX_ERROR; + } + +allocated: + + sd = (ngx_meta_lua_shdict_node_t *) &node->color; + + node->key = hash; + sd->key_len = (u_short) key_len; + + if (exptime > 0) { + tp = ngx_timeofday(); + sd->expires = (uint64_t) tp->sec * 1000 + tp->msec + + (uint64_t) exptime; + + } else { + sd->expires = 0; + } + + sd->user_flags = user_flags; + sd->value_len = (uint32_t) str_value_len; + dd("setting value type to %d", value_type); + sd->value_type = (uint8_t) value_type; + + p = ngx_copy(sd->data, key, key_len); + ngx_memcpy(p, str_value_buf, str_value_len); + + ngx_rbtree_insert(&ctx->sh->rbtree, node); + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return NGX_OK; +} + + +int +ngx_meta_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, + size_t key_len, int *value_type, u_char **str_value_buf, + size_t *str_value_len, double *num_value, int *user_flags, + int get_stale, int *is_stale, char **err) +{ + uint32_t hash; + ngx_str_t name, value; + ngx_int_t rc; + ngx_meta_lua_shdict_ctx_t *ctx; + ngx_meta_lua_shdict_node_t *sd; + + *err = NULL; + + ctx = zone->data; + name = ctx->name; + + hash = ngx_crc32_short(key, key_len); + +#if (NGX_DEBUG) + ngx_log_debug3(NGX_LOG_DEBUG_CORE, ctx->log, 0, + "fetching key \"%*s\" in shared dict \"%V\"", key_len, + key, &name); +#endif + + ngx_shmtx_lock(&ctx->shpool->mutex); + +#if 1 + if (!get_stale) { + ngx_meta_lua_shdict_expire(ctx, 1); + } +#endif + + rc = ngx_meta_lua_shdict_lookup(zone, hash, key, key_len, &sd); + + dd("shdict lookup returns %d", (int) rc); + + if (rc == NGX_DECLINED || (rc == NGX_DONE && !get_stale)) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + *value_type = LUA_TNIL; + return NGX_OK; + } + + /* rc == NGX_OK || (rc == NGX_DONE && get_stale) */ + + *value_type = sd->value_type; + + dd("data: %p", sd->data); + dd("key len: %d", (int) sd->key_len); + + value.data = sd->data + sd->key_len; + value.len = (size_t) sd->value_len; + + if (*str_value_len < (size_t) value.len) { + if (*value_type == SHDICT_TBOOLEAN) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + return NGX_ERROR; + } + + if (*value_type == SHDICT_TSTRING) { + *str_value_buf = malloc(value.len); + if (*str_value_buf == NULL) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + return NGX_ERROR; + } + } + } + + switch (*value_type) { + + case SHDICT_TSTRING: + *str_value_len = value.len; + ngx_memcpy(*str_value_buf, value.data, value.len); + break; + + case SHDICT_TNUMBER: + + if (value.len != sizeof(double)) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "bad lua number value size found for key %*s " + "in shared_dict %V: %z", key_len, key, + &name, value.len); + return NGX_ERROR; + } + + *str_value_len = value.len; + ngx_memcpy(num_value, value.data, sizeof(double)); + break; + + case SHDICT_TBOOLEAN: + + if (value.len != sizeof(u_char)) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "bad lua boolean value size found for key %*s " + "in shared_dict %V: %z", key_len, key, &name, + value.len); + return NGX_ERROR; + } + + ngx_memcpy(*str_value_buf, value.data, value.len); + break; + + case SHDICT_TLIST: + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + *err = "value is a list"; + return NGX_ERROR; + + default: + + ngx_shmtx_unlock(&ctx->shpool->mutex); + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "bad value type found for key %*s in " + "shared_dict %V: %d", key_len, key, &name, + *value_type); + return NGX_ERROR; + } + + *user_flags = sd->user_flags; + dd("user flags: %d", *user_flags); + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + if (get_stale) { + + /* always return value, flags, stale */ + + *is_stale = (rc == NGX_DONE); + return NGX_OK; + } + + return NGX_OK; +} + + +int +ngx_meta_lua_ffi_shdict_incr(ngx_shm_zone_t *zone, u_char *key, + size_t key_len, double *value, char **err, int has_init, double init, + long init_ttl, int *forcible) +{ + int i, n; + uint32_t hash; + double num; + u_char *p; + ngx_int_t rc; + ngx_time_t *tp = NULL; + ngx_rbtree_node_t *node; + ngx_queue_t *queue, *q; + ngx_meta_lua_shdict_ctx_t *ctx; + ngx_meta_lua_shdict_node_t *sd; + + if (init_ttl > 0) { + tp = ngx_timeofday(); + } + + ctx = zone->data; + + *forcible = 0; + + hash = ngx_crc32_short(key, key_len); + + dd("looking up key %.*s in shared dict %.*s", (int) key_len, key, + (int) ctx->name.len, ctx->name.data); + + ngx_shmtx_lock(&ctx->shpool->mutex); +#if 1 + ngx_meta_lua_shdict_expire(ctx, 1); +#endif + rc = ngx_meta_lua_shdict_lookup(zone, hash, key, key_len, &sd); + + dd("shdict lookup returned %d", (int) rc); + + if (rc == NGX_DECLINED || rc == NGX_DONE) { + if (!has_init) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + *err = "not found"; + return NGX_ERROR; + } + + /* add value */ + num = *value + init; + + if (rc == NGX_DONE) { + + /* found an expired item */ + + if ((size_t) sd->value_len == sizeof(double) + && sd->value_type != SHDICT_TLIST) + { + ngx_log_debug0(NGX_LOG_DEBUG_CORE, ctx->log, 0, + "lua shared dict incr: found old entry and " + "value size matched, reusing it"); + + ngx_queue_remove(&sd->queue); + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); + + dd("go to setvalue"); + goto setvalue; + } + + dd("go to remove"); + goto remove; + } + + dd("go to insert"); + goto insert; + } + + /* rc == NGX_OK */ + + if (sd->value_type != SHDICT_TNUMBER || sd->value_len != sizeof(double)) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + *err = "not a number"; + return NGX_ERROR; + } + + ngx_queue_remove(&sd->queue); + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); + + dd("setting value type to %d", (int) sd->value_type); + + p = sd->data + key_len; + + ngx_memcpy(&num, p, sizeof(double)); + num += *value; + + ngx_memcpy(p, (double *) &num, sizeof(double)); + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + *value = num; + return NGX_OK; + +remove: + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, ctx->log, 0, + "lua shared dict incr: found old entry but value size " + "NOT matched, removing it first"); + + if (sd->value_type == SHDICT_TLIST) { + queue = ngx_meta_lua_shdict_get_list_head(sd, key_len); + + for (q = ngx_queue_head(queue); + q != ngx_queue_sentinel(queue); + q = ngx_queue_next(q)) + { + p = (u_char *) ngx_queue_data(q, ngx_meta_lua_shdict_list_node_t, + queue); + + ngx_slab_free_locked(ctx->shpool, p); + } + } + + ngx_queue_remove(&sd->queue); + + node = (ngx_rbtree_node_t *) + ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); + + ngx_rbtree_delete(&ctx->sh->rbtree, node); + + ngx_slab_free_locked(ctx->shpool, node); + +insert: + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, ctx->log, 0, + "lua shared dict incr: creating a new entry"); + + n = offsetof(ngx_rbtree_node_t, color) + + offsetof(ngx_meta_lua_shdict_node_t, data) + + key_len + + sizeof(double); + + node = ngx_slab_alloc_locked(ctx->shpool, n); + + if (node == NULL) { + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0, + "lua shared dict incr: overriding non-expired items " + "due to memory shortage for entry \"%*s\"", key_len, + key); + + for (i = 0; i < 30; i++) { + if (ngx_meta_lua_shdict_expire(ctx, 0) == 0) { + break; + } + + *forcible = 1; + + node = ngx_slab_alloc_locked(ctx->shpool, n); + if (node != NULL) { + goto allocated; + } + } + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + *err = "no memory"; + return NGX_ERROR; + } + +allocated: + + sd = (ngx_meta_lua_shdict_node_t *) &node->color; + + node->key = hash; + + sd->key_len = (u_short) key_len; + sd->value_len = (uint32_t) sizeof(double); + + ngx_rbtree_insert(&ctx->sh->rbtree, node); + + ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue); + +setvalue: + + sd->user_flags = 0; + + if (init_ttl > 0) { + sd->expires = (uint64_t) tp->sec * 1000 + tp->msec + + (uint64_t) init_ttl; + + } else { + sd->expires = 0; + } + + dd("setting value type to %d", LUA_TNUMBER); + + sd->value_type = (uint8_t) LUA_TNUMBER; + + p = ngx_copy(sd->data, key, key_len); + ngx_memcpy(p, (double *) &num, sizeof(double)); + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + *value = num; + + return NGX_OK; +} + + +int +ngx_meta_lua_ffi_shdict_flush_all(ngx_shm_zone_t *zone) +{ + ngx_queue_t *q; + ngx_meta_lua_shdict_node_t *sd; + ngx_meta_lua_shdict_ctx_t *ctx; + + ctx = zone->data; + + ngx_shmtx_lock(&ctx->shpool->mutex); + + for (q = ngx_queue_head(&ctx->sh->lru_queue); + q != ngx_queue_sentinel(&ctx->sh->lru_queue); + q = ngx_queue_next(q)) + { + sd = ngx_queue_data(q, ngx_meta_lua_shdict_node_t, queue); + sd->expires = 1; + } + + ngx_meta_lua_shdict_expire(ctx, 0); + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return NGX_OK; +} + + +static ngx_int_t +ngx_meta_lua_shdict_peek(ngx_shm_zone_t *shm_zone, ngx_uint_t hash, + u_char *kdata, size_t klen, ngx_meta_lua_shdict_node_t **sdp) +{ + ngx_int_t rc; + ngx_rbtree_node_t *node, *sentinel; + ngx_meta_lua_shdict_ctx_t *ctx; + ngx_meta_lua_shdict_node_t *sd; + + ctx = shm_zone->data; + + node = ctx->sh->rbtree.root; + sentinel = ctx->sh->rbtree.sentinel; + + while (node != sentinel) { + + if (hash < node->key) { + node = node->left; + continue; + } + + if (hash > node->key) { + node = node->right; + continue; + } + + /* hash == node->key */ + + sd = (ngx_meta_lua_shdict_node_t *) &node->color; + + rc = ngx_memn2cmp(kdata, sd->data, klen, (size_t) sd->key_len); + + if (rc == 0) { + *sdp = sd; + + return NGX_OK; + } + + node = (rc < 0) ? node->left : node->right; + } + + *sdp = NULL; + + return NGX_DECLINED; +} + + +long +ngx_meta_lua_ffi_shdict_get_ttl(ngx_shm_zone_t *zone, u_char *key, + size_t key_len) +{ + uint32_t hash; + uint64_t now, expires; + ngx_int_t rc; + ngx_time_t *tp; + ngx_meta_lua_shdict_ctx_t *ctx; + ngx_meta_lua_shdict_node_t *sd; + + ctx = zone->data; + hash = ngx_crc32_short(key, key_len); + + ngx_shmtx_lock(&ctx->shpool->mutex); + + rc = ngx_meta_lua_shdict_peek(zone, hash, key, key_len, &sd); + + if (rc == NGX_DECLINED) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return NGX_DECLINED; + } + + /* rc == NGX_OK */ + + expires = sd->expires; + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + if (expires == 0) { + return 0; + } + + tp = ngx_timeofday(); + now = (uint64_t) tp->sec * 1000 + tp->msec; + + return expires - now; +} + + +int +ngx_meta_lua_ffi_shdict_set_expire(ngx_shm_zone_t *zone, u_char *key, + size_t key_len, long exptime) +{ + uint32_t hash; + ngx_int_t rc; + ngx_time_t *tp = NULL; + ngx_meta_lua_shdict_ctx_t *ctx; + ngx_meta_lua_shdict_node_t *sd; + + if (exptime > 0) { + tp = ngx_timeofday(); + } + + ctx = zone->data; + hash = ngx_crc32_short(key, key_len); + + ngx_shmtx_lock(&ctx->shpool->mutex); + + rc = ngx_meta_lua_shdict_peek(zone, hash, key, key_len, &sd); + + if (rc == NGX_DECLINED) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return NGX_DECLINED; + } + + /* rc == NGX_OK */ + + if (exptime > 0) { + sd->expires = (uint64_t) tp->sec * 1000 + tp->msec + + (uint64_t) exptime; + + } else { + sd->expires = 0; + } + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return NGX_OK; +} + + +size_t +ngx_meta_lua_ffi_shdict_capacity(ngx_shm_zone_t *zone) +{ + return zone->shm.size; +} + + +#if defined(nginx_version) && nginx_version >= 1011007 +size_t +ngx_meta_lua_ffi_shdict_free_space(ngx_shm_zone_t *zone) +{ + size_t bytes; + + ngx_meta_lua_shdict_ctx_t *ctx; + + ctx = zone->data; + + ngx_shmtx_lock(&ctx->shpool->mutex); + bytes = ctx->shpool->pfree * ngx_pagesize; + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return bytes; +} +#endif + + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/meta/ngx_meta_lua_shdict.h b/src/meta/ngx_meta_lua_shdict.h new file mode 100644 index 0000000..08ccaf9 --- /dev/null +++ b/src/meta/ngx_meta_lua_shdict.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_META_LUA_SHDICT_H_INCLUDED_ +#define _NGX_META_LUA_SHDICT_H_INCLUDED_ + + +#include "ngx_meta_lua_module.h" + + +typedef struct { + u_char color; + uint8_t value_type; + u_short key_len; + uint32_t value_len; + uint64_t expires; + ngx_queue_t queue; + uint32_t user_flags; + u_char data[1]; +} ngx_meta_lua_shdict_node_t; + + +typedef struct { + ngx_queue_t queue; + uint32_t value_len; + uint8_t value_type; + u_char data[1]; +} ngx_meta_lua_shdict_list_node_t; + + +typedef struct { + ngx_rbtree_t rbtree; + ngx_rbtree_node_t sentinel; + ngx_queue_t lru_queue; +} ngx_meta_lua_shdict_shctx_t; + + +typedef struct { +#if (NGX_DEBUG) + ngx_int_t isold; + ngx_int_t isinit; +#endif + ngx_str_t name; + ngx_meta_lua_shdict_shctx_t *sh; + ngx_slab_pool_t *shpool; + ngx_meta_lua_conf_t *mcf; + ngx_log_t *log; +} ngx_meta_lua_shdict_ctx_t; + + +typedef struct { + ngx_shm_zone_t zone; + ngx_cycle_t *cycle; + ngx_meta_lua_conf_t *mcf; + ngx_log_t *log; +} ngx_meta_lua_shm_zone_ctx_t; + + +char *ngx_meta_lua_shdict_directive(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + + +#endif /* _NGX_META_LUA_SHDICT_H_INCLUDED_ */ + + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/t/meta/lua_block.t b/t/meta/lua_block.t new file mode 100644 index 0000000..139583f --- /dev/null +++ b/t/meta/lua_block.t @@ -0,0 +1,104 @@ +use t::APISIX_NGINX 'no_plan'; + +add_block_preprocessor(sub { + my ($block) = @_; + + my $http_init_by_lua_block = $block->http_init_by_lua_block || ''; + my $stream_init_by_lua_block = $block->stream_init_by_lua_block || ''; + my $http_config = $block->http_config || ''; + my $stream_config = $block->stream_config || ''; + + $http_config .= <<_EOC_; + init_by_lua_block { $http_init_by_lua_block } +_EOC_ + + $stream_config .= <<_EOC_; + init_by_lua_block { $stream_init_by_lua_block } +_EOC_ + + $block->set_value("http_config", $http_config); + $block->set_value("stream_config", $stream_config); + $block->set_value("stream_server_config", <<_EOC_); + content_by_lua_block { ngx.say("ok") } +_EOC_ +}); + +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: lua{} block - sanity +--- main_config + lua {} + + + +=== TEST 2: lua{} block - duplicated block +--- main_config + lua {} + lua {} +--- must_die +--- error_log +"lua" directive is duplicate + + + +=== TEST 3: lua{} block - invalid context +--- http_config + lua {} +--- must_die +--- error_log +"lua" directive is not allowed here + + + +=== TEST 4: lua{} block - execute http{} init_by_lua +--- main_config + lua {} +--- http_init_by_lua_block +print("hello from http{} init_by_lua_block") +--- error_log +hello from http{} init_by_lua_block + + + +=== TEST 5: lua{} block - execute stream{} init_by_lua +--- main_config + lua {} +--- stream_init_by_lua_block +print("hello from stream{} init_by_lua_block") +--- error_log +hello from stream{} init_by_lua_block + + + +=== TEST 6: lua{} block - execute stream{} + http{} init_by_lua +--- main_config + lua {} +--- http_init_by_lua_block +print("hello from http{} init_by_lua_block") +--- stream_init_by_lua_block +print("hello from stream{} init_by_lua_block") +--- grep_error_log eval: qr/hello from (?:http|stream)\{\} init_by_lua_block/ +--- grep_error_log_out +hello from stream{} init_by_lua_block +hello from http{} init_by_lua_block + + + +=== TEST 7: lua{} block - execute stream{} + http{} delayed init_by_lua +--- main_config + lua { + lua_shared_dict shm 64k; + } +--- http_init_by_lua_block +print("hello from http{} init_by_lua_block") +--- stream_init_by_lua_block +print("hello from stream{} init_by_lua_block") +--- grep_error_log eval: qr/(?:hello from (?:http|stream)\{\} init_by_lua_block|lua run delayed init_handler: [0-9A-F]+)/ +--- grep_error_log_out eval +qr/lua run delayed init_handler: [0-9A-F]+ +hello from stream\{\} init_by_lua_block +lua run delayed init_handler: [0-9A-F]+ +hello from http\{\} init_by_lua_block/ diff --git a/t/meta/shdict.t b/t/meta/shdict.t new file mode 100644 index 0000000..4c8db71 --- /dev/null +++ b/t/meta/shdict.t @@ -0,0 +1,151 @@ +use t::APISIX_NGINX 'no_plan'; + +add_block_preprocessor(sub { + my ($block) = @_; + + if (!defined $block->config) { + $block->set_value("config", "location /t { return 200; }"); + } +}); + +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: http{} - sanity +--- http_config + lua_shared_dict dict 1m; +--- config + location = /t { + content_by_lua_block { + ngx.shared.dict:set("foo", 42) + ngx.say(ngx.shared.dict:get("foo")) + } + } +--- response_body +42 + + + +=== TEST 2: stream{} - sanity +--- stream_config + lua_shared_dict dict 1m; +--- stream_server_config + content_by_lua_block { + ngx.shared.dict:set("foo", 42) + ngx.say(ngx.shared.dict:get("foo")) + } +--- response_body +42 + + + +=== TEST 3: http{} and stream{} - shdicts are isolated +--- stream_config + lua_shared_dict stream_dict 1m; +--- stream_server_config + content_by_lua_block { + ngx.shared.stream_dict:set("foo", 42) + ngx.say("stream_dict: ", ngx.shared.stream_dict:get("foo")) + ngx.say("http_dict: ", tostring(ngx.shared.http_dict)) + } +--- http_config + lua_shared_dict http_dict 1m; + + log_by_lua_block { + ngx.log(ngx.NOTICE, "in http stream_dict: ", + tostring(ngx.shared.stream_dict)) + } +--- response_body +stream_dict: 42 +http_dict: nil +--- error_log +in http stream_dict: nil + + + +=== TEST 4: lua{} - shdict is shared by all subsystems +--- main_config + lua { + lua_shared_dict dict 1m; + } +--- stream_server_config + content_by_lua_block { + ngx.say("from stream{}: ", ngx.shared.dict:get("key")) + ngx.shared.dict:set("key", "set from stream{}") + } +--- http_config + access_by_lua_block { + ngx.shared.dict:set("key", "set from http{}") + } + + log_by_lua_block { + ngx.log(ngx.NOTICE, "from http{}: ", ngx.shared.dict:get("key")) + } +--- response_body +from stream{}: set from http{} +--- error_log +from http{}: set from stream{} + + + +=== TEST 5: lua{} and http{} - same shdict name is invalid +--- main_config + lua { + lua_shared_dict dict 1m; + } +--- http_config + lua_shared_dict dict 1m; +--- ignore_response_body +--- must_die +--- error_log +the shared memory zone "dict" is already declared + + + +=== TEST 6: lua{} and stream{} - same shdict name is invalid +--- main_config + lua { + lua_shared_dict dict 1m; + } +--- stream_config + lua_shared_dict dict 1m; +--- ignore_response_body +--- must_die +--- error_log +the shared memory zone "dict" is already declared + + + +=== TEST 7: sanity check on ngx.shared size for each Lua VM +--- main_config + lua { + lua_shared_dict d1 1m; + lua_shared_dict d2 1m; + } +--- stream_config + lua_shared_dict sd1 1m; + lua_shared_dict sd2 1m; +--- stream_server_config + content_by_lua_block { + local n = 0 + for k in pairs(ngx.shared) do + n = n + 1 + end + ngx.say("stream ngx.shared nkeys: ", n) + } +--- http_config + lua_shared_dict hd1 1m; + + log_by_lua_block { + local n = 0 + for k in pairs(ngx.shared) do + n = n + 1 + end + ngx.log(ngx.NOTICE, "http ngx.shared nkeys: ", n) + } +--- response_body +stream ngx.shared nkeys: 4 +--- error_log +http ngx.shared nkeys: 3