diff --git a/core/cache.c b/core/cache.c index de9c6502..91936a47 100644 --- a/core/cache.c +++ b/core/cache.c @@ -416,6 +416,24 @@ char *uwsgi_cache_get2(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint6 return NULL; } +int64_t uwsgi_cache_num2(struct uwsgi_cache *uc, char *key, uint16_t keylen) { + + uint64_t index = uwsgi_cache_get_index(uc, key, keylen); + + if (index) { + struct uwsgi_cache_item *uci = cache_item(index); + if (uci->flags & UWSGI_CACHE_FLAG_UNGETTABLE) + return 0; + uci->hits++; + uc->hits++; + int64_t *num = (int64_t *) (uc->data + (uci->first_block * uc->blocksize)); + return *num; + } + + uc->miss++; + return 0; +} + char *uwsgi_cache_get3(struct uwsgi_cache *uc, char *key, uint16_t keylen, uint64_t * valsize, uint64_t *expires) { uint64_t index = uwsgi_cache_get_index(uc, key, keylen); @@ -662,7 +680,7 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v } else if (flags & UWSGI_CACHE_FLAG_UPDATE) { uci = cache_item(index); - if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE)) { + if (expires && !(flags & UWSGI_CACHE_FLAG_ABSEXPIRE) && !(flags & UWSGI_CACHE_FLAG_FIXEXPIRE)) { now = uwsgi_now(); expires += now; uci->expires = expires; @@ -1019,6 +1037,7 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) { char *c_udp_servers = NULL; char *c_bitmap = NULL; char *c_use_last_modified = NULL; + char *c_math_initial = NULL; if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=', "name", &c_name, @@ -1045,6 +1064,7 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) { "udpserver", &c_udp_servers, "bitmap", &c_bitmap, "lastmod", &c_use_last_modified, + "math_initial", &c_math_initial, NULL)) { uwsgi_log("unable to parse cache definition\n"); exit(1); @@ -1091,6 +1111,8 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) { } if (c_use_last_modified) uc->use_last_modified = 1; + if (c_math_initial) uc->math_initial = strtol(c_math_initial, NULL, 10); + uc->store_sync = uwsgi.cache_store_sync; if (c_store_sync) { uc->store_sync = uwsgi_n64(c_store_sync); } diff --git a/core/utils.c b/core/utils.c index 4d150174..4a97e392 100644 --- a/core/utils.c +++ b/core/utils.c @@ -1826,6 +1826,12 @@ char *uwsgi_num2str(int num) { return str; } +char *uwsgi_64bit2str(int64_t num) { + char *str = uwsgi_malloc(sizeof(MAX64_STR)+1); + snprintf(str, sizeof(MAX64_STR)+1, "%lld", (long long) num); + return str; +} + int uwsgi_num2str2(int num, char *ptr) { return snprintf(ptr, 11, "%d", num); diff --git a/plugins/python/uwsgi_pymodule.c b/plugins/python/uwsgi_pymodule.c index 3137b5e3..d3e9d422 100644 --- a/plugins/python/uwsgi_pymodule.c +++ b/plugins/python/uwsgi_pymodule.c @@ -2555,7 +2555,7 @@ PyObject *py_uwsgi_cache_set(PyObject * self, PyObject * args) { uint64_t expires = 0; - if (!PyArg_ParseTuple(args, "s#s#|is:cache_set", &key, &keylen, &value, &vallen, &expires, &remote)) { + if (!PyArg_ParseTuple(args, "s#s#|ls:cache_set", &key, &keylen, &value, &vallen, &expires, &remote)) { return NULL; } @@ -2582,7 +2582,7 @@ PyObject *py_uwsgi_cache_update(PyObject * self, PyObject * args) { uint64_t expires = 0; - if (!PyArg_ParseTuple(args, "s#s#|is:cache_update", &key, &keylen, &value, &vallen, &expires, &remote)) { + if (!PyArg_ParseTuple(args, "s#s#|ls:cache_update", &key, &keylen, &value, &vallen, &expires, &remote)) { return NULL; } @@ -2599,6 +2599,106 @@ PyObject *py_uwsgi_cache_update(PyObject * self, PyObject * args) { } +PyObject *py_uwsgi_cache_inc(PyObject * self, PyObject * args) { + + char *key; + Py_ssize_t keylen = 0; + char *remote = NULL; + int64_t value = 1; + uint64_t expires = 0; + + if (!PyArg_ParseTuple(args, "s#|lls:cache_inc", &key, &keylen, &value, &expires, &remote)) { + return NULL; + } + + UWSGI_RELEASE_GIL + if (uwsgi_cache_magic_set(key, keylen, (char *) &value, 8, expires, UWSGI_CACHE_FLAG_UPDATE|UWSGI_CACHE_FLAG_MATH|UWSGI_CACHE_FLAG_FIXEXPIRE|UWSGI_CACHE_FLAG_INC, remote)) { + UWSGI_GET_GIL + Py_INCREF(Py_None); + return Py_None; + } + UWSGI_GET_GIL + + Py_INCREF(Py_True); + return Py_True; + +} + +PyObject *py_uwsgi_cache_dec(PyObject * self, PyObject * args) { + + char *key; + Py_ssize_t keylen = 0; + char *remote = NULL; + int64_t value = 1; + uint64_t expires = 0; + + if (!PyArg_ParseTuple(args, "s#|lls:cache_dec", &key, &keylen, &value, &expires, &remote)) { + return NULL; + } + + UWSGI_RELEASE_GIL + if (uwsgi_cache_magic_set(key, keylen, (char *) &value, 8, expires, UWSGI_CACHE_FLAG_UPDATE|UWSGI_CACHE_FLAG_MATH|UWSGI_CACHE_FLAG_FIXEXPIRE|UWSGI_CACHE_FLAG_DEC, remote)) { + UWSGI_GET_GIL + Py_INCREF(Py_None); + return Py_None; + } + UWSGI_GET_GIL + + Py_INCREF(Py_True); + return Py_True; + +} + +PyObject *py_uwsgi_cache_mul(PyObject * self, PyObject * args) { + + char *key; + Py_ssize_t keylen = 0; + char *remote = NULL; + int64_t value = 2; + uint64_t expires = 0; + + if (!PyArg_ParseTuple(args, "s#|lls:cache_mul", &key, &keylen, &value, &expires, &remote)) { + return NULL; + } + + UWSGI_RELEASE_GIL + if (uwsgi_cache_magic_set(key, keylen, (char *) &value, 8, expires, UWSGI_CACHE_FLAG_UPDATE|UWSGI_CACHE_FLAG_MATH|UWSGI_CACHE_FLAG_FIXEXPIRE|UWSGI_CACHE_FLAG_MUL, remote)) { + UWSGI_GET_GIL + Py_INCREF(Py_None); + return Py_None; + } + UWSGI_GET_GIL + + Py_INCREF(Py_True); + return Py_True; + +} + +PyObject *py_uwsgi_cache_div(PyObject * self, PyObject * args) { + + char *key; + Py_ssize_t keylen = 0; + char *remote = NULL; + int64_t value = 2; + uint64_t expires = 0; + + if (!PyArg_ParseTuple(args, "s#|lls:cache_div", &key, &keylen, &value, &expires, &remote)) { + return NULL; + } + + UWSGI_RELEASE_GIL + if (uwsgi_cache_magic_set(key, keylen, (char *) &value, 8, expires, UWSGI_CACHE_FLAG_UPDATE|UWSGI_CACHE_FLAG_MATH|UWSGI_CACHE_FLAG_FIXEXPIRE|UWSGI_CACHE_FLAG_DIV, remote)) { + UWSGI_GET_GIL + Py_INCREF(Py_None); + return Py_None; + } + UWSGI_GET_GIL + + Py_INCREF(Py_True); + return Py_True; + +} + PyObject *py_uwsgi_cache_exists(PyObject * self, PyObject * args) { @@ -2940,6 +3040,31 @@ PyObject *py_uwsgi_cache_get(PyObject * self, PyObject * args) { } +PyObject *py_uwsgi_cache_num(PyObject * self, PyObject * args) { + + char *key; + Py_ssize_t keylen = 0; + char *cache = NULL; + + if (!PyArg_ParseTuple(args, "s#|s:cache_num", &key, &keylen, &cache)) { + return NULL; + } + + uint64_t vallen = 0; + UWSGI_RELEASE_GIL + char *value = uwsgi_cache_magic_get(key, keylen, &vallen, NULL, cache); + UWSGI_GET_GIL + if (value && vallen == 8) { + int64_t *num = (int64_t *) value; + PyObject *ret = PyLong_FromLong(*num); + free(value); + return ret; + } + + return PyLong_FromLong(0); + +} + static PyMethodDef uwsgi_cache_methods[] = { {"cache_get", py_uwsgi_cache_get, METH_VARARGS, ""}, {"cache_set", py_uwsgi_cache_set, METH_VARARGS, ""}, @@ -2947,6 +3072,11 @@ static PyMethodDef uwsgi_cache_methods[] = { {"cache_del", py_uwsgi_cache_del, METH_VARARGS, ""}, {"cache_exists", py_uwsgi_cache_exists, METH_VARARGS, ""}, {"cache_clear", py_uwsgi_cache_clear, METH_VARARGS, ""}, + {"cache_inc", py_uwsgi_cache_inc, METH_VARARGS, ""}, + {"cache_dec", py_uwsgi_cache_dec, METH_VARARGS, ""}, + {"cache_mul", py_uwsgi_cache_mul, METH_VARARGS, ""}, + {"cache_div", py_uwsgi_cache_div, METH_VARARGS, ""}, + {"cache_num", py_uwsgi_cache_num, METH_VARARGS, ""}, {NULL, NULL}, }; diff --git a/plugins/router_cache/router_cache.c b/plugins/router_cache/router_cache.c index 7dd73862..e1a6749d 100644 --- a/plugins/router_cache/router_cache.c +++ b/plugins/router_cache/router_cache.c @@ -32,6 +32,8 @@ struct uwsgi_router_cache_conf { // use mime types ? char *mime; + char *as_num; + #ifdef UWSGI_ZLIB char *gzip; size_t gzip_len; @@ -211,6 +213,17 @@ static int uwsgi_routing_func_cachevar(struct wsgi_request *wsgi_req, struct uws char *value = uwsgi_cache_magic_get(ub->buf, ub->pos, &valsize, NULL, urcc->name); uwsgi_buffer_destroy(ub); if (value) { + if (urcc->as_num) { + char *tmp = value; + if (valsize == 8) { + int64_t *num = (int64_t *) value; + value = uwsgi_64bit2str(*num); + } + else { + value = uwsgi_64bit2str(0); + } + free(tmp); + } if (!uwsgi_req_append(wsgi_req, urcc->var, urcc->var_len, value, valsize)) { free(value); return UWSGI_ROUTE_BREAK; @@ -409,6 +422,8 @@ static int uwsgi_router_cachevar(struct uwsgi_route *ur, char *args) { "key", &urcc->key, "var", &urcc->var, "name", &urcc->name, + "num", &urcc->as_num, + "as_num", &urcc->as_num, NULL)) { uwsgi_log("invalid route syntax: %s\n", args); exit(1); diff --git a/uwsgi.h b/uwsgi.h index 8a93019f..6ffe2971 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -9,7 +9,8 @@ extern "C" { #define UMAX16 65536 #define UMAX8 256 -#define UMAX64_STR "18446744073709551616" +#define UMAX64_STR "18446744073709551615" +#define MAX64_STR "−9223372036854775808" #define uwsgi_error(x) uwsgi_log("%s: %s [%s line %d]\n", x, strerror(errno), __FILE__, __LINE__); #define uwsgi_error_realpath(x) uwsgi_log("realpath() of %s failed: %s [%s line %d]\n", x, strerror(errno), __FILE__, __LINE__); @@ -321,6 +322,7 @@ extern int pivot_root(const char *new_root, const char *put_old); #define UWSGI_CACHE_FLAG_DEC 1 << 6 #define UWSGI_CACHE_FLAG_MUL 1 << 7 #define UWSGI_CACHE_FLAG_DIV 1 << 8 +#define UWSGI_CACHE_FLAG_FIXEXPIRE 1 << 9 #ifdef UWSGI_SSL #include "openssl/conf.h" @@ -2759,6 +2761,7 @@ struct uwsgi_cache *uwsgi_cache_by_namelen(char *, uint16_t); void uwsgi_cache_create_all(void); void uwsgi_cache_sync_from_nodes(struct uwsgi_cache *); void uwsgi_cache_setup_nodes(struct uwsgi_cache *); +int64_t uwsgi_cache_num2(struct uwsgi_cache *, char *, uint16_t); void uwsgi_cache_sync_all(void); void uwsgi_cache_start_sweepers(void); @@ -2828,6 +2831,7 @@ void uwsgi_detach_daemons(); void emperor_loop(void); char *uwsgi_num2str(int); +char *uwsgi_64bit2str(int64_t); char *magic_sub(char *, size_t, size_t *, char *[]); void init_magic_table(char *[]);