From cf03ee6911063fd2f59b7021e25634370c124c3b Mon Sep 17 00:00:00 2001 From: tokers Date: Sat, 23 Feb 2019 21:44:02 +0800 Subject: [PATCH] feature: implemented the shdict:lindex method --- .travis.yml | 2 +- lib/resty/core/shdict.lua | 78 ++++++++++++++++ t/shdict.t | 189 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 268 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7b62e9729..3df4e2f41 100644 --- a/.travis.yml +++ b/.travis.yml @@ -60,7 +60,7 @@ install: - git clone https://github.com/openresty/openresty.git ../openresty - git clone https://github.com/openresty/openresty-devel-utils.git - git clone https://github.com/simpl/ngx_devel_kit.git ../ndk-nginx-module - - git clone https://github.com/openresty/lua-nginx-module.git ../lua-nginx-module + - git clone -b feature/shdict-lindex https://github.com/tokers/lua-nginx-module.git ../lua-nginx-module - git clone https://github.com/openresty/no-pool-nginx.git ../no-pool-nginx - git clone https://github.com/openresty/echo-nginx-module.git ../echo-nginx-module - git clone https://github.com/openresty/lua-resty-lrucache.git diff --git a/lib/resty/core/shdict.lua b/lib/resty/core/shdict.lua index 6876d6eb3..7b8fe759c 100644 --- a/lib/resty/core/shdict.lua +++ b/lib/resty/core/shdict.lua @@ -30,6 +30,7 @@ local ngx_lua_ffi_shdict_set_expire local ngx_lua_ffi_shdict_capacity local ngx_lua_ffi_shdict_free_space local ngx_lua_ffi_shdict_udata_to_zone +local ngx_lua_ffi_shdict_lindex if subsystem == 'http' then @@ -60,6 +61,10 @@ int ngx_http_lua_ffi_shdict_set_expire(void *zone, size_t ngx_http_lua_ffi_shdict_capacity(void *zone); void *ngx_http_lua_ffi_shdict_udata_to_zone(void *zone_udata); + +int ngx_http_lua_ffi_shdict_lindex(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 index, char **errmsg); ]] ngx_lua_ffi_shdict_get = C.ngx_http_lua_ffi_shdict_get @@ -71,6 +76,7 @@ void *ngx_http_lua_ffi_shdict_udata_to_zone(void *zone_udata); 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 + ngx_lua_ffi_shdict_lindex = C.ngx_http_lua_ffi_shdict_lindex if not pcall(function () return C.ngx_http_lua_ffi_shdict_free_space @@ -588,6 +594,77 @@ local function shdict_free_space(zone) end +local function shdict_lindex(zone, key, index) + zone = check_zone(zone) + + if key == nil then + return nil, "nil key" + end + + if type(key) ~= "string" then + key = tostring(key) + end + + local key_len = #key + if key_len == 0 then + return nil, "empty key" + end + + if key_len > 65535 then + return nil, "key too long" + end + + if type(index) ~= "number" then + return nil, "bad index" + end + + local size = get_string_buf_size() + local buf = get_string_buf(size) + str_value_buf[0] = buf + local value_len = get_size_ptr() + value_len[0] = size + + local rc = ngx_lua_ffi_shdict_lindex(zone, key, key_len, value_type, + str_value_buf, value_len, + num_value, index, errmsg) + + if rc ~= 0 then + if errmsg[0] then + return nil, ffi_str(errmsg[0]) + end + + error("failed to index the key") + end + + local typ = value_type[0] + + if typ == 0 then -- LUA_TNIL + return nil + end + + local val + + if typ == 4 then -- LUA_TSTRING + if str_value_buf[0] ~= buf then + buf = str_value_buf[0] + val = ffi_str(buf, value_len[0]) + C.free(buf) + + else + val = ffi_str(buf, value_len[0]) + end + + elseif typ == 3 then -- LUA_TNUMBER + val = tonumber(num_value[0]) + + else + error("unknown value type: " .. typ) + end + + return val +end + + if ngx_shared then local _, dict = next(ngx_shared, nil) if dict then @@ -609,6 +686,7 @@ if ngx_shared then mt.expire = shdict_expire mt.capacity = shdict_capacity mt.free_space = shdict_free_space + mt.lindex = shdict_lindex end end end diff --git a/t/shdict.t b/t/shdict.t index a9cdea024..8fb5ce850 100644 --- a/t/shdict.t +++ b/t/shdict.t @@ -1620,3 +1620,192 @@ ok [error] [alert] [crit] + + + +=== TEST 51: lindex index argument is not a number +--- config + location = /t { + content_by_lua_block { + local dogs = ngx.shared.dogs + dogs:flush_all() + local ok, err = dogs:lindex("corgi", nil) + ngx.say("ok: ", ok, " err: ", err) + } + } +--- request +GET /t +--- response_body +ok: nil err: bad index +--- no_error_log +[error] +[alert] +[crit] + + + +=== TEST 52: lindex value is not a list +--- config + location = /t { + content_by_lua_block { + local dogs = ngx.shared.dogs + dogs:flush_all() + local ok, err = dogs:set("corgi", "cute") + if not ok then + ngx.say("dogs:set() error: ", err) + return + end + + local ok, err = dogs:lindex("corgi", -1) + ngx.say("ok: ", ok, " err: ", err) + } + } +--- request +GET /t +--- response_body +ok: nil err: value not a list +--- no_error_log +[error] +[alert] +[crit] + + + +=== TEST 53: lindex value is nil +--- config + location = /t { + content_by_lua_block { + local dogs = ngx.shared.dogs + dogs:flush_all() + local ok, err = dogs:lindex("corgi", -1) + ngx.say("ok: ", ok, " err: ", err) + } + } +--- request +GET /t +--- response_body +ok: nil err: nil +--- no_error_log +[error] +[alert] +[crit] + + + +=== TEST 54: lindex negative index +--- config + location = /t { + content_by_lua_block { + local dogs = ngx.shared.dogs + dogs:flush_all() + local value = { 2147, 483647, "meat", "bone" } + for i = 1, #value do + local ok, err = dogs:lpush("corgi", value[i]) + if not ok then + ngx.say("dogs:lpush() error: ", err) + return + end + end + + -- bone meat 483647 2147 + + for i = -1, -(#value), -1 do + local val, err = dogs:lindex("corgi", i) + if err ~= nil then + ngx.say("index: ", i, " error: ", err) + return + end + + ngx.say("index: ", i, " value: ", val) + end + } + } +--- request +GET /t +--- response_body +index: -1 value: 2147 +index: -2 value: 483647 +index: -3 value: meat +index: -4 value: bone +--- no_error_log +[error] +[alert] +[crit] + + + +=== TEST 55: lindex non-negative index +--- config + location = /t { + content_by_lua_block { + local dogs = ngx.shared.dogs + dogs:flush_all() + local value = { 2147, 483647, "meat", "bone" } + for i = 1, #value do + local ok, err = dogs:lpush("corgi", value[i]) + if not ok then + ngx.say("dogs:lpush() error: ", err) + return + end + end + + -- bone meat 483647 2147 + + for i = 0, #value - 1 do + local val, err = dogs:lindex("corgi", i) + if err ~= nil then + ngx.say("index: ", i, " error: ", err) + return + end + + ngx.say("index: ", i, " value: ", val) + end + } + } +--- request +GET /t +--- response_body +index: 0 value: bone +index: 1 value: meat +index: 2 value: 483647 +index: 3 value: 2147 +--- no_error_log +[error] +[alert] +[crit] + + + +=== TEST 56: lindex index out of bound +--- config + location = /t { + content_by_lua_block { + local dogs = ngx.shared.dogs + dogs:flush_all() + local value = { 2147, 483647, "meat", "bone" } + for i = 1, #value do + local ok, err = dogs:lpush("corgi", value[i]) + if not ok then + ngx.say("dogs:lpush() error: ", err) + return + end + end + + -- bone meat 483647 2147 + + local val, err = dogs:lindex("corgi", -5) + ngx.say("val: ", val, " err: ", err) + + local val, err = dogs:lindex("corgi", 4) + ngx.say("val: ", val, " err: ", err) + } + } +--- request +GET /t +--- response_body +val: nil err: nil +val: nil err: nil +--- no_error_log +[error] +[alert] +[crit]