diff --git a/core/cache.c b/core/cache.c index 8b113ac8..ab5da35b 100644 --- a/core/cache.c +++ b/core/cache.c @@ -751,18 +751,6 @@ static void cache_send_udp_command(struct uwsgi_cache *uc, char *key, uint16_t k } -void uwsgi_cache_wlock(struct uwsgi_cache *uc) { - uwsgi.lock_ops.wlock(uc->lock); -} - -void uwsgi_cache_rlock(struct uwsgi_cache *uc) { - uwsgi.lock_ops.rlock(uc->lock); -} - -void uwsgi_cache_rwunlock(struct uwsgi_cache *uc) { - uwsgi.lock_ops.rwunlock(uc->lock); -} - void *cache_udp_server_loop(void *ucache) { // block all signals sigset_t smask; @@ -1231,6 +1219,22 @@ error: return NULL; } +struct uwsgi_buffer *uwsgi_cache_prepare_magic_clear(char *cache_name, uint16_t cache_name_len) { + struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); + ub->pos = 4; + + if (uwsgi_buffer_append_keyval(ub, "cmd", 3, "clear", 5)) goto error; + if (cache_name) { + if (uwsgi_buffer_append_keyval(ub, "cache", 5, cache_name, cache_name_len)) goto error; + } + + return ub; +error: + uwsgi_buffer_destroy(ub); + return NULL; +} + + struct uwsgi_buffer *uwsgi_cache_prepare_magic_set(char *cache_name, uint16_t cache_name_len, char *key, uint16_t key_len, uint64_t len, uint64_t expires) { struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); ub->pos = 4; @@ -1609,3 +1613,77 @@ int uwsgi_cache_magic_del(char *key, uint16_t keylen, char *cache) { return -1 ; } + +int uwsgi_cache_magic_clear(char *cache) { + + struct uwsgi_cache_magic_context ucmc; + struct uwsgi_cache *uc = NULL; + char *cache_server = NULL; + char *cache_name = NULL; + uint16_t cache_name_len = 0; + if (cache) { + char *at = strchr(cache, '@'); + if (!at) { + uc = uwsgi_cache_by_name(cache); + } + else { + cache_server = at + 1; + cache_name = cache; + cache_name_len = at - cache; + } + } + // use default (local) cache + else { + uc = uwsgi.caches; + } + + // we have a local cache !!! + if (uc) { + uint64_t i; + uwsgi_wlock(uc->lock); + for (i = 1; i < uwsgi.caches->max_items; i++) { + if (uwsgi_cache_del2(uc, NULL, 0, i, 0)) { + uwsgi_rwunlock(uc->lock); + return -1; + } + } + uwsgi_rwunlock(uc->lock); + return 0; + } + + // we have a remote one + if (cache_server) { + int fd = uwsgi_connect(cache_server, 0, 1); + if (fd < 0) return -1; + + int ret = uwsgi.wait_write_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]); + if (ret <= 0) { + close(fd); + return -1; + } + + struct uwsgi_buffer *ub = uwsgi_cache_prepare_magic_clear(cache_name, cache_name_len); + if (!ub) { + close(fd); + return -1; + } + + if (cache_magic_send_and_manage(fd, ub, NULL, 0, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], &ucmc)) { + close(fd); + uwsgi_buffer_destroy(ub); + return -1; + } + + if (uwsgi_strncmp(ucmc.status, ucmc.status_len, "ok", 2)) { + close(fd); + uwsgi_buffer_destroy(ub); + return -1; + } + + return 0; + } + + return -1 ; + +} + diff --git a/plugins/cache/cache.c b/plugins/cache/cache.c index 4f1253a8..70a020d6 100644 --- a/plugins/cache/cache.c +++ b/plugins/cache/cache.c @@ -135,6 +135,28 @@ static void manage_magic_context(struct wsgi_request *wsgi_req, struct uwsgi_cac return; } + // cache clear + if (!uwsgi_strncmp(ucmc->cmd, ucmc->cmd_len, "clear", 5)) { + uint64_t i; + uwsgi_wlock(uc->lock); + for (i = 1; i < uwsgi.caches->max_items; i++) { + if (uwsgi_cache_del2(uc, NULL, 0, i, 0)) { + uwsgi_rwunlock(uc->lock); + return; + } + } + // we are still locked !!! + ub = uwsgi_buffer_new(uwsgi.page_size); + ub->pos = 4; + if (uwsgi_buffer_append_keyval(ub, "status", 6, "ok", 2)) goto error; + if (uwsgi_buffer_set_uh(ub, 111, 17)) goto error; + // unlock !!! + uwsgi_rwunlock(uc->lock); + uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); + uwsgi_buffer_destroy(ub); + return; + } + // cache set if (!uwsgi_strncmp(ucmc->cmd, ucmc->cmd_len, "set", 3) || !uwsgi_strncmp(ucmc->cmd, ucmc->cmd_len, "update", 6)) { if (ucmc->size == 0 || ucmc->size > uc->max_item_size) return; diff --git a/plugins/python/uwsgi_pymodule.c b/plugins/python/uwsgi_pymodule.c index ac1d6f8b..4319b534 100644 --- a/plugins/python/uwsgi_pymodule.c +++ b/plugins/python/uwsgi_pymodule.c @@ -2526,18 +2526,22 @@ static PyMethodDef uwsgi_sa_methods[] = { PyObject *py_uwsgi_cache_clear(PyObject * self, PyObject * args) { - uint64_t i; - // skip the first slot - for (i = 1; i < uwsgi.caches->max_items; i++) { - UWSGI_RELEASE_GIL - uwsgi_wlock(uwsgi.caches->lock); - uwsgi_cache_del(NULL, 0, i, 0); - uwsgi_rwunlock(uwsgi.caches->lock); - UWSGI_GET_GIL - } + char *cache = NULL; - Py_INCREF(Py_None); - return Py_None; + if (!PyArg_ParseTuple(args, "|s:cache_clear", &cache)) { + return NULL; + } + + UWSGI_RELEASE_GIL + if (!uwsgi_cache_magic_clear(cache)) { + UWSGI_GET_GIL + Py_INCREF(Py_True); + return Py_True; + } + UWSGI_GET_GIL + + Py_INCREF(Py_None); + return Py_None; } @@ -2628,7 +2632,7 @@ PyObject *py_uwsgi_cache_exists(PyObject * self, PyObject * args) { Py_ssize_t keylen = 0; char *cache = NULL; - if (!PyArg_ParseTuple(args, "s#|s:cache_get", &key, &keylen, &cache)) { + if (!PyArg_ParseTuple(args, "s#|s:cache_exists", &key, &keylen, &cache)) { return NULL; } diff --git a/uwsgi.h b/uwsgi.h index fffdf0c5..3f447181 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -3727,16 +3727,12 @@ void uwsgi_daemons_spawn_all(); int uwsgi_send_http_stats(int); ssize_t uwsgi_simple_request_read(struct wsgi_request *, char *, size_t); - int uwsgi_plugin_modifier1(char *); +int uwsgi_plugin_modifier1(char *); - void uwsgi_cache_wlock(struct uwsgi_cache *); - void uwsgi_cache_rlock(struct uwsgi_cache *); - void uwsgi_cache_rwunlock(struct uwsgi_cache *); +void *cache_udp_server_loop(void *); - void *cache_udp_server_loop(void *); - - void uwsgi_user_lock(int); - void uwsgi_user_unlock(int); +void uwsgi_user_lock(int); +void uwsgi_user_unlock(int); void simple_loop_run_int(int); @@ -3908,6 +3904,7 @@ char *uwsgi_cache_magic_get(char *, uint16_t, uint64_t *, char *); int uwsgi_cache_magic_set(char *, uint16_t, char *, uint64_t, uint64_t, uint64_t, char *); int uwsgi_cache_magic_del(char *, uint16_t, char *); int uwsgi_cache_magic_exists(char *, uint16_t, char *); +int uwsgi_cache_magic_clear(char *); void uwsgi_cache_magic_context_hook(char *, uint16_t, char *, uint16_t, void *); #ifdef UWSGI_ZLIB