added support for (working, high-performance) static file offloading in linux

This commit is contained in:
roberto@quantal64
2012-10-02 08:51:35 +02:00
parent 3beead6459
commit d12ddded55
5 changed files with 113 additions and 4 deletions
+1 -1
View File
@@ -1910,7 +1910,7 @@ int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, si
wsgi_req->header_cnt += 2;
// Ok, the file must be transferred from uWSGI
if (!wsgi_req->socket->can_offload) {
if (wsgi_req->socket->can_offload) {
if (!uwsgi_offload_request_do(wsgi_req, real_filename, st->st_size)) goto done;
}
+95 -1
View File
@@ -13,6 +13,10 @@ int uwsgi_offload_request_do(struct wsgi_request *wsgi_req, char *filename, size
// avoid closing the connection
wsgi_req->fd_closed = 1;
#ifdef TCP_CORK
// enable CORK mode (if available)
#endif
// fill offload request
struct uwsgi_offload_request uor;
uor.fd = open(filename, O_RDONLY | O_NONBLOCK);
@@ -24,6 +28,8 @@ int uwsgi_offload_request_do(struct wsgi_request *wsgi_req, char *filename, size
uor.pos = 0;
uor.len = len;
uor.written = 0;
uor.prev = NULL;
uor.next = NULL;
if (write(uwsgi.offload_thread->pipe[0], &uor, sizeof(struct uwsgi_offload_request)) != sizeof(struct uwsgi_offload_request)) {
goto error2;
@@ -38,6 +44,59 @@ error:
return -1;
}
static void uwsgi_offload_close(struct uwsgi_offload_request *uor) {
// close the socket and the file descriptor
close(uor->s);
close(uor->fd);
// remove the structure from the linked list;
struct uwsgi_offload_request *prev = uor->prev;
struct uwsgi_offload_request *next = uor->next;
if (uor == uwsgi.offload_requests_head) {
uwsgi.offload_requests_head = next;
}
if (uor == uwsgi.offload_requests_tail) {
uwsgi.offload_requests_tail = prev;
}
if (prev) {
prev->next = next;
}
if (next) {
next->prev = prev;
}
free(uor);
}
static void uwsgi_offload_append(struct uwsgi_offload_request *uor) {
if (!uwsgi.offload_requests_head) {
uwsgi.offload_requests_head = uor;
}
if (uwsgi.offload_requests_tail) {
uwsgi.offload_requests_tail->next = uor;
uor->prev = uwsgi.offload_requests_tail;
}
uwsgi.offload_requests_tail = uor;
}
static struct uwsgi_offload_request *uwsgi_offload_get_by_socket(int s) {
struct uwsgi_offload_request *uor = uwsgi.offload_requests_head;
while(uor) {
if (uor->s == s) {
return uor;
}
uor = uor->next;
}
return NULL;
}
static void uwsgi_offload_loop(struct uwsgi_thread *ut) {
int i;
@@ -46,7 +105,42 @@ static void uwsgi_offload_loop(struct uwsgi_thread *ut) {
for(;;) {
int nevents = event_queue_wait_multi(ut->queue, -1, events, uwsgi.static_offload_to_thread);
for (i=0;i<nevents;i++) {
//int interesting_fd = event_queue_interesting_fd(events, i);
int interesting_fd = event_queue_interesting_fd(events, i);
if (interesting_fd == uwsgi.offload_thread->pipe[1]) {
struct uwsgi_offload_request *uor = uwsgi_malloc(sizeof(struct uwsgi_offload_request));
ssize_t len = read(uwsgi.offload_thread->pipe[1], uor, sizeof(struct uwsgi_offload_request));
if (len != sizeof(struct uwsgi_offload_request)) {
uwsgi_error("read()");
free(uor);
continue;
}
// start monitoring socket for write
if (event_queue_add_fd_write(ut->queue, uor->s) < 0) {
free(uor);
continue;
}
uwsgi_offload_append(uor);
continue;
}
// ok check for socket writability
struct uwsgi_offload_request *uor = uwsgi_offload_get_by_socket(interesting_fd);
if (!uor) continue;
// sendfile() in chunks (128k is a good size...)
#if defined(__linux__)
ssize_t len = sendfile(uor->s, uor->fd, &uor->pos, 128*1024);
if (len > 0) {
uor->written += len;
if (uor->written >= uor->len) {
uwsgi_offload_close(uor);
}
continue;
}
else if (len < 0) {
if (errno == EAGAIN) continue;
uwsgi_error("sendfile()");
}
uwsgi_offload_close(uor);
#endif
}
}
}
+4 -2
View File
@@ -1751,7 +1751,8 @@ setup_proto:
uwsgi_sock->proto_writev_header = uwsgi_proto_uwsgi_writev_header;
uwsgi_sock->proto_sendfile = NULL;
uwsgi_sock->proto_close = uwsgi_proto_base_close;
uwsgi_sock->can_offload = 1;
if (uwsgi.static_offload_to_thread)
uwsgi_sock->can_offload = 1;
}
else if (requested_protocol && (!strcmp("fastcgi", requested_protocol) || !strcmp("fcgi", requested_protocol))) {
if (!strcmp(uwsgi.protocol, "fastcgi") || !strcmp(uwsgi.protocol, "fcgi")) {
@@ -1780,7 +1781,8 @@ setup_proto:
uwsgi_sock->proto_writev_header = uwsgi_proto_uwsgi_writev_header;
uwsgi_sock->proto_sendfile = NULL;
uwsgi_sock->proto_close = uwsgi_proto_base_close;
uwsgi_sock->can_offload = 1;
if (uwsgi.static_offload_to_thread)
uwsgi_sock->can_offload = 1;
}
nextsock:
uwsgi_sock = uwsgi_sock->next;
+8
View File
@@ -2599,6 +2599,14 @@ next2:
// set default wsgi_req (for loading apps);
uwsgi.wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[0].req;
if (uwsgi.static_offload_to_thread) {
uwsgi.offload_thread = uwsgi_offload_thread_start();
if (!uwsgi.offload_thread) {
uwsgi_log("unable to offload static file serving !!!\n");
uwsgi.static_offload_to_thread = 0;
}
}
// must be run before running apps
for (i = 0; i < 256; i++) {
if (uwsgi.p[i]->post_fork) {
+5
View File
@@ -1491,6 +1491,9 @@ struct uwsgi_server {
int check_static_docroot;
int static_offload_to_thread;
struct uwsgi_thread *offload_thread;
// linked list for offloaded requests
struct uwsgi_offload_request *offload_requests_head;
struct uwsgi_offload_request *offload_requests_tail;
char *daemonize;
char *daemonize2;
@@ -3325,6 +3328,8 @@ struct uwsgi_offload_request {
off_t pos;
size_t len;
size_t written;
struct uwsgi_offload_request *prev;
struct uwsgi_offload_request *next;
};
struct uwsgi_thread *uwsgi_offload_thread_start(void);