zoukankan      html  css  js  c++  java
  • ngx.shared.DICT.set

    ngx.shared.DICT.set

    原文: ngx.shared.DICT.set

    syntax: success, err, forcible = ngx.shared.DICT:set(key, value, exptime?, flags)
    
    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*
    

    无条件地将键值对设置到 ngx.shared.DICT 中。返回三个值:

    • success:布尔值,指示键值对是否成功设置到共享内存中
    • err:文本错误信息,可能为 "no memory"
    • forcible:布尔值,指示当共享内存中内存不足时是否是通过强制移除有效项来将当前的键值对设置到共享内存中

    要插入的 valua 参数可以为 Lua boolean,number,string,或者 nil。它们的值类型也将保存到共享内存中,以后可以通过 get 方法获取到同样的数据类型。

    可选地 exptime 参数指定了插入的键值对的过期时间(以秒为单位)。时间分辨率为 0.001 秒。如果 exptime 值为 0(默认),则该插入的项将永不过期。

    可选的 flags 参数指定了要保存的项相关联的用户标志值。以后可以通过 value 获取它。用户标志在内部作为一个无符号 32 位整数值保存。默认为 0。

    当为当前的 key-value 项分配内存失败时,set 方法将会尝试按照最近最少使用(即 LRU 算法)来移除共享内存中存在的项。注意,LRU 优于过期时间。如果已经移除数十个存在的项,并且剩余内存仍然不足(由于 lua_shared_dict 指定的总内存限制或者内存分片),则 err 错误描述信息为 "no memory",而 success 将为 false。

    如果该方法通过 LRU 算法强制将共享内存中其他未过期的项移除来成功保存当前的项,则 forcible 返回值将为 true。如果不是通过强制移除其他有效项来成功保存当前项,则 forcible 返回值为 false。

    该方法的第一个参数必须为字典本身,如下:

    local cats = ngx.shared.cats
    local succ, err, forcible = cats.set(cats, "Marry", "it is a nice cat!")
    

    或者:

    local cats = ngx.shared.cats
    local succ, err, forcible = cats:set("Marry", "it is a nice cat!")
    

    set 源码实现

    local function shdict_set(zone, key, value, exptime, flags)
        return shdict_store(zone, 0, key, value, exptime, flags)
    end
    

    shdict_store

    local tostring = tostring
    local type = type
    local error = error
    
    local function check_zone(zone)
        if not zone or type(zone) ~= "table" then
            error("bad "zone" argument", 2)
        end
    
        zone = zone[1]
        if type(zone) ~= "userdata" then
            error("bad "zone" argument", 2)
        end
    
        return zone
    end
    
    local function shdict_store(zone, op, key, value, exptime, flags)
        zone = check_zone(zone)
        
        if not exptime then
            exptime = 0
        elseif exptime < 0 then
            error('bad "exptime" argument', 2)
        end
        
        if not flags then
            flags = 0
        end
        
        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 str_val_buf
        local str_val_len = 0
        local num_val = 0
        local valtyp = type(value)
        
        -- print("value type: ", valtyp)
        -- print("exptime: ", exptime)
    
        if valtyp == "string" then
            valtyp = 4  -- LUA_TSTRING
            str_val_buf = value
            str_val_len = #value
            
        elseif valtyp == "number" then
            valtyp = 3  -- LUA_TNUMBER
            num_val = value
            
        elseif value == nil then
            valtyp = 0  - LUA_TNIL
            
        elseif valtyp == "boolean" then
            valtyp = 1  -- LUA_TBOOLEAN
            num_val = value and 1 or 0
            
        else
            return nil, "bad value type"
        end
        
        local rc = C.ngx_http_lua_ffi_shdict_store(zone, op, key, key_len, 
                                                   valtyp, str_val_buf, 
                                                   str_val_len, num_val,
                                                   exptime * 1000, flags, errmsg,
                                                   forcible)
                                                   
        -- print("rc == ", rc)
        
        if rc == 0 then -- NGX_OK
            return true, nil, forcible[0] == 1
        end
        
        -- NGX_DECLIEND or NGX_ERROR
        return false, ffi_str(errmsg[0]), forcible[0] == 1
    end
    

    ngx_http_lua_ffi_shdict_store

    #ifndef NGX_LUA_NO_FFI_API
    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;
        
        if (zone == NULL) {
            return NGX_ERROR;
        }
        
        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 returnd %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("dd 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;
    }
    
  • 相关阅读:
    欧拉函数 || [SDOI2008]仪仗队 || BZOJ 2190 || Luogu P2158
    欧拉函数 || Calculation 2 || HDU 3501
    并查集+时光倒流 || [JSOI2008]星球大战starwar || BZOJ 1015 || Luogu P1197
    并查集+启发式合并+LCA思想 || 冷战 || BZOJ 4668
    并查集+优先队列+启发式合并 || 罗马游戏 || BZOJ 1455 || Luogu p2713
    BZOJ-USACO被虐记
    #1
    BZOJ2441: [中山市选2011]小W的问题
    BZOJ2726: [SDOI2012]任务安排
    BZOJ1492: [NOI2007]货币兑换Cash
  • 原文地址:https://www.cnblogs.com/jimodetiantang/p/9445952.html
Copyright © 2011-2022 走看看