原文: ngx.shared.DICT.getnode
syntax: value, flags = ngx.shared.DICT:get(key) context: init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua* requires: resty.core.shdict or resty.core
檢索 ngx.shared.DICT 共享內存中 key 對應的值。若是 key 不存在或者超時,則返回 nil。nginx
若是發生錯誤,返回 nil 和錯誤描述字符串。git
在插入字典後,返回的值具備原始數據類型,如 Lua boolean,number,或者 string。github
該方法的第一個參數是字典自身,以下:session
local cats = ngx.shared.cats local value, flags = cats.get(cats, "Mary")
或者用以下方法調用:函數
local cats = ngx.shared.cats local value, flags = cats:get("Marry")
若是用戶標誌 flag 爲 0(默認),則不返回任何標誌值。fetch
local value_type = ffi_new("int[1]") local user_flags = ffi_new("int[1]") local num_value = ffi_new("double[1]") local is_stale = ffi_new("int[1]") local str_value_buf = ffi_new("unsigned char *[1]") local errmsg = base.get_errmsg_ptr() local function shdict_get(zone, key) 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 local size = get_string_buf_size() -- 4096 local buf = get_string_buf(size) str_value_buf[0] = buf -- str_value_buf = ffi_new("unsigned char *[1]") local value_len = get_size_ptr() value_len[0] = size local rc = C.ngx_http_lua_ffi_shdict_get(zone, key, key_len, value_type, str_value_buf, value_len, num_value, user_flags, 0, is_stale, errmsg) if rc ~= 0 then if errmsg[0] then return nil, ffi_str(errmsg[0]) end error("failed to get the key") end local typ = value_type[0] if typ == 0 then -- LUA_TNIL return nil end local flags = tonumber(user_flags[0]) local val if typ == 4 then -- LUA_TSTRING if str_value_buf[0] ~= buf then -- ngx.say("len: ", tonumber(value_len[0])) 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]) elseif typ == 1 then -- LUA_TBOOLEAN val = (tonumber(buf[0]) ~= 0) else error("unknown value type: " .. typ) end if flags ~= 0 then return val, flags end return val end
這兩個函數位於 resty.core.base.lua 文件中:ui
local ffi = require = 'ffi' local ffi_new = ffi.new local str_buf_size = 4096 local str_buf local size_ptr local FREE_LIST_REF = 0 local c_buf_type = ffi.typeof("char[?]") local errmsg function _M.get_errmsg_ptr() if not errmsg then errmsg = ffi_new("char *[1]") end return errmsg end function _M.get_string_buf_size() return str_buf_size end function _M.get_string_buf(size, must_alloc) -- ngx.log(ngx.ERR, "str buf size: ", str_buf_size) if size > str_buf_size or must_alloc then return ffi_new(c_buf_type, size) end if not str_buf then str_buf = ffi_new(c_buf_type, str_buf_size) end return str_buf end function _M.get_size_ptr() if not size_ptr then size_ptr = ffi_new("size_t[1]") end return size_ptr end
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; if (zone == NULL) { return NGX_ERROR; } *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); end ngx_shmtx_lock(&ctx->shpool->mutex); #if 1 if (!get_stale) { /* 刪除共享內存中過時的 1~2 個項 */ ngx_http_lua_shdict_expire(ctx, 1); } end 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: ", 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 SHDCIT_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 */ /* 爲 true 表示已通過期了 */ *is_stale = (rc == NGX_DONE); return NGX_OK; } return NGX_OK; }