Skip to content

Commit f16d6aa

Browse files
committed
feature: ngx.shared.dict add an option arg init, it will add a new
value with the initial value when not found.
1 parent fe50cff commit f16d6aa

File tree

5 files changed

+353
-16
lines changed

5 files changed

+353
-16
lines changed

README.markdown

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5844,17 +5844,24 @@ See also [ngx.shared.DICT](#ngxshareddict).
58445844

58455845
ngx.shared.DICT.incr
58465846
--------------------
5847-
**syntax:** *newval, err = ngx.shared.DICT:incr(key, value)*
5847+
**syntax:** *newval, err, forcible? = ngx.shared.DICT:incr(key, value, init?)*
58485848

58495849
**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.**
58505850

58515851
Increments the (numerical) value for `key` in the shm-based dictionary [ngx.shared.DICT](#ngxshareddict) by the step value `value`. Returns the new resulting number if the operation is successfully completed or `nil` and an error message otherwise.
58525852

5853-
The key must already exist in the dictionary, otherwise it will return `nil` and `"not found"`.
5853+
When the key is not exist in the dictionary and if `init` argument,
5854+
5855+
1. is not specified, it will return `nil` and `"not found"`,
5856+
1. is specified, it will create a new `key` with the new value: `value + init`.
5857+
5858+
Like the [add](#ngxshareddictadd) method, it also overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone.
5859+
5860+
The `forcible` return value will not be returned when `init` argument is not specified.
58545861

58555862
If the original value is not a valid Lua number in the dictionary, it will return `nil` and `"not a number"`.
58565863

5857-
The `value` argument can be any valid Lua numbers, like negative numbers or floating-point numbers.
5864+
The `value` argument and `init` argument can be any valid Lua numbers, like negative numbers or floating-point numbers.
58585865

58595866
This feature was first introduced in the `v0.3.1rc22` release.
58605867

doc/HttpLuaModule.wiki

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4886,17 +4886,24 @@ This feature was first introduced in the <code>v0.3.1rc22</code> release.
48864886
See also [[#ngx.shared.DICT|ngx.shared.DICT]].
48874887
48884888
== ngx.shared.DICT.incr ==
4889-
'''syntax:''' ''newval, err = ngx.shared.DICT:incr(key, value)''
4889+
'''syntax:''' ''newval, err, forcible? = ngx.shared.DICT:incr(key, value, init?)''
48904890
48914891
'''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.*''
48924892
48934893
Increments the (numerical) value for <code>key</code> in the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]] by the step value <code>value</code>. Returns the new resulting number if the operation is successfully completed or <code>nil</code> and an error message otherwise.
48944894
4895-
The key must already exist in the dictionary, otherwise it will return <code>nil</code> and <code>"not found"</code>.
4895+
When the key is not exist in the dictionary and if <code>init</code> argument,
4896+
4897+
# is not specified, it will return <code>nil</code> and <code>"not found"</code>,
4898+
# is specified, it will create a new <code>key</code> with the new value: <code>value + init</code>.
4899+
4900+
Like the [[#ngx.shared.DICT.add|add]] method, it also overrides the (least recently used) unexpired items in the store when running out of storage in the shared memory zone.
4901+
4902+
The <code>forcible</code> return value will not be returned when <code>init</code> argument is not specified.
48964903
48974904
If the original value is not a valid Lua number in the dictionary, it will return <code>nil</code> and <code>"not a number"</code>.
48984905
4899-
The <code>value</code> argument can be any valid Lua numbers, like negative numbers or floating-point numbers.
4906+
The <code>value</code> argument and <code>init</code> argument can be any valid Lua numbers, like negative numbers or floating-point numbers.
49004907
49014908
This feature was first introduced in the <code>v0.3.1rc22</code> release.
49024909

src/ngx_http_lua_shdict.c

Lines changed: 126 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,7 +1163,7 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags)
11631163
static int
11641164
ngx_http_lua_shdict_incr(lua_State *L)
11651165
{
1166-
int n;
1166+
int i, n;
11671167
ngx_str_t key;
11681168
uint32_t hash;
11691169
ngx_int_t rc;
@@ -1173,11 +1173,15 @@ ngx_http_lua_shdict_incr(lua_State *L)
11731173
u_char *p;
11741174
ngx_shm_zone_t *zone;
11751175
double value;
1176+
ngx_rbtree_node_t *node;
1177+
/* indicates whether to foricibly override other
1178+
* valid entries */
1179+
int forcible = 0;
11761180

11771181
n = lua_gettop(L);
11781182

1179-
if (n != 3) {
1180-
return luaL_error(L, "expecting 3 arguments, but only seen %d", n);
1183+
if (n != 3 && n != 4) {
1184+
return luaL_error(L, "expecting 3 or 4 arguments, but only seen %d", n);
11811185
}
11821186

11831187
if (lua_type(L, 1) != LUA_TTABLE) {
@@ -1229,11 +1233,38 @@ ngx_http_lua_shdict_incr(lua_State *L)
12291233
dd("shdict lookup returned %d", (int) rc);
12301234

12311235
if (rc == NGX_DECLINED || rc == NGX_DONE) {
1232-
ngx_shmtx_unlock(&ctx->shpool->mutex);
12331236

1234-
lua_pushnil(L);
1235-
lua_pushliteral(L, "not found");
1236-
return 2;
1237+
if (n == 3) {
1238+
ngx_shmtx_unlock(&ctx->shpool->mutex);
1239+
1240+
lua_pushnil(L);
1241+
lua_pushliteral(L, "not found");
1242+
return 2;
1243+
}
1244+
1245+
/* add value */
1246+
num = value + luaL_checknumber(L, 4);
1247+
1248+
if (rc == NGX_DONE) {
1249+
1250+
if ((size_t) sd->value_len == sizeof(double)) {
1251+
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
1252+
"lua shared dict incr: found old entry and value "
1253+
"size matched, reusing it");
1254+
1255+
ngx_queue_remove(&sd->queue);
1256+
ngx_queue_insert_head(&ctx->sh->queue, &sd->queue);
1257+
1258+
dd("go to setvalue");
1259+
goto setvalue;
1260+
}
1261+
1262+
dd("go to remove");
1263+
goto remove;
1264+
}
1265+
1266+
dd("go to insert");
1267+
goto insert;
12371268
}
12381269

12391270
/* rc == NGX_OK */
@@ -1263,6 +1294,94 @@ ngx_http_lua_shdict_incr(lua_State *L)
12631294
lua_pushnumber(L, num);
12641295
lua_pushnil(L);
12651296
return 2;
1297+
1298+
remove:
1299+
1300+
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
1301+
"lua shared dict incr: found old entry but value size "
1302+
"NOT matched, removing it first");
1303+
1304+
ngx_queue_remove(&sd->queue);
1305+
1306+
node = (ngx_rbtree_node_t *)
1307+
((u_char *) sd - offsetof(ngx_rbtree_node_t, color));
1308+
1309+
ngx_rbtree_delete(&ctx->sh->rbtree, node);
1310+
1311+
ngx_slab_free_locked(ctx->shpool, node);
1312+
1313+
insert:
1314+
1315+
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
1316+
"lua shared dict incr: creating a new entry");
1317+
1318+
n = offsetof(ngx_rbtree_node_t, color)
1319+
+ offsetof(ngx_http_lua_shdict_node_t, data)
1320+
+ key.len
1321+
+ sizeof(double);
1322+
1323+
node = ngx_slab_alloc_locked(ctx->shpool, n);
1324+
1325+
if (node == NULL) {
1326+
1327+
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
1328+
"lua shared dict incr: overriding non-expired items "
1329+
"due to memory shortage for entry \"%V\"", &key);
1330+
1331+
for (i = 0; i < 30; i++) {
1332+
if (ngx_http_lua_shdict_expire(ctx, 0) == 0) {
1333+
break;
1334+
}
1335+
1336+
forcible = 1;
1337+
1338+
node = ngx_slab_alloc_locked(ctx->shpool, n);
1339+
if (node != NULL) {
1340+
goto allocated;
1341+
}
1342+
}
1343+
1344+
ngx_shmtx_unlock(&ctx->shpool->mutex);
1345+
1346+
lua_pushboolean(L, 0);
1347+
lua_pushliteral(L, "no memory");
1348+
lua_pushboolean(L, forcible);
1349+
return 3;
1350+
}
1351+
1352+
allocated:
1353+
1354+
sd = (ngx_http_lua_shdict_node_t *) &node->color;
1355+
1356+
node->key = hash;
1357+
1358+
sd->key_len = (u_short) key.len;
1359+
1360+
sd->value_len = (uint32_t) sizeof(double);
1361+
1362+
ngx_rbtree_insert(&ctx->sh->rbtree, node);
1363+
1364+
ngx_queue_insert_head(&ctx->sh->queue, &sd->queue);
1365+
1366+
setvalue:
1367+
1368+
sd->user_flags = 0;
1369+
1370+
sd->expires = 0;
1371+
1372+
dd("setting value type to %d", LUA_TNUMBER);
1373+
1374+
sd->value_type = (uint8_t) LUA_TNUMBER;
1375+
1376+
p = ngx_copy(sd->data, key.data, key.len);
1377+
ngx_memcpy(p, (double *) &num, sizeof(double));
1378+
1379+
ngx_shmtx_unlock(&ctx->shpool->mutex);
1380+
1381+
lua_pushnumber(L, num);
1382+
lua_pushnil(L);
1383+
lua_pushboolean(L, forcible);
1384+
return 3;
12661385
}
12671386

12681387

t/043-shdict.t

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -816,7 +816,7 @@ foo = hello
816816

817817

818818

819-
=== TEST 31: incr key (key exists)
819+
=== TEST 31: replace key (key exists)
820820
--- http_config
821821
lua_shared_dict dogs 1m;
822822
--- config
@@ -950,7 +950,7 @@ foo = 10534
950950

951951

952952

953-
=== TEST 36: replace key (key not exists)
953+
=== TEST 36: incr key (key not exists)
954954
--- http_config
955955
lua_shared_dict dogs 1m;
956956
--- config
@@ -973,7 +973,7 @@ foo = nil
973973

974974

975975

976-
=== TEST 37: replace key (key expired)
976+
=== TEST 37: incr key (key expired)
977977
--- http_config
978978
lua_shared_dict dogs 1m;
979979
--- config

0 commit comments

Comments
 (0)