Skip to content

Commit 4c56169

Browse files
committed
feature: implemented the lindex method for list type share dict value
The `lindex` method returns the element at index `index` in the shared dict list. Just like the `LINDEX` of Redis.
1 parent ee47e55 commit 4c56169

File tree

4 files changed

+335
-1
lines changed

4 files changed

+335
-1
lines changed

Diff for: README.markdown

+19
Original file line numberDiff line numberDiff line change
@@ -3185,6 +3185,7 @@ Nginx API for Lua
31853185
* [ngx.shared.DICT.lpop](#ngxshareddictlpop)
31863186
* [ngx.shared.DICT.rpop](#ngxshareddictrpop)
31873187
* [ngx.shared.DICT.llen](#ngxshareddictllen)
3188+
* [ngx.shared.DICT.lindex](#ngxshareddictlindex)
31883189
* [ngx.shared.DICT.ttl](#ngxshareddictttl)
31893190
* [ngx.shared.DICT.expire](#ngxshareddictexpire)
31903191
* [ngx.shared.DICT.flush_all](#ngxshareddictflush_all)
@@ -6235,6 +6236,7 @@ The resulting object `dict` has the following methods:
62356236
* [lpop](#ngxshareddictlpop)
62366237
* [rpop](#ngxshareddictrpop)
62376238
* [llen](#ngxshareddictllen)
6239+
* [lindex](#ngxshareddictlindex)
62386240
* [ttl](#ngxshareddictttl)
62396241
* [expire](#ngxshareddictexpire)
62406242
* [flush_all](#ngxshareddictflush_all)
@@ -6607,6 +6609,23 @@ See also [ngx.shared.DICT](#ngxshareddict).
66076609

66086610
[Back to TOC](#nginx-api-for-lua)
66096611

6612+
ngx.shared.DICT.lindex
6613+
----------------------
6614+
6615+
**syntax:** *val, err = ngx.shared.DICT:lindex(key, index)*
6616+
6617+
**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**
6618+
6619+
Returns the element which at the index `index` of the list named `key` in the shm-base dictionary [ngx.shared.DICT](#ngxshareddict).
6620+
6621+
The index is zero-based, so `0` means the first element, `1` for the second element and so forth. Also, negative index can be used to designate elements starting at the tail of the list, here `-1` means the last element and `-2` means the penultimate and so on.
6622+
6623+
If `key` does not exist, it will return `nil`. When the `key` already takes a value that is not a list, it will return `nil` and `"value not a list"`. When `index` is out of the list length bound, the method will return `nil`.
6624+
6625+
See also [ngx.shared.DICT](#ngxshareddict).
6626+
6627+
[Back to TOC](#nginx-api-for-lua)
6628+
66106629
ngx.shared.DICT.ttl
66116630
-------------------
66126631
**syntax:** *ttl, err = ngx.shared.DICT:ttl(key)*

Diff for: doc/HttpLuaModule.wiki

+15
Original file line numberDiff line numberDiff line change
@@ -5232,6 +5232,7 @@ The resulting object <code>dict</code> has the following methods:
52325232
* [[#ngx.shared.DICT.lpop|lpop]]
52335233
* [[#ngx.shared.DICT.rpop|rpop]]
52345234
* [[#ngx.shared.DICT.llen|llen]]
5235+
* [[#ngx.shared.DICT.lindex|lindex]]
52355236
* [[#ngx.shared.DICT.ttl|ttl]]
52365237
* [[#ngx.shared.DICT.expire|expire]]
52375238
* [[#ngx.shared.DICT.flush_all|flush_all]]
@@ -5553,6 +5554,20 @@ This feature was first introduced in the <code>v0.10.6</code> release.
55535554
55545555
See also [[#ngx.shared.DICT|ngx.shared.DICT]].
55555556
5557+
== ngx.shared.DICT.lindex ==
5558+
5559+
'''syntax:''' ''val, err = ngx.shared.DICT:lindex(key, index)''
5560+
5561+
'''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*''
5562+
5563+
Returns the element which at the index <code>index</code> of the list named <code>key</code> in the shm-base dictionary [[#ngx.shared.DICT|ngx.shared.DICT]].
5564+
5565+
The index is zero-based, so <code>0</code> means the first element, <code>1</code> for the second element and so forth. Also, negative index can be used to designate elements starting at the tail of the list, here <code>-1</code> means the last element and <code>-2</code> means the penultimate and so on.
5566+
5567+
If <code>key</code> does not exist, it will return <code>nil</code>. When the <code>key</code> already takes a value that is not a list, it will return <code>nil</code> and <code>"value not a list"</code>. When <code>index</code> is out of the list length bound, the method will return `nil`.
5568+
5569+
See also [[#ngx.shared.DICT|ngx.shared.DICT]].
5570+
55565571
== ngx.shared.DICT.ttl ==
55575572
'''syntax:''' ''ttl, err = ngx.shared.DICT:ttl(key)''
55585573

Diff for: src/ngx_http_lua_shdict.c

+164-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ static int ngx_http_lua_shdict_lpop(lua_State *L);
4141
static int ngx_http_lua_shdict_rpop(lua_State *L);
4242
static int ngx_http_lua_shdict_pop_helper(lua_State *L, int flags);
4343
static int ngx_http_lua_shdict_llen(lua_State *L);
44+
static int ngx_http_lua_shdict_lindex(lua_State *L);
4445

4546

4647
static ngx_inline ngx_shm_zone_t *ngx_http_lua_shdict_get_zone(lua_State *L,
@@ -331,7 +332,7 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L)
331332
lua_createtable(L, 0, lmcf->shdict_zones->nelts /* nrec */);
332333
/* ngx.shared */
333334

334-
lua_createtable(L, 0 /* narr */, 18 /* nrec */); /* shared mt */
335+
lua_createtable(L, 0 /* narr */, 19 /* nrec */); /* shared mt */
335336

336337
lua_pushcfunction(L, ngx_http_lua_shdict_get);
337338
lua_setfield(L, -2, "get");
@@ -375,6 +376,9 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L)
375376
lua_pushcfunction(L, ngx_http_lua_shdict_llen);
376377
lua_setfield(L, -2, "llen");
377378

379+
lua_pushcfunction(L, ngx_http_lua_shdict_lindex);
380+
lua_setfield(L, -2, "lindex");
381+
378382
lua_pushcfunction(L, ngx_http_lua_shdict_flush_all);
379383
lua_setfield(L, -2, "flush_all");
380384

@@ -2176,6 +2180,165 @@ ngx_http_lua_shdict_llen(lua_State *L)
21762180
}
21772181

21782182

2183+
static int
2184+
ngx_http_lua_shdict_lindex(lua_State *L)
2185+
{
2186+
int n, i, index;
2187+
uint8_t value_type;
2188+
uint32_t hash;
2189+
double num;
2190+
ngx_int_t rc;
2191+
ngx_str_t name, key, value;
2192+
ngx_queue_t *queue;
2193+
ngx_http_lua_shdict_ctx_t *ctx;
2194+
ngx_http_lua_shdict_node_t *sd;
2195+
ngx_shm_zone_t *zone;
2196+
ngx_http_lua_shdict_list_node_t *lnode;
2197+
2198+
2199+
n = lua_gettop(L);
2200+
2201+
if (n != 3) {
2202+
return luaL_error(L, "expecting 3 arguments, "
2203+
"but only seen %d", n);
2204+
}
2205+
2206+
if (lua_type(L, 1) != LUA_TTABLE) {
2207+
return luaL_error(L, "bad \"zone\" argument");
2208+
}
2209+
2210+
zone = ngx_http_lua_shdict_get_zone(L, 1);
2211+
if (zone == NULL) {
2212+
return luaL_error(L, "bad \"zone\" argument");
2213+
}
2214+
2215+
ctx = zone->data;
2216+
name = ctx->name;
2217+
2218+
if (lua_isnil(L, 2)) {
2219+
lua_pushnil(L);
2220+
lua_pushliteral(L, "nil key");
2221+
return 2;
2222+
}
2223+
2224+
key.data = (u_char *) luaL_checklstring(L, 2, &key.len);
2225+
2226+
if (key.len == 0) {
2227+
lua_pushnil(L);
2228+
lua_pushliteral(L, "empty key");
2229+
return 2;
2230+
}
2231+
2232+
if (key.len > 65535) {
2233+
lua_pushnil(L);
2234+
lua_pushliteral(L, "key too long");
2235+
return 2;
2236+
}
2237+
2238+
index = luaL_checkint(L, 3);
2239+
2240+
hash = ngx_crc32_short(key.data, key.len);
2241+
2242+
ngx_shmtx_lock(&ctx->shpool->mutex);
2243+
2244+
#if 1
2245+
ngx_http_lua_shdict_expire(ctx, 1);
2246+
#endif
2247+
2248+
rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd);
2249+
2250+
dd("shdict lookup returned %d", (int) rc);
2251+
2252+
if (rc == NGX_DECLINED || rc == NGX_DONE) {
2253+
ngx_shmtx_unlock(&ctx->shpool->mutex);
2254+
lua_pushnil(L);
2255+
return 1;
2256+
}
2257+
2258+
/* rc == NGX_OK */
2259+
2260+
if (sd->value_type != SHDICT_TLIST) {
2261+
ngx_shmtx_unlock(&ctx->shpool->mutex);
2262+
2263+
lua_pushnil(L);
2264+
lua_pushliteral(L, "value not a list");
2265+
return 2;
2266+
}
2267+
2268+
ngx_queue_remove(&sd->queue);
2269+
ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue);
2270+
2271+
if (index >= (int) sd->value_len || -index > (int) sd->value_len) {
2272+
ngx_shmtx_unlock(&ctx->shpool->mutex);
2273+
2274+
lua_pushnil(L);
2275+
return 1;
2276+
}
2277+
2278+
queue = ngx_http_lua_shdict_get_list_head(sd, key.len);
2279+
2280+
if (index >= 0) { /* forward */
2281+
2282+
for (i = 0; i <= index; i++) {
2283+
queue = ngx_queue_next(queue);
2284+
}
2285+
2286+
} else { /* backward */
2287+
2288+
for (i = -1; i >= index; i--) {
2289+
queue = ngx_queue_prev(queue);
2290+
}
2291+
}
2292+
2293+
lnode = ngx_queue_data(queue, ngx_http_lua_shdict_list_node_t, queue);
2294+
2295+
value_type = lnode->value_type;
2296+
2297+
dd("data: %p", lnode->data);
2298+
dd("value len: %d", (int) sd->value_len);
2299+
2300+
value.data = lnode->data;
2301+
value.len = (size_t) lnode->value_len;
2302+
2303+
switch (value_type) {
2304+
2305+
case SHDICT_TSTRING:
2306+
2307+
lua_pushlstring(L, (char *) value.data, value.len);
2308+
break;
2309+
2310+
case SHDICT_TNUMBER:
2311+
2312+
if (value.len != sizeof(double)) {
2313+
2314+
ngx_shmtx_unlock(&ctx->shpool->mutex);
2315+
2316+
return luaL_error(L, "bad lua list node number value size found"
2317+
" for key %s in shared_dict %s: %lu",
2318+
key.data, name.data,
2319+
(unsigned long) value.len);
2320+
}
2321+
2322+
ngx_memcpy(&num, value.data, sizeof(double));
2323+
2324+
lua_pushnumber(L, num);
2325+
break;
2326+
2327+
default:
2328+
2329+
ngx_shmtx_unlock(&ctx->shpool->mutex);
2330+
2331+
return luaL_error(L, "bad list node value type found for key %s in "
2332+
"shared_dict %s: %d", key.data, name.data,
2333+
value_type);
2334+
}
2335+
2336+
ngx_shmtx_unlock(&ctx->shpool->mutex);
2337+
2338+
return 1;
2339+
}
2340+
2341+
21792342
ngx_shm_zone_t *
21802343
ngx_http_lua_find_zone(u_char *name_data, size_t name_len)
21812344
{

0 commit comments

Comments
 (0)