Skip to content

Commit

Permalink
feature: implemented the lindex method for list type share dict value
Browse files Browse the repository at this point in the history
The `lindex` method returns the element at index `index` in the shared
dict list. Just like the `LINDEX` of Redis.
  • Loading branch information
tokers committed Feb 21, 2019
1 parent ee47e55 commit 4c56169
Show file tree
Hide file tree
Showing 4 changed files with 335 additions and 1 deletion.
19 changes: 19 additions & 0 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -3185,6 +3185,7 @@ Nginx API for Lua
* [ngx.shared.DICT.lpop](#ngxshareddictlpop)
* [ngx.shared.DICT.rpop](#ngxshareddictrpop)
* [ngx.shared.DICT.llen](#ngxshareddictllen)
* [ngx.shared.DICT.lindex](#ngxshareddictlindex)
* [ngx.shared.DICT.ttl](#ngxshareddictttl)
* [ngx.shared.DICT.expire](#ngxshareddictexpire)
* [ngx.shared.DICT.flush_all](#ngxshareddictflush_all)
Expand Down Expand Up @@ -6235,6 +6236,7 @@ The resulting object `dict` has the following methods:
* [lpop](#ngxshareddictlpop)
* [rpop](#ngxshareddictrpop)
* [llen](#ngxshareddictllen)
* [lindex](#ngxshareddictlindex)
* [ttl](#ngxshareddictttl)
* [expire](#ngxshareddictexpire)
* [flush_all](#ngxshareddictflush_all)
Expand Down Expand Up @@ -6607,6 +6609,23 @@ See also [ngx.shared.DICT](#ngxshareddict).

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

ngx.shared.DICT.lindex
----------------------

**syntax:** *val, err = ngx.shared.DICT:lindex(key, index)*

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

Returns the element which at the index `index` of the list named `key` in the shm-base dictionary [ngx.shared.DICT](#ngxshareddict).

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.

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`.

See also [ngx.shared.DICT](#ngxshareddict).

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

ngx.shared.DICT.ttl
-------------------
**syntax:** *ttl, err = ngx.shared.DICT:ttl(key)*
Expand Down
15 changes: 15 additions & 0 deletions doc/HttpLuaModule.wiki
Original file line number Diff line number Diff line change
Expand Up @@ -5232,6 +5232,7 @@ The resulting object <code>dict</code> has the following methods:
* [[#ngx.shared.DICT.lpop|lpop]]
* [[#ngx.shared.DICT.rpop|rpop]]
* [[#ngx.shared.DICT.llen|llen]]
* [[#ngx.shared.DICT.lindex|lindex]]
* [[#ngx.shared.DICT.ttl|ttl]]
* [[#ngx.shared.DICT.expire|expire]]
* [[#ngx.shared.DICT.flush_all|flush_all]]
Expand Down Expand Up @@ -5553,6 +5554,20 @@ This feature was first introduced in the <code>v0.10.6</code> release.
See also [[#ngx.shared.DICT|ngx.shared.DICT]].
== ngx.shared.DICT.lindex ==
'''syntax:''' ''val, err = ngx.shared.DICT:lindex(key, index)''
'''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*''
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]].
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.
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`.
See also [[#ngx.shared.DICT|ngx.shared.DICT]].
== ngx.shared.DICT.ttl ==
'''syntax:''' ''ttl, err = ngx.shared.DICT:ttl(key)''
Expand Down
165 changes: 164 additions & 1 deletion src/ngx_http_lua_shdict.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ static int ngx_http_lua_shdict_lpop(lua_State *L);
static int ngx_http_lua_shdict_rpop(lua_State *L);
static int ngx_http_lua_shdict_pop_helper(lua_State *L, int flags);
static int ngx_http_lua_shdict_llen(lua_State *L);
static int ngx_http_lua_shdict_lindex(lua_State *L);


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

lua_createtable(L, 0 /* narr */, 18 /* nrec */); /* shared mt */
lua_createtable(L, 0 /* narr */, 19 /* nrec */); /* shared mt */

lua_pushcfunction(L, ngx_http_lua_shdict_get);
lua_setfield(L, -2, "get");
Expand Down Expand Up @@ -375,6 +376,9 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L)
lua_pushcfunction(L, ngx_http_lua_shdict_llen);
lua_setfield(L, -2, "llen");

lua_pushcfunction(L, ngx_http_lua_shdict_lindex);
lua_setfield(L, -2, "lindex");

lua_pushcfunction(L, ngx_http_lua_shdict_flush_all);
lua_setfield(L, -2, "flush_all");

Expand Down Expand Up @@ -2176,6 +2180,165 @@ ngx_http_lua_shdict_llen(lua_State *L)
}


static int
ngx_http_lua_shdict_lindex(lua_State *L)
{
int n, i, index;
uint8_t value_type;
uint32_t hash;
double num;
ngx_int_t rc;
ngx_str_t name, key, value;
ngx_queue_t *queue;
ngx_http_lua_shdict_ctx_t *ctx;
ngx_http_lua_shdict_node_t *sd;
ngx_shm_zone_t *zone;
ngx_http_lua_shdict_list_node_t *lnode;


n = lua_gettop(L);

if (n != 3) {
return luaL_error(L, "expecting 3 arguments, "
"but only seen %d", n);
}

if (lua_type(L, 1) != LUA_TTABLE) {
return luaL_error(L, "bad \"zone\" argument");
}

zone = ngx_http_lua_shdict_get_zone(L, 1);
if (zone == NULL) {
return luaL_error(L, "bad \"zone\" argument");
}

ctx = zone->data;
name = ctx->name;

if (lua_isnil(L, 2)) {
lua_pushnil(L);
lua_pushliteral(L, "nil key");
return 2;
}

key.data = (u_char *) luaL_checklstring(L, 2, &key.len);

if (key.len == 0) {
lua_pushnil(L);
lua_pushliteral(L, "empty key");
return 2;
}

if (key.len > 65535) {
lua_pushnil(L);
lua_pushliteral(L, "key too long");
return 2;
}

index = luaL_checkint(L, 3);

hash = ngx_crc32_short(key.data, key.len);

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.data, key.len, &sd);

dd("shdict lookup returned %d", (int) rc);

if (rc == NGX_DECLINED || rc == NGX_DONE) {
ngx_shmtx_unlock(&ctx->shpool->mutex);
lua_pushnil(L);
return 1;
}

/* rc == NGX_OK */

if (sd->value_type != SHDICT_TLIST) {
ngx_shmtx_unlock(&ctx->shpool->mutex);

lua_pushnil(L);
lua_pushliteral(L, "value not a list");
return 2;
}

ngx_queue_remove(&sd->queue);
ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue);

if (index >= (int) sd->value_len || -index > (int) sd->value_len) {
ngx_shmtx_unlock(&ctx->shpool->mutex);

lua_pushnil(L);
return 1;
}

queue = ngx_http_lua_shdict_get_list_head(sd, key.len);

if (index >= 0) { /* forward */

for (i = 0; i <= index; i++) {
queue = ngx_queue_next(queue);
}

} else { /* backward */

for (i = -1; i >= index; i--) {
queue = ngx_queue_prev(queue);
}
}

lnode = ngx_queue_data(queue, ngx_http_lua_shdict_list_node_t, queue);

value_type = lnode->value_type;

dd("data: %p", lnode->data);
dd("value len: %d", (int) sd->value_len);

value.data = lnode->data;
value.len = (size_t) lnode->value_len;

switch (value_type) {

case SHDICT_TSTRING:

lua_pushlstring(L, (char *) value.data, value.len);
break;

case SHDICT_TNUMBER:

if (value.len != sizeof(double)) {

ngx_shmtx_unlock(&ctx->shpool->mutex);

return luaL_error(L, "bad lua list node number value size found"
" for key %s in shared_dict %s: %lu",
key.data, name.data,
(unsigned long) value.len);
}

ngx_memcpy(&num, value.data, sizeof(double));

lua_pushnumber(L, num);
break;

default:

ngx_shmtx_unlock(&ctx->shpool->mutex);

return luaL_error(L, "bad list node value type found for key %s in "
"shared_dict %s: %d", key.data, name.data,
value_type);
}

ngx_shmtx_unlock(&ctx->shpool->mutex);

return 1;
}


ngx_shm_zone_t *
ngx_http_lua_find_zone(u_char *name_data, size_t name_len)
{
Expand Down
Loading

0 comments on commit 4c56169

Please sign in to comment.