• ngx.shared.DICT.get 详解


    ngx.shared.DICT.get

    原文: ngx.shared.DICT.get

    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。

    如果发生错误,返回 nil 和错误描述字符串。

    在插入字典后,返回的值具有原始数据类型,如 Lua boolean,number,或者 string。

    该方法的第一个参数是字典自身,如下:

    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(默认),则不返回任何标志值。

    get 源码实现如下

    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
    

    get_string_buf_size 和 get_string_buf

    这两个函数位于 resty.core.base.lua 文件中:

    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
    

    ngx_http_lua_ffi_shdict_get

    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;
    }
    
  • 相关阅读:
    volcanol的工控博客
    volcanol的工控博客
    volcanol的工控博客
    volcanol的工控博客
    volcanol的工控博客
    volcanol的工控博客
    volcanol的工控博客
    volcanol的工控博客
    volcanol的工控博客
    volcanol的工控博客
  • 原文地址:https://www.cnblogs.com/jimodetiantang/p/9439907.html
Copyright © 2020-2023  润新知