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;
}

ngx.shared.DICT.set的更多相关文章

  1. ngx.shared.DICT.get 详解

    ngx.shared.DICT.get 原文: ngx.shared.DICT.get syntax: value, flags = ngx.shared.DICT:get(key) context: ...

  2. ngx.shared.DICT.expire 详解

    ngx.shared.DICT.expire 原文链接: ngx.shared.DICT.expire syntax: success, err = ngx.shared.DICT:expire(ke ...

  3. ngx.shared.DICT.incr 详解

    ngx.shared.DICT.incr 原文: ngx.shared.DICT.incr syntax: newval, err, forcible? = ngx.shared.DICT:incr( ...

  4. OpenResty之ngx.shared.DICT

    参考链接: resty.core.shdict ngx_shared.DICT 源码正文: dict.lua 部分源码如下: local ffi = require 'ffi' local base ...

  5. Nginx-Lua模块的执行顺序

    一.nginx执行步骤 nginx在处理每一个用户请求时,都是按照若干个不同的阶段依次处理的,与配置文件上的顺序没有关系,详细内容可以阅读<深入理解nginx:模块开发与架构解析>这本书, ...

  6. Nginx-ngx_lua模块原理和内置函数

    ngx_lua模块的原理: 1.每个worker(工作进程)创建一个Lua VM,worker内所有协程共享VM:2.将Nginx I/O原语封装后注入 Lua VM,允许Lua代码直接访问:3.每个 ...

  7. Openresty 与 Tengine

    Openresty 与 Tengine Openresty和Tengine基于 Nginx 的两个衍生版本,某种意义上他们都和淘宝有关系,前者是前淘宝工程师agentzh主导开发的,后者是淘宝的一个开 ...

  8. 分布式环境下限流方案的实现redis RateLimiter Guava,Token Bucket, Leaky Bucket

    业务背景介绍 对于web应用的限流,光看标题,似乎过于抽象,难以理解,那我们还是以具体的某一个应用场景来引入这个话题吧. 在日常生活中,我们肯定收到过不少不少这样的短信,“双11约吗?,千款….”,“ ...

  9. 【技术干货】听阿里云CDN安防技术专家金九讲tengine+lua开发

    一.介绍 二.安装 三.运行 四.开发 1.介绍 Tengine:轻量级.高性能.高并发.配置化.模块化.可扩展.可移植的Web和反向代理 服务器,Tengine是nginx超集,但做了很多优化,包含 ...

随机推荐

  1. Python 自己实现可迭代对象

    import time from collections import Iterable from collections import Iterator class Classmate(object ...

  2. zabbix推送内存监控单应用shell

    利用top方式获取指定第三方的内存使用率 #!/bin/bash process=$1 if [ ! -z $process ];then cd /zabbix/zabbix-agent/script ...

  3. 阿里云服务器(Ubuntu16.04 64位)的使用

    购买阿里云服务器 1.打开阿里云官方网站,账号登录,选择产品中的云服务器 ECS 2.根据自身需求,选择合适的阿里云服务器系统,(1)点击一键购买,(2)选择地域,(3)根据自身需求,选择系统,这里选 ...

  4. LNMP环境搭建BBS论坛及伪静态

    我们在mysql备份 LNMP环境中的数据库迁移为独立的服务器的基础上搭建BBS论坛:  [root@bqh-117 ~]# mysql -uroot -p123456 Welcome to the ...

  5. Computer Vision_33_SIFT:ORB_An efficient alternative to SIFT or SURF——2012

    此部分是计算机视觉部分,主要侧重在底层特征提取,视频分析,跟踪,目标检测和识别方面等方面.对于自己不太熟悉的领域比如摄像机标定和立体视觉,仅仅列出上google上引用次数比较多的文献.有一些刚刚出版的 ...

  6. linux网络编程之简单的线程池实现

    转眼间离15年的春节越来越近了,还有两周的工作时间貌似心已经不在异乡了,期待与家人团聚的日子,当然最后两周也得坚持站好最后一班岗,另外期待的日子往往是心里不能平静的,越是想着过年,反而日子过得越慢,于 ...

  7. python数据类型:dict(字典)

    一.字典的简单介绍 字典(dict)是python中唯一的一个映射类型.他是以{}括起来的键值对组成. 语法: {key1:value1,key2:value2......} 注意:key必须是不可变 ...

  8. Vue、webpack中默认的config.js、index.js 配置详情

    在vue.js 框架搭建好后,其vue-cli 自动构建的目录里面相关环境变量及其基本变量配置,如下代码所示: module.exports = { build: { index: path.reso ...

  9. 混合应用 微信登录授权 微信登录认证失败 ios PGWXAPI错误-1 code:-100 / 安卓 message:invalid appsecret innerCode:40125

    最近项目需要做微信登录,于是利用HTML5+ API Reference的OAuth模块管理客户端的用户登录授权验证功能,允许应用访问第三方平台的资源.(链接:https://www.dcloud.i ...

  10. Robot Framework--Scalar变量

    一.变量赋值 1)Set赋值 通常使用Set Variable关键字对变量进行赋值,其他Set相关的带Variable的关键字也可以进行赋值 赋值的时候,变量后面写不写『=』都可以,如下: 如果${v ...