int ngx_http_lua_ffi_shdict_incr(ngx_shm_zone_t *zone, u_char *key, size_t key_len, double *value, char **err) { uint32_t hash; ngx_int_t rc; ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; double num; u_char *p; ctx = zone->data; hash = ngx_crc32_short(key, key_len); dd("looking up key %.*s in shared dict %.*s", (int) key_len, key, (int) ctx->name.len, ctx->name.data); ngx_shmtx_lock(&ctx->shpool->mutex); #if 1 ngx_http_lua_shdict_expire(ctx, 1); #endif rc = ngx_http_lua_shdict_lookup(zone, hash, key, key_len, &sd); dd("shdict lookup returned %d", (int) rc); if (rc == NGX_DECLINED || rc == NGX_DONE) { ngx_shmtx_unlock(&ctx->shpool->mutex); *err = "not found"; return NGX_ERROR; } /* rc == NGX_OK */ if (sd->value_type != LUA_TNUMBER || sd->value_len != sizeof(double)) { ngx_shmtx_unlock(&ctx->shpool->mutex); *err = "not a number"; return NGX_ERROR; } ngx_queue_remove(&sd->queue); ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); dd("setting value type to %d", (int) sd->value_type); p = sd->data + key_len; num = *(double *) p; num += *value; ngx_memcpy(p, (double *) &num, sizeof(double)); ngx_shmtx_unlock(&ctx->shpool->mutex); *value = num; return NGX_OK; }
static int ngx_http_lua_shdict_incr(lua_State *L) { int n; ngx_str_t key; uint32_t hash; ngx_int_t rc; ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; lua_Number num; u_char *p; ngx_shm_zone_t *zone; lua_Number value; n = lua_gettop(L); if (n != 3) { return luaL_error(L, "expecting 3 arguments, " "but only seen %d", n); } luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); zone = lua_touserdata(L, 1); if (zone == NULL) { return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer"); } ctx = zone->data; key.data = (u_char *) luaL_checklstring(L, 2, &key.len); if (key.len == 0) { return luaL_error(L, "attempt to use empty keys"); } if (key.len > 65535) { return luaL_error(L, "the key argument is more than 65535 bytes: %d", (int) key.len); } hash = ngx_crc32_short(key.data, key.len); value = luaL_checknumber(L, 3); dd("looking up key %.*s in shared dict %.*s", (int) key.len, key.data, (int) ctx->name.len, ctx->name.data); ngx_shmtx_lock(&ctx->shpool->mutex); #if 1 ngx_http_lua_shdict_expire(ctx, 1); #endif rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); dd("shdict lookup returned %d", (int) rc); if (rc == NGX_DECLINED || rc == NGX_DONE) { ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushnil(L); lua_pushliteral(L, "not found"); return 2; } /* rc == NGX_OK */ if (sd->value_type != LUA_TNUMBER || sd->value_len != sizeof(lua_Number)) { ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushnil(L); lua_pushliteral(L, "not a number"); return 2; } ngx_queue_remove(&sd->queue); ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); dd("setting value type to %d", (int) sd->value_type); p = sd->data + key.len; num = *(lua_Number *) p; num += value; ngx_memcpy(p, (lua_Number *) &num, sizeof(lua_Number)); ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushnumber(L, num); lua_pushnil(L); return 2; }
static int ngx_http_lua_shdict_set_helper(lua_State *L, int flags) { int i, n; ngx_str_t name; ngx_str_t key; uint32_t hash; ngx_int_t rc; ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; ngx_str_t value; int value_type; lua_Number num; u_char c; lua_Number exptime = 0; u_char *p; ngx_rbtree_node_t *node; ngx_time_t *tp; ngx_shm_zone_t *zone; int forcible = 0; /* indicates whether to foricibly override other * valid entries */ int32_t user_flags = 0; n = lua_gettop(L); if (n != 3 && n != 4 && n != 5) { return luaL_error(L, "expecting 3, 4 or 5 arguments, " "but only seen %d", n); } luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); zone = lua_touserdata(L, 1); if (zone == NULL) { return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer"); } ctx = zone->data; name = ctx->name; key.data = (u_char *) luaL_checklstring(L, 2, &key.len); if (key.len == 0) { return luaL_error(L, "attempt to use empty keys"); } if (key.len > 65535) { return luaL_error(L, "the key argument is more than 65535 bytes: %d", (int) key.len); } hash = ngx_crc32_short(key.data, key.len); value_type = lua_type(L, 3); switch (value_type) { case LUA_TSTRING: value.data = (u_char *) lua_tolstring(L, 3, &value.len); break; case LUA_TNUMBER: value.len = sizeof(lua_Number); num = lua_tonumber(L, 3); value.data = (u_char *) # break; case LUA_TBOOLEAN: value.len = sizeof(u_char); c = lua_toboolean(L, 3) ? 1 : 0; value.data = &c; break; case LUA_TNIL: if (flags & (NGX_HTTP_LUA_SHDICT_ADD|NGX_HTTP_LUA_SHDICT_REPLACE)) { return luaL_error(L, "attempt to add or replace nil values"); } value.len = 0; value.data = NULL; break; default: return luaL_error(L, "unsupported value type for key \"%s\" in " "shared_dict \"%s\": %s", key.data, name.data, lua_typename(L, value_type)); } if (n >= 4) { exptime = luaL_checknumber(L, 4); if (exptime < 0) { exptime = 0; } } if (n == 5) { user_flags = (uint32_t) luaL_checkinteger(L, 5); } dd("looking up key %s in shared dict %s", key.data, name.data); ngx_shmtx_lock(&ctx->shpool->mutex); #if 1 ngx_http_lua_shdict_expire(ctx, 1); #endif rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); dd("shdict lookup returned %d", (int) rc); if (flags & NGX_HTTP_LUA_SHDICT_REPLACE) { if (rc == NGX_DECLINED || rc == NGX_DONE) { ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushboolean(L, 0); lua_pushliteral(L, "not found"); lua_pushboolean(L, forcible); return 3; } /* rc == NGX_OK */ goto replace; } if (flags & NGX_HTTP_LUA_SHDICT_ADD) { if (rc == NGX_OK) { ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushboolean(L, 0); lua_pushliteral(L, "exists"); lua_pushboolean(L, forcible); return 3; } if (rc == NGX_DONE) { /* exists but expired */ dd("go to replace"); goto replace; } /* rc == NGX_DECLINED */ dd("go to insert"); goto insert; } if (rc == NGX_OK || rc == NGX_DONE) { if (value_type == LUA_TNIL) { goto remove; } replace: if (value.data && value.len == (size_t) sd->value_len) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "lua shared dict set: found old entry and value size matched, " "reusing it"); ngx_queue_remove(&sd->queue); ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); sd->key_len = key.len; if (exptime > 0) { tp = ngx_timeofday(); sd->expires = (uint64_t) tp->sec * 1000 + tp->msec + exptime * 1000; } else { sd->expires = 0; } sd->user_flags = user_flags; sd->value_len = (uint32_t) value.len; dd("setting value type to %d", value_type); sd->value_type = value_type; p = ngx_copy(sd->data, key.data, key.len); ngx_memcpy(p, value.data, value.len); ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushboolean(L, 1); lua_pushnil(L); lua_pushboolean(L, forcible); return 3; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "lua shared dict set: found old entry bug value size NOT matched, " "removing it first"); remove: ngx_queue_remove(&sd->queue); node = (ngx_rbtree_node_t *) ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); ngx_rbtree_delete(&ctx->sh->rbtree, node); ngx_slab_free_locked(ctx->shpool, node); } insert: /* rc == NGX_DECLINED or value size unmatch */ if (value.data == NULL) { ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushboolean(L, 1); lua_pushnil(L); lua_pushboolean(L, 0); return 3; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "lua shared dict set: creating a new entry"); n = offsetof(ngx_rbtree_node_t, color) + offsetof(ngx_http_lua_shdict_node_t, data) + key.len + value.len; node = ngx_slab_alloc_locked(ctx->shpool, n); if (node == NULL) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "lua shared dict set: overriding non-expired items due to memory " "shortage for entry \"%V\"", &name); for (i = 0; i < 30; i++) { if (ngx_http_lua_shdict_expire(ctx, 0) == 0) { break; } forcible = 1; node = ngx_slab_alloc_locked(ctx->shpool, n); if (node != NULL) { goto allocated; } } ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushboolean(L, 0); lua_pushliteral(L, "no memory"); lua_pushboolean(L, forcible); return 3; } allocated: sd = (ngx_http_lua_shdict_node_t *) &node->color; node->key = hash; sd->key_len = key.len; if (exptime > 0) { tp = ngx_timeofday(); sd->expires = (uint64_t) tp->sec * 1000 + tp->msec + exptime * 1000; } else { sd->expires = 0; } sd->user_flags = user_flags; sd->value_len = (uint32_t) value.len; dd("setting value type to %d", value_type); sd->value_type = value_type; p = ngx_copy(sd->data, key.data, key.len); ngx_memcpy(p, value.data, value.len); ngx_rbtree_insert(&ctx->sh->rbtree, node); ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushboolean(L, 1); lua_pushnil(L); lua_pushboolean(L, forcible); return 3; }
static int ngx_http_lua_shdict_get(lua_State *L) { int n; ngx_str_t name; ngx_str_t key; uint32_t hash; ngx_int_t rc; ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; ngx_str_t value; int value_type; lua_Number num; u_char c; ngx_shm_zone_t *zone; uint32_t user_flags = 0; n = lua_gettop(L); if (n != 2) { return luaL_error(L, "expecting exactly two arguments, " "but only seen %d", n); } luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); zone = lua_touserdata(L, 1); if (zone == NULL) { return luaL_error(L, "bad user data for the ngx_shm_zone_t pointer"); } ctx = zone->data; name = ctx->name; key.data = (u_char *) luaL_checklstring(L, 2, &key.len); if (key.len == 0) { lua_pushnil(L); return 1; } if (key.len > 65535) { return luaL_error(L, "the key argument is more than 65535 bytes: \"%s\"", key.data); } hash = ngx_crc32_short(key.data, key.len); #if (NGX_DEBUG) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "fetching key \"%V\" in shared dict \"%V\"", &key, &name); #endif /* NGX_DEBUG */ ngx_shmtx_lock(&ctx->shpool->mutex); #if 1 ngx_http_lua_shdict_expire(ctx, 1); #endif rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); dd("shdict lookup returns %d", (int) rc); if (rc == NGX_DECLINED || rc == NGX_DONE) { ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushnil(L); return 1; } /* rc == NGX_OK */ value_type = sd->value_type; dd("data: %p", sd->data); dd("key len: %d", (int) sd->key_len); value.data = sd->data + sd->key_len; value.len = (size_t) sd->value_len; switch (value_type) { case LUA_TSTRING: lua_pushlstring(L, (char *) value.data, value.len); break; case LUA_TNUMBER: if (value.len != sizeof(lua_Number)) { ngx_shmtx_unlock(&ctx->shpool->mutex); return luaL_error(L, "bad lua number value size found for key %s " "in shared_dict %s: %lu", key.data, name.data, (unsigned long) value.len); } num = *(lua_Number *) value.data; lua_pushnumber(L, num); break; case LUA_TBOOLEAN: if (value.len != sizeof(u_char)) { ngx_shmtx_unlock(&ctx->shpool->mutex); return luaL_error(L, "bad lua boolean value size found for key %s " "in shared_dict %s: %lu", key.data, name.data, (unsigned long) value.len); } c = *value.data; lua_pushboolean(L, c ? 1 : 0); break; default: ngx_shmtx_unlock(&ctx->shpool->mutex); return luaL_error(L, "bad value type found for key %s in " "shared_dict %s: %d", key.data, name.data, value_type); } user_flags = sd->user_flags; ngx_shmtx_unlock(&ctx->shpool->mutex); if (user_flags) { lua_pushinteger(L, (lua_Integer) user_flags); return 2; } return 1; }
int ngx_http_lua_ffi_shdict_get(ngx_shm_zone_t *zone, u_char *key, size_t key_len, int *value_type, u_char **str_value_buf, size_t *str_value_len, double *num_value, int *user_flags, int get_stale, int *is_stale) { ngx_str_t name; uint32_t hash; ngx_int_t rc; ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; ngx_str_t value; if (zone == NULL) { return NGX_ERROR; } ctx = zone->data; name = ctx->name; hash = ngx_crc32_short(key, key_len); #if (NGX_DEBUG) ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "fetching key \"%*s\" in shared dict \"%V\"", key_len, key, &name); #endif /* NGX_DEBUG */ ngx_shmtx_lock(&ctx->shpool->mutex); #if 1 if (!get_stale) { ngx_http_lua_shdict_expire(ctx, 1); } #endif rc = ngx_http_lua_shdict_lookup(zone, hash, key, key_len, &sd); dd("shdict lookup returns %d", (int) rc); if (rc == NGX_DECLINED || (rc == NGX_DONE && !get_stale)) { ngx_shmtx_unlock(&ctx->shpool->mutex); *value_type = LUA_TNIL; return NGX_OK; } /* rc == NGX_OK || (rc == NGX_DONE && get_stale) */ *value_type = sd->value_type; dd("data: %p", sd->data); dd("key len: %d", (int) sd->key_len); value.data = sd->data + sd->key_len; value.len = (size_t) sd->value_len; if (*str_value_len < (size_t) value.len) { if (*value_type != LUA_TSTRING) { return NGX_ERROR; } *str_value_buf = malloc(value.len); if (*str_value_buf == NULL) { ngx_shmtx_unlock(&ctx->shpool->mutex); return NGX_ERROR; } } *str_value_len = value.len; switch (*value_type) { case LUA_TSTRING: ngx_memcpy(*str_value_buf, value.data, value.len); break; case LUA_TNUMBER: if (value.len != sizeof(double)) { ngx_shmtx_unlock(&ctx->shpool->mutex); ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "bad lua number value size found for key %*s " "in shared_dict %V: %z", key_len, key, &name, value.len); return NGX_ERROR; } *num_value = *(double *) value.data; break; case LUA_TBOOLEAN: if (value.len != sizeof(u_char)) { ngx_shmtx_unlock(&ctx->shpool->mutex); ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "bad lua boolean value size found for key %*s " "in shared_dict %V: %z", key_len, key, &name, value.len); return NGX_ERROR; } ngx_memcpy(*str_value_buf, value.data, value.len); break; default: ngx_shmtx_unlock(&ctx->shpool->mutex); ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "bad value type found for key %*s in " "shared_dict %V: %d", key_len, key, &name, *value_type); } *user_flags = sd->user_flags; dd("user flags: %d", *user_flags); ngx_shmtx_unlock(&ctx->shpool->mutex); if (get_stale) { /* always return value, flags, stale */ *is_stale = (rc == NGX_DONE); return NGX_OK; } return NGX_OK; }
int ngx_http_lua_ffi_shdict_store(ngx_shm_zone_t *zone, int op, u_char *key, size_t key_len, int value_type, u_char *str_value_buf, size_t str_value_len, double num_value, int exptime, int user_flags, char **errmsg, int *forcible) { int i, n; u_char c, *p; uint32_t hash; ngx_int_t rc; ngx_time_t *tp; ngx_rbtree_node_t *node; ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; if (zone == NULL) { return NGX_ERROR; } dd("exptime: %d", exptime); ctx = zone->data; *forcible = 0; hash = ngx_crc32_short(key, key_len); switch (value_type) { case LUA_TSTRING: /* do nothing */ break; case LUA_TNUMBER: dd("num value: %lf", num_value); str_value_buf = (u_char *) &num_value; str_value_len = sizeof(double); break; case LUA_TBOOLEAN: c = num_value ? 1 : 0; str_value_buf = &c; str_value_len = sizeof(u_char); break; case LUA_TNIL: if (op & (NGX_HTTP_LUA_SHDICT_ADD|NGX_HTTP_LUA_SHDICT_REPLACE)) { *errmsg = "attempt to add or replace nil values"; return NGX_ERROR; } str_value_buf = NULL; str_value_len = 0; break; default: *errmsg = "unsupported value type"; return NGX_ERROR; } ngx_shmtx_lock(&ctx->shpool->mutex); #if 1 ngx_http_lua_shdict_expire(ctx, 1); #endif rc = ngx_http_lua_shdict_lookup(zone, hash, key, key_len, &sd); dd("lookup returns %d", (int) rc); if (op & NGX_HTTP_LUA_SHDICT_REPLACE) { if (rc == NGX_DECLINED || rc == NGX_DONE) { ngx_shmtx_unlock(&ctx->shpool->mutex); *errmsg = "not found"; return NGX_DECLINED; } /* rc == NGX_OK */ goto replace; } if (op & NGX_HTTP_LUA_SHDICT_ADD) { if (rc == NGX_OK) { ngx_shmtx_unlock(&ctx->shpool->mutex); *errmsg = "exists"; return NGX_DECLINED; } if (rc == NGX_DONE) { /* exists but expired */ dd("go to replace"); goto replace; } /* rc == NGX_DECLINED */ dd("go to insert"); goto insert; } if (rc == NGX_OK || rc == NGX_DONE) { if (value_type == LUA_TNIL) { goto remove; } replace: if (str_value_buf && str_value_len == (size_t) sd->value_len) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "lua shared dict set: found old entry and value " "size matched, reusing it"); ngx_queue_remove(&sd->queue); ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); sd->key_len = (u_short) key_len; if (exptime > 0) { tp = ngx_timeofday(); sd->expires = (uint64_t) tp->sec * 1000 + tp->msec + (uint64_t) exptime; } else { sd->expires = 0; } sd->user_flags = user_flags; sd->value_len = (uint32_t) str_value_len; dd("setting value type to %d", value_type); sd->value_type = (uint8_t) value_type; p = ngx_copy(sd->data, key, key_len); ngx_memcpy(p, str_value_buf, str_value_len); ngx_shmtx_unlock(&ctx->shpool->mutex); return NGX_OK; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "lua shared dict set: found old entry bug value size " "NOT matched, removing it first"); remove: ngx_queue_remove(&sd->queue); node = (ngx_rbtree_node_t *) ((u_char *) sd - offsetof(ngx_rbtree_node_t, color)); ngx_rbtree_delete(&ctx->sh->rbtree, node); ngx_slab_free_locked(ctx->shpool, node); } insert: /* rc == NGX_DECLINED or value size unmatch */ if (str_value_buf == NULL) { ngx_shmtx_unlock(&ctx->shpool->mutex); return NGX_OK; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "lua shared dict set: creating a new entry"); n = offsetof(ngx_rbtree_node_t, color) + offsetof(ngx_http_lua_shdict_node_t, data) + key_len + str_value_len; node = ngx_slab_alloc_locked(ctx->shpool, n); if (node == NULL) { if (op & NGX_HTTP_LUA_SHDICT_SAFE_STORE) { ngx_shmtx_unlock(&ctx->shpool->mutex); *errmsg = "no memory"; return NGX_ERROR; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "lua shared dict set: overriding non-expired items " "due to memory shortage for entry \"%*s\"", key_len, key); for (i = 0; i < 30; i++) { if (ngx_http_lua_shdict_expire(ctx, 0) == 0) { break; } *forcible = 1; node = ngx_slab_alloc_locked(ctx->shpool, n); if (node != NULL) { goto allocated; } } ngx_shmtx_unlock(&ctx->shpool->mutex); *errmsg = "no memory"; return NGX_ERROR; } allocated: sd = (ngx_http_lua_shdict_node_t *) &node->color; node->key = hash; sd->key_len = (u_short) key_len; if (exptime > 0) { tp = ngx_timeofday(); sd->expires = (uint64_t) tp->sec * 1000 + tp->msec + (uint64_t) exptime; } else { sd->expires = 0; } sd->user_flags = user_flags; sd->value_len = (uint32_t) str_value_len; dd("setting value type to %d", value_type); sd->value_type = (uint8_t) value_type; p = ngx_copy(sd->data, key, key_len); ngx_memcpy(p, str_value_buf, str_value_len); ngx_rbtree_insert(&ctx->sh->rbtree, node); ngx_queue_insert_head(&ctx->sh->queue, &sd->queue); ngx_shmtx_unlock(&ctx->shpool->mutex); return NGX_OK; }
ngx_int_t ngx_http_lua_shared_dict_get(ngx_shm_zone_t *zone, u_char *key_data, size_t key_len, ngx_http_lua_value_t *value) { u_char *data; size_t len; uint32_t hash; ngx_int_t rc; ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; if (zone == NULL) { return NGX_ERROR; } hash = ngx_crc32_short(key_data, key_len); ctx = zone->data; ngx_shmtx_lock(&ctx->shpool->mutex); rc = ngx_http_lua_shdict_lookup(zone, hash, key_data, key_len, &sd); dd("shdict lookup returned %d", (int) rc); if (rc == NGX_DECLINED || rc == NGX_DONE) { ngx_shmtx_unlock(&ctx->shpool->mutex); return rc; } /* rc == NGX_OK */ value->type = sd->value_type; dd("type: %d", (int) value->type); data = sd->data + sd->key_len; len = (size_t) sd->value_len; switch (value->type) { case LUA_TSTRING: if (value->value.s.data == NULL || value->value.s.len == 0) { ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "no string buffer " "initialized"); return NGX_ERROR; } if (len > value->value.s.len) { len = value->value.s.len; } else { value->value.s.len = len; } ngx_memcpy(value->value.s.data, data, len); break; case LUA_TNUMBER: if (len != sizeof(double)) { ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "bad lua number " "value size found for key %*s: %lu", key_len, key_data, (unsigned long) len); ngx_shmtx_unlock(&ctx->shpool->mutex); return NGX_ERROR; } ngx_memcpy(&value->value.b, data, len); break; case LUA_TBOOLEAN: if (len != sizeof(u_char)) { ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "bad lua boolean " "value size found for key %*s: %lu", key_len, key_data, (unsigned long) len); ngx_shmtx_unlock(&ctx->shpool->mutex); return NGX_ERROR; } value->value.b = *data; break; default: ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "bad lua value type " "found for key %*s: %d", key_len, key_data, (int) value->type); ngx_shmtx_unlock(&ctx->shpool->mutex); return NGX_ERROR; } ngx_shmtx_unlock(&ctx->shpool->mutex); return NGX_OK; }
static int ngx_http_lua_shdict_get_helper(lua_State *L, int get_stale) { int n; ngx_str_t name; ngx_str_t key; uint32_t hash; ngx_int_t rc; ngx_http_lua_shdict_ctx_t *ctx; ngx_http_lua_shdict_node_t *sd; ngx_str_t value; int value_type; double num; u_char c; ngx_shm_zone_t *zone; uint32_t user_flags = 0; n = lua_gettop(L); if (n != 2) { return luaL_error(L, "expecting exactly two arguments, " "but only seen %d", n); } zone = lua_touserdata(L, 1); if (zone == NULL) { return luaL_error(L, "bad \"zone\" argument"); } ctx = zone->data; name = ctx->name; if (lua_isnil(L, 2)) { lua_pushnil(L); lua_pushliteral(L, "nil key"); return 2; } key.data = (u_char *) luaL_checklstring(L, 2, &key.len); if (key.len == 0) { lua_pushnil(L); lua_pushliteral(L, "empty key"); return 2; } if (key.len > 65535) { lua_pushnil(L); lua_pushliteral(L, "key too long"); return 2; } hash = ngx_crc32_short(key.data, key.len); #if (NGX_DEBUG) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "fetching key \"%V\" in shared dict \"%V\"", &key, &name); #endif /* NGX_DEBUG */ ngx_shmtx_lock(&ctx->shpool->mutex); #if 1 if (!get_stale) { ngx_http_lua_shdict_expire(ctx, 1); } #endif rc = ngx_http_lua_shdict_lookup(zone, hash, key.data, key.len, &sd); dd("shdict lookup returns %d", (int) rc); if (rc == NGX_DECLINED || (rc == NGX_DONE && !get_stale)) { ngx_shmtx_unlock(&ctx->shpool->mutex); lua_pushnil(L); return 1; } /* rc == NGX_OK || (rc == NGX_DONE && get_stale) */ value_type = sd->value_type; dd("data: %p", sd->data); dd("key len: %d", (int) sd->key_len); value.data = sd->data + sd->key_len; value.len = (size_t) sd->value_len; switch (value_type) { case LUA_TSTRING: lua_pushlstring(L, (char *) value.data, value.len); break; case LUA_TNUMBER: if (value.len != sizeof(double)) { ngx_shmtx_unlock(&ctx->shpool->mutex); return luaL_error(L, "bad lua number value size found for key %s " "in shared_dict %s: %lu", key.data, name.data, (unsigned long) value.len); } num = *(double *) value.data; lua_pushnumber(L, num); break; case LUA_TBOOLEAN: if (value.len != sizeof(u_char)) { ngx_shmtx_unlock(&ctx->shpool->mutex); return luaL_error(L, "bad lua boolean value size found for key %s " "in shared_dict %s: %lu", key.data, name.data, (unsigned long) value.len); } c = *value.data; lua_pushboolean(L, c ? 1 : 0); break; default: ngx_shmtx_unlock(&ctx->shpool->mutex); return luaL_error(L, "bad value type found for key %s in " "shared_dict %s: %d", key.data, name.data, value_type); } user_flags = sd->user_flags; ngx_shmtx_unlock(&ctx->shpool->mutex); if (get_stale) { /* always return value, flags, stale */ if (user_flags) { lua_pushinteger(L, (lua_Integer) user_flags); } else { lua_pushnil(L); } lua_pushboolean(L, rc == NGX_DONE); return 3; } if (user_flags) { lua_pushinteger(L, (lua_Integer) user_flags); return 2; } return 1; }
static int shared_dict_get2mqtt(lua_State * L) { ngx_http_lua_shdict_ctx_t *ctx; ngx_shm_zone_t *zone; ngx_queue_t *q, *prev; ngx_http_lua_shdict_node_t *sd; ngx_time_t *tp; int n; int total = 0; int attempts = 1024; uint64_t now; ngx_str_t zone_name,topic; double *num; bool is_expression; uint32_t hash; u_char c; n = lua_gettop(L); if (n != 2) { return luaL_error(L, "expecting 2 arguments, " "but only seen %d", n); } //zone = lua_touserdata(L, 1); //if (zone == NULL) { //return luaL_error(L, "bad \"zone\" argument"); //} zone_name.data = (u_char *) luaL_checklstring(L, 1, &zone_name.len); if (zone_name.len == 0) { lua_pushnil(L); lua_pushliteral(L, "empty zone_name"); return 2; } topic.data = (u_char *) luaL_checklstring(L, 2, &topic.len); if (topic.len == 0) { lua_pushnil(L); lua_pushliteral(L, "empty topic"); return 2; } zone = ngx_http_lua_find_zone(zone_name.data,zone_name.len); if (zone == NULL) { return luaL_error(L, "not found \"zone\" by argument: %s",zone_name.data); } ctx = zone->data; if (ctx == NULL) { return luaL_error(L, "bad \"ctx\" argument"); } tp = ngx_timeofday(); now = (uint64_t) tp->sec * 1000 + tp->msec; for(n=topic.len-1;n>=0;n--){ switch(topic.data[n]){ case '+': case '#': n=-1; is_expression=true; break; } } if(!is_expression) hash = ngx_crc32_short(topic.data, topic.len); //ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "is_expression %d,topic: %s",is_expression,topic.data); ngx_shmtx_lock(&ctx->shpool->mutex); if(!is_expression){ n = ngx_http_lua_shdict_lookup(zone, hash, topic.data, topic.len, &sd); ngx_shmtx_unlock(&ctx->shpool->mutex); if (n == NGX_OK) { lua_createtable(L, 1, 0); lua_pushlstring(L, sd->data, sd->key_len); num = (double *) (sd->data+sd->key_len); lua_pushnumber(L, *num); lua_rawset(L, -3); }else{ lua_createtable(L, 0, 0); } return 1; } if (ngx_queue_empty(&ctx->sh->queue)) { ngx_shmtx_unlock(&ctx->shpool->mutex); lua_createtable(L, 0, 0); return 1; } lua_createtable(L, 10000, 0); total = 0; q = ngx_queue_last(&ctx->sh->queue); while (q != ngx_queue_sentinel(&ctx->sh->queue)) { prev = ngx_queue_prev(q); sd = ngx_queue_data(q, ngx_http_lua_shdict_node_t, queue); if(ngx_mqtt_str_is_match(sd->data, sd->key_len,topic.data,topic.len)){ if (sd->expires == 0 || sd->expires > now) { lua_pushlstring(L, sd->data, sd->key_len); num = (double *) (sd->data+sd->key_len); lua_pushnumber(L, *num); //lua_rawseti(L, -3);//, ++total); lua_rawset(L, -3); } } q = prev; } ngx_shmtx_unlock(&ctx->shpool->mutex); return 1; }