diff --git a/core/cache.c b/core/cache.c index 1498761b..1da3e074 100644 --- a/core/cache.c +++ b/core/cache.c @@ -546,7 +546,7 @@ int uwsgi_cache_set2(struct uwsgi_cache *uc, char *key, uint16_t keylen, char *v if (keylen > uc->keysize) return -1; - if (!uc->blocks_bitmap && vallen > uc->blocksize) return -1; + if (vallen > uc->max_item_size) return -1; //uwsgi_log("putting cache data in key %.*s %d\n", keylen, key, vallen); index = uwsgi_cache_get_index(uc, key, keylen); @@ -946,6 +946,7 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) { uc->name = "default"; uc->name_len = strlen(uc->name); uc->blocksize = uwsgi.cache_blocksize; + uc->max_item_size = uc->blocksize; if (!uc->blocksize) uc->blocksize = UMAX16; uc->max_items = uwsgi.cache_max_items; uc->blocks = uwsgi.cache_max_items; @@ -1024,6 +1025,7 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) { // defaults uc->blocks = uc->max_items; uc->blocksize = UMAX16; + uc->max_item_size = uc->blocksize; uc->keysize = 2048; uc->hashsize = UMAX16; uc->hash = uwsgi_hash_algo_get("djb33x"); @@ -1039,7 +1041,10 @@ struct uwsgi_cache *uwsgi_cache_create(char *arg) { if (!uc->hashsize) { uwsgi_log("invalid cache hashsize for \"%s\"\n", uc->name); exit(1); } if (c_keysize) uc->keysize = uwsgi_n64(c_keysize); if (!uc->keysize || uc->keysize >= UMAX16) { uwsgi_log("invalid cache keysize for \"%s\"\n", uc->name); exit(1); } - if (c_bitmap) uc->use_blocks_bitmap = 1; + if (c_bitmap) { + uc->use_blocks_bitmap = 1; + uc->max_item_size = uc->blocksize * uc->blocks; + } uc->store_sync = uwsgi.cache_store_sync; if (c_store_sync) { uc->store_sync = uwsgi_n64(c_store_sync); } @@ -1268,6 +1273,28 @@ error: return NULL; } +static int cache_magic_send_and_manage(int fd, struct uwsgi_buffer *ub, char *stream, uint64_t stream_len, int timeout, struct uwsgi_cache_magic_context *ucmc) { + if (uwsgi_buffer_set_uh(ub, 111, 17)) return -1; + + if (stream) { + if (uwsgi_buffer_append(ub, stream, stream_len)) return -1; + } + + if (uwsgi_write_true_nb(fd, ub->buf, ub->pos, timeout)) return -1; + + // ok now wait for the response, using the same buffer of the request + // NOTE: after using a uwsgi_buffer in that way we basically destroy (even if we can safely free it) + size_t rlen = ub->pos; + if (uwsgi_read_with_realloc(fd, &ub->buf, &rlen, timeout)) return -1; + // try to fix the buffer to maintain size info + ub->pos = rlen; + + // now we have a uwsgi dictionary with all of the options needed, let's parse it + memset(ucmc, 0, sizeof(struct uwsgi_cache_magic_context)); + if (uwsgi_hooked_parse(ub->buf, rlen, uwsgi_cache_magic_context_hook, ucmc)) return -1; + return 0; +} + char *uwsgi_cache_magic_get(char *key, uint16_t keylen, uint64_t *vallen, char *cache) { struct uwsgi_cache_magic_context ucmc; struct uwsgi_cache *uc = NULL; @@ -1309,7 +1336,6 @@ char *uwsgi_cache_magic_get(char *key, uint16_t keylen, uint64_t *vallen, char * int fd = uwsgi_connect(cache_server, 0, 1); if (fd < 0) return NULL; - // wait for connection; int ret = uwsgi.wait_write_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]); if (ret <= 0) { close(fd); @@ -1322,33 +1348,10 @@ char *uwsgi_cache_magic_get(char *key, uint16_t keylen, uint64_t *vallen, char * return NULL; } - if (uwsgi_buffer_set_uh(ub, 111, 17)) { + 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 NULL; - } - - if (uwsgi_write_true_nb(fd, ub->buf, ub->pos, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) { - close(fd); - uwsgi_buffer_destroy(ub); - return NULL; - } - - // ok now wait for the response, using the same buffer of the request - // NOTE: after using a uwsgi_buffer in that way we basically destroy (even if we can safely free it) - size_t rlen = ub->pos; - if (uwsgi_read_with_realloc(fd, &ub->buf, &rlen, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) { - close(fd); - uwsgi_buffer_destroy(ub); - return NULL; - } - - // now we have a uwsgi dictionary with all of the options needed, let's parse it - memset(&ucmc, 0, sizeof(struct uwsgi_cache_magic_context)); - if (uwsgi_hooked_parse(ub->buf, rlen, uwsgi_cache_magic_context_hook, &ucmc)) { - close(fd); - uwsgi_buffer_destroy(ub); - return NULL; + uwsgi_buffer_destroy(ub); + return NULL; } if (uwsgi_strncmp(ucmc.status, ucmc.status_len, "ok", 2)) { @@ -1364,7 +1367,7 @@ char *uwsgi_cache_magic_get(char *key, uint16_t keylen, uint64_t *vallen, char * } // ok we now need to fix our buffer (if needed) - if (ucmc.size > rlen) { + if (ucmc.size > ub->pos) { char *tmp_buf = realloc(ub->buf, ucmc.size); if (!tmp_buf) { uwsgi_error("uwsgi_cache_magic_get()/realloc()"); @@ -1375,6 +1378,7 @@ char *uwsgi_cache_magic_get(char *key, uint16_t keylen, uint64_t *vallen, char * ub->buf = tmp_buf; } + // read the raw value from the socket if (uwsgi_read_whole_true_nb(fd, ub->buf, ucmc.size, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) { close(fd); uwsgi_buffer_destroy(ub); @@ -1394,16 +1398,21 @@ char *uwsgi_cache_magic_get(char *key, uint16_t keylen, uint64_t *vallen, char * } -int uwsgi_cache_magic_set(char *key, uint16_t keylen, char *value, uint64_t vallen, uint64_t expires, uint64_t flags, char *cachename) { - - struct uwsgi_cache *uc = NULL; +int uwsgi_cache_magic_set(char *key, uint16_t keylen, char *value, uint64_t vallen, uint64_t expires, uint64_t flags, char *cache) { + struct uwsgi_cache_magic_context ucmc; + struct uwsgi_cache *uc = NULL; char *cache_server = NULL; - if (cachename) { - char *at = strchr(cachename, '@'); + char *cache_name = NULL; + uint16_t cache_name_len = 0; + if (cache) { + char *at = strchr(cache, '@'); if (!at) { - uc = uwsgi_cache_by_name(cachename); + uc = uwsgi_cache_by_name(cache); } else { + cache_server = at + 1; + cache_name = cache; + cache_name_len = at - cache; } } // use default (local) cache @@ -1421,6 +1430,36 @@ int uwsgi_cache_magic_set(char *key, uint16_t keylen, char *value, uint64_t vall // 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_set(cache_name, cache_name_len, key, keylen, vallen, expires); + if (!ub) { + close(fd); + return -1; + } + + if (cache_magic_send_and_manage(fd, ub, value, vallen, 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; + } + + uwsgi_buffer_destroy(ub); + return 0; + } return -1; diff --git a/plugins/cache/cache.c b/plugins/cache/cache.c index d921d488..9fc85089 100644 --- a/plugins/cache/cache.c +++ b/plugins/cache/cache.c @@ -97,6 +97,12 @@ static void manage_magic_context(struct wsgi_request *wsgi_req, struct uwsgi_cac return; } + // cache set + if (!uwsgi_strncmp(ucmc->cmd, ucmc->cmd_len, "set", 3)) { + // allocate memory for the item + } + + return; error: uwsgi_rwunlock(uc->lock); uwsgi_buffer_destroy(ub); diff --git a/plugins/python/uwsgi_pymodule.c b/plugins/python/uwsgi_pymodule.c index ae390aeb..1969518c 100644 --- a/plugins/python/uwsgi_pymodule.c +++ b/plugins/python/uwsgi_pymodule.c @@ -2581,25 +2581,21 @@ PyObject *py_uwsgi_cache_set(PyObject * self, PyObject * args) { char *value; Py_ssize_t vallen = 0; Py_ssize_t keylen = 0; + char *remote = NULL; uint64_t expires = 0; - if (!PyArg_ParseTuple(args, "s#s#|i:cache_set", &key, &keylen, &value, &vallen, &expires)) { + if (!PyArg_ParseTuple(args, "s#s#|is:cache_set", &key, &keylen, &value, &vallen, &expires, &remote)) { return NULL; } - if (uwsgi.caches) { - UWSGI_RELEASE_GIL - uwsgi_wlock(uwsgi.caches->lock); - if (uwsgi_cache_set(key, keylen, value, vallen, expires, 0)) { - uwsgi_rwunlock(uwsgi.caches->lock); - UWSGI_GET_GIL - Py_INCREF(Py_None); - return Py_None; - } - uwsgi_rwunlock(uwsgi.caches->lock); + UWSGI_RELEASE_GIL + if (uwsgi_cache_magic_set(key, keylen, value, vallen, expires, 0, remote)) { UWSGI_GET_GIL + Py_INCREF(Py_None); + return Py_None; } + UWSGI_GET_GIL Py_INCREF(Py_True); return Py_True; diff --git a/uwsgi.h b/uwsgi.h index 37b2858c..b7e31482 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -690,6 +690,7 @@ struct uwsgi_cache { uint64_t blocks_bitmap_size; uint64_t max_items; + uint64_t max_item_size; uint64_t n_items; struct uwsgi_cache_item *items;