LCOV - code coverage report
Current view: top level - home/build/openresty-1.13.6.1/build/ngx_lua-0.10.11/src - ngx_http_lua_shdict.c (source / functions) Hit Total Coverage
Test: coverage ngix Lines: 5 1293 0.4 %
Date: 2020-03-03 04:25:50 Functions: 1 39 2.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : 
       2             : /*
       3             :  * Copyright (C) Yichun Zhang (agentzh)
       4             :  */
       5             : 
       6             : 
       7             : #ifndef DDEBUG
       8             : #define DDEBUG 0
       9             : #endif
      10             : #include "ddebug.h"
      11             : 
      12             : 
      13             : #include "ngx_http_lua_shdict.h"
      14             : #include "ngx_http_lua_util.h"
      15             : #include "ngx_http_lua_api.h"
      16             : 
      17             : 
      18             : static int ngx_http_lua_shdict_set(lua_State *L);
      19             : static int ngx_http_lua_shdict_safe_set(lua_State *L);
      20             : static int ngx_http_lua_shdict_get(lua_State *L);
      21             : static int ngx_http_lua_shdict_get_stale(lua_State *L);
      22             : static int ngx_http_lua_shdict_get_helper(lua_State *L, int get_stale);
      23             : static int ngx_http_lua_shdict_expire(ngx_http_lua_shdict_ctx_t *ctx,
      24             :     ngx_uint_t n);
      25             : static ngx_int_t ngx_http_lua_shdict_lookup(ngx_shm_zone_t *shm_zone,
      26             :     ngx_uint_t hash, u_char *kdata, size_t klen,
      27             :     ngx_http_lua_shdict_node_t **sdp);
      28             : static int ngx_http_lua_shdict_set_helper(lua_State *L, int flags);
      29             : static int ngx_http_lua_shdict_add(lua_State *L);
      30             : static int ngx_http_lua_shdict_safe_add(lua_State *L);
      31             : static int ngx_http_lua_shdict_replace(lua_State *L);
      32             : static int ngx_http_lua_shdict_incr(lua_State *L);
      33             : static int ngx_http_lua_shdict_delete(lua_State *L);
      34             : static int ngx_http_lua_shdict_flush_all(lua_State *L);
      35             : static int ngx_http_lua_shdict_flush_expired(lua_State *L);
      36             : static int ngx_http_lua_shdict_get_keys(lua_State *L);
      37             : static int ngx_http_lua_shdict_lpush(lua_State *L);
      38             : static int ngx_http_lua_shdict_rpush(lua_State *L);
      39             : static int ngx_http_lua_shdict_push_helper(lua_State *L, int flags);
      40             : static int ngx_http_lua_shdict_lpop(lua_State *L);
      41             : static int ngx_http_lua_shdict_rpop(lua_State *L);
      42             : static int ngx_http_lua_shdict_pop_helper(lua_State *L, int flags);
      43             : static int ngx_http_lua_shdict_llen(lua_State *L);
      44             : 
      45             : 
      46             : static ngx_inline ngx_shm_zone_t *ngx_http_lua_shdict_get_zone(lua_State *L,
      47             :                                                                int index);
      48             : 
      49             : 
      50             : #define NGX_HTTP_LUA_SHDICT_ADD         0x0001
      51             : #define NGX_HTTP_LUA_SHDICT_REPLACE     0x0002
      52             : #define NGX_HTTP_LUA_SHDICT_SAFE_STORE  0x0004
      53             : 
      54             : 
      55             : #define NGX_HTTP_LUA_SHDICT_LEFT        0x0001
      56             : #define NGX_HTTP_LUA_SHDICT_RIGHT       0x0002
      57             : 
      58             : 
      59             : enum {
      60             :     SHDICT_USERDATA_INDEX = 1,
      61             : };
      62             : 
      63             : 
      64             : enum {
      65             :     SHDICT_TNIL = 0,        /* same as LUA_TNIL */
      66             :     SHDICT_TBOOLEAN = 1,    /* same as LUA_TBOOLEAN */
      67             :     SHDICT_TNUMBER = 3,     /* same as LUA_TNUMBER */
      68             :     SHDICT_TSTRING = 4,     /* same as LUA_TSTRING */
      69             :     SHDICT_TLIST = 5,
      70             : };
      71             : 
      72             : 
      73             : static ngx_inline ngx_queue_t *
      74           0 : ngx_http_lua_shdict_get_list_head(ngx_http_lua_shdict_node_t *sd, size_t len)
      75             : {
      76           0 :     return (ngx_queue_t *) ngx_align_ptr(((u_char *) &sd->data + len),
      77             :                                          NGX_ALIGNMENT);
      78             : }
      79             : 
      80             : 
      81             : ngx_int_t
      82           0 : ngx_http_lua_shdict_init_zone(ngx_shm_zone_t *shm_zone, void *data)
      83             : {
      84           0 :     ngx_http_lua_shdict_ctx_t  *octx = data;
      85             : 
      86             :     size_t                      len;
      87             :     ngx_http_lua_shdict_ctx_t  *ctx;
      88             : 
      89             :     dd("init zone");
      90             : 
      91           0 :     ctx = shm_zone->data;
      92             : 
      93           0 :     if (octx) {
      94           0 :         ctx->sh = octx->sh;
      95           0 :         ctx->shpool = octx->shpool;
      96             : 
      97           0 :         return NGX_OK;
      98             :     }
      99             : 
     100           0 :     ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
     101             : 
     102           0 :     if (shm_zone->shm.exists) {
     103           0 :         ctx->sh = ctx->shpool->data;
     104             : 
     105           0 :         return NGX_OK;
     106             :     }
     107             : 
     108           0 :     ctx->sh = ngx_slab_alloc(ctx->shpool, sizeof(ngx_http_lua_shdict_shctx_t));
     109           0 :     if (ctx->sh == NULL) {
     110           0 :         return NGX_ERROR;
     111             :     }
     112             : 
     113           0 :     ctx->shpool->data = ctx->sh;
     114             : 
     115           0 :     ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel,
     116             :                     ngx_http_lua_shdict_rbtree_insert_value);
     117             : 
     118           0 :     ngx_queue_init(&ctx->sh->lru_queue);
     119             : 
     120           0 :     len = sizeof(" in lua_shared_dict zone \"\"") + shm_zone->shm.name.len;
     121             : 
     122           0 :     ctx->shpool->log_ctx = ngx_slab_alloc(ctx->shpool, len);
     123           0 :     if (ctx->shpool->log_ctx == NULL) {
     124           0 :         return NGX_ERROR;
     125             :     }
     126             : 
     127           0 :     ngx_sprintf(ctx->shpool->log_ctx, " in lua_shared_dict zone \"%V\"%Z",
     128             :                 &shm_zone->shm.name);
     129             : 
     130             : #if defined(nginx_version) && nginx_version >= 1005013
     131           0 :     ctx->shpool->log_nomem = 0;
     132             : #endif
     133             : 
     134           0 :     return NGX_OK;
     135             : }
     136             : 
     137             : 
     138             : void
     139           0 : ngx_http_lua_shdict_rbtree_insert_value(ngx_rbtree_node_t *temp,
     140             :     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
     141             : {
     142             :     ngx_rbtree_node_t           **p;
     143             :     ngx_http_lua_shdict_node_t   *sdn, *sdnt;
     144             : 
     145             :     for ( ;; ) {
     146             : 
     147           0 :         if (node->key < temp->key) {
     148             : 
     149           0 :             p = &temp->left;
     150             : 
     151           0 :         } else if (node->key > temp->key) {
     152             : 
     153           0 :             p = &temp->right;
     154             : 
     155             :         } else { /* node->key == temp->key */
     156             : 
     157           0 :             sdn = (ngx_http_lua_shdict_node_t *) &node->color;
     158           0 :             sdnt = (ngx_http_lua_shdict_node_t *) &temp->color;
     159             : 
     160           0 :             p = ngx_memn2cmp(sdn->data, sdnt->data, sdn->key_len,
     161           0 :                              sdnt->key_len) < 0 ? &temp->left : &temp->right;
     162             :         }
     163             : 
     164           0 :         if (*p == sentinel) {
     165           0 :             break;
     166             :         }
     167             : 
     168           0 :         temp = *p;
     169             :     }
     170             : 
     171           0 :     *p = node;
     172           0 :     node->parent = temp;
     173           0 :     node->left = sentinel;
     174           0 :     node->right = sentinel;
     175           0 :     ngx_rbt_red(node);
     176           0 : }
     177             : 
     178             : 
     179             : static ngx_int_t
     180           0 : ngx_http_lua_shdict_lookup(ngx_shm_zone_t *shm_zone, ngx_uint_t hash,
     181             :     u_char *kdata, size_t klen, ngx_http_lua_shdict_node_t **sdp)
     182             : {
     183             :     ngx_int_t                    rc;
     184             :     ngx_time_t                  *tp;
     185             :     uint64_t                     now;
     186             :     int64_t                      ms;
     187             :     ngx_rbtree_node_t           *node, *sentinel;
     188             :     ngx_http_lua_shdict_ctx_t   *ctx;
     189             :     ngx_http_lua_shdict_node_t  *sd;
     190             : 
     191           0 :     ctx = shm_zone->data;
     192             : 
     193           0 :     node = ctx->sh->rbtree.root;
     194           0 :     sentinel = ctx->sh->rbtree.sentinel;
     195             : 
     196           0 :     while (node != sentinel) {
     197             : 
     198           0 :         if (hash < node->key) {
     199           0 :             node = node->left;
     200           0 :             continue;
     201             :         }
     202             : 
     203           0 :         if (hash > node->key) {
     204           0 :             node = node->right;
     205           0 :             continue;
     206             :         }
     207             : 
     208             :         /* hash == node->key */
     209             : 
     210           0 :         sd = (ngx_http_lua_shdict_node_t *) &node->color;
     211             : 
     212           0 :         rc = ngx_memn2cmp(kdata, sd->data, klen, (size_t) sd->key_len);
     213             : 
     214           0 :         if (rc == 0) {
     215           0 :             ngx_queue_remove(&sd->queue);
     216           0 :             ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue);
     217             : 
     218           0 :             *sdp = sd;
     219             : 
     220             :             dd("node expires: %lld", (long long) sd->expires);
     221             : 
     222           0 :             if (sd->expires != 0) {
     223           0 :                 tp = ngx_timeofday();
     224             : 
     225           0 :                 now = (uint64_t) tp->sec * 1000 + tp->msec;
     226           0 :                 ms = sd->expires - now;
     227             : 
     228             :                 dd("time to live: %lld", (long long) ms);
     229             : 
     230           0 :                 if (ms < 0) {
     231             :                     dd("node already expired");
     232           0 :                     return NGX_DONE;
     233             :                 }
     234             :             }
     235             : 
     236           0 :             return NGX_OK;
     237             :         }
     238             : 
     239           0 :         node = (rc < 0) ? node->left : node->right;
     240             :     }
     241             : 
     242           0 :     *sdp = NULL;
     243             : 
     244           0 :     return NGX_DECLINED;
     245             : }
     246             : 
     247             : 
     248             : static int
     249           0 : ngx_http_lua_shdict_expire(ngx_http_lua_shdict_ctx_t *ctx, ngx_uint_t n)
     250             : {
     251             :     ngx_time_t                      *tp;
     252             :     uint64_t                         now;
     253             :     ngx_queue_t                     *q, *list_queue, *lq;
     254             :     int64_t                          ms;
     255             :     ngx_rbtree_node_t               *node;
     256             :     ngx_http_lua_shdict_node_t      *sd;
     257           0 :     int                              freed = 0;
     258             :     ngx_http_lua_shdict_list_node_t *lnode;
     259             : 
     260           0 :     tp = ngx_timeofday();
     261             : 
     262           0 :     now = (uint64_t) tp->sec * 1000 + tp->msec;
     263             : 
     264             :     /*
     265             :      * n == 1 deletes one or two expired entries
     266             :      * n == 0 deletes oldest entry by force
     267             :      *        and one or two zero rate entries
     268             :      */
     269             : 
     270           0 :     while (n < 3) {
     271             : 
     272           0 :         if (ngx_queue_empty(&ctx->sh->lru_queue)) {
     273           0 :             return freed;
     274             :         }
     275             : 
     276           0 :         q = ngx_queue_last(&ctx->sh->lru_queue);
     277             : 
     278           0 :         sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue);
     279             : 
     280           0 :         if (n++ != 0) {
     281             : 
     282           0 :             if (sd->expires == 0) {
     283           0 :                 return freed;
     284             :             }
     285             : 
     286           0 :             ms = sd->expires - now;
     287           0 :             if (ms > 0) {
     288           0 :                 return freed;
     289             :             }
     290             :         }
     291             : 
     292           0 :         if (sd->value_type == SHDICT_TLIST) {
     293           0 :             list_queue = ngx_http_lua_shdict_get_list_head(sd, sd->key_len);
     294             : 
     295           0 :             for (lq = ngx_queue_head(list_queue);
     296             :                  lq != ngx_queue_sentinel(list_queue);
     297           0 :                  lq = ngx_queue_next(lq))
     298             :             {
     299           0 :                 lnode = ngx_queue_data(lq, ngx_http_lua_shdict_list_node_t,
     300             :                                        queue);
     301             : 
     302           0 :                 ngx_slab_free_locked(ctx->shpool, lnode);
     303             :             }
     304             :         }
     305             : 
     306           0 :         ngx_queue_remove(q);
     307             : 
     308           0 :         node = (ngx_rbtree_node_t *)
     309             :                    ((u_char *) sd - offsetof(ngx_rbtree_node_t, color));
     310             : 
     311           0 :         ngx_rbtree_delete(&ctx->sh->rbtree, node);
     312             : 
     313           0 :         ngx_slab_free_locked(ctx->shpool, node);
     314             : 
     315           0 :         freed++;
     316             :     }
     317             : 
     318           0 :     return freed;
     319             : }
     320             : 
     321             : 
     322             : void
     323          18 : ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L)
     324             : {
     325             :     ngx_http_lua_shdict_ctx_t   *ctx;
     326             :     ngx_uint_t                   i;
     327             :     ngx_shm_zone_t             **zone;
     328             : 
     329          18 :     if (lmcf->shdict_zones != NULL) {
     330           0 :         lua_createtable(L, 0, lmcf->shdict_zones->nelts /* nrec */);
     331             :                 /* ngx.shared */
     332             : 
     333           0 :         lua_createtable(L, 0 /* narr */, 18 /* nrec */); /* shared mt */
     334             : 
     335           0 :         lua_pushcfunction(L, ngx_http_lua_shdict_get);
     336           0 :         lua_setfield(L, -2, "get");
     337             : 
     338           0 :         lua_pushcfunction(L, ngx_http_lua_shdict_get_stale);
     339           0 :         lua_setfield(L, -2, "get_stale");
     340             : 
     341           0 :         lua_pushcfunction(L, ngx_http_lua_shdict_set);
     342           0 :         lua_setfield(L, -2, "set");
     343             : 
     344           0 :         lua_pushcfunction(L, ngx_http_lua_shdict_safe_set);
     345           0 :         lua_setfield(L, -2, "safe_set");
     346             : 
     347           0 :         lua_pushcfunction(L, ngx_http_lua_shdict_add);
     348           0 :         lua_setfield(L, -2, "add");
     349             : 
     350           0 :         lua_pushcfunction(L, ngx_http_lua_shdict_safe_add);
     351           0 :         lua_setfield(L, -2, "safe_add");
     352             : 
     353           0 :         lua_pushcfunction(L, ngx_http_lua_shdict_replace);
     354           0 :         lua_setfield(L, -2, "replace");
     355             : 
     356           0 :         lua_pushcfunction(L, ngx_http_lua_shdict_incr);
     357           0 :         lua_setfield(L, -2, "incr");
     358             : 
     359           0 :         lua_pushcfunction(L, ngx_http_lua_shdict_delete);
     360           0 :         lua_setfield(L, -2, "delete");
     361             : 
     362           0 :         lua_pushcfunction(L, ngx_http_lua_shdict_lpush);
     363           0 :         lua_setfield(L, -2, "lpush");
     364             : 
     365           0 :         lua_pushcfunction(L, ngx_http_lua_shdict_rpush);
     366           0 :         lua_setfield(L, -2, "rpush");
     367             : 
     368           0 :         lua_pushcfunction(L, ngx_http_lua_shdict_lpop);
     369           0 :         lua_setfield(L, -2, "lpop");
     370             : 
     371           0 :         lua_pushcfunction(L, ngx_http_lua_shdict_rpop);
     372           0 :         lua_setfield(L, -2, "rpop");
     373             : 
     374           0 :         lua_pushcfunction(L, ngx_http_lua_shdict_llen);
     375           0 :         lua_setfield(L, -2, "llen");
     376             : 
     377           0 :         lua_pushcfunction(L, ngx_http_lua_shdict_flush_all);
     378           0 :         lua_setfield(L, -2, "flush_all");
     379             : 
     380           0 :         lua_pushcfunction(L, ngx_http_lua_shdict_flush_expired);
     381           0 :         lua_setfield(L, -2, "flush_expired");
     382             : 
     383           0 :         lua_pushcfunction(L, ngx_http_lua_shdict_get_keys);
     384           0 :         lua_setfield(L, -2, "get_keys");
     385             : 
     386           0 :         lua_pushvalue(L, -1); /* shared mt mt */
     387           0 :         lua_setfield(L, -2, "__index"); /* shared mt */
     388             : 
     389           0 :         zone = lmcf->shdict_zones->elts;
     390             : 
     391           0 :         for (i = 0; i < lmcf->shdict_zones->nelts; i++) {
     392           0 :             ctx = zone[i]->data;
     393             : 
     394           0 :             lua_pushlstring(L, (char *) ctx->name.data, ctx->name.len);
     395             :                 /* shared mt key */
     396             : 
     397           0 :             lua_createtable(L, 1 /* narr */, 0 /* nrec */);
     398             :                 /* table of zone[i] */
     399           0 :             lua_pushlightuserdata(L, zone[i]); /* shared mt key ud */
     400           0 :             lua_rawseti(L, -2, SHDICT_USERDATA_INDEX); /* {zone[i]} */
     401           0 :             lua_pushvalue(L, -3); /* shared mt key ud mt */
     402           0 :             lua_setmetatable(L, -2); /* shared mt key ud */
     403           0 :             lua_rawset(L, -4); /* shared mt */
     404             :         }
     405             : 
     406           0 :         lua_pop(L, 1); /* shared */
     407             : 
     408             :     } else {
     409          18 :         lua_newtable(L);    /* ngx.shared */
     410             :     }
     411             : 
     412          18 :     lua_setfield(L, -2, "shared");
     413          18 : }
     414             : 
     415             : 
     416             : static int
     417           0 : ngx_http_lua_shdict_get(lua_State *L)
     418             : {
     419           0 :     return ngx_http_lua_shdict_get_helper(L, 0 /* stale */);
     420             : }
     421             : 
     422             : 
     423             : static int
     424           0 : ngx_http_lua_shdict_get_stale(lua_State *L)
     425             : {
     426           0 :     return ngx_http_lua_shdict_get_helper(L, 1 /* stale */);
     427             : }
     428             : 
     429             : 
     430             : static ngx_inline ngx_shm_zone_t *
     431           0 : ngx_http_lua_shdict_get_zone(lua_State *L, int index)
     432             : {
     433             :     ngx_shm_zone_t      *zone;
     434             : 
     435           0 :     lua_rawgeti(L, index, SHDICT_USERDATA_INDEX);
     436           0 :     zone = lua_touserdata(L, -1);
     437           0 :     lua_pop(L, 1);
     438             : 
     439           0 :     return zone;
     440             : }
     441             : 
     442             : 
     443             : static int
     444           0 : ngx_http_lua_shdict_get_helper(lua_State *L, int get_stale)
     445             : {
     446             :     int                          n;
     447             :     ngx_str_t                    name;
     448             :     ngx_str_t                    key;
     449             :     uint32_t                     hash;
     450             :     ngx_int_t                    rc;
     451             :     ngx_http_lua_shdict_ctx_t   *ctx;
     452             :     ngx_http_lua_shdict_node_t  *sd;
     453             :     ngx_str_t                    value;
     454             :     int                          value_type;
     455             :     double                       num;
     456             :     u_char                       c;
     457             :     ngx_shm_zone_t              *zone;
     458           0 :     uint32_t                     user_flags = 0;
     459             : 
     460           0 :     n = lua_gettop(L);
     461             : 
     462           0 :     if (n != 2) {
     463           0 :         return luaL_error(L, "expecting exactly two arguments, "
     464             :                           "but only seen %d", n);
     465             :     }
     466             : 
     467           0 :     if (lua_type(L, 1) != LUA_TTABLE) {
     468           0 :         return luaL_error(L, "bad \"zone\" argument");
     469             :     }
     470             : 
     471           0 :     zone = ngx_http_lua_shdict_get_zone(L, 1);
     472           0 :     if (zone == NULL) {
     473           0 :         return luaL_error(L, "bad \"zone\" argument");
     474             :     }
     475             : 
     476           0 :     ctx = zone->data;
     477           0 :     name = ctx->name;
     478             : 
     479           0 :     if (lua_isnil(L, 2)) {
     480           0 :         lua_pushnil(L);
     481           0 :         lua_pushliteral(L, "nil key");
     482           0 :         return 2;
     483             :     }
     484             : 
     485           0 :     key.data = (u_char *) luaL_checklstring(L, 2, &key.len);
     486             : 
     487           0 :     if (key.len == 0) {
     488           0 :         lua_pushnil(L);
     489           0 :         lua_pushliteral(L, "empty key");
     490           0 :         return 2;
     491             :     }
     492             : 
     493           0 :     if (key.len > 65535) {
     494           0 :         lua_pushnil(L);
     495           0 :         lua_pushliteral(L, "key too long");
     496           0 :         return 2;
     497             :     }
     498             : 
     499           0 :     hash = ngx_crc32_short(key.data, key.len);
     500             : 
     501             : #if (NGX_DEBUG)
     502           0 :     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
     503             :                    "fetching key \"%V\" in shared dict \"%V\"", &key, &name);
     504             : #endif /* NGX_DEBUG */
     505             : 
     506           0 :     ngx_shmtx_lock(&ctx->shpool->mutex);
     507             : 
     508             : #if 1
     509           0 :     if (!get_stale) {
     510           0 :         ngx_http_lua_shdict_expire(ctx, 1);
     511             :     }
     512             : #endif
     513             : 
     514           0 :     rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd);
     515             : 
     516             :     dd("shdict lookup returns %d", (int) rc);
     517             : 
     518           0 :     if (rc == NGX_DECLINED || (rc == NGX_DONE && !get_stale)) {
     519           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
     520           0 :         lua_pushnil(L);
     521           0 :         return 1;
     522             :     }
     523             : 
     524             :     /* rc == NGX_OK || (rc == NGX_DONE && get_stale) */
     525             : 
     526           0 :     value_type = sd->value_type;
     527             : 
     528             :     dd("data: %p", sd->data);
     529             :     dd("key len: %d", (int) sd->key_len);
     530             : 
     531           0 :     value.data = sd->data + sd->key_len;
     532           0 :     value.len = (size_t) sd->value_len;
     533             : 
     534           0 :     switch (value_type) {
     535             : 
     536           0 :     case SHDICT_TSTRING:
     537             : 
     538           0 :         lua_pushlstring(L, (char *) value.data, value.len);
     539           0 :         break;
     540             : 
     541           0 :     case SHDICT_TNUMBER:
     542             : 
     543           0 :         if (value.len != sizeof(double)) {
     544             : 
     545           0 :             ngx_shmtx_unlock(&ctx->shpool->mutex);
     546             : 
     547           0 :             return luaL_error(L, "bad lua number value size found for key %s "
     548             :                               "in shared_dict %s: %lu", key.data, name.data,
     549           0 :                               (unsigned long) value.len);
     550             :         }
     551             : 
     552           0 :         ngx_memcpy(&num, value.data, sizeof(double));
     553             : 
     554           0 :         lua_pushnumber(L, num);
     555           0 :         break;
     556             : 
     557           0 :     case SHDICT_TBOOLEAN:
     558             : 
     559           0 :         if (value.len != sizeof(u_char)) {
     560             : 
     561           0 :             ngx_shmtx_unlock(&ctx->shpool->mutex);
     562             : 
     563           0 :             return luaL_error(L, "bad lua boolean value size found for key %s "
     564             :                               "in shared_dict %s: %lu", key.data, name.data,
     565           0 :                               (unsigned long) value.len);
     566             :         }
     567             : 
     568           0 :         c = *value.data;
     569             : 
     570           0 :         lua_pushboolean(L, c ? 1 : 0);
     571           0 :         break;
     572             : 
     573           0 :     case SHDICT_TLIST:
     574             : 
     575           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
     576             : 
     577           0 :         lua_pushnil(L);
     578           0 :         lua_pushliteral(L, "value is a list");
     579           0 :         return 2;
     580             : 
     581           0 :     default:
     582             : 
     583           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
     584             : 
     585           0 :         return luaL_error(L, "bad value type found for key %s in "
     586             :                           "shared_dict %s: %d", key.data, name.data,
     587             :                           value_type);
     588             :     }
     589             : 
     590           0 :     user_flags = sd->user_flags;
     591             : 
     592           0 :     ngx_shmtx_unlock(&ctx->shpool->mutex);
     593             : 
     594           0 :     if (get_stale) {
     595             : 
     596             :         /* always return value, flags, stale */
     597             : 
     598           0 :         if (user_flags) {
     599           0 :             lua_pushinteger(L, (lua_Integer) user_flags);
     600             : 
     601             :         } else {
     602           0 :             lua_pushnil(L);
     603             :         }
     604             : 
     605           0 :         lua_pushboolean(L, rc == NGX_DONE);
     606           0 :         return 3;
     607             :     }
     608             : 
     609           0 :     if (user_flags) {
     610           0 :         lua_pushinteger(L, (lua_Integer) user_flags);
     611           0 :         return 2;
     612             :     }
     613             : 
     614           0 :     return 1;
     615             : }
     616             : 
     617             : 
     618             : static int
     619           0 : ngx_http_lua_shdict_delete(lua_State *L)
     620             : {
     621             :     int             n;
     622             : 
     623           0 :     n = lua_gettop(L);
     624             : 
     625           0 :     if (n != 2) {
     626           0 :         return luaL_error(L, "expecting 2 arguments, "
     627             :                           "but only seen %d", n);
     628             :     }
     629             : 
     630           0 :     lua_pushnil(L);
     631             : 
     632           0 :     return ngx_http_lua_shdict_set_helper(L, 0);
     633             : }
     634             : 
     635             : 
     636             : static int
     637           0 : ngx_http_lua_shdict_flush_all(lua_State *L)
     638             : {
     639             :     ngx_queue_t                 *q;
     640             :     ngx_http_lua_shdict_node_t  *sd;
     641             :     int                          n;
     642             :     ngx_http_lua_shdict_ctx_t   *ctx;
     643             :     ngx_shm_zone_t              *zone;
     644             : 
     645           0 :     n = lua_gettop(L);
     646             : 
     647           0 :     if (n != 1) {
     648           0 :         return luaL_error(L, "expecting 1 argument, but seen %d", n);
     649             :     }
     650             : 
     651           0 :     luaL_checktype(L, 1, LUA_TTABLE);
     652             : 
     653           0 :     zone = ngx_http_lua_shdict_get_zone(L, 1);
     654           0 :     if (zone == NULL) {
     655           0 :         return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer");
     656             :     }
     657             : 
     658           0 :     ctx = zone->data;
     659             : 
     660           0 :     ngx_shmtx_lock(&ctx->shpool->mutex);
     661             : 
     662           0 :     for (q = ngx_queue_head(&ctx->sh->lru_queue);
     663           0 :          q != ngx_queue_sentinel(&ctx->sh->lru_queue);
     664           0 :          q = ngx_queue_next(q))
     665             :     {
     666           0 :         sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue);
     667           0 :         sd->expires = 1;
     668             :     }
     669             : 
     670           0 :     ngx_http_lua_shdict_expire(ctx, 0);
     671             : 
     672           0 :     ngx_shmtx_unlock(&ctx->shpool->mutex);
     673             : 
     674           0 :     return 0;
     675             : }
     676             : 
     677             : 
     678             : static int
     679           0 : ngx_http_lua_shdict_flush_expired(lua_State *L)
     680             : {
     681             :     ngx_queue_t                     *q, *prev, *list_queue, *lq;
     682             :     ngx_http_lua_shdict_node_t      *sd;
     683             :     ngx_http_lua_shdict_ctx_t       *ctx;
     684             :     ngx_shm_zone_t                  *zone;
     685             :     ngx_time_t                      *tp;
     686           0 :     int                              freed = 0;
     687           0 :     int                              attempts = 0;
     688             :     ngx_rbtree_node_t               *node;
     689             :     uint64_t                         now;
     690             :     int                              n;
     691             :     ngx_http_lua_shdict_list_node_t *lnode;
     692             : 
     693           0 :     n = lua_gettop(L);
     694             : 
     695           0 :     if (n != 1 && n != 2) {
     696           0 :         return luaL_error(L, "expecting 1 or 2 argument(s), but saw %d", n);
     697             :     }
     698             : 
     699           0 :     luaL_checktype(L, 1, LUA_TTABLE);
     700             : 
     701           0 :     zone = ngx_http_lua_shdict_get_zone(L, 1);
     702           0 :     if (zone == NULL) {
     703           0 :         return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer");
     704             :     }
     705             : 
     706           0 :     if (n == 2) {
     707           0 :         attempts = luaL_checkint(L, 2);
     708             :     }
     709             : 
     710           0 :     ctx = zone->data;
     711             : 
     712           0 :     ngx_shmtx_lock(&ctx->shpool->mutex);
     713             : 
     714           0 :     if (ngx_queue_empty(&ctx->sh->lru_queue)) {
     715           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
     716           0 :         lua_pushnumber(L, 0);
     717           0 :         return 1;
     718             :     }
     719             : 
     720           0 :     tp = ngx_timeofday();
     721             : 
     722           0 :     now = (uint64_t) tp->sec * 1000 + tp->msec;
     723             : 
     724           0 :     q = ngx_queue_last(&ctx->sh->lru_queue);
     725             : 
     726           0 :     while (q != ngx_queue_sentinel(&ctx->sh->lru_queue)) {
     727           0 :         prev = ngx_queue_prev(q);
     728             : 
     729           0 :         sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue);
     730             : 
     731           0 :         if (sd->expires != 0 && sd->expires <= now) {
     732             : 
     733           0 :             if (sd->value_type == SHDICT_TLIST) {
     734           0 :                 list_queue = ngx_http_lua_shdict_get_list_head(sd, sd->key_len);
     735             : 
     736           0 :                 for (lq = ngx_queue_head(list_queue);
     737             :                      lq != ngx_queue_sentinel(list_queue);
     738           0 :                      lq = ngx_queue_next(lq))
     739             :                 {
     740           0 :                     lnode = ngx_queue_data(lq, ngx_http_lua_shdict_list_node_t,
     741             :                                            queue);
     742             : 
     743           0 :                     ngx_slab_free_locked(ctx->shpool, lnode);
     744             :                 }
     745             :             }
     746             : 
     747           0 :             ngx_queue_remove(q);
     748             : 
     749           0 :             node = (ngx_rbtree_node_t *)
     750             :                 ((u_char *) sd - offsetof(ngx_rbtree_node_t, color));
     751             : 
     752           0 :             ngx_rbtree_delete(&ctx->sh->rbtree, node);
     753           0 :             ngx_slab_free_locked(ctx->shpool, node);
     754           0 :             freed++;
     755             : 
     756           0 :             if (attempts && freed == attempts) {
     757           0 :                 break;
     758             :             }
     759             :         }
     760             : 
     761           0 :         q = prev;
     762             :     }
     763             : 
     764           0 :     ngx_shmtx_unlock(&ctx->shpool->mutex);
     765             : 
     766           0 :     lua_pushnumber(L, freed);
     767           0 :     return 1;
     768             : }
     769             : 
     770             : 
     771             : /*
     772             :  * This trades CPU for memory. This is potentially slow. O(2n)
     773             :  */
     774             : 
     775             : static int
     776           0 : ngx_http_lua_shdict_get_keys(lua_State *L)
     777             : {
     778             :     ngx_queue_t                 *q, *prev;
     779             :     ngx_http_lua_shdict_node_t  *sd;
     780             :     ngx_http_lua_shdict_ctx_t   *ctx;
     781             :     ngx_shm_zone_t              *zone;
     782             :     ngx_time_t                  *tp;
     783           0 :     int                          total = 0;
     784           0 :     int                          attempts = 1024;
     785             :     uint64_t                     now;
     786             :     int                          n;
     787             : 
     788           0 :     n = lua_gettop(L);
     789             : 
     790           0 :     if (n != 1 && n != 2) {
     791           0 :         return luaL_error(L, "expecting 1 or 2 argument(s), "
     792             :                           "but saw %d", n);
     793             :     }
     794             : 
     795           0 :     luaL_checktype(L, 1, LUA_TTABLE);
     796             : 
     797           0 :     zone = ngx_http_lua_shdict_get_zone(L, 1);
     798           0 :     if (zone == NULL) {
     799           0 :         return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer");
     800             :     }
     801             : 
     802           0 :     if (n == 2) {
     803           0 :         attempts = luaL_checkint(L, 2);
     804             :     }
     805             : 
     806           0 :     ctx = zone->data;
     807             : 
     808           0 :     ngx_shmtx_lock(&ctx->shpool->mutex);
     809             : 
     810           0 :     if (ngx_queue_empty(&ctx->sh->lru_queue)) {
     811           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
     812           0 :         lua_createtable(L, 0, 0);
     813           0 :         return 1;
     814             :     }
     815             : 
     816           0 :     tp = ngx_timeofday();
     817             : 
     818           0 :     now = (uint64_t) tp->sec * 1000 + tp->msec;
     819             : 
     820             :     /* first run through: get total number of elements we need to allocate */
     821             : 
     822           0 :     q = ngx_queue_last(&ctx->sh->lru_queue);
     823             : 
     824           0 :     while (q != ngx_queue_sentinel(&ctx->sh->lru_queue)) {
     825           0 :         prev = ngx_queue_prev(q);
     826             : 
     827           0 :         sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue);
     828             : 
     829           0 :         if (sd->expires == 0 || sd->expires > now) {
     830           0 :             total++;
     831           0 :             if (attempts && total == attempts) {
     832           0 :                 break;
     833             :             }
     834             :         }
     835             : 
     836           0 :         q = prev;
     837             :     }
     838             : 
     839           0 :     lua_createtable(L, total, 0);
     840             : 
     841             :     /* second run through: add keys to table */
     842             : 
     843           0 :     total = 0;
     844           0 :     q = ngx_queue_last(&ctx->sh->lru_queue);
     845             : 
     846           0 :     while (q != ngx_queue_sentinel(&ctx->sh->lru_queue)) {
     847           0 :         prev = ngx_queue_prev(q);
     848             : 
     849           0 :         sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue);
     850             : 
     851           0 :         if (sd->expires == 0 || sd->expires > now) {
     852           0 :             lua_pushlstring(L, (char *) sd->data, sd->key_len);
     853           0 :             lua_rawseti(L, -2, ++total);
     854           0 :             if (attempts && total == attempts) {
     855           0 :                 break;
     856             :             }
     857             :         }
     858             : 
     859           0 :         q = prev;
     860             :     }
     861             : 
     862           0 :     ngx_shmtx_unlock(&ctx->shpool->mutex);
     863             : 
     864             :     /* table is at top of stack */
     865           0 :     return 1;
     866             : }
     867             : 
     868             : 
     869             : static int
     870           0 : ngx_http_lua_shdict_add(lua_State *L)
     871             : {
     872           0 :     return ngx_http_lua_shdict_set_helper(L, NGX_HTTP_LUA_SHDICT_ADD);
     873             : }
     874             : 
     875             : 
     876             : static int
     877           0 : ngx_http_lua_shdict_safe_add(lua_State *L)
     878             : {
     879           0 :     return ngx_http_lua_shdict_set_helper(L, NGX_HTTP_LUA_SHDICT_ADD
     880             :                                           |NGX_HTTP_LUA_SHDICT_SAFE_STORE);
     881             : }
     882             : 
     883             : 
     884             : static int
     885           0 : ngx_http_lua_shdict_replace(lua_State *L)
     886             : {
     887           0 :     return ngx_http_lua_shdict_set_helper(L, NGX_HTTP_LUA_SHDICT_REPLACE);
     888             : }
     889             : 
     890             : 
     891             : static int
     892           0 : ngx_http_lua_shdict_set(lua_State *L)
     893             : {
     894           0 :     return ngx_http_lua_shdict_set_helper(L, 0);
     895             : }
     896             : 
     897             : 
     898             : static int
     899           0 : ngx_http_lua_shdict_safe_set(lua_State *L)
     900             : {
     901           0 :     return ngx_http_lua_shdict_set_helper(L, NGX_HTTP_LUA_SHDICT_SAFE_STORE);
     902             : }
     903             : 
     904             : 
     905             : static int
     906           0 : ngx_http_lua_shdict_set_helper(lua_State *L, int flags)
     907             : {
     908             :     int                          i, n;
     909             :     ngx_str_t                    key;
     910             :     uint32_t                     hash;
     911             :     ngx_int_t                    rc;
     912             :     ngx_http_lua_shdict_ctx_t   *ctx;
     913             :     ngx_http_lua_shdict_node_t  *sd;
     914             :     ngx_str_t                    value;
     915             :     int                          value_type;
     916             :     double                       num;
     917             :     u_char                       c;
     918           0 :     lua_Number                   exptime = 0;
     919             :     u_char                      *p;
     920             :     ngx_rbtree_node_t           *node;
     921             :     ngx_time_t                  *tp;
     922             :     ngx_shm_zone_t              *zone;
     923           0 :     int                          forcible = 0;
     924             :                          /* indicates whether to foricibly override other
     925             :                           * valid entries */
     926           0 :     int32_t                      user_flags = 0;
     927             :     ngx_queue_t                 *queue, *q;
     928             : 
     929           0 :     n = lua_gettop(L);
     930             : 
     931           0 :     if (n != 3 && n != 4 && n != 5) {
     932           0 :         return luaL_error(L, "expecting 3, 4 or 5 arguments, "
     933             :                           "but only seen %d", n);
     934             :     }
     935             : 
     936           0 :     if (lua_type(L, 1) != LUA_TTABLE) {
     937           0 :         return luaL_error(L, "bad \"zone\" argument");
     938             :     }
     939             : 
     940           0 :     zone = ngx_http_lua_shdict_get_zone(L, 1);
     941           0 :     if (zone == NULL) {
     942           0 :         return luaL_error(L, "bad \"zone\" argument");
     943             :     }
     944             : 
     945           0 :     ctx = zone->data;
     946             : 
     947           0 :     if (lua_isnil(L, 2)) {
     948           0 :         lua_pushnil(L);
     949           0 :         lua_pushliteral(L, "nil key");
     950           0 :         return 2;
     951             :     }
     952             : 
     953           0 :     key.data = (u_char *) luaL_checklstring(L, 2, &key.len);
     954             : 
     955           0 :     if (key.len == 0) {
     956           0 :         lua_pushnil(L);
     957           0 :         lua_pushliteral(L, "empty key");
     958           0 :         return 2;
     959             :     }
     960             : 
     961           0 :     if (key.len > 65535) {
     962           0 :         lua_pushnil(L);
     963           0 :         lua_pushliteral(L, "key too long");
     964           0 :         return 2;
     965             :     }
     966             : 
     967           0 :     hash = ngx_crc32_short(key.data, key.len);
     968             : 
     969           0 :     value_type = lua_type(L, 3);
     970             : 
     971           0 :     switch (value_type) {
     972             : 
     973           0 :     case SHDICT_TSTRING:
     974           0 :         value.data = (u_char *) lua_tolstring(L, 3, &value.len);
     975           0 :         break;
     976             : 
     977           0 :     case SHDICT_TNUMBER:
     978           0 :         value.len = sizeof(double);
     979           0 :         num = lua_tonumber(L, 3);
     980           0 :         value.data = (u_char *) &num;
     981           0 :         break;
     982             : 
     983           0 :     case SHDICT_TBOOLEAN:
     984           0 :         value.len = sizeof(u_char);
     985           0 :         c = lua_toboolean(L, 3) ? 1 : 0;
     986           0 :         value.data = &c;
     987           0 :         break;
     988             : 
     989           0 :     case LUA_TNIL:
     990           0 :         if (flags & (NGX_HTTP_LUA_SHDICT_ADD|NGX_HTTP_LUA_SHDICT_REPLACE)) {
     991           0 :             lua_pushnil(L);
     992           0 :             lua_pushliteral(L, "attempt to add or replace nil values");
     993           0 :             return 2;
     994             :         }
     995             : 
     996           0 :         ngx_str_null(&value);
     997           0 :         break;
     998             : 
     999           0 :     default:
    1000           0 :         lua_pushnil(L);
    1001           0 :         lua_pushliteral(L, "bad value type");
    1002           0 :         return 2;
    1003             :     }
    1004             : 
    1005           0 :     if (n >= 4) {
    1006           0 :         exptime = luaL_checknumber(L, 4);
    1007           0 :         if (exptime < 0) {
    1008           0 :             return luaL_error(L, "bad \"exptime\" argument");
    1009             :         }
    1010             :     }
    1011             : 
    1012           0 :     if (n == 5) {
    1013           0 :         user_flags = (uint32_t) luaL_checkinteger(L, 5);
    1014             :     }
    1015             : 
    1016           0 :     ngx_shmtx_lock(&ctx->shpool->mutex);
    1017             : 
    1018             : #if 1
    1019           0 :     ngx_http_lua_shdict_expire(ctx, 1);
    1020             : #endif
    1021             : 
    1022           0 :     rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd);
    1023             : 
    1024             :     dd("shdict lookup returned %d", (int) rc);
    1025             : 
    1026           0 :     if (flags & NGX_HTTP_LUA_SHDICT_REPLACE) {
    1027             : 
    1028           0 :         if (rc == NGX_DECLINED || rc == NGX_DONE) {
    1029           0 :             ngx_shmtx_unlock(&ctx->shpool->mutex);
    1030             : 
    1031           0 :             lua_pushboolean(L, 0);
    1032           0 :             lua_pushliteral(L, "not found");
    1033           0 :             lua_pushboolean(L, forcible);
    1034           0 :             return 3;
    1035             :         }
    1036             : 
    1037             :         /* rc == NGX_OK */
    1038             : 
    1039           0 :         goto replace;
    1040             :     }
    1041             : 
    1042           0 :     if (flags & NGX_HTTP_LUA_SHDICT_ADD) {
    1043             : 
    1044           0 :         if (rc == NGX_OK) {
    1045           0 :             ngx_shmtx_unlock(&ctx->shpool->mutex);
    1046             : 
    1047           0 :             lua_pushboolean(L, 0);
    1048           0 :             lua_pushliteral(L, "exists");
    1049           0 :             lua_pushboolean(L, forcible);
    1050           0 :             return 3;
    1051             :         }
    1052             : 
    1053           0 :         if (rc == NGX_DONE) {
    1054             :             /* exists but expired */
    1055             : 
    1056             :             dd("go to replace");
    1057           0 :             goto replace;
    1058             :         }
    1059             : 
    1060             :         /* rc == NGX_DECLINED */
    1061             : 
    1062             :         dd("go to insert");
    1063           0 :         goto insert;
    1064             :     }
    1065             : 
    1066           0 :     if (rc == NGX_OK || rc == NGX_DONE) {
    1067             : 
    1068           0 :         if (value_type == LUA_TNIL) {
    1069           0 :             goto remove;
    1070             :         }
    1071             : 
    1072           0 : replace:
    1073             : 
    1074           0 :         if (value.data
    1075           0 :             && value.len == (size_t) sd->value_len
    1076           0 :             && sd->value_type != SHDICT_TLIST)
    1077             :         {
    1078             : 
    1079           0 :             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
    1080             :                            "lua shared dict set: found old entry and value "
    1081             :                            "size matched, reusing it");
    1082             : 
    1083           0 :             ngx_queue_remove(&sd->queue);
    1084           0 :             ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue);
    1085             : 
    1086           0 :             sd->key_len = (u_short) key.len;
    1087             : 
    1088           0 :             if (exptime > 0) {
    1089           0 :                 tp = ngx_timeofday();
    1090           0 :                 sd->expires = (uint64_t) tp->sec * 1000 + tp->msec
    1091           0 :                               + (uint64_t) (exptime * 1000);
    1092             : 
    1093             :             } else {
    1094           0 :                 sd->expires = 0;
    1095             :             }
    1096             : 
    1097           0 :             sd->user_flags = user_flags;
    1098             : 
    1099           0 :             sd->value_len = (uint32_t) value.len;
    1100             : 
    1101             :             dd("setting value type to %d", value_type);
    1102             : 
    1103           0 :             sd->value_type = (uint8_t) value_type;
    1104             : 
    1105           0 :             p = ngx_copy(sd->data, key.data, key.len);
    1106           0 :             ngx_memcpy(p, value.data, value.len);
    1107             : 
    1108           0 :             ngx_shmtx_unlock(&ctx->shpool->mutex);
    1109             : 
    1110           0 :             lua_pushboolean(L, 1);
    1111           0 :             lua_pushnil(L);
    1112           0 :             lua_pushboolean(L, forcible);
    1113           0 :             return 3;
    1114             :         }
    1115             : 
    1116           0 :         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
    1117             :                        "lua shared dict set: found old entry but value size "
    1118             :                        "NOT matched, removing it first");
    1119             : 
    1120           0 : remove:
    1121             : 
    1122           0 :         if (sd->value_type == SHDICT_TLIST) {
    1123           0 :             queue = ngx_http_lua_shdict_get_list_head(sd, key.len);
    1124             : 
    1125           0 :             for (q = ngx_queue_head(queue);
    1126             :                  q != ngx_queue_sentinel(queue);
    1127           0 :                  q = ngx_queue_next(q))
    1128             :             {
    1129           0 :                 p = (u_char *) ngx_queue_data(q,
    1130             :                                               ngx_http_lua_shdict_list_node_t,
    1131             :                                               queue);
    1132             : 
    1133           0 :                 ngx_slab_free_locked(ctx->shpool, p);
    1134             :             }
    1135             :         }
    1136             : 
    1137           0 :         ngx_queue_remove(&sd->queue);
    1138             : 
    1139           0 :         node = (ngx_rbtree_node_t *)
    1140           0 :                    ((u_char *) sd - offsetof(ngx_rbtree_node_t, color));
    1141             : 
    1142           0 :         ngx_rbtree_delete(&ctx->sh->rbtree, node);
    1143             : 
    1144           0 :         ngx_slab_free_locked(ctx->shpool, node);
    1145             : 
    1146             :     }
    1147             : 
    1148           0 : insert:
    1149             : 
    1150             :     /* rc == NGX_DECLINED or value size unmatch */
    1151             : 
    1152           0 :     if (value.data == NULL) {
    1153           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
    1154             : 
    1155           0 :         lua_pushboolean(L, 1);
    1156           0 :         lua_pushnil(L);
    1157           0 :         lua_pushboolean(L, 0);
    1158           0 :         return 3;
    1159             :     }
    1160             : 
    1161           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
    1162             :                    "lua shared dict set: creating a new entry");
    1163             : 
    1164           0 :     n = offsetof(ngx_rbtree_node_t, color)
    1165             :         + offsetof(ngx_http_lua_shdict_node_t, data)
    1166           0 :         + key.len
    1167           0 :         + value.len;
    1168             : 
    1169             :     dd("overhead = %d", (int) (offsetof(ngx_rbtree_node_t, color)
    1170             :        + offsetof(ngx_http_lua_shdict_node_t, data)));
    1171             : 
    1172           0 :     node = ngx_slab_alloc_locked(ctx->shpool, n);
    1173             : 
    1174           0 :     if (node == NULL) {
    1175             : 
    1176           0 :         if (flags & NGX_HTTP_LUA_SHDICT_SAFE_STORE) {
    1177           0 :             ngx_shmtx_unlock(&ctx->shpool->mutex);
    1178             : 
    1179           0 :             lua_pushboolean(L, 0);
    1180           0 :             lua_pushliteral(L, "no memory");
    1181           0 :             return 2;
    1182             :         }
    1183             : 
    1184           0 :         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
    1185             :                        "lua shared dict set: overriding non-expired items "
    1186             :                        "due to memory shortage for entry \"%V\"", &key);
    1187             : 
    1188           0 :         for (i = 0; i < 30; i++) {
    1189           0 :             if (ngx_http_lua_shdict_expire(ctx, 0) == 0) {
    1190           0 :                 break;
    1191             :             }
    1192             : 
    1193           0 :             forcible = 1;
    1194             : 
    1195           0 :             node = ngx_slab_alloc_locked(ctx->shpool, n);
    1196           0 :             if (node != NULL) {
    1197           0 :                 goto allocated;
    1198             :             }
    1199             :         }
    1200             : 
    1201           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
    1202             : 
    1203           0 :         lua_pushboolean(L, 0);
    1204           0 :         lua_pushliteral(L, "no memory");
    1205           0 :         lua_pushboolean(L, forcible);
    1206           0 :         return 3;
    1207             :     }
    1208             : 
    1209           0 : allocated:
    1210             : 
    1211           0 :     sd = (ngx_http_lua_shdict_node_t *) &node->color;
    1212             : 
    1213           0 :     node->key = hash;
    1214           0 :     sd->key_len = (u_short) key.len;
    1215             : 
    1216           0 :     if (exptime > 0) {
    1217           0 :         tp = ngx_timeofday();
    1218           0 :         sd->expires = (uint64_t) tp->sec * 1000 + tp->msec
    1219           0 :                       + (uint64_t) (exptime * 1000);
    1220             : 
    1221             :     } else {
    1222           0 :         sd->expires = 0;
    1223             :     }
    1224             : 
    1225           0 :     sd->user_flags = user_flags;
    1226             : 
    1227           0 :     sd->value_len = (uint32_t) value.len;
    1228             : 
    1229             :     dd("setting value type to %d", value_type);
    1230             : 
    1231           0 :     sd->value_type = (uint8_t) value_type;
    1232             : 
    1233           0 :     p = ngx_copy(sd->data, key.data, key.len);
    1234           0 :     ngx_memcpy(p, value.data, value.len);
    1235             : 
    1236           0 :     ngx_rbtree_insert(&ctx->sh->rbtree, node);
    1237             : 
    1238           0 :     ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue);
    1239             : 
    1240           0 :     ngx_shmtx_unlock(&ctx->shpool->mutex);
    1241             : 
    1242           0 :     lua_pushboolean(L, 1);
    1243           0 :     lua_pushnil(L);
    1244           0 :     lua_pushboolean(L, forcible);
    1245           0 :     return 3;
    1246             : }
    1247             : 
    1248             : 
    1249             : static int
    1250           0 : ngx_http_lua_shdict_incr(lua_State *L)
    1251             : {
    1252             :     int                          i, n;
    1253             :     ngx_str_t                    key;
    1254             :     uint32_t                     hash;
    1255             :     ngx_int_t                    rc;
    1256             :     ngx_http_lua_shdict_ctx_t   *ctx;
    1257             :     ngx_http_lua_shdict_node_t  *sd;
    1258             :     double                       num;
    1259           0 :     double                       init = 0;
    1260             :     u_char                      *p;
    1261             :     ngx_shm_zone_t              *zone;
    1262             :     double                       value;
    1263             :     ngx_rbtree_node_t           *node;
    1264             :                          /* indicates whether to foricibly override other
    1265             :                           * valid entries */
    1266           0 :     int                          forcible = 0;
    1267             :     ngx_queue_t                 *queue, *q;
    1268             : 
    1269           0 :     n = lua_gettop(L);
    1270             : 
    1271           0 :     if (n != 3 && n != 4) {
    1272           0 :         return luaL_error(L, "expecting 3 or 4 arguments, but only seen %d", n);
    1273             :     }
    1274             : 
    1275           0 :     if (lua_type(L, 1) != LUA_TTABLE) {
    1276           0 :         return luaL_error(L, "bad \"zone\" argument");
    1277             :     }
    1278             : 
    1279           0 :     zone = ngx_http_lua_shdict_get_zone(L, 1);
    1280           0 :     if (zone == NULL) {
    1281           0 :         return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer");
    1282             :     }
    1283             : 
    1284           0 :     ctx = zone->data;
    1285             : 
    1286           0 :     if (lua_isnil(L, 2)) {
    1287           0 :         lua_pushnil(L);
    1288           0 :         lua_pushliteral(L, "nil key");
    1289           0 :         return 2;
    1290             :     }
    1291             : 
    1292           0 :     key.data = (u_char *) luaL_checklstring(L, 2, &key.len);
    1293             : 
    1294           0 :     if (key.len == 0) {
    1295           0 :         lua_pushnil(L);
    1296           0 :         lua_pushliteral(L, "empty key");
    1297           0 :         return 2;
    1298             :     }
    1299             : 
    1300           0 :     if (key.len > 65535) {
    1301           0 :         lua_pushnil(L);
    1302           0 :         lua_pushliteral(L, "key too long");
    1303           0 :         return 2;
    1304             :     }
    1305             : 
    1306           0 :     hash = ngx_crc32_short(key.data, key.len);
    1307             : 
    1308           0 :     value = luaL_checknumber(L, 3);
    1309             : 
    1310           0 :     if (n == 4) {
    1311           0 :         init = luaL_checknumber(L, 4);
    1312             :     }
    1313             : 
    1314             :     dd("looking up key %.*s in shared dict %.*s", (int) key.len, key.data,
    1315             :        (int) ctx->name.len, ctx->name.data);
    1316             : 
    1317           0 :     ngx_shmtx_lock(&ctx->shpool->mutex);
    1318             : 
    1319             : #if 1
    1320           0 :     ngx_http_lua_shdict_expire(ctx, 1);
    1321             : #endif
    1322             : 
    1323           0 :     rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd);
    1324             : 
    1325             :     dd("shdict lookup returned %d", (int) rc);
    1326             : 
    1327           0 :     if (rc == NGX_DECLINED || rc == NGX_DONE) {
    1328             : 
    1329           0 :         if (n == 3) {
    1330           0 :             ngx_shmtx_unlock(&ctx->shpool->mutex);
    1331             : 
    1332           0 :             lua_pushnil(L);
    1333           0 :             lua_pushliteral(L, "not found");
    1334           0 :             return 2;
    1335             :         }
    1336             : 
    1337             :         /* add value */
    1338           0 :         num = value + init;
    1339             : 
    1340           0 :         if (rc == NGX_DONE) {
    1341             : 
    1342             :             /* found an expired item */
    1343             : 
    1344           0 :             if ((size_t) sd->value_len == sizeof(double)
    1345           0 :                 && sd->value_type != SHDICT_TLIST)
    1346             :             {
    1347           0 :                 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
    1348             :                                "lua shared dict incr: found old entry and "
    1349             :                                "value size matched, reusing it");
    1350             : 
    1351           0 :                 ngx_queue_remove(&sd->queue);
    1352           0 :                 ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue);
    1353             : 
    1354             :                 dd("go to setvalue");
    1355           0 :                 goto setvalue;
    1356             :             }
    1357             : 
    1358             :             dd("go to remove");
    1359           0 :             goto remove;
    1360             :         }
    1361             : 
    1362             :         dd("go to insert");
    1363           0 :         goto insert;
    1364             :     }
    1365             : 
    1366             :     /* rc == NGX_OK */
    1367             : 
    1368           0 :     if (sd->value_type != SHDICT_TNUMBER || sd->value_len != sizeof(double)) {
    1369           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
    1370             : 
    1371           0 :         lua_pushnil(L);
    1372           0 :         lua_pushliteral(L, "not a number");
    1373           0 :         return 2;
    1374             :     }
    1375             : 
    1376           0 :     ngx_queue_remove(&sd->queue);
    1377           0 :     ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue);
    1378             : 
    1379             :     dd("setting value type to %d", (int) sd->value_type);
    1380             : 
    1381           0 :     p = sd->data + key.len;
    1382             : 
    1383           0 :     ngx_memcpy(&num, p, sizeof(double));
    1384           0 :     num += value;
    1385             : 
    1386           0 :     ngx_memcpy(p, (double *) &num, sizeof(double));
    1387             : 
    1388           0 :     ngx_shmtx_unlock(&ctx->shpool->mutex);
    1389             : 
    1390           0 :     lua_pushnumber(L, num);
    1391           0 :     lua_pushnil(L);
    1392           0 :     return 2;
    1393             : 
    1394           0 : remove:
    1395             : 
    1396           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
    1397             :                    "lua shared dict incr: found old entry but value size "
    1398             :                    "NOT matched, removing it first");
    1399             : 
    1400           0 :     if (sd->value_type == SHDICT_TLIST) {
    1401           0 :         queue = ngx_http_lua_shdict_get_list_head(sd, key.len);
    1402             : 
    1403           0 :         for (q = ngx_queue_head(queue);
    1404             :              q != ngx_queue_sentinel(queue);
    1405           0 :              q = ngx_queue_next(q))
    1406             :         {
    1407           0 :             p = (u_char *) ngx_queue_data(q,
    1408             :                                           ngx_http_lua_shdict_list_node_t,
    1409             :                                           queue);
    1410             : 
    1411           0 :             ngx_slab_free_locked(ctx->shpool, p);
    1412             :         }
    1413             :     }
    1414             : 
    1415           0 :     ngx_queue_remove(&sd->queue);
    1416             : 
    1417           0 :     node = (ngx_rbtree_node_t *)
    1418           0 :                ((u_char *) sd - offsetof(ngx_rbtree_node_t, color));
    1419             : 
    1420           0 :     ngx_rbtree_delete(&ctx->sh->rbtree, node);
    1421             : 
    1422           0 :     ngx_slab_free_locked(ctx->shpool, node);
    1423             : 
    1424           0 : insert:
    1425             : 
    1426           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
    1427             :                    "lua shared dict incr: creating a new entry");
    1428             : 
    1429           0 :     n = offsetof(ngx_rbtree_node_t, color)
    1430             :         + offsetof(ngx_http_lua_shdict_node_t, data)
    1431           0 :         + key.len
    1432           0 :         + sizeof(double);
    1433             : 
    1434           0 :     node = ngx_slab_alloc_locked(ctx->shpool, n);
    1435             : 
    1436           0 :     if (node == NULL) {
    1437             : 
    1438           0 :         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
    1439             :                        "lua shared dict incr: overriding non-expired items "
    1440             :                        "due to memory shortage for entry \"%V\"", &key);
    1441             : 
    1442           0 :         for (i = 0; i < 30; i++) {
    1443           0 :             if (ngx_http_lua_shdict_expire(ctx, 0) == 0) {
    1444           0 :                 break;
    1445             :             }
    1446             : 
    1447           0 :             forcible = 1;
    1448             : 
    1449           0 :             node = ngx_slab_alloc_locked(ctx->shpool, n);
    1450           0 :             if (node != NULL) {
    1451           0 :                 goto allocated;
    1452             :             }
    1453             :         }
    1454             : 
    1455           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
    1456             : 
    1457           0 :         lua_pushboolean(L, 0);
    1458           0 :         lua_pushliteral(L, "no memory");
    1459           0 :         lua_pushboolean(L, forcible);
    1460           0 :         return 3;
    1461             :     }
    1462             : 
    1463           0 : allocated:
    1464             : 
    1465           0 :     sd = (ngx_http_lua_shdict_node_t *) &node->color;
    1466             : 
    1467           0 :     node->key = hash;
    1468             : 
    1469           0 :     sd->key_len = (u_short) key.len;
    1470             : 
    1471           0 :     sd->value_len = (uint32_t) sizeof(double);
    1472             : 
    1473           0 :     ngx_rbtree_insert(&ctx->sh->rbtree, node);
    1474             : 
    1475           0 :     ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue);
    1476             : 
    1477           0 : setvalue:
    1478             : 
    1479           0 :     sd->user_flags = 0;
    1480             : 
    1481           0 :     sd->expires = 0;
    1482             : 
    1483             :     dd("setting value type to %d", LUA_TNUMBER);
    1484             : 
    1485           0 :     sd->value_type = (uint8_t) LUA_TNUMBER;
    1486             : 
    1487           0 :     p = ngx_copy(sd->data, key.data, key.len);
    1488           0 :     ngx_memcpy(p, (double *) &num, sizeof(double));
    1489             : 
    1490           0 :     ngx_shmtx_unlock(&ctx->shpool->mutex);
    1491             : 
    1492           0 :     lua_pushnumber(L, num);
    1493           0 :     lua_pushnil(L);
    1494           0 :     lua_pushboolean(L, forcible);
    1495           0 :     return 3;
    1496             : }
    1497             : 
    1498             : 
    1499             : ngx_int_t
    1500           0 : ngx_http_lua_shared_dict_get(ngx_shm_zone_t *zone, u_char *key_data,
    1501             :     size_t key_len, ngx_http_lua_value_t *value)
    1502             : {
    1503             :     u_char                      *data;
    1504             :     size_t                       len;
    1505             :     uint32_t                     hash;
    1506             :     ngx_int_t                    rc;
    1507             :     ngx_http_lua_shdict_ctx_t   *ctx;
    1508             :     ngx_http_lua_shdict_node_t  *sd;
    1509             : 
    1510           0 :     if (zone == NULL) {
    1511           0 :         return NGX_ERROR;
    1512             :     }
    1513             : 
    1514           0 :     hash = ngx_crc32_short(key_data, key_len);
    1515             : 
    1516           0 :     ctx = zone->data;
    1517             : 
    1518           0 :     ngx_shmtx_lock(&ctx->shpool->mutex);
    1519             : 
    1520           0 :     rc = ngx_http_lua_shdict_lookup(zone, hash, key_data, key_len, &sd);
    1521             : 
    1522             :     dd("shdict lookup returned %d", (int) rc);
    1523             : 
    1524           0 :     if (rc == NGX_DECLINED || rc == NGX_DONE) {
    1525           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
    1526             : 
    1527           0 :         return rc;
    1528             :     }
    1529             : 
    1530             :     /* rc == NGX_OK */
    1531             : 
    1532           0 :     value->type = sd->value_type;
    1533             : 
    1534             :     dd("type: %d", (int) value->type);
    1535             : 
    1536           0 :     data = sd->data + sd->key_len;
    1537           0 :     len = (size_t) sd->value_len;
    1538             : 
    1539           0 :     switch (value->type) {
    1540             : 
    1541           0 :     case SHDICT_TSTRING:
    1542             : 
    1543           0 :         if (value->value.s.data == NULL || value->value.s.len == 0) {
    1544           0 :             ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "no string buffer "
    1545             :                           "initialized");
    1546           0 :             ngx_shmtx_unlock(&ctx->shpool->mutex);
    1547           0 :             return NGX_ERROR;
    1548             :         }
    1549             : 
    1550           0 :         if (len > value->value.s.len) {
    1551           0 :             len = value->value.s.len;
    1552             : 
    1553             :         } else {
    1554           0 :             value->value.s.len = len;
    1555             :         }
    1556             : 
    1557           0 :         ngx_memcpy(value->value.s.data, data, len);
    1558           0 :         break;
    1559             : 
    1560           0 :     case SHDICT_TNUMBER:
    1561             : 
    1562           0 :         if (len != sizeof(double)) {
    1563           0 :             ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "bad lua number "
    1564             :                           "value size found for key %*s: %lu", key_len,
    1565             :                           key_data, (unsigned long) len);
    1566             : 
    1567           0 :             ngx_shmtx_unlock(&ctx->shpool->mutex);
    1568           0 :             return NGX_ERROR;
    1569             :         }
    1570             : 
    1571           0 :         ngx_memcpy(&value->value.b, data, len);
    1572           0 :         break;
    1573             : 
    1574           0 :     case SHDICT_TBOOLEAN:
    1575             : 
    1576           0 :         if (len != sizeof(u_char)) {
    1577           0 :             ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "bad lua boolean "
    1578             :                           "value size found for key %*s: %lu", key_len,
    1579             :                           key_data, (unsigned long) len);
    1580             : 
    1581           0 :             ngx_shmtx_unlock(&ctx->shpool->mutex);
    1582           0 :             return NGX_ERROR;
    1583             :         }
    1584             : 
    1585           0 :         value->value.b = *data;
    1586           0 :         break;
    1587             : 
    1588           0 :     default:
    1589           0 :         ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "bad lua value type "
    1590             :                       "found for key %*s: %d", key_len, key_data,
    1591             :                       (int) value->type);
    1592             : 
    1593           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
    1594           0 :         return NGX_ERROR;
    1595             :     }
    1596             : 
    1597           0 :     ngx_shmtx_unlock(&ctx->shpool->mutex);
    1598           0 :     return NGX_OK;
    1599             : }
    1600             : 
    1601             : 
    1602             : static int
    1603           0 : ngx_http_lua_shdict_lpush(lua_State *L)
    1604             : {
    1605           0 :     return ngx_http_lua_shdict_push_helper(L, NGX_HTTP_LUA_SHDICT_LEFT);
    1606             : }
    1607             : 
    1608             : 
    1609             : static int
    1610           0 : ngx_http_lua_shdict_rpush(lua_State *L)
    1611             : {
    1612           0 :     return ngx_http_lua_shdict_push_helper(L, NGX_HTTP_LUA_SHDICT_RIGHT);
    1613             : }
    1614             : 
    1615             : 
    1616             : static int
    1617           0 : ngx_http_lua_shdict_push_helper(lua_State *L, int flags)
    1618             : {
    1619             :     int                              n;
    1620             :     ngx_str_t                        key;
    1621             :     uint32_t                         hash;
    1622             :     ngx_int_t                        rc;
    1623             :     ngx_http_lua_shdict_ctx_t       *ctx;
    1624             :     ngx_http_lua_shdict_node_t      *sd;
    1625             :     ngx_str_t                        value;
    1626             :     int                              value_type;
    1627             :     double                           num;
    1628             :     ngx_rbtree_node_t               *node;
    1629             :     ngx_shm_zone_t                  *zone;
    1630             :     ngx_queue_t                     *queue, *q;
    1631             :     ngx_http_lua_shdict_list_node_t *lnode;
    1632             : 
    1633           0 :     n = lua_gettop(L);
    1634             : 
    1635           0 :     if (n != 3) {
    1636           0 :         return luaL_error(L, "expecting 3 arguments, "
    1637             :                           "but only seen %d", n);
    1638             :     }
    1639             : 
    1640           0 :     if (lua_type(L, 1) != LUA_TTABLE) {
    1641           0 :         return luaL_error(L, "bad \"zone\" argument");
    1642             :     }
    1643             : 
    1644           0 :     zone = ngx_http_lua_shdict_get_zone(L, 1);
    1645           0 :     if (zone == NULL) {
    1646           0 :         return luaL_error(L, "bad \"zone\" argument");
    1647             :     }
    1648             : 
    1649           0 :     ctx = zone->data;
    1650             : 
    1651           0 :     if (lua_isnil(L, 2)) {
    1652           0 :         lua_pushnil(L);
    1653           0 :         lua_pushliteral(L, "nil key");
    1654           0 :         return 2;
    1655             :     }
    1656             : 
    1657           0 :     key.data = (u_char *) luaL_checklstring(L, 2, &key.len);
    1658             : 
    1659           0 :     if (key.len == 0) {
    1660           0 :         lua_pushnil(L);
    1661           0 :         lua_pushliteral(L, "empty key");
    1662           0 :         return 2;
    1663             :     }
    1664             : 
    1665           0 :     if (key.len > 65535) {
    1666           0 :         lua_pushnil(L);
    1667           0 :         lua_pushliteral(L, "key too long");
    1668           0 :         return 2;
    1669             :     }
    1670             : 
    1671           0 :     hash = ngx_crc32_short(key.data, key.len);
    1672             : 
    1673           0 :     value_type = lua_type(L, 3);
    1674             : 
    1675           0 :     switch (value_type) {
    1676             : 
    1677           0 :     case SHDICT_TSTRING:
    1678           0 :         value.data = (u_char *) lua_tolstring(L, 3, &value.len);
    1679           0 :         break;
    1680             : 
    1681           0 :     case SHDICT_TNUMBER:
    1682           0 :         value.len = sizeof(double);
    1683           0 :         num = lua_tonumber(L, 3);
    1684           0 :         value.data = (u_char *) &num;
    1685           0 :         break;
    1686             : 
    1687           0 :     default:
    1688           0 :         lua_pushnil(L);
    1689           0 :         lua_pushliteral(L, "bad value type");
    1690           0 :         return 2;
    1691             :     }
    1692             : 
    1693           0 :     ngx_shmtx_lock(&ctx->shpool->mutex);
    1694             : 
    1695             : #if 1
    1696           0 :     ngx_http_lua_shdict_expire(ctx, 1);
    1697             : #endif
    1698             : 
    1699           0 :     rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd);
    1700             : 
    1701             :     dd("shdict lookup returned %d", (int) rc);
    1702             : 
    1703             :     /* exists but expired */
    1704             : 
    1705           0 :     if (rc == NGX_DONE) {
    1706             : 
    1707           0 :         if (sd->value_type != SHDICT_TLIST) {
    1708             :             /* TODO: reuse when length matched */
    1709             : 
    1710           0 :             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
    1711             :                            "lua shared dict push: found old entry and value "
    1712             :                            "type not matched, remove it first");
    1713             : 
    1714           0 :             ngx_queue_remove(&sd->queue);
    1715             : 
    1716           0 :             node = (ngx_rbtree_node_t *)
    1717           0 :                         ((u_char *) sd - offsetof(ngx_rbtree_node_t, color));
    1718             : 
    1719           0 :             ngx_rbtree_delete(&ctx->sh->rbtree, node);
    1720             : 
    1721           0 :             ngx_slab_free_locked(ctx->shpool, node);
    1722             : 
    1723             :             dd("go to init_list");
    1724           0 :             goto init_list;
    1725             :         }
    1726             : 
    1727           0 :         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
    1728             :                        "lua shared dict push: found old entry and value "
    1729             :                        "type matched, reusing it");
    1730             : 
    1731           0 :         sd->expires = 0;
    1732             : 
    1733             :         /* free list nodes */
    1734             : 
    1735           0 :         queue = ngx_http_lua_shdict_get_list_head(sd, key.len);
    1736             : 
    1737           0 :         for (q = ngx_queue_head(queue);
    1738             :              q != ngx_queue_sentinel(queue);
    1739           0 :              q = ngx_queue_next(q))
    1740             :         {
    1741             :             /* TODO: reuse matched size list node */
    1742           0 :             lnode = ngx_queue_data(q, ngx_http_lua_shdict_list_node_t, queue);
    1743           0 :             ngx_slab_free_locked(ctx->shpool, lnode);
    1744             :         }
    1745             : 
    1746           0 :         ngx_queue_init(queue);
    1747             : 
    1748           0 :         ngx_queue_remove(&sd->queue);
    1749           0 :         ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue);
    1750             : 
    1751             :         dd("go to push_node");
    1752           0 :         goto push_node;
    1753             :     }
    1754             : 
    1755             :     /* exists and not expired */
    1756             : 
    1757           0 :     if (rc == NGX_OK) {
    1758             : 
    1759           0 :         if (sd->value_type != SHDICT_TLIST) {
    1760           0 :             ngx_shmtx_unlock(&ctx->shpool->mutex);
    1761             : 
    1762           0 :             lua_pushnil(L);
    1763           0 :             lua_pushliteral(L, "value not a list");
    1764           0 :             return 2;
    1765             :         }
    1766             : 
    1767           0 :         queue = ngx_http_lua_shdict_get_list_head(sd, key.len);
    1768             : 
    1769           0 :         ngx_queue_remove(&sd->queue);
    1770           0 :         ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue);
    1771             : 
    1772             :         dd("go to push_node");
    1773           0 :         goto push_node;
    1774             :     }
    1775             : 
    1776             :     /* rc == NGX_DECLINED, not found */
    1777             : 
    1778           0 : init_list:
    1779             : 
    1780           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
    1781             :                    "lua shared dict list: creating a new entry");
    1782             : 
    1783             :     /* NOTICE: we assume the begin point aligned in slab, be careful */
    1784           0 :     n = offsetof(ngx_rbtree_node_t, color)
    1785             :         + offsetof(ngx_http_lua_shdict_node_t, data)
    1786           0 :         + key.len
    1787           0 :         + sizeof(ngx_queue_t);
    1788             : 
    1789             :     dd("length before aligned: %d", n);
    1790             : 
    1791           0 :     n = (int) (uintptr_t) ngx_align_ptr(n, NGX_ALIGNMENT);
    1792             : 
    1793             :     dd("length after aligned: %d", n);
    1794             : 
    1795           0 :     node = ngx_slab_alloc_locked(ctx->shpool, n);
    1796             : 
    1797           0 :     if (node == NULL) {
    1798           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
    1799             : 
    1800           0 :         lua_pushboolean(L, 0);
    1801           0 :         lua_pushliteral(L, "no memory");
    1802           0 :         return 2;
    1803             :     }
    1804             : 
    1805           0 :     sd = (ngx_http_lua_shdict_node_t *) &node->color;
    1806             : 
    1807           0 :     queue = ngx_http_lua_shdict_get_list_head(sd, key.len);
    1808             : 
    1809           0 :     node->key = hash;
    1810           0 :     sd->key_len = (u_short) key.len;
    1811             : 
    1812           0 :     sd->expires = 0;
    1813             : 
    1814           0 :     sd->value_len = 0;
    1815             : 
    1816             :     dd("setting value type to %d", (int) SHDICT_TLIST);
    1817             : 
    1818           0 :     sd->value_type = (uint8_t) SHDICT_TLIST;
    1819             : 
    1820           0 :     ngx_memcpy(sd->data, key.data, key.len);
    1821             : 
    1822           0 :     ngx_queue_init(queue);
    1823             : 
    1824           0 :     ngx_rbtree_insert(&ctx->sh->rbtree, node);
    1825             : 
    1826           0 :     ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue);
    1827             : 
    1828           0 : push_node:
    1829             : 
    1830           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
    1831             :                    "lua shared dict list: creating a new list node");
    1832             : 
    1833           0 :     n = offsetof(ngx_http_lua_shdict_list_node_t, data)
    1834           0 :         + value.len;
    1835             : 
    1836             :     dd("list node length: %d", n);
    1837             : 
    1838           0 :     lnode = ngx_slab_alloc_locked(ctx->shpool, n);
    1839             : 
    1840           0 :     if (lnode == NULL) {
    1841             : 
    1842           0 :         if (sd->value_len == 0) {
    1843             : 
    1844           0 :             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
    1845             :                            "lua shared dict list: no memory for create"
    1846             :                            " list node and list empty, remove it");
    1847             : 
    1848           0 :             ngx_queue_remove(&sd->queue);
    1849             : 
    1850           0 :             node = (ngx_rbtree_node_t *)
    1851           0 :                         ((u_char *) sd - offsetof(ngx_rbtree_node_t, color));
    1852             : 
    1853           0 :             ngx_rbtree_delete(&ctx->sh->rbtree, node);
    1854             : 
    1855           0 :             ngx_slab_free_locked(ctx->shpool, node);
    1856             :         }
    1857             : 
    1858           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
    1859             : 
    1860           0 :         lua_pushboolean(L, 0);
    1861           0 :         lua_pushliteral(L, "no memory");
    1862           0 :         return 2;
    1863             :     }
    1864             : 
    1865             :     dd("setting list length to %d", sd->value_len + 1);
    1866             : 
    1867           0 :     sd->value_len = sd->value_len + 1;
    1868             : 
    1869             :     dd("setting list node value length to %d", (int) value.len);
    1870             : 
    1871           0 :     lnode->value_len = (uint32_t) value.len;
    1872             : 
    1873             :     dd("setting list node value type to %d", value_type);
    1874             : 
    1875           0 :     lnode->value_type = (uint8_t) value_type;
    1876             : 
    1877           0 :     ngx_memcpy(lnode->data, value.data, value.len);
    1878             : 
    1879           0 :     if (flags == NGX_HTTP_LUA_SHDICT_LEFT) {
    1880           0 :         ngx_queue_insert_head(queue, &lnode->queue);
    1881             : 
    1882             :     } else {
    1883           0 :         ngx_queue_insert_tail(queue, &lnode->queue);
    1884             :     }
    1885             : 
    1886           0 :     ngx_shmtx_unlock(&ctx->shpool->mutex);
    1887             : 
    1888           0 :     lua_pushnumber(L, sd->value_len);
    1889           0 :     return 1;
    1890             : }
    1891             : 
    1892             : 
    1893             : static int
    1894           0 : ngx_http_lua_shdict_lpop(lua_State *L)
    1895             : {
    1896           0 :     return ngx_http_lua_shdict_pop_helper(L, NGX_HTTP_LUA_SHDICT_LEFT);
    1897             : }
    1898             : 
    1899             : 
    1900             : static int
    1901           0 : ngx_http_lua_shdict_rpop(lua_State *L)
    1902             : {
    1903           0 :     return ngx_http_lua_shdict_pop_helper(L, NGX_HTTP_LUA_SHDICT_RIGHT);
    1904             : }
    1905             : 
    1906             : 
    1907             : static int
    1908           0 : ngx_http_lua_shdict_pop_helper(lua_State *L, int flags)
    1909             : {
    1910             :     int                              n;
    1911             :     ngx_str_t                        name;
    1912             :     ngx_str_t                        key;
    1913             :     uint32_t                         hash;
    1914             :     ngx_int_t                        rc;
    1915             :     ngx_http_lua_shdict_ctx_t       *ctx;
    1916             :     ngx_http_lua_shdict_node_t      *sd;
    1917             :     ngx_str_t                        value;
    1918             :     int                              value_type;
    1919             :     double                           num;
    1920             :     ngx_rbtree_node_t               *node;
    1921             :     ngx_shm_zone_t                  *zone;
    1922             :     ngx_queue_t                     *queue;
    1923             :     ngx_http_lua_shdict_list_node_t *lnode;
    1924             : 
    1925           0 :     n = lua_gettop(L);
    1926             : 
    1927           0 :     if (n != 2) {
    1928           0 :         return luaL_error(L, "expecting 2 arguments, "
    1929             :                           "but only seen %d", n);
    1930             :     }
    1931             : 
    1932           0 :     if (lua_type(L, 1) != LUA_TTABLE) {
    1933           0 :         return luaL_error(L, "bad \"zone\" argument");
    1934             :     }
    1935             : 
    1936           0 :     zone = ngx_http_lua_shdict_get_zone(L, 1);
    1937           0 :     if (zone == NULL) {
    1938           0 :         return luaL_error(L, "bad \"zone\" argument");
    1939             :     }
    1940             : 
    1941           0 :     ctx = zone->data;
    1942           0 :     name = ctx->name;
    1943             : 
    1944           0 :     if (lua_isnil(L, 2)) {
    1945           0 :         lua_pushnil(L);
    1946           0 :         lua_pushliteral(L, "nil key");
    1947           0 :         return 2;
    1948             :     }
    1949             : 
    1950           0 :     key.data = (u_char *) luaL_checklstring(L, 2, &key.len);
    1951             : 
    1952           0 :     if (key.len == 0) {
    1953           0 :         lua_pushnil(L);
    1954           0 :         lua_pushliteral(L, "empty key");
    1955           0 :         return 2;
    1956             :     }
    1957             : 
    1958           0 :     if (key.len > 65535) {
    1959           0 :         lua_pushnil(L);
    1960           0 :         lua_pushliteral(L, "key too long");
    1961           0 :         return 2;
    1962             :     }
    1963             : 
    1964           0 :     hash = ngx_crc32_short(key.data, key.len);
    1965             : 
    1966           0 :     ngx_shmtx_lock(&ctx->shpool->mutex);
    1967             : 
    1968             : #if 1
    1969           0 :     ngx_http_lua_shdict_expire(ctx, 1);
    1970             : #endif
    1971             : 
    1972           0 :     rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd);
    1973             : 
    1974             :     dd("shdict lookup returned %d", (int) rc);
    1975             : 
    1976           0 :     if (rc == NGX_DECLINED || rc == NGX_DONE) {
    1977           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
    1978           0 :         lua_pushnil(L);
    1979           0 :         return 1;
    1980             :     }
    1981             : 
    1982             :     /* rc == NGX_OK */
    1983             : 
    1984           0 :     if (sd->value_type != SHDICT_TLIST) {
    1985           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
    1986             : 
    1987           0 :         lua_pushnil(L);
    1988           0 :         lua_pushliteral(L, "value not a list");
    1989           0 :         return 2;
    1990             :     }
    1991             : 
    1992           0 :     if (sd->value_len <= 0) {
    1993           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
    1994             : 
    1995           0 :         return luaL_error(L, "bad lua list length found for key %s "
    1996             :                           "in shared_dict %s: %lu", key.data, name.data,
    1997           0 :                           (unsigned long) sd->value_len);
    1998             :     }
    1999             : 
    2000           0 :     queue = ngx_http_lua_shdict_get_list_head(sd, key.len);
    2001             : 
    2002           0 :     if (flags == NGX_HTTP_LUA_SHDICT_LEFT) {
    2003           0 :         queue = ngx_queue_head(queue);
    2004             : 
    2005             :     } else {
    2006           0 :         queue = ngx_queue_last(queue);
    2007             :     }
    2008             : 
    2009           0 :     lnode = ngx_queue_data(queue, ngx_http_lua_shdict_list_node_t, queue);
    2010             : 
    2011           0 :     value_type = lnode->value_type;
    2012             : 
    2013             :     dd("data: %p", lnode->data);
    2014             :     dd("value len: %d", (int) sd->value_len);
    2015             : 
    2016           0 :     value.data = lnode->data;
    2017           0 :     value.len = (size_t) lnode->value_len;
    2018             : 
    2019           0 :     switch (value_type) {
    2020             : 
    2021           0 :     case SHDICT_TSTRING:
    2022             : 
    2023           0 :         lua_pushlstring(L, (char *) value.data, value.len);
    2024           0 :         break;
    2025             : 
    2026           0 :     case SHDICT_TNUMBER:
    2027             : 
    2028           0 :         if (value.len != sizeof(double)) {
    2029             : 
    2030           0 :             ngx_shmtx_unlock(&ctx->shpool->mutex);
    2031             : 
    2032           0 :             return luaL_error(L, "bad lua list node number value size found "
    2033             :                               "for key %s in shared_dict %s: %lu", key.data,
    2034           0 :                               name.data, (unsigned long) value.len);
    2035             :         }
    2036             : 
    2037           0 :         ngx_memcpy(&num, value.data, sizeof(double));
    2038             : 
    2039           0 :         lua_pushnumber(L, num);
    2040           0 :         break;
    2041             : 
    2042           0 :     default:
    2043             : 
    2044           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
    2045             : 
    2046           0 :         return luaL_error(L, "bad list node value type found for key %s in "
    2047             :                           "shared_dict %s: %d", key.data, name.data,
    2048             :                           value_type);
    2049             :     }
    2050             : 
    2051           0 :     ngx_queue_remove(queue);
    2052             : 
    2053           0 :     ngx_slab_free_locked(ctx->shpool, lnode);
    2054             : 
    2055           0 :     if (sd->value_len == 1) {
    2056             : 
    2057           0 :         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
    2058             :                        "lua shared dict list: empty node after pop, "
    2059             :                        "remove it");
    2060             : 
    2061           0 :         ngx_queue_remove(&sd->queue);
    2062             : 
    2063           0 :         node = (ngx_rbtree_node_t *)
    2064           0 :                     ((u_char *) sd - offsetof(ngx_rbtree_node_t, color));
    2065             : 
    2066           0 :         ngx_rbtree_delete(&ctx->sh->rbtree, node);
    2067             : 
    2068           0 :         ngx_slab_free_locked(ctx->shpool, node);
    2069             : 
    2070             :     } else {
    2071           0 :         sd->value_len = sd->value_len - 1;
    2072             : 
    2073           0 :         ngx_queue_remove(&sd->queue);
    2074           0 :         ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue);
    2075             :     }
    2076             : 
    2077           0 :     ngx_shmtx_unlock(&ctx->shpool->mutex);
    2078             : 
    2079           0 :     return 1;
    2080             : }
    2081             : 
    2082             : 
    2083             : static int
    2084           0 : ngx_http_lua_shdict_llen(lua_State *L)
    2085             : {
    2086             :     int                          n;
    2087             :     ngx_str_t                    key;
    2088             :     uint32_t                     hash;
    2089             :     ngx_int_t                    rc;
    2090             :     ngx_http_lua_shdict_ctx_t   *ctx;
    2091             :     ngx_http_lua_shdict_node_t  *sd;
    2092             :     ngx_shm_zone_t              *zone;
    2093             : 
    2094           0 :     n = lua_gettop(L);
    2095             : 
    2096           0 :     if (n != 2) {
    2097           0 :         return luaL_error(L, "expecting 2 arguments, "
    2098             :                           "but only seen %d", n);
    2099             :     }
    2100             : 
    2101           0 :     if (lua_type(L, 1) != LUA_TTABLE) {
    2102           0 :         return luaL_error(L, "bad \"zone\" argument");
    2103             :     }
    2104             : 
    2105           0 :     zone = ngx_http_lua_shdict_get_zone(L, 1);
    2106           0 :     if (zone == NULL) {
    2107           0 :         return luaL_error(L, "bad \"zone\" argument");
    2108             :     }
    2109             : 
    2110           0 :     ctx = zone->data;
    2111             : 
    2112           0 :     if (lua_isnil(L, 2)) {
    2113           0 :         lua_pushnil(L);
    2114           0 :         lua_pushliteral(L, "nil key");
    2115           0 :         return 2;
    2116             :     }
    2117             : 
    2118           0 :     key.data = (u_char *) luaL_checklstring(L, 2, &key.len);
    2119             : 
    2120           0 :     if (key.len == 0) {
    2121           0 :         lua_pushnil(L);
    2122           0 :         lua_pushliteral(L, "empty key");
    2123           0 :         return 2;
    2124             :     }
    2125             : 
    2126           0 :     if (key.len > 65535) {
    2127           0 :         lua_pushnil(L);
    2128           0 :         lua_pushliteral(L, "key too long");
    2129           0 :         return 2;
    2130             :     }
    2131             : 
    2132           0 :     hash = ngx_crc32_short(key.data, key.len);
    2133             : 
    2134           0 :     ngx_shmtx_lock(&ctx->shpool->mutex);
    2135             : 
    2136             : #if 1
    2137           0 :     ngx_http_lua_shdict_expire(ctx, 1);
    2138             : #endif
    2139             : 
    2140           0 :     rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd);
    2141             : 
    2142             :     dd("shdict lookup returned %d", (int) rc);
    2143             : 
    2144           0 :     if (rc == NGX_OK) {
    2145             : 
    2146           0 :         if (sd->value_type != SHDICT_TLIST) {
    2147           0 :             ngx_shmtx_unlock(&ctx->shpool->mutex);
    2148             : 
    2149           0 :             lua_pushnil(L);
    2150           0 :             lua_pushliteral(L, "value not a list");
    2151           0 :             return 2;
    2152             :         }
    2153             : 
    2154           0 :         ngx_queue_remove(&sd->queue);
    2155           0 :         ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue);
    2156             : 
    2157           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
    2158             : 
    2159           0 :         lua_pushnumber(L, (lua_Number) sd->value_len);
    2160           0 :         return 1;
    2161             :     }
    2162             : 
    2163           0 :     ngx_shmtx_unlock(&ctx->shpool->mutex);
    2164             : 
    2165           0 :     lua_pushnumber(L, 0);
    2166           0 :     return 1;
    2167             : }
    2168             : 
    2169             : 
    2170             : ngx_shm_zone_t *
    2171           0 : ngx_http_lua_find_zone(u_char *name_data, size_t name_len)
    2172             : {
    2173             :     ngx_str_t                       *name;
    2174             :     ngx_uint_t                       i;
    2175             :     ngx_shm_zone_t                  *zone;
    2176             :     ngx_http_lua_shm_zone_ctx_t     *ctx;
    2177             :     volatile ngx_list_part_t        *part;
    2178             : 
    2179           0 :     part = &ngx_cycle->shared_memory.part;
    2180           0 :     zone = part->elts;
    2181             : 
    2182           0 :     for (i = 0; /* void */ ; i++) {
    2183             : 
    2184           0 :         if (i >= part->nelts) {
    2185           0 :             if (part->next == NULL) {
    2186           0 :                 break;
    2187             :             }
    2188             : 
    2189           0 :             part = part->next;
    2190           0 :             zone = part->elts;
    2191           0 :             i = 0;
    2192             :         }
    2193             : 
    2194           0 :         name = &zone[i].shm.name;
    2195             : 
    2196             :         dd("name: [%.*s] %d", (int) name->len, name->data, (int) name->len);
    2197             :         dd("name2: [%.*s] %d", (int) name_len, name_data, (int) name_len);
    2198             : 
    2199           0 :         if (name->len == name_len
    2200           0 :             && ngx_strncmp(name->data, name_data, name_len) == 0)
    2201             :         {
    2202           0 :             ctx = (ngx_http_lua_shm_zone_ctx_t *) zone[i].data;
    2203           0 :             return &ctx->zone;
    2204             :         }
    2205             :     }
    2206             : 
    2207           0 :     return NULL;
    2208             : }
    2209             : 
    2210             : 
    2211             : #ifndef NGX_LUA_NO_FFI_API
    2212             : int
    2213           0 : ngx_http_lua_ffi_shdict_store(ngx_shm_zone_t *zone, int op, u_char *key,
    2214             :     size_t key_len, int value_type, u_char *str_value_buf,
    2215             :     size_t str_value_len, double num_value, int exptime, int user_flags,
    2216             :     char **errmsg, int *forcible)
    2217             : {
    2218             :     int                          i, n;
    2219             :     u_char                       c, *p;
    2220             :     uint32_t                     hash;
    2221             :     ngx_int_t                    rc;
    2222             :     ngx_time_t                  *tp;
    2223             :     ngx_queue_t                 *queue, *q;
    2224             :     ngx_rbtree_node_t           *node;
    2225             :     ngx_http_lua_shdict_ctx_t   *ctx;
    2226             :     ngx_http_lua_shdict_node_t  *sd;
    2227             : 
    2228           0 :     if (zone == NULL) {
    2229           0 :         return NGX_ERROR;
    2230             :     }
    2231             : 
    2232             :     dd("exptime: %d", exptime);
    2233             : 
    2234           0 :     ctx = zone->data;
    2235             : 
    2236           0 :     *forcible = 0;
    2237             : 
    2238           0 :     hash = ngx_crc32_short(key, key_len);
    2239             : 
    2240           0 :     switch (value_type) {
    2241             : 
    2242           0 :     case SHDICT_TSTRING:
    2243             :         /* do nothing */
    2244           0 :         break;
    2245             : 
    2246           0 :     case SHDICT_TNUMBER:
    2247             :         dd("num value: %lf", num_value);
    2248           0 :         str_value_buf = (u_char *) &num_value;
    2249           0 :         str_value_len = sizeof(double);
    2250           0 :         break;
    2251             : 
    2252           0 :     case SHDICT_TBOOLEAN:
    2253           0 :         c = num_value ? 1 : 0;
    2254           0 :         str_value_buf = &c;
    2255           0 :         str_value_len = sizeof(u_char);
    2256           0 :         break;
    2257             : 
    2258           0 :     case LUA_TNIL:
    2259           0 :         if (op & (NGX_HTTP_LUA_SHDICT_ADD|NGX_HTTP_LUA_SHDICT_REPLACE)) {
    2260           0 :             *errmsg = "attempt to add or replace nil values";
    2261           0 :             return NGX_ERROR;
    2262             :         }
    2263             : 
    2264           0 :         str_value_buf = NULL;
    2265           0 :         str_value_len = 0;
    2266           0 :         break;
    2267             : 
    2268           0 :     default:
    2269           0 :         *errmsg = "unsupported value type";
    2270           0 :         return NGX_ERROR;
    2271             :     }
    2272             : 
    2273           0 :     ngx_shmtx_lock(&ctx->shpool->mutex);
    2274             : 
    2275             : #if 1
    2276           0 :     ngx_http_lua_shdict_expire(ctx, 1);
    2277             : #endif
    2278             : 
    2279           0 :     rc = ngx_http_lua_shdict_lookup(zone, hash, key, key_len, &sd);
    2280             : 
    2281             :     dd("lookup returns %d", (int) rc);
    2282             : 
    2283           0 :     if (op & NGX_HTTP_LUA_SHDICT_REPLACE) {
    2284             : 
    2285           0 :         if (rc == NGX_DECLINED || rc == NGX_DONE) {
    2286           0 :             ngx_shmtx_unlock(&ctx->shpool->mutex);
    2287           0 :             *errmsg = "not found";
    2288           0 :             return NGX_DECLINED;
    2289             :         }
    2290             : 
    2291             :         /* rc == NGX_OK */
    2292             : 
    2293           0 :         goto replace;
    2294             :     }
    2295             : 
    2296           0 :     if (op & NGX_HTTP_LUA_SHDICT_ADD) {
    2297             : 
    2298           0 :         if (rc == NGX_OK) {
    2299           0 :             ngx_shmtx_unlock(&ctx->shpool->mutex);
    2300           0 :             *errmsg = "exists";
    2301           0 :             return NGX_DECLINED;
    2302             :         }
    2303             : 
    2304           0 :         if (rc == NGX_DONE) {
    2305             :             /* exists but expired */
    2306             : 
    2307             :             dd("go to replace");
    2308           0 :             goto replace;
    2309             :         }
    2310             : 
    2311             :         /* rc == NGX_DECLINED */
    2312             : 
    2313             :         dd("go to insert");
    2314           0 :         goto insert;
    2315             :     }
    2316             : 
    2317           0 :     if (rc == NGX_OK || rc == NGX_DONE) {
    2318             : 
    2319           0 :         if (value_type == LUA_TNIL) {
    2320           0 :             goto remove;
    2321             :         }
    2322             : 
    2323           0 : replace:
    2324             : 
    2325           0 :         if (str_value_buf
    2326           0 :             && str_value_len == (size_t) sd->value_len
    2327           0 :             && sd->value_type != SHDICT_TLIST)
    2328             :         {
    2329             : 
    2330           0 :             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
    2331             :                            "lua shared dict set: found old entry and value "
    2332             :                            "size matched, reusing it");
    2333             : 
    2334           0 :             ngx_queue_remove(&sd->queue);
    2335           0 :             ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue);
    2336             : 
    2337           0 :             sd->key_len = (u_short) key_len;
    2338             : 
    2339           0 :             if (exptime > 0) {
    2340           0 :                 tp = ngx_timeofday();
    2341           0 :                 sd->expires = (uint64_t) tp->sec * 1000 + tp->msec
    2342           0 :                               + (uint64_t) exptime;
    2343             : 
    2344             :             } else {
    2345           0 :                 sd->expires = 0;
    2346             :             }
    2347             : 
    2348           0 :             sd->user_flags = user_flags;
    2349             : 
    2350           0 :             sd->value_len = (uint32_t) str_value_len;
    2351             : 
    2352             :             dd("setting value type to %d", value_type);
    2353             : 
    2354           0 :             sd->value_type = (uint8_t) value_type;
    2355             : 
    2356           0 :             p = ngx_copy(sd->data, key, key_len);
    2357           0 :             ngx_memcpy(p, str_value_buf, str_value_len);
    2358             : 
    2359           0 :             ngx_shmtx_unlock(&ctx->shpool->mutex);
    2360             : 
    2361           0 :             return NGX_OK;
    2362             :         }
    2363             : 
    2364           0 :         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
    2365             :                        "lua shared dict set: found old entry but value size "
    2366             :                        "NOT matched, removing it first");
    2367             : 
    2368           0 : remove:
    2369             : 
    2370           0 :         if (sd->value_type == SHDICT_TLIST) {
    2371           0 :             queue = ngx_http_lua_shdict_get_list_head(sd, key_len);
    2372             : 
    2373           0 :             for (q = ngx_queue_head(queue);
    2374             :                  q != ngx_queue_sentinel(queue);
    2375           0 :                  q = ngx_queue_next(q))
    2376             :             {
    2377           0 :                 p = (u_char *) ngx_queue_data(q,
    2378             :                                               ngx_http_lua_shdict_list_node_t,
    2379             :                                               queue);
    2380             : 
    2381           0 :                 ngx_slab_free_locked(ctx->shpool, p);
    2382             :             }
    2383             :         }
    2384             : 
    2385           0 :         ngx_queue_remove(&sd->queue);
    2386             : 
    2387           0 :         node = (ngx_rbtree_node_t *)
    2388           0 :                    ((u_char *) sd - offsetof(ngx_rbtree_node_t, color));
    2389             : 
    2390           0 :         ngx_rbtree_delete(&ctx->sh->rbtree, node);
    2391             : 
    2392           0 :         ngx_slab_free_locked(ctx->shpool, node);
    2393             : 
    2394             :     }
    2395             : 
    2396           0 : insert:
    2397             : 
    2398             :     /* rc == NGX_DECLINED or value size unmatch */
    2399             : 
    2400           0 :     if (str_value_buf == NULL) {
    2401           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
    2402           0 :         return NGX_OK;
    2403             :     }
    2404             : 
    2405           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
    2406             :                    "lua shared dict set: creating a new entry");
    2407             : 
    2408           0 :     n = offsetof(ngx_rbtree_node_t, color)
    2409             :         + offsetof(ngx_http_lua_shdict_node_t, data)
    2410             :         + key_len
    2411           0 :         + str_value_len;
    2412             : 
    2413           0 :     node = ngx_slab_alloc_locked(ctx->shpool, n);
    2414             : 
    2415           0 :     if (node == NULL) {
    2416             : 
    2417           0 :         if (op & NGX_HTTP_LUA_SHDICT_SAFE_STORE) {
    2418           0 :             ngx_shmtx_unlock(&ctx->shpool->mutex);
    2419             : 
    2420           0 :             *errmsg = "no memory";
    2421           0 :             return NGX_ERROR;
    2422             :         }
    2423             : 
    2424           0 :         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
    2425             :                        "lua shared dict set: overriding non-expired items "
    2426             :                        "due to memory shortage for entry \"%*s\"", key_len,
    2427             :                        key);
    2428             : 
    2429           0 :         for (i = 0; i < 30; i++) {
    2430           0 :             if (ngx_http_lua_shdict_expire(ctx, 0) == 0) {
    2431           0 :                 break;
    2432             :             }
    2433             : 
    2434           0 :             *forcible = 1;
    2435             : 
    2436           0 :             node = ngx_slab_alloc_locked(ctx->shpool, n);
    2437           0 :             if (node != NULL) {
    2438           0 :                 goto allocated;
    2439             :             }
    2440             :         }
    2441             : 
    2442           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
    2443             : 
    2444           0 :         *errmsg = "no memory";
    2445           0 :         return NGX_ERROR;
    2446             :     }
    2447             : 
    2448           0 : allocated:
    2449             : 
    2450           0 :     sd = (ngx_http_lua_shdict_node_t *) &node->color;
    2451             : 
    2452           0 :     node->key = hash;
    2453           0 :     sd->key_len = (u_short) key_len;
    2454             : 
    2455           0 :     if (exptime > 0) {
    2456           0 :         tp = ngx_timeofday();
    2457           0 :         sd->expires = (uint64_t) tp->sec * 1000 + tp->msec
    2458           0 :                       + (uint64_t) exptime;
    2459             : 
    2460             :     } else {
    2461           0 :         sd->expires = 0;
    2462             :     }
    2463             : 
    2464           0 :     sd->user_flags = user_flags;
    2465           0 :     sd->value_len = (uint32_t) str_value_len;
    2466             :     dd("setting value type to %d", value_type);
    2467           0 :     sd->value_type = (uint8_t) value_type;
    2468             : 
    2469           0 :     p = ngx_copy(sd->data, key, key_len);
    2470           0 :     ngx_memcpy(p, str_value_buf, str_value_len);
    2471             : 
    2472           0 :     ngx_rbtree_insert(&ctx->sh->rbtree, node);
    2473           0 :     ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue);
    2474           0 :     ngx_shmtx_unlock(&ctx->shpool->mutex);
    2475             : 
    2476           0 :     return NGX_OK;
    2477             : }
    2478             : 
    2479             : 
    2480             : int
    2481           0 : ngx_http_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key,
    2482             :     size_t key_len, int *value_type, u_char **str_value_buf,
    2483             :     size_t *str_value_len, double *num_value, int *user_flags,
    2484             :     int get_stale, int *is_stale, char **err)
    2485             : {
    2486             :     ngx_str_t                    name;
    2487             :     uint32_t                     hash;
    2488             :     ngx_int_t                    rc;
    2489             :     ngx_http_lua_shdict_ctx_t   *ctx;
    2490             :     ngx_http_lua_shdict_node_t  *sd;
    2491             :     ngx_str_t                    value;
    2492             : 
    2493           0 :     if (zone == NULL) {
    2494           0 :         return NGX_ERROR;
    2495             :     }
    2496             : 
    2497           0 :     *err = NULL;
    2498             : 
    2499           0 :     ctx = zone->data;
    2500           0 :     name = ctx->name;
    2501             : 
    2502           0 :     hash = ngx_crc32_short(key, key_len);
    2503             : 
    2504             : #if (NGX_DEBUG)
    2505           0 :     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
    2506             :                    "fetching key \"%*s\" in shared dict \"%V\"", key_len,
    2507             :                    key, &name);
    2508             : #endif /* NGX_DEBUG */
    2509             : 
    2510           0 :     ngx_shmtx_lock(&ctx->shpool->mutex);
    2511             : 
    2512             : #if 1
    2513           0 :     if (!get_stale) {
    2514           0 :         ngx_http_lua_shdict_expire(ctx, 1);
    2515             :     }
    2516             : #endif
    2517             : 
    2518           0 :     rc = ngx_http_lua_shdict_lookup(zone, hash, key, key_len, &sd);
    2519             : 
    2520             :     dd("shdict lookup returns %d", (int) rc);
    2521             : 
    2522           0 :     if (rc == NGX_DECLINED || (rc == NGX_DONE && !get_stale)) {
    2523           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
    2524           0 :         *value_type = LUA_TNIL;
    2525           0 :         return NGX_OK;
    2526             :     }
    2527             : 
    2528             :     /* rc == NGX_OK || (rc == NGX_DONE && get_stale) */
    2529             : 
    2530           0 :     *value_type = sd->value_type;
    2531             : 
    2532             :     dd("data: %p", sd->data);
    2533             :     dd("key len: %d", (int) sd->key_len);
    2534             : 
    2535           0 :     value.data = sd->data + sd->key_len;
    2536           0 :     value.len = (size_t) sd->value_len;
    2537             : 
    2538           0 :     if (*str_value_len < (size_t) value.len) {
    2539           0 :         if (*value_type == SHDICT_TBOOLEAN) {
    2540           0 :             ngx_shmtx_unlock(&ctx->shpool->mutex);
    2541           0 :             return NGX_ERROR;
    2542             :         }
    2543             : 
    2544           0 :         if (*value_type == SHDICT_TSTRING) {
    2545           0 :             *str_value_buf = malloc(value.len);
    2546           0 :             if (*str_value_buf == NULL) {
    2547           0 :                 ngx_shmtx_unlock(&ctx->shpool->mutex);
    2548           0 :                 return NGX_ERROR;
    2549             :             }
    2550             :         }
    2551             :     }
    2552             : 
    2553           0 :     switch (*value_type) {
    2554             : 
    2555           0 :     case SHDICT_TSTRING:
    2556           0 :         *str_value_len = value.len;
    2557           0 :         ngx_memcpy(*str_value_buf, value.data, value.len);
    2558           0 :         break;
    2559             : 
    2560           0 :     case SHDICT_TNUMBER:
    2561             : 
    2562           0 :         if (value.len != sizeof(double)) {
    2563           0 :             ngx_shmtx_unlock(&ctx->shpool->mutex);
    2564           0 :             ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
    2565             :                           "bad lua number value size found for key %*s "
    2566             :                           "in shared_dict %V: %z", key_len, key,
    2567             :                           &name, value.len);
    2568           0 :             return NGX_ERROR;
    2569             :         }
    2570             : 
    2571           0 :         *str_value_len = value.len;
    2572           0 :         ngx_memcpy(num_value, value.data, sizeof(double));
    2573           0 :         break;
    2574             : 
    2575           0 :     case SHDICT_TBOOLEAN:
    2576             : 
    2577           0 :         if (value.len != sizeof(u_char)) {
    2578           0 :             ngx_shmtx_unlock(&ctx->shpool->mutex);
    2579           0 :             ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
    2580             :                           "bad lua boolean value size found for key %*s "
    2581             :                           "in shared_dict %V: %z", key_len, key, &name,
    2582             :                           value.len);
    2583           0 :             return NGX_ERROR;
    2584             :         }
    2585             : 
    2586           0 :         ngx_memcpy(*str_value_buf, value.data, value.len);
    2587           0 :         break;
    2588             : 
    2589           0 :     case SHDICT_TLIST:
    2590             : 
    2591           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
    2592             : 
    2593           0 :         *err = "value is a list";
    2594           0 :         return NGX_ERROR;
    2595             : 
    2596           0 :     default:
    2597             : 
    2598           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
    2599           0 :         ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
    2600             :                       "bad value type found for key %*s in "
    2601             :                       "shared_dict %V: %d", key_len, key, &name,
    2602             :                       *value_type);
    2603           0 :         return NGX_ERROR;
    2604             :     }
    2605             : 
    2606           0 :     *user_flags = sd->user_flags;
    2607             :     dd("user flags: %d", *user_flags);
    2608             : 
    2609           0 :     ngx_shmtx_unlock(&ctx->shpool->mutex);
    2610             : 
    2611           0 :     if (get_stale) {
    2612             : 
    2613             :         /* always return value, flags, stale */
    2614             : 
    2615           0 :         *is_stale = (rc == NGX_DONE);
    2616           0 :         return NGX_OK;
    2617             :     }
    2618             : 
    2619           0 :     return NGX_OK;
    2620             : }
    2621             : 
    2622             : 
    2623             : int
    2624           0 : ngx_http_lua_ffi_shdict_incr(ngx_shm_zone_t *zone, u_char *key,
    2625             :     size_t key_len, double *value, char **err, int has_init, double init,
    2626             :     int *forcible)
    2627             : {
    2628             :     int                          i, n;
    2629             :     uint32_t                     hash;
    2630             :     ngx_int_t                    rc;
    2631             :     ngx_http_lua_shdict_ctx_t   *ctx;
    2632             :     ngx_http_lua_shdict_node_t  *sd;
    2633             :     double                       num;
    2634             :     ngx_rbtree_node_t           *node;
    2635             :     u_char                      *p;
    2636             :     ngx_queue_t                 *queue, *q;
    2637             : 
    2638           0 :     if (zone == NULL) {
    2639           0 :         return NGX_ERROR;
    2640             :     }
    2641             : 
    2642           0 :     ctx = zone->data;
    2643             : 
    2644           0 :     *forcible = 0;
    2645             : 
    2646           0 :     hash = ngx_crc32_short(key, key_len);
    2647             : 
    2648             :     dd("looking up key %.*s in shared dict %.*s", (int) key_len, key,
    2649             :        (int) ctx->name.len, ctx->name.data);
    2650             : 
    2651           0 :     ngx_shmtx_lock(&ctx->shpool->mutex);
    2652             : #if 1
    2653           0 :     ngx_http_lua_shdict_expire(ctx, 1);
    2654             : #endif
    2655           0 :     rc = ngx_http_lua_shdict_lookup(zone, hash, key, key_len, &sd);
    2656             : 
    2657             :     dd("shdict lookup returned %d", (int) rc);
    2658             : 
    2659           0 :     if (rc == NGX_DECLINED || rc == NGX_DONE) {
    2660           0 :         if (!has_init) {
    2661           0 :             ngx_shmtx_unlock(&ctx->shpool->mutex);
    2662           0 :             *err = "not found";
    2663           0 :             return NGX_ERROR;
    2664             :         }
    2665             : 
    2666             :         /* add value */
    2667           0 :         num = *value + init;
    2668             : 
    2669           0 :         if (rc == NGX_DONE) {
    2670             : 
    2671             :             /* found an expired item */
    2672             : 
    2673           0 :             if ((size_t) sd->value_len == sizeof(double)
    2674           0 :                 && sd->value_type != SHDICT_TLIST)
    2675             :             {
    2676           0 :                 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
    2677             :                                "lua shared dict incr: found old entry and "
    2678             :                                "value size matched, reusing it");
    2679             : 
    2680           0 :                 ngx_queue_remove(&sd->queue);
    2681           0 :                 ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue);
    2682             : 
    2683             :                 dd("go to setvalue");
    2684           0 :                 goto setvalue;
    2685             :             }
    2686             : 
    2687             :             dd("go to remove");
    2688           0 :             goto remove;
    2689             :         }
    2690             : 
    2691             :         dd("go to insert");
    2692           0 :         goto insert;
    2693             :     }
    2694             : 
    2695             :     /* rc == NGX_OK */
    2696             : 
    2697           0 :     if (sd->value_type != SHDICT_TNUMBER || sd->value_len != sizeof(double)) {
    2698           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
    2699           0 :         *err = "not a number";
    2700           0 :         return NGX_ERROR;
    2701             :     }
    2702             : 
    2703           0 :     ngx_queue_remove(&sd->queue);
    2704           0 :     ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue);
    2705             : 
    2706             :     dd("setting value type to %d", (int) sd->value_type);
    2707             : 
    2708           0 :     p = sd->data + key_len;
    2709             : 
    2710           0 :     ngx_memcpy(&num, p, sizeof(double));
    2711           0 :     num += *value;
    2712             : 
    2713           0 :     ngx_memcpy(p, (double *) &num, sizeof(double));
    2714             : 
    2715           0 :     ngx_shmtx_unlock(&ctx->shpool->mutex);
    2716             : 
    2717           0 :     *value = num;
    2718           0 :     return NGX_OK;
    2719             : 
    2720           0 : remove:
    2721             : 
    2722           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
    2723             :                    "lua shared dict incr: found old entry but value size "
    2724             :                    "NOT matched, removing it first");
    2725             : 
    2726           0 :     if (sd->value_type == SHDICT_TLIST) {
    2727           0 :         queue = ngx_http_lua_shdict_get_list_head(sd, key_len);
    2728             : 
    2729           0 :         for (q = ngx_queue_head(queue);
    2730             :              q != ngx_queue_sentinel(queue);
    2731           0 :              q = ngx_queue_next(q))
    2732             :         {
    2733           0 :             p = (u_char *) ngx_queue_data(q, ngx_http_lua_shdict_list_node_t,
    2734             :                                           queue);
    2735             : 
    2736           0 :             ngx_slab_free_locked(ctx->shpool, p);
    2737             :         }
    2738             :     }
    2739             : 
    2740           0 :     ngx_queue_remove(&sd->queue);
    2741             : 
    2742           0 :     node = (ngx_rbtree_node_t *)
    2743           0 :                ((u_char *) sd - offsetof(ngx_rbtree_node_t, color));
    2744             : 
    2745           0 :     ngx_rbtree_delete(&ctx->sh->rbtree, node);
    2746             : 
    2747           0 :     ngx_slab_free_locked(ctx->shpool, node);
    2748             : 
    2749           0 : insert:
    2750             : 
    2751           0 :     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
    2752             :                    "lua shared dict incr: creating a new entry");
    2753             : 
    2754           0 :     n = offsetof(ngx_rbtree_node_t, color)
    2755             :         + offsetof(ngx_http_lua_shdict_node_t, data)
    2756             :         + key_len
    2757           0 :         + sizeof(double);
    2758             : 
    2759           0 :     node = ngx_slab_alloc_locked(ctx->shpool, n);
    2760             : 
    2761           0 :     if (node == NULL) {
    2762             : 
    2763           0 :         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
    2764             :                        "lua shared dict incr: overriding non-expired items "
    2765             :                        "due to memory shortage for entry \"%*s\"", key_len,
    2766             :                        key);
    2767             : 
    2768           0 :         for (i = 0; i < 30; i++) {
    2769           0 :             if (ngx_http_lua_shdict_expire(ctx, 0) == 0) {
    2770           0 :                 break;
    2771             :             }
    2772             : 
    2773           0 :             *forcible = 1;
    2774             : 
    2775           0 :             node = ngx_slab_alloc_locked(ctx->shpool, n);
    2776           0 :             if (node != NULL) {
    2777           0 :                 goto allocated;
    2778             :             }
    2779             :         }
    2780             : 
    2781           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
    2782             : 
    2783           0 :         *err = "no memory";
    2784           0 :         return NGX_ERROR;
    2785             :     }
    2786             : 
    2787           0 : allocated:
    2788             : 
    2789           0 :     sd = (ngx_http_lua_shdict_node_t *) &node->color;
    2790             : 
    2791           0 :     node->key = hash;
    2792             : 
    2793           0 :     sd->key_len = (u_short) key_len;
    2794             : 
    2795           0 :     sd->value_len = (uint32_t) sizeof(double);
    2796             : 
    2797           0 :     ngx_rbtree_insert(&ctx->sh->rbtree, node);
    2798             : 
    2799           0 :     ngx_queue_insert_head(&ctx->sh->lru_queue, &sd->queue);
    2800             : 
    2801           0 : setvalue:
    2802             : 
    2803           0 :     sd->user_flags = 0;
    2804             : 
    2805           0 :     sd->expires = 0;
    2806             : 
    2807             :     dd("setting value type to %d", LUA_TNUMBER);
    2808             : 
    2809           0 :     sd->value_type = (uint8_t) LUA_TNUMBER;
    2810             : 
    2811           0 :     p = ngx_copy(sd->data, key, key_len);
    2812           0 :     ngx_memcpy(p, (double *) &num, sizeof(double));
    2813             : 
    2814           0 :     ngx_shmtx_unlock(&ctx->shpool->mutex);
    2815             : 
    2816           0 :     *value = num;
    2817           0 :     return NGX_OK;
    2818             : }
    2819             : 
    2820             : 
    2821             : int
    2822           0 : ngx_http_lua_ffi_shdict_flush_all(ngx_shm_zone_t *zone)
    2823             : {
    2824             :     ngx_queue_t                 *q;
    2825             :     ngx_http_lua_shdict_node_t  *sd;
    2826             :     ngx_http_lua_shdict_ctx_t   *ctx;
    2827             : 
    2828           0 :     ctx = zone->data;
    2829             : 
    2830           0 :     ngx_shmtx_lock(&ctx->shpool->mutex);
    2831             : 
    2832           0 :     for (q = ngx_queue_head(&ctx->sh->lru_queue);
    2833           0 :          q != ngx_queue_sentinel(&ctx->sh->lru_queue);
    2834           0 :          q = ngx_queue_next(q))
    2835             :     {
    2836           0 :         sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue);
    2837           0 :         sd->expires = 1;
    2838             :     }
    2839             : 
    2840           0 :     ngx_http_lua_shdict_expire(ctx, 0);
    2841             : 
    2842           0 :     ngx_shmtx_unlock(&ctx->shpool->mutex);
    2843             : 
    2844           0 :     return NGX_OK;
    2845             : }
    2846             : 
    2847             : 
    2848             : static ngx_int_t
    2849           0 : ngx_http_lua_shdict_peek(ngx_shm_zone_t *shm_zone, ngx_uint_t hash,
    2850             :     u_char *kdata, size_t klen, ngx_http_lua_shdict_node_t **sdp)
    2851             : {
    2852             :     ngx_int_t                    rc;
    2853             :     ngx_rbtree_node_t           *node, *sentinel;
    2854             :     ngx_http_lua_shdict_ctx_t   *ctx;
    2855             :     ngx_http_lua_shdict_node_t  *sd;
    2856             : 
    2857           0 :     ctx = shm_zone->data;
    2858             : 
    2859           0 :     node = ctx->sh->rbtree.root;
    2860           0 :     sentinel = ctx->sh->rbtree.sentinel;
    2861             : 
    2862           0 :     while (node != sentinel) {
    2863             : 
    2864           0 :         if (hash < node->key) {
    2865           0 :             node = node->left;
    2866           0 :             continue;
    2867             :         }
    2868             : 
    2869           0 :         if (hash > node->key) {
    2870           0 :             node = node->right;
    2871           0 :             continue;
    2872             :         }
    2873             : 
    2874             :         /* hash == node->key */
    2875             : 
    2876           0 :         sd = (ngx_http_lua_shdict_node_t *) &node->color;
    2877             : 
    2878           0 :         rc = ngx_memn2cmp(kdata, sd->data, klen, (size_t) sd->key_len);
    2879             : 
    2880           0 :         if (rc == 0) {
    2881           0 :             *sdp = sd;
    2882             : 
    2883           0 :             return NGX_OK;
    2884             :         }
    2885             : 
    2886           0 :         node = (rc < 0) ? node->left : node->right;
    2887             :     }
    2888             : 
    2889           0 :     *sdp = NULL;
    2890             : 
    2891           0 :     return NGX_DECLINED;
    2892             : }
    2893             : 
    2894             : 
    2895             : int
    2896           0 : ngx_http_lua_ffi_shdict_get_ttl(ngx_shm_zone_t *zone, u_char *key,
    2897             :     size_t key_len)
    2898             : {
    2899             :     uint32_t                     hash;
    2900             :     uint64_t                     now;
    2901             :     uint64_t                     expires;
    2902             :     ngx_int_t                    rc;
    2903             :     ngx_time_t                  *tp;
    2904             :     ngx_http_lua_shdict_ctx_t   *ctx;
    2905             :     ngx_http_lua_shdict_node_t  *sd;
    2906             : 
    2907           0 :     if (zone == NULL) {
    2908           0 :         return NGX_ERROR;
    2909             :     }
    2910             : 
    2911           0 :     ctx = zone->data;
    2912           0 :     hash = ngx_crc32_short(key, key_len);
    2913             : 
    2914           0 :     ngx_shmtx_lock(&ctx->shpool->mutex);
    2915             : 
    2916           0 :     rc = ngx_http_lua_shdict_peek(zone, hash, key, key_len, &sd);
    2917             : 
    2918           0 :     if (rc == NGX_DECLINED) {
    2919           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
    2920             : 
    2921           0 :         return NGX_DECLINED;
    2922             :     }
    2923             : 
    2924             :     /* rc == NGX_OK */
    2925             : 
    2926           0 :     expires = sd->expires;
    2927             : 
    2928           0 :     ngx_shmtx_unlock(&ctx->shpool->mutex);
    2929             : 
    2930           0 :     if (expires == 0) {
    2931           0 :         return 0;
    2932             :     }
    2933             : 
    2934           0 :     tp = ngx_timeofday();
    2935           0 :     now = (uint64_t) tp->sec * 1000 + tp->msec;
    2936             : 
    2937           0 :     return expires - now;
    2938             : }
    2939             : 
    2940             : 
    2941             : int
    2942           0 : ngx_http_lua_ffi_shdict_set_expire(ngx_shm_zone_t *zone, u_char *key,
    2943             :     size_t key_len, int exptime)
    2944             : {
    2945             :     uint32_t                     hash;
    2946             :     ngx_int_t                    rc;
    2947           0 :     ngx_time_t                  *tp = NULL;
    2948             :     ngx_http_lua_shdict_ctx_t   *ctx;
    2949             :     ngx_http_lua_shdict_node_t  *sd;
    2950             : 
    2951           0 :     if (zone == NULL) {
    2952           0 :         return NGX_ERROR;
    2953             :     }
    2954             : 
    2955           0 :     if (exptime > 0) {
    2956           0 :         tp = ngx_timeofday();
    2957             :     }
    2958             : 
    2959           0 :     ctx = zone->data;
    2960           0 :     hash = ngx_crc32_short(key, key_len);
    2961             : 
    2962           0 :     ngx_shmtx_lock(&ctx->shpool->mutex);
    2963             : 
    2964           0 :     rc = ngx_http_lua_shdict_peek(zone, hash, key, key_len, &sd);
    2965             : 
    2966           0 :     if (rc == NGX_DECLINED) {
    2967           0 :         ngx_shmtx_unlock(&ctx->shpool->mutex);
    2968             : 
    2969           0 :         return NGX_DECLINED;
    2970             :     }
    2971             : 
    2972             :     /* rc == NGX_OK */
    2973             : 
    2974           0 :     if (exptime > 0) {
    2975           0 :         sd->expires = (uint64_t) tp->sec * 1000 + tp->msec
    2976           0 :                       + (uint64_t) exptime;
    2977             : 
    2978             :     } else {
    2979           0 :         sd->expires = 0;
    2980             :     }
    2981             : 
    2982           0 :     ngx_shmtx_unlock(&ctx->shpool->mutex);
    2983             : 
    2984           0 :     return NGX_OK;
    2985             : }
    2986             : 
    2987             : 
    2988             : size_t
    2989           0 : ngx_http_lua_ffi_shdict_capacity(ngx_shm_zone_t *zone)
    2990             : {
    2991           0 :     return zone->shm.size;
    2992             : }
    2993             : 
    2994             : 
    2995             : #    if nginx_version >= 1011007
    2996             : size_t
    2997           0 : ngx_http_lua_ffi_shdict_free_space(ngx_shm_zone_t *zone)
    2998             : {
    2999             :     size_t                       bytes;
    3000             :     ngx_http_lua_shdict_ctx_t   *ctx;
    3001             : 
    3002           0 :     ctx = zone->data;
    3003             : 
    3004           0 :     ngx_shmtx_lock(&ctx->shpool->mutex);
    3005           0 :     bytes = ctx->shpool->pfree * ngx_pagesize;
    3006           0 :     ngx_shmtx_unlock(&ctx->shpool->mutex);
    3007             : 
    3008           0 :     return bytes;
    3009             : }
    3010             : #    endif /* nginx_version >= 1011007 */
    3011             : 
    3012             : 
    3013             : #endif /* NGX_LUA_NO_FFI_API */
    3014             : 
    3015             : 
    3016             : /* vi:set ft=c ts=4 sw=4 et fdm=marker: */

Generated by: LCOV version 1.13