improvements in multiple interpreter management

This commit is contained in:
roberto@maverick64
2011-01-06 19:45:43 +01:00
parent 515b9f2838
commit ed5f501a19
8 changed files with 103 additions and 162 deletions
+7 -14
View File
@@ -6,20 +6,18 @@ import rrdtool
s_freq = 10
# this is a cron emulator done with the Spooler :)
def rrdtool_updater(env):
uwsgi.set_spooler_frequency(s_freq)
rrdtool.update('../test.rrd', str(int(time.time()))+':'+str(uwsgi.total_requests()))
uwsgi.send_to_spooler({})
# this task will be executed every s_freq seconds
def rrdtool_updater(sig, sec):
rrdtool.update('test.rrd', str(int(time.time()))+':'+str(uwsgi.total_requests()))
uwsgi.spooler = rrdtool_updater
uwsgi.register_timer(0, s_freq, uwsgi.KIND_WORKER, rrdtool_updater)
def hello_world(env, start_response):
start_response('200 Ok', [('Content-type', 'text/plain')])
yield 'Hello world !'
return 'Hello world !'
def graph(env, start_response):
@@ -27,12 +25,7 @@ def graph(env, start_response):
now = int(time.time())
graph_range = (3600*24)
rrdtool.graph('uwsgi_graph.png', '--start', str(now - graph_range), '--end', str(now), 'DEF:urequests=test.rrd:requests:AVERAGE', 'LINE2:urequests#00FF00')
fd = open('uwsgi_graph.png', 'r')
# send file to browser
return env['wsgi.file_wrapper'](fd, 4096)
# start the simil-cron
uwsgi.send_to_spooler({})
# send file to client
uwsgi.sendfile('uwsgi_graph.png')
uwsgi.applications = {'/': hello_world, '/graph':graph}
+63 -12
View File
@@ -18,11 +18,13 @@ PyMethodDef uwsgi_eventfd_read_method[] = { {"uwsgi_eventfd_read", py_eventfd_re
PyMethodDef uwsgi_eventfd_write_method[] = { {"uwsgi_eventfd_write", py_eventfd_write, METH_VARARGS, ""}};
#endif
int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, int new_interpreter) {
int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThreadState *interpreter) {
PyObject *zero;
PyObject *app_list = NULL, *applications = NULL;
int id = uwsgi.apps_cnt;
int multiapp = 0;
#ifdef UWSGI_ASYNC
int i;
@@ -35,11 +37,11 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, int ne
if (wsgi_req->script_name_len == 0) {
wsgi_req->script_name = "";
if (!uwsgi.vhost) id = 0;
}
else if (wsgi_req->script_name_len == 1) {
if (wsgi_req->script_name[0] == '/') {
if (!uwsgi.vhost) id = 0;
wsgi_req->script_name = "";
wsgi_req->script_name_len = 0;
}
}
@@ -77,7 +79,7 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, int ne
// Initialize a new environment for the new interpreter
if (new_interpreter && id) {
if (interpreter == NULL && id) {
wi->interpreter = Py_NewInterpreter();
if (!wi->interpreter) {
uwsgi_log( "unable to initialize the new python interpreter\n");
@@ -93,6 +95,9 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, int ne
init_uwsgi_vars();
}
else if (interpreter) {
wi->interpreter = interpreter;
}
else {
wi->interpreter = up.main_thread;
}
@@ -105,6 +110,32 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, int ne
goto doh;
}
// the module contains multiple apps
if (PyDict_Check(wi->callable)) {
applications = wi->callable;
uwsgi_log("found a multiapp module...\n");
app_list = PyDict_Keys(applications);
multiapp = PyList_Size(app_list);
if (multiapp < 1) {
uwsgi_log("you have to define at least one app in the apllications dictionary\n");
goto doh;
}
PyObject *app_mnt = PyList_GetItem(app_list, 0);
if (!PyString_Check(app_mnt)) {
uwsgi_log("the app mountpoint must be a string\n");
goto doh;
}
wi->mountpoint = PyString_AsString(app_mnt);
wi->mountpoint_len = strlen(wi->mountpoint);
wsgi_req->script_name = wi->mountpoint;
wsgi_req->script_name_len = wi->mountpoint_len;
uwsgi_log("main mountpoint = %s\n", wi->mountpoint);
wi->callable = PyDict_GetItem(applications, app_mnt);
}
#ifdef UWSGI_ASYNC
wi->environ = malloc(sizeof(PyObject*)*uwsgi.cores);
if (!wi->environ) {
@@ -216,7 +247,7 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, int ne
#endif
}
if (new_interpreter && id) {
if (interpreter == NULL && id) {
// if we have multiple threads we need to initialize a PyThreadState for each one
if (uwsgi.threads > 1) {
for(i=0;i<uwsgi.threads;i++) {
@@ -240,23 +271,35 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, int ne
uwsgi_log( "WSGI application %d (SCRIPT_NAME=%.*s) ready on interpreter %p", id, wi->mountpoint_len, wi->mountpoint, wi->interpreter);
}
if (id == 0) {
if (!wsgi_req->script_name_len) {
uwsgi_log(" (default app)");
uwsgi.default_app = 0;
if (uwsgi.vhost) uwsgi.apps_cnt++;
}
else {
uwsgi.apps_cnt++;
uwsgi.default_app = id;
}
uwsgi.apps_cnt++;
uwsgi_log("\n");
if (multiapp > 1) {
for(i=1;i<multiapp;i++) {
PyObject *app_mnt = PyList_GetItem(app_list, i);
if (!PyString_Check(app_mnt)) {
uwsgi_log("applications dictionary key must be a string, skipping.\n");
continue;
}
wsgi_req->script_name = PyString_AsString(app_mnt);
wsgi_req->script_name_len = strlen(wsgi_req->script_name);
init_uwsgi_app(LOADER_CALLABLE, PyDict_GetItem(applications, app_mnt), wsgi_req, wi->interpreter);
}
}
return id;
doh:
free(mountpoint);
PyErr_Print();
if (new_interpreter && id) {
if (interpreter == NULL && id) {
Py_EndInterpreter(wi->interpreter);
if (uwsgi.threads > 1) {
PyThreadState_Swap((PyThreadState *) pthread_getspecific(up.upt_save_key));
@@ -308,6 +351,8 @@ PyObject *uwsgi_uwsgi_loader(void *arg1) {
char *quick_callable;
PyObject *tmp_callable;
PyObject *applications;
PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi");
char *module = (char *) arg1;
@@ -330,6 +375,12 @@ PyObject *uwsgi_uwsgi_loader(void *arg1) {
return NULL;
}
applications = PyDict_GetItemString(uwsgi_dict, "applications");
if (applications) return applications;
applications = PyDict_GetItemString(wsgi_dict, "applications");
if (applications) return applications;
// quick callable -> thanks gunicorn for the idea
// we have extended the concept a bit...
if (quick_callable[strlen(quick_callable) -2 ] == '(' && quick_callable[strlen(quick_callable) -1] ==')') {
+21 -130
View File
@@ -91,6 +91,7 @@ int uwsgi_python_init() {
up.main_thread = PyThreadState_Get();
uwsgi_log("Python main interpreter initialized at %p\n", up.main_thread);
#ifdef UWSGI_MINTERPRETERS
init_uwsgi_embedded_module();
@@ -337,125 +338,6 @@ void init_uwsgi_vars() {
}
void uwsgi_uwsgi_config(char *module) {
#ifdef UWSGI_EMBEDDED
PyObject *uwsgi_module, *uwsgi_dict;
#endif
PyObject *applications;
PyObject *app_list;
Py_ssize_t i;
PyObject *app_mnt, *app_app = NULL;
char *quick_callable;
quick_callable = get_uwsgi_pymodule(module);
if (quick_callable == NULL) {
if (up.callable) {
quick_callable = up.callable;
}
else {
quick_callable = "application";
}
}
up.loader_dict = get_uwsgi_pydict(module);
if (!up.loader_dict) {
exit(1);
}
uwsgi_log( "...getting the applications list from the '%s' module...\n", module);
#ifdef UWSGI_EMBEDDED
uwsgi_module = PyImport_ImportModule("uwsgi");
if (!uwsgi_module) {
PyErr_Print();
exit(1);
}
uwsgi_dict = PyModule_GetDict(uwsgi_module);
if (!uwsgi_dict) {
PyErr_Print();
exit(1);
}
applications = PyDict_GetItemString(uwsgi_dict, "applications");
if (!PyDict_Check(applications)) {
uwsgi_log( "uwsgi.applications dictionary is not defined, trying with the \"applications\" one...\n");
#endif
applications = PyDict_GetItemString(up.loader_dict, "applications");
if (!applications) {
uwsgi_log( "applications dictionary is not defined, trying with the \"application\" callable.\n");
quick_callable = uwsgi_concat3(module, ":", quick_callable);
if (init_uwsgi_app(LOADER_UWSGI, (void *) quick_callable, uwsgi.wsgi_req, 0) < 0) {
uwsgi_log( "...goodbye cruel world...\n");
exit(1);
}
free(quick_callable);
return;
}
#ifdef UWSGI_EMBEDDED
}
#endif
if (!PyDict_Check(applications)) {
uwsgi_log( "The 'applications' object must be a dictionary.\n");
exit(1);
}
app_list = PyDict_Keys(applications);
if (!app_list) {
PyErr_Print();
exit(1);
}
if (PyList_Size(app_list) < 1) {
uwsgi_log( "You must define an app.\n");
exit(1);
}
for (i = 0; i < PyList_Size(app_list); i++) {
app_mnt = PyList_GetItem(app_list, i);
if (!PyString_Check(app_mnt)) {
uwsgi_log( "the app mountpoint must be a bytestring.\n");
exit(1);
}
uwsgi.wsgi_req->script_name = PyString_AsString(app_mnt);
uwsgi.wsgi_req->script_name_len = strlen(uwsgi.wsgi_req->script_name);
app_app = PyDict_GetItem(applications, app_mnt);
if (!PyString_Check(app_app) && !PyFunction_Check(app_app) && !PyCallable_Check(app_app)) {
uwsgi_log( "the app callable must be a string, a function or a callable. (found %s)\n", app_app->ob_type->tp_name);
exit(1);
}
#ifdef PYTHREE
if (PyUnicode_Check(app_app)) {
#else
if (PyString_Check(app_app)) {
#endif
if (init_uwsgi_app(LOADER_STRING_CALLABLE, (void *) PyString_AsString(app_app), uwsgi.wsgi_req, 0) < 0) {
uwsgi_log( "...goodbye cruel world...\n");
exit(1);
}
}
else {
if (init_uwsgi_app(LOADER_CALLABLE, (void *) app_app, uwsgi.wsgi_req, 0) < 0) {
uwsgi_log( "...goodbye cruel world...\n");
exit(1);
}
}
Py_DECREF(app_mnt);
Py_DECREF(app_app);
}
}
#ifdef PYTHREE
static PyModuleDef uwsgi_module3 = {
@@ -755,26 +637,29 @@ int uwsgi_python_mount_app(char *mountpoint, char *app) {
uwsgi.wsgi_req->script_name = mountpoint;
uwsgi.wsgi_req->script_name_len = strlen(mountpoint);
return init_uwsgi_app(LOADER_MOUNT, app, uwsgi.wsgi_req, uwsgi.single_interpreter-1);
if (uwsgi.single_interpreter) {
return init_uwsgi_app(LOADER_MOUNT, app, uwsgi.wsgi_req, up.main_thread);
}
return init_uwsgi_app(LOADER_MOUNT, app, uwsgi.wsgi_req, NULL);
}
void uwsgi_python_init_apps() {
if (up.wsgi_config != NULL) {
init_uwsgi_app(LOADER_UWSGI, up.wsgi_config, uwsgi.wsgi_req, 0);
init_uwsgi_app(LOADER_UWSGI, up.wsgi_config, uwsgi.wsgi_req, up.main_thread);
}
if (up.file_config != NULL) {
init_uwsgi_app(LOADER_FILE, up.file_config, uwsgi.wsgi_req, 0);
init_uwsgi_app(LOADER_FILE, up.file_config, uwsgi.wsgi_req, up.main_thread);
}
#ifdef UWSGI_PASTE
if (up.paste != NULL) {
init_uwsgi_app(LOADER_PASTE, up.paste, uwsgi.wsgi_req, 0);
init_uwsgi_app(LOADER_PASTE, up.paste, uwsgi.wsgi_req, up.main_thread);
}
#endif
if (up.eval != NULL) {
init_uwsgi_app(LOADER_EVAL, up.eval, uwsgi.wsgi_req, 0);
init_uwsgi_app(LOADER_EVAL, up.eval, uwsgi.wsgi_req, up.main_thread);
}
}
@@ -806,17 +691,23 @@ int uwsgi_python_mount_app(char *mountpoint, char *app) {
int uwsgi_python_xml(char *node, char *content) {
PyThreadState *interpreter = NULL;
if (uwsgi.single_interpreter) {
interpreter = up.main_thread;
}
if (!strcmp("script", node)) {
return init_uwsgi_app(LOADER_UWSGI, content, uwsgi.wsgi_req, uwsgi.single_interpreter-1);
return init_uwsgi_app(LOADER_UWSGI, content, uwsgi.wsgi_req, interpreter);
}
else if (!strcmp("file", node)) {
return init_uwsgi_app(LOADER_FILE, content, uwsgi.wsgi_req, uwsgi.single_interpreter-1);
return init_uwsgi_app(LOADER_FILE, content, uwsgi.wsgi_req, interpreter);
}
else if (!strcmp("eval", node)) {
return init_uwsgi_app(LOADER_EVAL, content, uwsgi.wsgi_req, uwsgi.single_interpreter-1);
return init_uwsgi_app(LOADER_EVAL, content, uwsgi.wsgi_req, interpreter);
}
else if (!strcmp("wsgi", node)) {
return init_uwsgi_app(LOADER_EVAL, content, uwsgi.wsgi_req, uwsgi.single_interpreter-1);
return init_uwsgi_app(LOADER_EVAL, content, uwsgi.wsgi_req, interpreter);
}
else if (!strcmp("module", node)) {
uwsgi.wsgi_req->module = content;
@@ -827,7 +718,7 @@ int uwsgi_python_xml(char *node, char *content) {
uwsgi.wsgi_req->callable++;
uwsgi.wsgi_req->callable_len = strlen(uwsgi.wsgi_req->callable);
uwsgi.wsgi_req->module_len = strlen(uwsgi.wsgi_req->module);
return init_uwsgi_app(LOADER_DYN, uwsgi.wsgi_req, uwsgi.wsgi_req, uwsgi.single_interpreter-1);
return init_uwsgi_app(LOADER_DYN, uwsgi.wsgi_req, uwsgi.wsgi_req, interpreter);
}
return 1;
}
@@ -839,7 +730,7 @@ int uwsgi_python_xml(char *node, char *content) {
else if (!strcmp("callable", node)) {
uwsgi.wsgi_req->callable = content;
uwsgi.wsgi_req->callable_len = strlen(content);
return init_uwsgi_app(LOADER_DYN, uwsgi.wsgi_req, uwsgi.wsgi_req, uwsgi.single_interpreter-1);
return init_uwsgi_app(LOADER_DYN, uwsgi.wsgi_req, uwsgi.wsgi_req, interpreter);
}
return 0;
+1 -1
View File
@@ -137,7 +137,7 @@ void uwsgi_paste_config(char *);
void uwsgi_file_config(char *);
void uwsgi_eval_config(char *);
int init_uwsgi_app(int, void *, struct wsgi_request *wsgi_req, int);
int init_uwsgi_app(int, void *, struct wsgi_request *wsgi_req, PyThreadState *);
PyObject *py_eventfd_read(PyObject *, PyObject *);
+8 -3
View File
@@ -153,7 +153,12 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
pthread_mutex_lock(&up.lock_pyloaders);
}
UWSGI_GET_GIL
wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, uwsgi.single_interpreter-1);
if (uwsgi.single_interpreter) {
wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, up.main_thread);
}
else {
wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, NULL);
}
UWSGI_RELEASE_GIL
if (uwsgi.threads > 1) {
pthread_mutex_unlock(&up.lock_pyloaders);
@@ -186,7 +191,7 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) {
wi = &uwsgi.apps[wsgi_req->app_id];
if (uwsgi.single_interpreter == 0 && wsgi_req->app_id > 0) {
if (uwsgi.single_interpreter == 0 && wi->interpreter != up.main_thread) {
if (!wi->interpreter) {
internal_server_error(wsgi_req->poll.fd, "wsgi application's %d interpreter not found");
goto clear2;
@@ -339,7 +344,7 @@ clear:
UWSGI_GET_GIL
if (uwsgi.single_interpreter == 0 && wsgi_req->app_id > 0) {
if (uwsgi.single_interpreter == 0 && wi->interpreter != up.main_thread) {
// restoring main interpreter
if (uwsgi.threads > 1) {
PyThreadState_Swap((PyThreadState *) pthread_getspecific(up.upt_save_key));
+1 -1
View File
@@ -525,7 +525,7 @@ int uwsgi_parse_vars(struct wsgi_request *wsgi_req) {
wsgi_req->var_cnt++;
script_name = wsgi_req->var_cnt;
}
for(i=1;i<uwsgi.apps_cnt;i++) {
for(i=0;i<uwsgi.apps_cnt;i++) {
uwsgi_log("app mountpoint = %.*s\n", uwsgi.apps[i].mountpoint_len, uwsgi.apps[i].mountpoint);
if (orig_path_info_len >= uwsgi.apps[i].mountpoint_len) {
if (!uwsgi_startswith(orig_path_info, uwsgi.apps[i].mountpoint, uwsgi.apps[i].mountpoint_len) && uwsgi.apps[i].mountpoint_len > best_found) {
+1
View File
@@ -907,6 +907,7 @@ int uwsgi_get_app_id(char *script_name, int script_name_len, int modifier1) {
int i;
for(i=0;i<uwsgi.apps_cnt;i++) {
uwsgi_log("searching for %.*s in %.*s %p\n", script_name_len, script_name, uwsgi.apps[i].mountpoint_len, uwsgi.apps[i].mountpoint, uwsgi.apps[i].callable);
if (!uwsgi.apps[i].mountpoint_len) {
continue;
}
+1 -1
View File
@@ -411,7 +411,7 @@ int main(int argc, char *argv[], char *envp[])
uwsgi.cluster_fd = -1;
uwsgi.cores = 1;
uwsgi.apps_cnt = 1;
uwsgi.apps_cnt = 0;
uwsgi.default_app = -1;
uwsgi.buffer_size = 4096;