From 15fa2be4ee476618510fac83c46441c74f9c83df Mon Sep 17 00:00:00 2001 From: Unbit Date: Sat, 4 Jan 2014 19:28:01 +0100 Subject: [PATCH] preliminary refactoring for the spooler --- core/spooler.c | 136 +++++++++++++++++++++------ plugins/python/uwsgi_pymodule.c | 155 +++++++++---------------------- plugins/rack/rack_api.c | 97 ++++++------------- plugins/spooler/spooler_plugin.c | 17 ++-- uwsgi.h | 4 +- 5 files changed, 189 insertions(+), 220 deletions(-) diff --git a/core/spooler.c b/core/spooler.c index 150df907..dfc21d91 100644 --- a/core/spooler.c +++ b/core/spooler.c @@ -72,12 +72,12 @@ struct uwsgi_spooler *uwsgi_new_spooler(char *dir) { } -struct uwsgi_spooler *uwsgi_get_spooler_by_name(char *name) { +struct uwsgi_spooler *uwsgi_get_spooler_by_name(char *name, size_t name_len) { struct uwsgi_spooler *uspool = uwsgi.spoolers; while (uspool) { - if (!strcmp(uspool->dir, name)) { + if (!uwsgi_strncmp(uspool->dir, strlen(uspool->dir), name, name_len)) { return uspool; } uspool = uspool->next; @@ -167,47 +167,122 @@ void destroy_spool(char *dir, char *file) { } +struct spooler_req { + char *spooler; + size_t spooler_len; + char *priority; + size_t priority_len; + time_t at; +}; -int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core_id, char *buffer, int size, char *priority, time_t at, char *body, size_t body_len) { +static void spooler_req_parser_hook(char *key, uint16_t key_len, char *value, uint16_t value_len, void *data) { + struct spooler_req *sr = (struct spooler_req *) data; + if (!uwsgi_strncmp(key, key_len, "spooler", 7)) { + sr->spooler = value; + sr->spooler_len = value_len; + return; + } + + if (!uwsgi_strncmp(key, key_len, "priority", 8)) { + sr->priority = value; + sr->priority_len = value_len; + return; + } + + if (!uwsgi_strncmp(key, key_len, "at", 2)) { + sr->at = uwsgi_str_num(value, value_len); + return; + } +} + +char *uwsgi_spool_request(struct wsgi_request *wsgi_req, char *buf, size_t len, char *body, size_t body_len) { struct timeval tv; - int fd; - struct uwsgi_header uh; + static uint64_t internal_counter = 0; + int core_id = 0; + int fd = -1; + struct spooler_req sr; + if (len > 0xffff) { + uwsgi_log("[uwsgi-spooler] args buffer is limited to 64k, use the 'body' for bigger values\n"); + return NULL; + } + + // parse the request buffer + memset(&sr, 0, sizeof(struct spooler_req)); + uwsgi_hooked_parse(buf, len, spooler_req_parser_hook, &sr); + + struct uwsgi_spooler *uspool = uwsgi.spoolers; if (!uspool) { - uspool = uwsgi.spoolers; + uwsgi_log("[uwsgi-spooler] no spooler available\n"); + return NULL; + } + + // if it is a number, get the spooler by id instead of by name + if (sr.spooler && sr.spooler_len) { + uspool = uwsgi_get_spooler_by_name(sr.spooler, sr.spooler_len); + if (!uspool) { + uwsgi_log("[uwsgi-spooler] unable to find spooler \"%.*s\"\n", sr.spooler_len, sr.spooler); + return NULL; + } + } + + if (wsgi_req) { + core_id = wsgi_req->async_id; } // this lock is for threads, the pid value in filename will avoid multiprocess races uwsgi_lock(uspool->lock); + // we increase it even if the request fails + internal_counter++; + gettimeofday(&tv, NULL); - if (priority) { - if (snprintf(filename, 1024, "%s/%s", uspool->dir, priority) <= 0) { + char *filename = NULL; + size_t filename_len = 0; + + if (sr.priority && sr.priority_len) { + filename_len = strlen(uspool->dir) + sr.priority_len + strlen(uwsgi.hostname) + 256; + filename = uwsgi_malloc(filename_len); + int ret = snprintf(filename, filename_len, "%s/%.*s", uspool->dir, sr.priority_len, sr.priority); + if (ret <= 0 || ret >= (int) filename_len) { + uwsgi_log("[uwsgi-spooler] error generating spooler filename\n"); + free(filename); uwsgi_unlock(uspool->lock); - return 0; + return NULL; } // no need to check for errors... (void) mkdir(filename, 0777); - if (snprintf(filename, 1024, "%s/%s/uwsgi_spoolfile_on_%s_%d_%d_%d_%llu_%llu", uspool->dir, priority, uwsgi.hostname, (int) getpid(), rn, core_id, (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec) <= 0) { + ret = snprintf(filename, filename_len, "%s/%.*s/uwsgi_spoolfile_on_%s_%d_%d_%d_%llu_%llu", uspool->dir, sr.priority_len, sr.priority, uwsgi.hostname, (int) getpid(), internal_counter, core_id, + (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec); + if (ret <= 0 || ret >=(int) filename_len) { + uwsgi_log("[uwsgi-spooler] error generating spooler filename\n"); + free(filename); uwsgi_unlock(uspool->lock); - return 0; + return NULL; } } else { - if (snprintf(filename, 1024, "%s/uwsgi_spoolfile_on_%s_%d_%d_%d_%llu_%llu", uspool->dir, uwsgi.hostname, (int) getpid(), rn, core_id, (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec) <= 0) { + filename_len = strlen(uspool->dir) + strlen(uwsgi.hostname) + 256; + filename = uwsgi_malloc(filename_len); + int ret = snprintf(filename, filename_len, "%s/uwsgi_spoolfile_on_%s_%d_%d_%d_%llu_%llu", uspool->dir, uwsgi.hostname, (int) getpid(), internal_counter, core_id, + (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec); + if (ret <= 0 || ret >= (int) filename_len) { + uwsgi_log("[uwsgi-spooler] error generating spooler filename\n"); + free(filename); uwsgi_unlock(uspool->lock); - return 0; + return NULL; } } fd = open(filename, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR); if (fd < 0) { uwsgi_error_open(filename); + free(filename); uwsgi_unlock(uspool->lock); - return 0; + return NULL; } // now lock the file, it will no be runnable, until the lock is not removed @@ -215,13 +290,15 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core // in such case the spooler will detect a zeroed file and will retry later if (uwsgi_fcntl_lock(fd)) { close(fd); + free(filename); uwsgi_unlock(uspool->lock); - return 0; + return NULL; } + struct uwsgi_header uh; uh.modifier1 = 17; uh.modifier2 = 0; - uh.pktsize = (uint16_t) size; + uh.pktsize = (uint16_t) len; #ifdef __BIG_ENDIAN__ uh.pktsize = uwsgi_swap16(uh.pktsize); #endif @@ -231,7 +308,7 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core goto clear; } - if (write(fd, buffer, size) != size) { + if (write(fd, buf, len) != (ssize_t) len) { uwsgi_log("[spooler] unable to write args for %s\n", filename); goto clear; } @@ -243,28 +320,28 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core } } - if (at > 0) { + if (sr.at > 0) { #ifdef __UCLIBC__ struct timespec ts[2]; - ts[0].tv_sec = at; + ts[0].tv_sec = sr.at; ts[0].tv_nsec = 0; - ts[1].tv_sec = at; + ts[1].tv_sec = sr.at; ts[1].tv_nsec = 0; if (futimens(fd, ts)) { - uwsgi_error("futimens()"); + uwsgi_error("uwsgi_spooler_request()/futimens()"); } #else struct timeval tv[2]; - tv[0].tv_sec = at; + tv[0].tv_sec = sr.at; tv[0].tv_usec = 0; - tv[1].tv_sec = at; + tv[1].tv_sec = sr.at; tv[1].tv_usec = 0; #ifdef __sun__ if (futimesat(fd, NULL, tv)) { #else if (futimes(fd, tv)) { #endif - uwsgi_error("futimes()"); + uwsgi_error("uwsgi_spooler_request()/futimes()"); } #endif } @@ -273,7 +350,7 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core close(fd); if (!uwsgi.spooler_quiet) - uwsgi_log("[spooler] written %lu bytes to file %s\n", (unsigned long) size + body_len + 4, filename); + uwsgi_log("[spooler] written %lu bytes to file %s\n", (unsigned long) len + body_len + 4, filename); // and here waiting threads can continue uwsgi_unlock(uspool->lock); @@ -293,18 +370,19 @@ int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core spoolers = spoolers->next; } - return 1; + return filename; clear: + if (filename) free(filename); uwsgi_unlock(uspool->lock); - uwsgi_error("write()"); + uwsgi_error("uwsgi_spool_request()/write()"); if (unlink(filename)) { - uwsgi_error("unlink()"); + uwsgi_error("uwsgi_spool_request()/unlink()"); } // unlock the file too close(fd); - return 0; + return NULL; } diff --git a/plugins/python/uwsgi_pymodule.c b/plugins/python/uwsgi_pymodule.c index 8b577236..8906f7f5 100644 --- a/plugins/python/uwsgi_pymodule.c +++ b/plugins/python/uwsgi_pymodule.c @@ -1745,25 +1745,13 @@ PyObject *py_uwsgi_send_spool(PyObject * self, PyObject * args, PyObject *kw) { PyObject *spool_dict, *spool_vars; PyObject *zero, *key, *val; uint16_t keysize, valsize; - char *cur_buf; - int i; - char spool_filename[1024]; struct wsgi_request *wsgi_req = py_current_wsgi_req(); - char *priority = NULL; - long numprio = 0; - time_t at = 0; char *body = NULL; size_t body_len= 0; - // this is a counter for non-request-related tasks (like threads or greenlet) - static int internal_counter = 0xffff; - - struct uwsgi_spooler *uspool = uwsgi.spoolers; - spool_dict = PyTuple_GetItem(args, 0); if (spool_dict) { - if (!PyDict_Check(spool_dict)) { return PyErr_Format(PyExc_ValueError, "The argument of spooler callable must be a dictionary"); } @@ -1774,46 +1762,10 @@ PyObject *py_uwsgi_send_spool(PyObject * self, PyObject * args, PyObject *kw) { spool_dict = kw; } - if (!spool_dict) { return PyErr_Format(PyExc_ValueError, "The argument of spooler callable must be a dictionary"); } - // TODO if "spooler" is a num, get the spooler by id, otherwise get it by directory - PyObject *py_spooler = uwsgi_py_dict_get(spool_dict, "spooler"); - if (py_spooler) { - if (PyString_Check(py_spooler)) { - uspool = uwsgi_get_spooler_by_name(PyString_AsString(py_spooler)); - if (!uspool) { - return PyErr_Format(PyExc_ValueError, "Unknown spooler requested"); - } - } - } - - PyObject *pyprio = uwsgi_py_dict_get(spool_dict, "priority"); - if (pyprio) { - if (PyInt_Check(pyprio)) { - numprio = PyInt_AsLong(pyprio); - uwsgi_py_dict_del(spool_dict, "priority"); - } - } - - PyObject *pyat = uwsgi_py_dict_get(spool_dict, "at"); - if (pyat) { - if (PyInt_Check(pyat)) { - at = (time_t) PyInt_AsLong(pyat); - uwsgi_py_dict_del(spool_dict, "at"); - } - else if (PyLong_Check(pyat)) { - at = (time_t) PyLong_AsLong(pyat); - uwsgi_py_dict_del(spool_dict, "at"); - } - else if (PyFloat_Check(pyat)) { - at = (time_t) PyFloat_AsDouble(pyat); - uwsgi_py_dict_del(spool_dict, "at"); - } - } - PyObject *pybody = uwsgi_py_dict_get(spool_dict, "body"); if (pybody) { if (PyString_Check(pybody)) { @@ -1830,9 +1782,8 @@ PyObject *py_uwsgi_send_spool(PyObject * self, PyObject * args, PyObject *kw) { return Py_None; } - char *spool_buffer = uwsgi_malloc(UMAX16); - - cur_buf = spool_buffer; + int i; + struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); for (i = 0; i < PyList_Size(spool_vars); i++) { zero = PyList_GetItem(spool_vars, i); @@ -1841,98 +1792,80 @@ PyObject *py_uwsgi_send_spool(PyObject * self, PyObject * args, PyObject *kw) { key = PyTuple_GetItem(zero, 0); val = PyTuple_GetItem(zero, 1); -#ifdef UWSGI_DEBUG - uwsgi_log("ob_type %s %s\n", key->ob_type->tp_name, val->ob_type->tp_name); -#endif - - if (PyString_Check(key) && PyString_Check(val)) { - + if (PyString_Check(key)) { keysize = PyString_Size(key); - valsize = PyString_Size(val); - if (cur_buf + keysize + 2 + valsize + 2 <= spool_buffer + UMAX16) { - - *cur_buf++ = (uint8_t) (keysize & 0xff); - *cur_buf++ = (uint8_t) ((keysize >> 8) & 0xff); - - memcpy(cur_buf, PyString_AsString(key), keysize); - cur_buf += keysize; - - *cur_buf++ = (uint8_t) (valsize & 0xff); - *cur_buf++ = (uint8_t) ((valsize >> 8) & 0xff); - - memcpy(cur_buf, PyString_AsString(val), valsize); - cur_buf += valsize; + + if (PyString_Check(val)) { + valsize = PyString_Size(val); + if (uwsgi_buffer_append_keyval(ub, PyString_AsString(key), keysize, PyString_AsString(val), valsize)) { + Py_DECREF(zero); + uwsgi_buffer_destroy(ub); + goto error; + } } else { - Py_DECREF(zero); - free(spool_buffer); - return PyErr_Format(PyExc_ValueError, "spooler packet cannot be more than %d bytes", UMAX16); + PyObject *str = PyObject_Str(val); + if (!str) { + Py_DECREF(zero); + uwsgi_buffer_destroy(ub); + goto error; + } + if (uwsgi_buffer_append_keyval(ub, PyString_AsString(key), keysize, PyString_AsString(str), PyString_Size(str))) { + Py_DECREF(zero); + Py_DECREF(str); + uwsgi_buffer_destroy(ub); + goto error; + } + Py_DECREF(str); } } else { Py_DECREF(zero); - free(spool_buffer); - return PyErr_Format(PyExc_ValueError, "spooler callable dictionary must contains only strings"); + uwsgi_buffer_destroy(ub); + goto error; } } else { - free(spool_buffer); Py_DECREF(zero); - Py_INCREF(Py_None); - return Py_None; + uwsgi_buffer_destroy(ub); + goto error; } + Py_DECREF(zero); } else { - free(spool_buffer); - Py_INCREF(Py_None); - return Py_None; + uwsgi_buffer_destroy(ub); + goto error; } } - if (numprio) { - priority = uwsgi_num2str(numprio); - } - - int async_id; - - if (wsgi_req) { - async_id = wsgi_req->async_id; - } - else { - // the GIL is protecting this counter... - async_id = internal_counter; - internal_counter++; - } - UWSGI_RELEASE_GIL - i = spool_request(uspool, spool_filename, uwsgi.workers[0].requests + 1, async_id, spool_buffer, cur_buf - spool_buffer, priority, at, body, body_len); + char *filename = uwsgi_spool_request(wsgi_req, ub->buf, ub->pos, body, body_len); + uwsgi_buffer_destroy(ub); UWSGI_GET_GIL + if (pybody) { Py_DECREF(pybody); } - if (priority) { - free(priority); - } - - free(spool_buffer); - - Py_DECREF(spool_vars); - if (i > 0) { - char *slash = uwsgi_get_last_char(spool_filename, '/'); - if (slash) { - return PyString_FromString(slash+1); - } - return PyString_FromString(spool_filename); + if (filename) { + PyObject *ret = PyString_FromString(filename); + free(filename); + return ret; } return PyErr_Format(PyExc_ValueError, "unable to spool job"); +error: +#ifdef PYTHREE + return PyErr_Format(PyExc_ValueError, "spooler callable dictionary must contains only bytes"); +#else + return PyErr_Format(PyExc_ValueError, "spooler callable dictionary must contains only strings"); +#endif } PyObject *py_uwsgi_spooler_pid(PyObject * self, PyObject * args) { diff --git a/plugins/rack/rack_api.c b/plugins/rack/rack_api.c index c027d51b..4a9eadc5 100644 --- a/plugins/rack/rack_api.c +++ b/plugins/rack/rack_api.c @@ -932,35 +932,35 @@ static VALUE uwsgi_ruby_signal(int argc, VALUE *argv, VALUE *class) { return Qtrue; } -int rack_uwsgi_build_spool(VALUE rbkey, VALUE rbval, VALUE argv) { - char **sa = (char **) argv; +static int rack_uwsgi_build_spool(VALUE rbkey, VALUE rbval, VALUE argv) { + struct uwsgi_buffer *ub = (struct uwsgi_buffer *) argv; - char *cur_buf = sa[0]; - char *watermark = sa[1]; - - if (TYPE(rbkey) != T_STRING || TYPE(rbval) != T_STRING) { + if (TYPE(rbkey) != T_STRING) { rb_raise(rb_eRuntimeError, "spool hash must contains only strings"); return ST_STOP; } char *key = RSTRING_PTR(rbkey); uint16_t keylen = RSTRING_LEN(rbkey); - char *val = RSTRING_PTR(rbval); uint16_t vallen = RSTRING_LEN(rbval); - if (cur_buf + (2+keylen+2+vallen) > watermark) { - rb_raise(rb_eRuntimeError, "spool hash size can be no more than 64K"); - return ST_STOP; + if (TYPE(rbval) == T_STRING) { + char *val = RSTRING_PTR(rbval); uint16_t vallen = RSTRING_LEN(rbval); + if (uwsgi_buffer_append_keyval(ub, key, keylen, val, vallen)) { + rb_raise(rb_eRuntimeError, "error building the spool packet"); + return ST_STOP; + } + } + else { + VALUE str = rb_any_to_s(rbval); + if (!str) { + rb_raise(rb_eRuntimeError, "error building the spool packet"); + return ST_STOP; + } + char *val = RSTRING_PTR(str); uint16_t vallen = RSTRING_LEN(str); + if (uwsgi_buffer_append_keyval(ub, key, keylen, val, vallen)) { + rb_raise(rb_eRuntimeError, "error building the spool packet"); + return ST_STOP; + } } - - *cur_buf++ = (uint8_t) (keylen & 0xff); - *cur_buf++ = (uint8_t) ((keylen >> 8) & 0xff); - memcpy(cur_buf, key, keylen); cur_buf += keylen; - - *cur_buf++ = (uint8_t) (vallen & 0xff); - *cur_buf++ = (uint8_t) ((vallen >> 8) & 0xff); - memcpy(cur_buf, val, vallen); cur_buf += vallen; - - // fix the ptr - sa[0] = cur_buf; return ST_CONTINUE; } @@ -968,38 +968,12 @@ int rack_uwsgi_build_spool(VALUE rbkey, VALUE rbval, VALUE argv) { static VALUE rack_uwsgi_send_spool(VALUE *class, VALUE args) { - char spool_filename[1024]; struct wsgi_request *wsgi_req = current_wsgi_req(); - char *priority = NULL; - long numprio = 0; - time_t at = 0; char *body = NULL; size_t body_len= 0; Check_Type(args, T_HASH); - // priority -#ifdef RUBY19 - VALUE rbprio = rb_hash_lookup(args, rb_str_new2("priority")); -#else - VALUE rbprio = rb_hash_aref(args, rb_str_new2("priority")); -#endif - if (TYPE(rbprio) == T_FIXNUM) { - numprio = NUM2INT(rbprio); - rb_hash_delete(args, rb_str_new2("priority")); - } - - // at -#ifdef RUBY19 - VALUE rbat = rb_hash_lookup(args, rb_str_new2("at")); -#else - VALUE rbat = rb_hash_aref(args, rb_str_new2("at")); -#endif - if (TYPE(rbat) == T_FIXNUM) { - at = NUM2INT(rbat); - rb_hash_delete(args, rb_str_new2("at")); - } - // body #ifdef RUBY19 VALUE rbbody = rb_hash_lookup(args, rb_str_new2("body")); @@ -1012,31 +986,18 @@ static VALUE rack_uwsgi_send_spool(VALUE *class, VALUE args) { rb_hash_delete(args, rb_str_new2("body")); } - char *spool_buffer = uwsgi_malloc(UMAX16); - char *argv[2]; - argv[0] = spool_buffer; - argv[1] = spool_buffer + UMAX16 ; + struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); - rb_hash_foreach(args, rack_uwsgi_build_spool, (VALUE) argv); + rb_hash_foreach(args, rack_uwsgi_build_spool, (VALUE) ub); - if (numprio) { - priority = uwsgi_num2str((int)numprio); - } + char *filename = uwsgi_spool_request(wsgi_req, ub->buf, ub->pos, body, body_len); - int ret = spool_request(uwsgi.spoolers, spool_filename, (int)(uwsgi.workers[0].requests + 1), wsgi_req->async_id, spool_buffer, (int)(argv[0] - spool_buffer), priority, at, body, body_len); + uwsgi_buffer_destroy(ub); - if (priority) { - free(priority); - } - - free(spool_buffer); - - if (ret > 0) { - char *slash = uwsgi_get_last_char(spool_filename, '/'); - if (slash) { - return rb_str_new2(slash+1); - } - return rb_str_new2(spool_filename); + if (filename) { + VALUE ret = rb_str_new2(filename); + free(filename); + return ret; } rb_raise(rb_eRuntimeError, "unable to spool job"); diff --git a/plugins/spooler/spooler_plugin.c b/plugins/spooler/spooler_plugin.c index d076269c..cab566fc 100644 --- a/plugins/spooler/spooler_plugin.c +++ b/plugins/spooler/spooler_plugin.c @@ -1,4 +1,4 @@ -#include "../../uwsgi.h" +#include /* @@ -10,15 +10,11 @@ extern struct uwsgi_server uwsgi; int uwsgi_request_spooler(struct wsgi_request *wsgi_req) { - int i; - char spool_filename[1024]; struct uwsgi_header uh; - // get the spooler from the modifier2 + // TODO get the spooler from the modifier2 - struct uwsgi_spooler *uspool = uwsgi.spoolers; - - if (uspool == NULL) { + if (uwsgi.spoolers == NULL) { uwsgi_log("the spooler is inactive !!!...skip\n"); uh.modifier1 = 255; uh.pktsize = 0; @@ -27,20 +23,21 @@ int uwsgi_request_spooler(struct wsgi_request *wsgi_req) { return -1; } - i = spool_request(uspool, spool_filename, uwsgi.workers[0].requests + 1, wsgi_req->async_id, wsgi_req->buffer, wsgi_req->uh->pktsize, NULL, 0, NULL, 0); + char *filename = uwsgi_spool_request(wsgi_req, wsgi_req->buffer, wsgi_req->uh->pktsize, NULL, 0); uh.modifier1 = 255; uh.pktsize = 0; - if (i > 0) { + if (filename) { uh.modifier2 = 1; if (uwsgi_response_write_body_do(wsgi_req, (char *) &uh, 4)) { uwsgi_log("disconnected client, remove spool file.\n"); /* client disconnect, remove spool file */ - if (unlink(spool_filename)) { + if (unlink(filename)) { uwsgi_error("uwsgi_request_spooler()/unlink()"); uwsgi_log("something horrible happened !!! check your spooler ASAP !!!\n"); exit(1); } } + free(filename); return 0; } else { diff --git a/uwsgi.h b/uwsgi.h index 569e170d..6453d731 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -2976,7 +2976,7 @@ void snmp_init(void); void uwsgi_master_manage_snmp(int); -int spool_request(struct uwsgi_spooler *uspool, char *, int, int, char *, int, char *, time_t, char *, size_t); +char *uwsgi_spool_request(struct wsgi_request *, char *, size_t, char *, size_t); void spooler(struct uwsgi_spooler *); pid_t spooler_start(struct uwsgi_spooler *); @@ -3615,7 +3615,7 @@ void *uwsgi_calloc_shared(size_t); struct uwsgi_spooler *uwsgi_new_spooler(char *); -struct uwsgi_spooler *uwsgi_get_spooler_by_name(char *); +struct uwsgi_spooler *uwsgi_get_spooler_by_name(char *, size_t); int uwsgi_zerg_attach(char *);