diff --git a/README.markdown b/README.markdown index 3df44953e0..d9521fefca 100644 --- a/README.markdown +++ b/README.markdown @@ -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) @@ -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) @@ -6607,6 +6609,25 @@ 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 or `index` is out of the list bound, 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"`. + +**Note:** This method requires the `resty.core.shdict` or `resty.core` modules from the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. + +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)* diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki index 9222811251..ca565f20cb 100644 --- a/doc/HttpLuaModule.wiki +++ b/doc/HttpLuaModule.wiki @@ -5232,6 +5232,7 @@ The resulting object dict 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]] @@ -5553,6 +5554,22 @@ This feature was first introduced in the v0.10.6 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 index of the list named key in the shm-base dictionary [[#ngx.shared.DICT|ngx.shared.DICT]]. + +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 or index is out of the list bound, 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". + +'''Note:''' This method requires the resty.core.shdict or resty.core modules from the [https://github.com/openresty/lua-resty-core lua-resty-core] library. + +See also [[#ngx.shared.DICT|ngx.shared.DICT]]. + == ngx.shared.DICT.ttl == '''syntax:''' ''ttl, err = ngx.shared.DICT:ttl(key)'' diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index b017bea658..9b41044973 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -3021,6 +3021,139 @@ ngx_http_lua_ffi_shdict_free_space(ngx_shm_zone_t *zone) # endif /* nginx_version >= 1011007 */ +int +ngx_http_lua_ffi_shdict_lindex(ngx_shm_zone_t *zone, u_char *key, + size_t key_len, int *value_type, u_char **str_value_buf, + size_t *str_value_len, double *num_value, int index, char **err) +{ + int i; + uint32_t hash; + ngx_int_t rc; + ngx_str_t name, value; + ngx_queue_t *queue; + ngx_http_lua_shdict_ctx_t *ctx; + ngx_http_lua_shdict_node_t *sd; + ngx_http_lua_shdict_list_node_t *lnode; + + ctx = zone->data; + name = ctx->name; + + hash = ngx_crc32_short(key, 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, key_len, &sd); + + dd("shdict lookup returned %d", (int) rc); + + if (rc == NGX_DECLINED || rc == NGX_DONE) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + + *value_type = LUA_TNIL; + return NGX_OK; + } + + /* rc == NGX_OK */ + + if (sd->value_type != SHDICT_TLIST) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + + *err = "value not a list"; + return NGX_ERROR; + } + + 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); + + *value_type = LUA_TNIL; + return NGX_OK; + } + + 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) lnode->value_len); + + value.data = lnode->data; + value.len = (size_t) lnode->value_len; + + if (*str_value_len < (size_t) value.len) { + if (*value_type == SHDICT_TSTRING) { + *str_value_buf = malloc(value.len); + if (*str_value_buf == NULL) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + return NGX_ERROR; + } + } + } + + switch (*value_type) { + + case SHDICT_TSTRING: + *str_value_len = value.len; + ngx_memcpy(*str_value_buf, lnode->data, value.len); + break; + + case SHDICT_TNUMBER: + + if (value.len != sizeof(double)) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "bad lua list node number value size found " + "for key %*s in shared_dict %V: %z", + key_len, key, &name, value.len); + + return NGX_ERROR; + } + + *str_value_len = value.len; + ngx_memcpy(num_value, value.data, sizeof(double)); + + break; + + default: + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "bad list node value type found " + "for key %*s in shared_dict %V: %d", + key_len, key, &name, *value_type); + + return NGX_ERROR; + } + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return NGX_OK; +} + + #endif /* NGX_LUA_NO_FFI_API */