summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorValentin Bartenev <vbart@nginx.com>2019-12-23 21:14:14 +0300
committerValentin Bartenev <vbart@nginx.com>2019-12-23 21:14:14 +0300
commit51af6ac0a1a73cd2c539188379f487557b80b341 (patch)
treefe708f246384aa92b5eb823ab9ef4c54163b7ba1
parent68a22923728ddbbda25bc3ee048520a76056fb33 (diff)
downloadunit-51af6ac0a1a73cd2c539188379f487557b80b341.tar.gz
unit-51af6ac0a1a73cd2c539188379f487557b80b341.tar.bz2
Python: pre-creation of objects for string constants.
This is an optimization to avoid creating them at runtime on each request.
-rw-r--r--src/nxt_python_wsgi.c194
1 files changed, 156 insertions, 38 deletions
diff --git a/src/nxt_python_wsgi.c b/src/nxt_python_wsgi.c
index 5bb2fb2c..3b13bea1 100644
--- a/src/nxt_python_wsgi.c
+++ b/src/nxt_python_wsgi.c
@@ -50,6 +50,8 @@
#define PyBytes_Check PyString_Check
#define PyBytes_GET_SIZE PyString_GET_SIZE
#define PyBytes_AS_STRING PyString_AS_STRING
+#define PyUnicode_InternInPlace PyString_InternInPlace
+#define PyUnicode_AsUTF8 PyString_AS_STRING
#endif
typedef struct nxt_python_run_ctx_s nxt_python_run_ctx_t;
@@ -64,15 +66,18 @@ typedef struct {
} nxt_py_error_t;
static nxt_int_t nxt_python_init(nxt_task_t *task, nxt_common_app_conf_t *conf);
+static nxt_int_t nxt_python_init_strings(void);
static void nxt_python_request_handler(nxt_unit_request_info_t *req);
static void nxt_python_atexit(void);
static PyObject *nxt_python_create_environ(nxt_task_t *task);
static PyObject *nxt_python_get_environ(nxt_python_run_ctx_t *ctx);
-static int nxt_python_add_sptr(nxt_python_run_ctx_t *ctx, const char *name,
+static int nxt_python_add_sptr(nxt_python_run_ctx_t *ctx, PyObject *name,
nxt_unit_sptr_t *sptr, uint32_t size);
-static int nxt_python_add_str(nxt_python_run_ctx_t *ctx, const char *name,
- const char *str, uint32_t size);
+static int nxt_python_add_field(nxt_python_run_ctx_t *ctx,
+ nxt_unit_field_t *field);
+static int nxt_python_add_obj(nxt_python_run_ctx_t *ctx, PyObject *name,
+ PyObject *value);
static PyObject *nxt_py_start_resp(PyObject *self, PyObject *args);
static int nxt_python_response_add_field(nxt_python_run_ctx_t *ctx,
@@ -157,6 +162,48 @@ static PyThreadState *nxt_python_thread_state;
static nxt_python_run_ctx_t *nxt_python_run_ctx;
+static PyObject *nxt_py_80_str;
+static PyObject *nxt_py_close_str;
+static PyObject *nxt_py_content_length_str;
+static PyObject *nxt_py_content_type_str;
+static PyObject *nxt_py_http_str;
+static PyObject *nxt_py_https_str;
+static PyObject *nxt_py_path_info_str;
+static PyObject *nxt_py_query_string_str;
+static PyObject *nxt_py_remote_addr_str;
+static PyObject *nxt_py_request_method_str;
+static PyObject *nxt_py_request_uri_str;
+static PyObject *nxt_py_server_addr_str;
+static PyObject *nxt_py_server_name_str;
+static PyObject *nxt_py_server_port_str;
+static PyObject *nxt_py_server_protocol_str;
+static PyObject *nxt_py_wsgi_uri_scheme_str;
+
+typedef struct {
+ nxt_str_t string;
+ PyObject **object_p;
+} nxt_python_string_t;
+
+static nxt_python_string_t nxt_python_strings[] = {
+ { nxt_string("80"), &nxt_py_80_str },
+ { nxt_string("close"), &nxt_py_close_str },
+ { nxt_string("CONTENT_LENGTH"), &nxt_py_content_length_str },
+ { nxt_string("CONTENT_TYPE"), &nxt_py_content_type_str },
+ { nxt_string("http"), &nxt_py_http_str },
+ { nxt_string("https"), &nxt_py_https_str },
+ { nxt_string("PATH_INFO"), &nxt_py_path_info_str },
+ { nxt_string("QUERY_STRING"), &nxt_py_query_string_str },
+ { nxt_string("REMOTE_ADDR"), &nxt_py_remote_addr_str },
+ { nxt_string("REQUEST_METHOD"), &nxt_py_request_method_str },
+ { nxt_string("REQUEST_URI"), &nxt_py_request_uri_str },
+ { nxt_string("SERVER_ADDR"), &nxt_py_server_addr_str },
+ { nxt_string("SERVER_NAME"), &nxt_py_server_name_str },
+ { nxt_string("SERVER_PORT"), &nxt_py_server_port_str },
+ { nxt_string("SERVER_PROTOCOL"), &nxt_py_server_protocol_str },
+ { nxt_string("wsgi.url_scheme"), &nxt_py_wsgi_uri_scheme_str },
+};
+
+
static nxt_int_t
nxt_python_init(nxt_task_t *task, nxt_common_app_conf_t *conf)
{
@@ -239,6 +286,12 @@ nxt_python_init(nxt_task_t *task, nxt_common_app_conf_t *conf)
Py_InitializeEx(0);
module = NULL;
+ obj = NULL;
+
+ if (nxt_slow_path(nxt_python_init_strings() != NXT_OK)) {
+ nxt_alert(task, "Python failed to init string objects");
+ goto fail;
+ }
obj = PySys_GetObject((char *) "stderr");
if (nxt_slow_path(obj == NULL)) {
@@ -382,6 +435,31 @@ fail:
}
+static nxt_int_t
+nxt_python_init_strings(void)
+{
+ PyObject *obj;
+ nxt_uint_t i;
+ nxt_python_string_t *pstr;
+
+ for (i = 0; i < nxt_nitems(nxt_python_strings); i++) {
+ pstr = &nxt_python_strings[i];
+
+ obj = PyString_FromStringAndSize((char *) pstr->string.start,
+ pstr->string.length);
+ if (nxt_slow_path(obj == NULL)) {
+ return NXT_ERROR;
+ }
+
+ PyUnicode_InternInPlace(&obj);
+
+ *pstr->object_p = obj;
+ }
+
+ return NXT_OK;
+}
+
+
static void
nxt_python_request_handler(nxt_unit_request_info_t *req)
{
@@ -478,7 +556,7 @@ nxt_python_request_handler(nxt_unit_request_info_t *req)
rc = NXT_UNIT_ERROR;
}
- close = PyObject_GetAttrString(response, "close");
+ close = PyObject_GetAttr(response, nxt_py_close_str);
if (close != NULL) {
result = PyObject_CallFunction(close, NULL);
@@ -512,6 +590,12 @@ done:
static void
nxt_python_atexit(void)
{
+ nxt_uint_t i;
+
+ for (i = 0; i < nxt_nitems(nxt_python_strings); i++) {
+ Py_XDECREF(*nxt_python_strings[i].object_p);
+ }
+
Py_XDECREF(nxt_py_stderr_flush);
Py_XDECREF(nxt_py_application);
Py_XDECREF(nxt_py_start_resp_obj);
@@ -655,7 +739,6 @@ static PyObject *
nxt_python_get_environ(nxt_python_run_ctx_t *ctx)
{
int rc;
- char *name;
uint32_t i;
PyObject *environ;
nxt_unit_field_t *f;
@@ -681,47 +764,52 @@ nxt_python_get_environ(nxt_python_run_ctx_t *ctx)
} \
} while(0)
- RC(nxt_python_add_sptr(ctx, "REQUEST_METHOD", &r->method,
+ RC(nxt_python_add_sptr(ctx, nxt_py_request_method_str, &r->method,
r->method_length));
- RC(nxt_python_add_sptr(ctx, "REQUEST_URI", &r->target, r->target_length));
- RC(nxt_python_add_sptr(ctx, "QUERY_STRING", &r->query, r->query_length));
- RC(nxt_python_add_sptr(ctx, "PATH_INFO", &r->path, r->path_length));
-
- RC(nxt_python_add_sptr(ctx, "REMOTE_ADDR", &r->remote, r->remote_length));
- RC(nxt_python_add_sptr(ctx, "SERVER_ADDR", &r->local, r->local_length));
+ RC(nxt_python_add_sptr(ctx, nxt_py_request_uri_str, &r->target,
+ r->target_length));
+ RC(nxt_python_add_sptr(ctx, nxt_py_query_string_str, &r->query,
+ r->query_length));
+ RC(nxt_python_add_sptr(ctx, nxt_py_path_info_str, &r->path,
+ r->path_length));
+
+ RC(nxt_python_add_sptr(ctx, nxt_py_remote_addr_str, &r->remote,
+ r->remote_length));
+ RC(nxt_python_add_sptr(ctx, nxt_py_server_addr_str, &r->local,
+ r->local_length));
if (r->tls) {
- RC(nxt_python_add_str(ctx, "wsgi.url_scheme", "https", 5));
-
+ RC(nxt_python_add_obj(ctx, nxt_py_wsgi_uri_scheme_str,
+ nxt_py_https_str));
} else {
- RC(nxt_python_add_str(ctx, "wsgi.url_scheme", "http", 4));
+ RC(nxt_python_add_obj(ctx, nxt_py_wsgi_uri_scheme_str,
+ nxt_py_http_str));
}
- RC(nxt_python_add_sptr(ctx, "SERVER_PROTOCOL", &r->version,
+ RC(nxt_python_add_sptr(ctx, nxt_py_server_protocol_str, &r->version,
r->version_length));
- RC(nxt_python_add_sptr(ctx, "SERVER_NAME", &r->server_name,
+ RC(nxt_python_add_sptr(ctx, nxt_py_server_name_str, &r->server_name,
r->server_name_length));
- RC(nxt_python_add_str(ctx, "SERVER_PORT", "80", 2));
+ RC(nxt_python_add_obj(ctx, nxt_py_server_port_str, nxt_py_80_str));
for (i = 0; i < r->fields_count; i++) {
f = r->fields + i;
- name = nxt_unit_sptr_get(&f->name);
- RC(nxt_python_add_sptr(ctx, name, &f->value, f->value_length));
+ RC(nxt_python_add_field(ctx, f));
}
if (r->content_length_field != NXT_UNIT_NONE_FIELD) {
f = r->fields + r->content_length_field;
- RC(nxt_python_add_sptr(ctx, "CONTENT_LENGTH", &f->value,
+ RC(nxt_python_add_sptr(ctx, nxt_py_content_length_str, &f->value,
f->value_length));
}
if (r->content_type_field != NXT_UNIT_NONE_FIELD) {
f = r->fields + r->content_type_field;
- RC(nxt_python_add_sptr(ctx, "CONTENT_TYPE", &f->value,
+ RC(nxt_python_add_sptr(ctx, nxt_py_content_type_str, &f->value,
f->value_length));
}
@@ -738,7 +826,7 @@ fail:
static int
-nxt_python_add_sptr(nxt_python_run_ctx_t *ctx, const char *name,
+nxt_python_add_sptr(nxt_python_run_ctx_t *ctx, PyObject *name,
nxt_unit_sptr_t *sptr, uint32_t size)
{
char *src;
@@ -756,10 +844,10 @@ nxt_python_add_sptr(nxt_python_run_ctx_t *ctx, const char *name,
return NXT_UNIT_ERROR;
}
- if (nxt_slow_path(PyDict_SetItemString(ctx->environ, name, value) != 0)) {
+ if (nxt_slow_path(PyDict_SetItem(ctx->environ, name, value) != 0)) {
nxt_unit_req_error(ctx->req,
"Python failed to set the \"%s\" environ value",
- name);
+ PyUnicode_AsUTF8(name));
Py_DECREF(value);
return NXT_UNIT_ERROR;
@@ -772,37 +860,67 @@ nxt_python_add_sptr(nxt_python_run_ctx_t *ctx, const char *name,
static int
-nxt_python_add_str(nxt_python_run_ctx_t *ctx, const char *name,
- const char *str, uint32_t size)
+nxt_python_add_field(nxt_python_run_ctx_t *ctx, nxt_unit_field_t *field)
{
- PyObject *value;
+ char *src;
+ PyObject *name, *value;
- if (nxt_slow_path(str == NULL)) {
- return NXT_UNIT_OK;
+ src = nxt_unit_sptr_get(&field->name);
+
+ name = PyString_FromStringAndSize(src, field->name_length);
+ if (nxt_slow_path(name == NULL)) {
+ nxt_unit_req_error(ctx->req,
+ "Python failed to create name string \"%.*s\"",
+ (int) field->name_length, src);
+ nxt_python_print_exception();
+
+ return NXT_UNIT_ERROR;
}
- value = PyString_FromStringAndSize(str, size);
+ src = nxt_unit_sptr_get(&field->value);
+
+ value = PyString_FromStringAndSize(src, field->value_length);
if (nxt_slow_path(value == NULL)) {
nxt_unit_req_error(ctx->req,
"Python failed to create value string \"%.*s\"",
- (int) size, str);
+ (int) field->value_length, src);
nxt_python_print_exception();
- return NXT_UNIT_ERROR;
+ goto fail;
}
- if (nxt_slow_path(PyDict_SetItemString(ctx->environ, name, value) != 0)) {
+ if (nxt_slow_path(PyDict_SetItem(ctx->environ, name, value) != 0)) {
nxt_unit_req_error(ctx->req,
"Python failed to set the \"%s\" environ value",
- name);
+ PyUnicode_AsUTF8(name));
+ goto fail;
+ }
- Py_DECREF(value);
+ Py_DECREF(name);
+ Py_DECREF(value);
+
+ return NXT_UNIT_OK;
+
+fail:
+
+ Py_DECREF(name);
+ Py_XDECREF(value);
+
+ return NXT_UNIT_ERROR;
+}
+
+
+static int
+nxt_python_add_obj(nxt_python_run_ctx_t *ctx, PyObject *name, PyObject *value)
+{
+ if (nxt_slow_path(PyDict_SetItem(ctx->environ, name, value) != 0)) {
+ nxt_unit_req_error(ctx->req,
+ "Python failed to set the \"%s\" environ value",
+ PyUnicode_AsUTF8(name));
return NXT_UNIT_ERROR;
}
- Py_DECREF(value);
-
return NXT_UNIT_OK;
}