Skip to content

Commit e352a08

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 d44f8e0 commit e352a08

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
@@ -6139,17 +6139,24 @@ See also [ngx.shared.DICT](#ngxshareddict).
61396139

61406140
ngx.shared.DICT.incr
61416141
--------------------
6142-
**syntax:** *newval, err = ngx.shared.DICT:incr(key, value)*
6142+
**syntax:** *newval, err, forcible? = ngx.shared.DICT:incr(key, value, init?)*
61436143

61446144
**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**
61456145

61466146
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.
61476147

6148-
The key must already exist in the dictionary, otherwise it will return `nil` and `"not found"`.
6148+
When the key does not exist in the dictionary and if the `init` argument
6149+
6150+
1. is not specified, it will return `nil` and `"not found"`,
6151+
1. is specified, it will create a new `key` with the new value: `value + init`.
6152+
6153+
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.
6154+
6155+
The `forcible` return value will not be returned when `init` argument is not specified.
61496156

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

6152-
The `value` argument can be any valid Lua numbers, like negative numbers or floating-point numbers.
6159+
The `value` argument and `init` argument can be any valid Lua numbers, like negative numbers or floating-point numbers.
61536160

61546161
This feature was first introduced in the `v0.3.1rc22` release.
61556162

doc/HttpLuaModule.wiki

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5140,17 +5140,24 @@ This feature was first introduced in the <code>v0.3.1rc22</code> release.
51405140
See also [[#ngx.shared.DICT|ngx.shared.DICT]].
51415141
51425142
== ngx.shared.DICT.incr ==
5143-
'''syntax:''' ''newval, err = ngx.shared.DICT:incr(key, value)''
5143+
'''syntax:''' ''newval, err, forcible? = ngx.shared.DICT:incr(key, value, init?)''
51445144
51455145
'''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*''
51465146
51475147
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.
51485148
5149-
The key must already exist in the dictionary, otherwise it will return <code>nil</code> and <code>"not found"</code>.
5149+
When the key does not exist in the dictionary and if the <code>init</code> argument
5150+
5151+
# is not specified, it will return <code>nil</code> and <code>"not found"</code>,
5152+
# is specified, it will create a new <code>key</code> with the new value: <code>value + init</code>.
5153+
5154+
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.
5155+
5156+
The <code>forcible</code> return value will not be returned when <code>init</code> argument is not specified.
51505157
51515158
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>.
51525159
5153-
The <code>value</code> argument can be any valid Lua numbers, like negative numbers or floating-point numbers.
5160+
The <code>value</code> argument and <code>init</code> argument can be any valid Lua numbers, like negative numbers or floating-point numbers.
51545161
51555162
This feature was first introduced in the <code>v0.3.1rc22</code> release.
51565163

src/ngx_http_lua_shdict.c

Lines changed: 126 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,7 +1172,7 @@ ngx_http_lua_shdict_set_helper(lua_State *L, int flags)
11721172
static int
11731173
ngx_http_lua_shdict_incr(lua_State *L)
11741174
{
1175-
int n;
1175+
int i, n;
11761176
ngx_str_t key;
11771177
uint32_t hash;
11781178
ngx_int_t rc;
@@ -1182,11 +1182,15 @@ ngx_http_lua_shdict_incr(lua_State *L)
11821182
u_char *p;
11831183
ngx_shm_zone_t *zone;
11841184
double value;
1185+
ngx_rbtree_node_t *node;
1186+
/* indicates whether to foricibly override other
1187+
* valid entries */
1188+
int forcible = 0;
11851189

11861190
n = lua_gettop(L);
11871191

1188-
if (n != 3) {
1189-
return luaL_error(L, "expecting 3 arguments, but only seen %d", n);
1192+
if (n != 3 && n != 4) {
1193+
return luaL_error(L, "expecting 3 or 4 arguments, but only seen %d", n);
11901194
}
11911195

11921196
if (lua_type(L, 1) != LUA_TTABLE) {
@@ -1238,11 +1242,38 @@ ngx_http_lua_shdict_incr(lua_State *L)
12381242
dd("shdict lookup returned %d", (int) rc);
12391243

12401244
if (rc == NGX_DECLINED || rc == NGX_DONE) {
1241-
ngx_shmtx_unlock(&ctx->shpool->mutex);
12421245

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

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

12771396

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)