From 0c3ca6b13b7815e945985d30b78ded98e2016e6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Sun, 29 Nov 2009 15:18:24 +0100 Subject: [PATCH] add liBuffer: a reference-counted memory chunk (using mempool) for basic network data --- include/lighttpd/base.h | 1 + include/lighttpd/buffer.h | 22 ++++ include/lighttpd/chunk.h | 42 +++++--- include/lighttpd/typedefs.h | 1 - src/CMakeLists.txt | 1 + src/common/Makefile.am | 1 + src/common/buffer.c | 39 +++++++ src/common/wscript | 1 + src/main/chunk.c | 206 +++++++++++++++++++++++------------- src/main/network.c | 13 ++- src/main/network_sendfile.c | 9 +- src/main/network_writev.c | 15 ++- 12 files changed, 246 insertions(+), 105 deletions(-) create mode 100644 include/lighttpd/buffer.h create mode 100644 src/common/buffer.c diff --git a/include/lighttpd/base.h b/include/lighttpd/base.h index ff8663c..687331b 100644 --- a/include/lighttpd/base.h +++ b/include/lighttpd/base.h @@ -30,6 +30,7 @@ #include #include +#include #include #include diff --git a/include/lighttpd/buffer.h b/include/lighttpd/buffer.h new file mode 100644 index 0000000..9b7970f --- /dev/null +++ b/include/lighttpd/buffer.h @@ -0,0 +1,22 @@ +#ifndef _LIGHTTPD_BUFFER_H_ +#define _LIGHTTPD_BUFFER_H_ + +#include + +#include + +typedef struct liBuffer liBuffer; +struct liBuffer { + gchar *addr; + gsize alloc_size; + gsize used; + gint refcount; + mempool_ptr mptr; +}; + +/* shared buffer; free memory after last reference is released */ +LI_API liBuffer* li_buffer_new(gsize max_size); +LI_API void li_buffer_acquire(liBuffer *buf); +LI_API void li_buffer_release(liBuffer *buf); + +#endif diff --git a/include/lighttpd/chunk.h b/include/lighttpd/chunk.h index e049d10..8287a6b 100644 --- a/include/lighttpd/chunk.h +++ b/include/lighttpd/chunk.h @@ -18,27 +18,33 @@ struct liChunkFile { }; struct liChunk { - enum { UNUSED_CHUNK, STRING_CHUNK, MEM_CHUNK, FILE_CHUNK } type; + enum { UNUSED_CHUNK, STRING_CHUNK, MEM_CHUNK, FILE_CHUNK, BUFFER_CHUNK } type; goffset offset; /* if type == FILE_CHUNK and mem != NULL, * mem contains the data [file.mmap.offset .. file.mmap.offset + file.mmap.length) * from the file, and file.mmap.start is NULL as mmap failed and read(...) was used. */ - GString *str; GByteArray *mem; - struct { - liChunkFile *file; - off_t start; /* starting offset in the file */ - off_t length; /* octets to send from the starting offset */ - + union { + GString *str; + struct { + liChunkFile *file; + off_t start; /* starting offset in the file */ + off_t length; /* octets to send from the starting offset */ + + struct { + char *data; /* the pointer of the mmap'ed area */ + size_t length; /* size of the mmap'ed area */ + off_t offset; /* start is octets away from the start of the file */ + } mmap; + } file; struct { - char *data; /* the pointer of the mmap'ed area */ - size_t length; /* size of the mmap'ed area */ - off_t offset; /* start is octets away from the start of the file */ - } mmap; - } file; + liBuffer *buffer; + gsize offset, length; + } buffer; + } data; /* a chunk can only be in one queue, so we just reserve the memory for the link in it */ GList cq_link; @@ -146,6 +152,12 @@ LI_API void li_chunkqueue_append_string(liChunkQueue *cq, GString *str); */ LI_API void li_chunkqueue_append_bytearr(liChunkQueue *cq, GByteArray *mem); + /* pass ownership of buffer to chunkqueue, do not free/modify it afterwards + * you may modify the data (not the length) if you are sure it isn't sent before. + * if the length is NULL, buffer is destroyed immediately + */ +LI_API void li_chunkqueue_append_buffer(liChunkQueue *cq, liBuffer *buffer); + /* memory gets copied */ LI_API void li_chunkqueue_append_mem(liChunkQueue *cq, const void *mem, gssize len); @@ -213,11 +225,13 @@ INLINE goffset li_chunk_length(liChunk *c) { case UNUSED_CHUNK: return 0; case STRING_CHUNK: - return c->str->len - c->offset; + return c->data.str->len - c->offset; case MEM_CHUNK: return c->mem->len - c->offset; case FILE_CHUNK: - return c->file.length - c->offset; + return c->data.file.length - c->offset; + case BUFFER_CHUNK: + return c->data.buffer.length - c->offset; } return 0; } diff --git a/include/lighttpd/typedefs.h b/include/lighttpd/typedefs.h index 33ee4d3..0cfde75 100644 --- a/include/lighttpd/typedefs.h +++ b/include/lighttpd/typedefs.h @@ -45,7 +45,6 @@ typedef enum { BACKEND_DEAD } liBackendError; - /* chunk.h */ typedef struct liChunkFile liChunkFile; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d57790e..ccc6ff1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -154,6 +154,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CM SET(COMMON_SRC angel_connection.c angel_data.c + buffer.c encoding.c idlist.c ip_parsers.c diff --git a/src/common/Makefile.am b/src/common/Makefile.am index e5b8d6f..a68bd98 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -5,6 +5,7 @@ common_cflags=-I$(top_srcdir)/include -I$(top_builddir)/include common_src= \ angel_connection.c \ angel_data.c \ + buffer.c \ encoding.c \ idlist.c \ ip_parsers.c \ diff --git a/src/common/buffer.c b/src/common/buffer.c new file mode 100644 index 0000000..7947e88 --- /dev/null +++ b/src/common/buffer.c @@ -0,0 +1,39 @@ + +#include + +static void _buffer_init(liBuffer *buf, gsize alloc_size) { + buf->alloc_size = alloc_size; + buf->used = 0; + buf->mptr = mempool_alloc(alloc_size); + buf->addr = buf->mptr.data; +} + +static void _buffer_destroy(liBuffer *buf) { + if (!buf || NULL == buf->addr) return; + mempool_free(buf->mptr, buf->alloc_size); + buf->addr = NULL; + buf->mptr.data = NULL; buf->mptr.priv_data = NULL; + buf->used = buf->alloc_size = 0; +} + + +liBuffer* li_buffer_new(gsize max_size) { + liBuffer *buf = g_slice_new0(liBuffer); + _buffer_init(buf, mempool_align_page_size(max_size)); + buf->refcount = 1; + return buf; +} + +void li_buffer_release(liBuffer *buf) { + if (!buf) return; + assert(g_atomic_int_get(&buf->refcount) > 0); + if (g_atomic_int_dec_and_test(&buf->refcount)) { + _buffer_destroy(buf); + g_slice_free(liBuffer, buf); + } +} + +void li_buffer_acquire(liBuffer *buf) { + assert(g_atomic_int_get(&buf->refcount) > 0); + g_atomic_int_inc(&buf->refcount); +} diff --git a/src/common/wscript b/src/common/wscript index 0f11573..7966ab5 100644 --- a/src/common/wscript +++ b/src/common/wscript @@ -17,6 +17,7 @@ def build(bld): source = ''' angel_connection.c angel_data.c + buffer.c encoding.c idlist.c ip_parsers.rl diff --git a/src/main/chunk.c b/src/main/chunk.c index b013990..b331baf 100644 --- a/src/main/chunk.c +++ b/src/main/chunk.c @@ -98,7 +98,7 @@ liHandlerResult li_chunkiter_read(liVRequest *vr, liChunkIter iter, off_t start, switch (c->type) { case UNUSED_CHUNK: return LI_HANDLER_ERROR; case STRING_CHUNK: - *data_start = c->str->str + c->offset + start; + *data_start = c->data.str->str + c->offset + start; *data_len = length; break; case MEM_CHUNK: @@ -106,7 +106,7 @@ liHandlerResult li_chunkiter_read(liVRequest *vr, liChunkIter iter, off_t start, *data_len = length; break; case FILE_CHUNK: - if (LI_HANDLER_GO_ON != (res = li_chunkfile_open(vr, c->file.file))) return res; + if (LI_HANDLER_GO_ON != (res = li_chunkfile_open(vr, c->data.file.file))) return res; if (length > MAX_MMAP_CHUNK) length = MAX_MMAP_CHUNK; @@ -116,21 +116,21 @@ liHandlerResult li_chunkiter_read(liVRequest *vr, liChunkIter iter, off_t start, g_byte_array_set_size(c->mem, length); } - our_start = start + c->offset + c->file.start; + our_start = start + c->offset + c->data.file.start; - if (-1 == lseek(c->file.file->fd, our_start, SEEK_SET)) { + if (-1 == lseek(c->data.file.file->fd, our_start, SEEK_SET)) { VR_ERROR(vr, "lseek failed for '%s' (fd = %i): %s", - GSTR_SAFE_STR(c->file.file->name), c->file.file->fd, + GSTR_SAFE_STR(c->data.file.file->name), c->data.file.file->fd, g_strerror(errno)); g_byte_array_free(c->mem, TRUE); c->mem = NULL; return LI_HANDLER_ERROR; } read_chunk: - if (-1 == (we_have = read(c->file.file->fd, c->mem->data, length))) { + if (-1 == (we_have = read(c->data.file.file->fd, c->mem->data, length))) { if (EINTR == errno) goto read_chunk; VR_ERROR(vr, "read failed for '%s' (fd = %i): %s", - GSTR_SAFE_STR(c->file.file->name), c->file.file->fd, + GSTR_SAFE_STR(c->data.file.file->name), c->data.file.file->fd, g_strerror(errno)); g_byte_array_free(c->mem, TRUE); c->mem = NULL; @@ -140,7 +140,7 @@ read_chunk: /* CON_TRACE(srv, "read return unexpected number of bytes"); */ if (we_have == 0) { VR_ERROR(vr, "read returned 0 bytes for '%s' (fd = %i): unexpected end of file?", - GSTR_SAFE_STR(c->file.file->name), c->file.file->fd); + GSTR_SAFE_STR(c->data.file.file->name), c->data.file.file->fd); g_byte_array_free(c->mem, TRUE); c->mem = NULL; return LI_HANDLER_ERROR; @@ -151,6 +151,10 @@ read_chunk: *data_start = (char*) c->mem->data; *data_len = length; break; + case BUFFER_CHUNK: + *data_start = (char*) c->data.buffer.buffer->addr + c->data.buffer.offset + c->offset + start; + *data_len = length; + break; } return LI_HANDLER_GO_ON; } @@ -174,7 +178,7 @@ liHandlerResult li_chunkiter_read_mmap(liVRequest *vr, liChunkIter iter, off_t s switch (c->type) { case UNUSED_CHUNK: return LI_HANDLER_ERROR; case STRING_CHUNK: - *data_start = c->str->str + c->offset + start; + *data_start = c->data.str->str + c->offset + start; *data_len = length; break; case MEM_CHUNK: @@ -182,16 +186,16 @@ liHandlerResult li_chunkiter_read_mmap(liVRequest *vr, liChunkIter iter, off_t s *data_len = length; break; case FILE_CHUNK: - if (LI_HANDLER_GO_ON != (res = li_chunkfile_open(vr, c->file.file))) return res; + if (LI_HANDLER_GO_ON != (res = li_chunkfile_open(vr, c->data.file.file))) return res; if (length > MAX_MMAP_CHUNK) length = MAX_MMAP_CHUNK; - if ( !(c->file.mmap.data != MAP_FAILED || c->mem) /* no data present */ + if ( !(c->data.file.mmap.data != MAP_FAILED || c->mem) /* no data present */ || !( /* or in the wrong range */ - (start + c->offset + c->file.start >= c->file.mmap.offset) - && (start + c->offset + c->file.start + length <= c->file.mmap.offset + (ssize_t) c->file.mmap.length)) ) { + (start + c->offset + c->data.file.start >= c->data.file.mmap.offset) + && (start + c->offset + c->data.file.start + length <= c->data.file.mmap.offset + (ssize_t) c->data.file.mmap.length)) ) { /* then find new range */ - our_start = start + c->offset + c->file.start; /* "start" maps to this offset in the file */ + our_start = start + c->offset + c->data.file.start; /* "start" maps to this offset in the file */ our_offset = our_start % MMAP_CHUNK_ALIGN; /* offset for "start" in new mmap block */ our_start -= our_offset; /* file offset for mmap */ @@ -199,32 +203,32 @@ liHandlerResult li_chunkiter_read_mmap(liVRequest *vr, liChunkIter iter, off_t s if (we_want > we_have) we_want = we_have; we_want += our_offset; - if (MAP_FAILED != c->file.mmap.data) { - munmap(c->file.mmap.data, c->file.mmap.length); - c->file.mmap.data = MAP_FAILED; + if (MAP_FAILED != c->data.file.mmap.data) { + munmap(c->data.file.mmap.data, c->data.file.mmap.length); + c->data.file.mmap.data = MAP_FAILED; } - c->file.mmap.offset = our_start; - c->file.mmap.length = we_want; + c->data.file.mmap.offset = our_start; + c->data.file.mmap.length = we_want; if (!c->mem) { /* mmap did not fail till now */ - c->file.mmap.data = mmap(0, we_want, PROT_READ, MAP_SHARED, c->file.file->fd, our_start); + c->data.file.mmap.data = mmap(0, we_want, PROT_READ, MAP_SHARED, c->data.file.file->fd, our_start); mmap_errno = errno; } - if (MAP_FAILED == c->file.mmap.data) { + if (MAP_FAILED == c->data.file.mmap.data) { /* fallback to read(...) */ if (!c->mem) { c->mem = g_byte_array_sized_new(we_want); } else { g_byte_array_set_size(c->mem, we_want); } - if (-1 == lseek(c->file.file->fd, our_start, SEEK_SET)) { + if (-1 == lseek(c->data.file.file->fd, our_start, SEEK_SET)) { /* prefer the error of the first syscall */ if (0 != mmap_errno) { VR_ERROR(vr, "mmap failed for '%s' (fd = %i): %s", - GSTR_SAFE_STR(c->file.file->name), c->file.file->fd, + GSTR_SAFE_STR(c->data.file.file->name), c->data.file.file->fd, g_strerror(mmap_errno)); } else { VR_ERROR(vr, "lseek failed for '%s' (fd = %i): %s", - GSTR_SAFE_STR(c->file.file->name), c->file.file->fd, + GSTR_SAFE_STR(c->data.file.file->name), c->data.file.file->fd, g_strerror(errno)); } g_byte_array_free(c->mem, TRUE); @@ -232,16 +236,16 @@ liHandlerResult li_chunkiter_read_mmap(liVRequest *vr, liChunkIter iter, off_t s return LI_HANDLER_ERROR; } read_chunk: - if (-1 == (we_have = read(c->file.file->fd, c->mem->data, we_want))) { + if (-1 == (we_have = read(c->data.file.file->fd, c->mem->data, we_want))) { if (EINTR == errno) goto read_chunk; /* prefer the error of the first syscall */ if (0 != mmap_errno) { VR_ERROR(vr, "mmap failed for '%s' (fd = %i): %s", - GSTR_SAFE_STR(c->file.file->name), c->file.file->fd, + GSTR_SAFE_STR(c->data.file.file->name), c->data.file.file->fd, g_strerror(mmap_errno)); } else { VR_ERROR(vr, "read failed for '%s' (fd = %i): %s", - GSTR_SAFE_STR(c->file.file->name), c->file.file->fd, + GSTR_SAFE_STR(c->data.file.file->name), c->data.file.file->fd, g_strerror(errno)); } g_byte_array_free(c->mem, TRUE); @@ -252,22 +256,26 @@ read_chunk: /* CON_TRACE(srv, "read return unexpected number of bytes"); */ we_want = we_have; if (length > we_have) length = we_have; - c->file.mmap.length = we_want; + c->data.file.mmap.length = we_want; g_byte_array_set_size(c->mem, we_want); } } else { #ifdef HAVE_MADVISE /* don't advise files < 64Kb */ - if (c->file.mmap.length > (64*1024) && - 0 != madvise(c->file.mmap.data, c->file.mmap.length, MADV_WILLNEED)) { + if (c->data.file.mmap.length > (64*1024) && + 0 != madvise(c->data.file.mmap.data, c->data.file.mmap.length, MADV_WILLNEED)) { VR_ERROR(vr, "madvise failed for '%s' (fd = %i): %s", - GSTR_SAFE_STR(c->file.file->name), c->file.file->fd, + GSTR_SAFE_STR(c->data.file.file->name), c->data.file.file->fd, g_strerror(errno)); } #endif } } - *data_start = (c->mem ? (char*) c->mem->data : c->file.mmap.data) + start + c->offset + c->file.start - c->file.mmap.offset; + *data_start = (c->mem ? (char*) c->mem->data : c->data.file.mmap.data) + start + c->offset + c->data.file.start - c->data.file.mmap.offset; + *data_len = length; + break; + case BUFFER_CHUNK: + *data_start = (char*) c->data.buffer.buffer->addr + c->data.buffer.offset + c->offset + start; *data_len = length; break; } @@ -280,7 +288,7 @@ read_chunk: static liChunk* chunk_new() { liChunk *c = g_slice_new0(liChunk); - c->file.mmap.data = MAP_FAILED; + c->data.file.mmap.data = MAP_FAILED; c->cq_link.data = c; return c; } @@ -290,16 +298,16 @@ static void chunk_reset(chunk *c) { if (!c) return; c->type = UNUSED_CHUNK; c->offset = 0; - if (c->str) g_string_free(c->str, TRUE); - c->str = NULL; - if (c->file.file) chunkfile_release(c->file.file); - c->file.file = NULL; - c->file.start = 0; - c->file.length = 0; - if (MAP_FAILED != c->file.mmap.data) munmap(c->file.mmap.data, c->file.mmap.length); - c->file.mmap.data = MAP_FAILED; - c->file.mmap.length = 0; - c->file.mmap.offset = 0; + if (c->data.str) g_string_free(c->data.str, TRUE); + c->data.str = NULL; + if (c->data.file.file) chunkfile_release(c->data.file.file); + c->data.file.file = NULL; + c->data.file.start = 0; + c->data.file.length = 0; + if (MAP_FAILED != c->data.file.mmap.data) munmap(c->data.file.mmap.data, c->data.file.mmap.length); + c->data.file.mmap.data = MAP_FAILED; + c->data.file.mmap.length = 0; + c->data.file.mmap.offset = 0; } */ @@ -308,23 +316,35 @@ static void chunk_free(liChunkQueue *cq, liChunk *c) { if (cq) { g_queue_unlink(&cq->queue, &c->cq_link); } - c->type = UNUSED_CHUNK; - if (c->str) { - g_string_free(c->str, TRUE); - c->str = NULL; + switch (c->type) { + case UNUSED_CHUNK: + break; + case STRING_CHUNK: + g_string_free(c->data.str, TRUE); + c->data.str = NULL; + break; + case MEM_CHUNK: + /* mem is handled extra below */ + break; + case FILE_CHUNK: + if (c->data.file.file) { + li_chunkfile_release(c->data.file.file); + c->data.file.file = NULL; + } + if (c->data.file.mmap.data != MAP_FAILED) { + munmap(c->data.file.mmap.data, c->data.file.mmap.length); + c->data.file.mmap.data = MAP_FAILED; + } + break; + case BUFFER_CHUNK: + li_buffer_release(c->data.buffer.buffer); + break; } + c->type = UNUSED_CHUNK; if (c->mem) { g_byte_array_free(c->mem, TRUE); c->mem = NULL; } - if (c->file.file) { - li_chunkfile_release(c->file.file); - c->file.file = NULL; - } - if (c->file.mmap.data != MAP_FAILED) { - munmap(c->file.mmap.data, c->file.mmap.length); - c->file.mmap.data = MAP_FAILED; - } g_slice_free(liChunk, c); } @@ -435,8 +455,9 @@ liChunkQueue* li_chunkqueue_new() { static void __chunk_free(gpointer _c, gpointer userdata) { liChunk *c = (liChunk *)_c; liChunkQueue *cq = (liChunkQueue*) userdata; - if (c->type == STRING_CHUNK) cqlimit_update(cq, - (goffset)c->str->len); + if (c->type == STRING_CHUNK) cqlimit_update(cq, - (goffset)c->data.str->len); else if (c->type == MEM_CHUNK) cqlimit_update(cq, - (goffset)c->mem->len); + else if (c->type == BUFFER_CHUNK) cqlimit_update(cq, - (goffset)c->data.buffer.length); chunk_free(cq, c); } @@ -498,7 +519,7 @@ void li_chunkqueue_append_string(liChunkQueue *cq, GString *str) { } c = chunk_new(); c->type = STRING_CHUNK; - c->str = str; + c->data.str = str; g_queue_push_tail_link(&cq->queue, &c->cq_link); cq->length += str->len; cq->bytes_in += str->len; @@ -524,6 +545,27 @@ void li_chunkqueue_append_bytearr(liChunkQueue *cq, GByteArray *mem) { cqlimit_update(cq, mem->len); } + /* pass ownership of buffer to chunkqueue, do not free/modify it afterwards + * you may modify the data (not the length) if you are sure it isn't sent before. + * if the length is NULL, buffer is destroyed immediately + */ +void li_chunkqueue_append_buffer(liChunkQueue *cq, liBuffer *buffer) { + liChunk *c; + if (!buffer->used) { + li_buffer_release(buffer); + return; + } + c = chunk_new(); + c->type = BUFFER_CHUNK; + c->data.buffer.buffer = buffer; + c->data.buffer.offset = 0; + c->data.buffer.length = buffer->used; + g_queue_push_tail_link(&cq->queue, &c->cq_link); + cq->length += buffer->used; + cq->bytes_in += buffer->used; + cqlimit_update(cq, buffer->used); +} + /* memory gets copied */ void li_chunkqueue_append_mem(liChunkQueue *cq, const void *mem, gssize len) { liChunk *c; @@ -545,9 +587,9 @@ void li_chunkqueue_append_chunkfile(liChunkQueue *cq, liChunkFile *cf, off_t sta li_chunkfile_acquire(cf); c->type = FILE_CHUNK; - c->file.file = cf; - c->file.start = start; - c->file.length = length; + c->data.file.file = cf; + c->data.file.start = start; + c->data.file.length = length; g_queue_push_tail_link(&cq->queue, &c->cq_link); cq->length += length; @@ -558,9 +600,9 @@ void li_chunkqueue_append_chunkfile(liChunkQueue *cq, liChunkFile *cf, off_t sta static void __chunkqueue_append_file(liChunkQueue *cq, GString *filename, off_t start, off_t length, int fd, gboolean is_temp) { liChunk *c = chunk_new(); c->type = FILE_CHUNK; - c->file.file = li_chunkfile_new(filename, fd, is_temp); - c->file.start = start; - c->file.length = length; + c->data.file.file = li_chunkfile_new(filename, fd, is_temp); + c->data.file.start = start; + c->data.file.length = length; g_queue_push_tail_link(&cq->queue, &c->cq_link); cq->length += length; @@ -608,8 +650,9 @@ goffset li_chunkqueue_steal_len(liChunkQueue *out, liChunkQueue *in, goffset len while ( (NULL != (c = li_chunkqueue_first_chunk(in))) && length > 0 ) { we_have = li_chunk_length(c); if (!we_have) { /* remove empty chunks */ - if (c->type == STRING_CHUNK) meminbytes -= c->str->len; + if (c->type == STRING_CHUNK) meminbytes -= c->data.str->len; else if (c->type == MEM_CHUNK) meminbytes -= c->mem->len; + else if (c->type == BUFFER_CHUNK) meminbytes -= c->data.buffer.length; chunk_free(in, c); continue; } @@ -618,11 +661,14 @@ goffset li_chunkqueue_steal_len(liChunkQueue *out, liChunkQueue *in, goffset len g_queue_push_tail_link(&out->queue, l); bytes += we_have; if (c->type == STRING_CHUNK) { - meminbytes -= c->str->len; - memoutbytes += c->str->len; + meminbytes -= c->data.str->len; + memoutbytes += c->data.str->len; } else if (c->type == MEM_CHUNK) { meminbytes -= c->mem->len; memoutbytes += c->mem->len; + } else if (c->type == BUFFER_CHUNK) { + meminbytes -= c->data.buffer.length; + memoutbytes += c->data.buffer.length; } length -= we_have; } else { /* copy first part of a chunk */ @@ -636,7 +682,7 @@ goffset li_chunkqueue_steal_len(liChunkQueue *out, liChunkQueue *in, goffset len case STRING_CHUNK: /* change type to MEM_CHUNK, as we copy it anyway */ cnew->type = MEM_CHUNK; cnew->mem = g_byte_array_sized_new(length); - g_byte_array_append(cnew->mem, (guint8*) c->str->str + c->offset, length); + g_byte_array_append(cnew->mem, (guint8*) c->data.str->str + c->offset, length); memoutbytes += length; break; case MEM_CHUNK: @@ -647,10 +693,18 @@ goffset li_chunkqueue_steal_len(liChunkQueue *out, liChunkQueue *in, goffset len break; case FILE_CHUNK: cnew->type = FILE_CHUNK; - li_chunkfile_acquire(c->file.file); - cnew->file.file = c->file.file; - cnew->file.start = c->file.start + c->offset; - cnew->file.length = length; + li_chunkfile_acquire(c->data.file.file); + cnew->data.file.file = c->data.file.file; + cnew->data.file.start = c->data.file.start + c->offset; + cnew->data.file.length = length; + break; + case BUFFER_CHUNK: + cnew->type = BUFFER_CHUNK; + li_buffer_acquire(c->data.buffer.buffer); + cnew->data.buffer.buffer = c->data.buffer.buffer; + cnew->data.buffer.offset = c->data.buffer.offset + c->offset; + cnew->data.buffer.length = length; + memoutbytes += length; break; } c->offset += length; @@ -724,11 +778,14 @@ goffset li_chunkqueue_steal_chunk(liChunkQueue *out, liChunkQueue *in) { out->length += length; if (in->limit != out->limit) { if (c->type == STRING_CHUNK) { - cqlimit_update(out, c->str->len); - cqlimit_update(in, - (goffset)c->str->len); + cqlimit_update(out, c->data.str->len); + cqlimit_update(in, - (goffset)c->data.str->len); } else if (c->type == MEM_CHUNK) { cqlimit_update(out, c->mem->len); cqlimit_update(in, - (goffset)c->mem->len); + } else if (c->type == BUFFER_CHUNK) { + cqlimit_update(out, c->data.buffer.length); + cqlimit_update(in, - (goffset)c->data.buffer.length); } } return length; @@ -743,8 +800,9 @@ goffset li_chunkqueue_skip(liChunkQueue *cq, goffset length) { while ( (NULL != (c = li_chunkqueue_first_chunk(cq))) && (0 == (we_have = li_chunk_length(c)) || length > 0) ) { if (we_have <= length) { /* skip (delete) complete chunk */ - if (c->type == STRING_CHUNK) cqlimit_update(cq, - (goffset)c->str->len); + if (c->type == STRING_CHUNK) cqlimit_update(cq, - (goffset)c->data.str->len); else if (c->type == MEM_CHUNK) cqlimit_update(cq, - (goffset)c->mem->len); + else if (c->type == BUFFER_CHUNK) cqlimit_update(cq, - (goffset)c->data.buffer.length); chunk_free(cq, c); bytes += we_have; length -= we_have; diff --git a/src/main/network.c b/src/main/network.c index 5210a38..e3376bf 100644 --- a/src/main/network.c +++ b/src/main/network.c @@ -78,8 +78,6 @@ liNetworkStatus li_network_read(liVRequest *vr, int fd, liChunkQueue *cq) { off_t max_read = 16 * blocksize; /* 256k */ ssize_t r; off_t len = 0; - liWorker *wrk = vr->wrk; - GByteArray *buf = wrk->network_read_buf; if (cq->limit && cq->limit->limit > 0) { if (max_read > cq->limit->limit - cq->limit->current) { @@ -92,8 +90,9 @@ liNetworkStatus li_network_read(liVRequest *vr, int fd, liChunkQueue *cq) { } do { - g_byte_array_set_size(buf, blocksize); - if (-1 == (r = li_net_read(fd, buf->data, blocksize))) { + liBuffer *buf = li_buffer_new(blocksize); + if (-1 == (r = li_net_read(fd, buf->addr, buf->alloc_size))) { + li_buffer_release(buf); switch (errno) { case EAGAIN: #if EWOULDBLOCK != EAGAIN @@ -107,11 +106,11 @@ liNetworkStatus li_network_read(liVRequest *vr, int fd, liChunkQueue *cq) { return LI_NETWORK_STATUS_FATAL_ERROR; } } else if (0 == r) { + li_buffer_release(buf); return len ? LI_NETWORK_STATUS_SUCCESS : LI_NETWORK_STATUS_CONNECTION_CLOSE; } - g_byte_array_set_size(buf, r); - li_chunkqueue_append_bytearr(cq, buf); - wrk->network_read_buf = buf = g_byte_array_sized_new(blocksize); + buf->used = r; + li_chunkqueue_append_buffer(cq, buf); len += r; } while (r == blocksize && len < max_read); diff --git a/src/main/network_sendfile.c b/src/main/network_sendfile.c index 98670b4..d3a005c 100644 --- a/src/main/network_sendfile.c +++ b/src/main/network_sendfile.c @@ -167,19 +167,19 @@ static liNetworkStatus network_backend_sendfile(liVRequest *vr, int fd, liChunkQ return did_write_something ? LI_NETWORK_STATUS_SUCCESS : LI_NETWORK_STATUS_FATAL_ERROR; } - switch (li_chunkfile_open(vr, c->file.file)) { + switch (li_chunkfile_open(vr, c->data.file.file)) { case LI_HANDLER_GO_ON: break; default: return LI_NETWORK_STATUS_FATAL_ERROR; } - file_offset = c->offset + c->file.start; - toSend = c->file.length - c->offset; + file_offset = c->offset + c->data.file.start; + toSend = c->data.file.length - c->offset; if (toSend > *write_max) toSend = *write_max; r = 0; - switch (lighty_sendfile(vr, fd, c->file.file->fd, file_offset, toSend, &r)) { + switch (lighty_sendfile(vr, fd, c->data.file.file->fd, file_offset, toSend, &r)) { case NSR_SUCCESS: li_chunkqueue_skip(cq, r); *write_max -= r; @@ -225,6 +225,7 @@ liNetworkStatus li_network_write_sendfile(liVRequest *vr, int fd, liChunkQueue * switch (li_chunkqueue_first_chunk(cq)->type) { case MEM_CHUNK: case STRING_CHUNK: + case BUFFER_CHUNK: LI_NETWORK_FALLBACK(li_network_backend_writev, write_max); break; case FILE_CHUNK: diff --git a/src/main/network_writev.c b/src/main/network_writev.c index 3a7a964..0f3aaa7 100644 --- a/src/main/network_writev.c +++ b/src/main/network_writev.c @@ -40,7 +40,7 @@ liNetworkStatus li_network_backend_writev(liVRequest *vr, int fd, liChunkQueue * do { ci = li_chunkqueue_iter(cq); - if (STRING_CHUNK != (c = li_chunkiter_chunk(ci))->type && MEM_CHUNK != c->type) { + if (STRING_CHUNK != (c = li_chunkiter_chunk(ci))->type && MEM_CHUNK != c->type && BUFFER_CHUNK != c->type) { res = did_write_something ? LI_NETWORK_STATUS_SUCCESS : LI_NETWORK_STATUS_FATAL_ERROR; goto cleanup; } @@ -52,16 +52,19 @@ liNetworkStatus li_network_backend_writev(liVRequest *vr, int fd, liChunkQueue * struct iovec *v; g_array_set_size(chunks, i + 1); v = &g_array_index(chunks, struct iovec, i); - if (c->type == STRING_CHUNK) - v->iov_base = c->str->str + c->offset; - else /* if c->type == MEM_CHUNK */ + if (c->type == STRING_CHUNK) { + v->iov_base = c->data.str->str + c->offset; + } else if (c->type == MEM_CHUNK) { v->iov_base = c->mem->data + c->offset; + } else { /* if (c->type == BUFFER_CHUNK) */ + v->iov_base = c->data.buffer.buffer->addr + c->data.buffer.offset + c->offset; + } if (len > *write_max - we_have) len = *write_max - we_have; v->iov_len = len; we_have += len; } while (we_have < *write_max && li_chunkiter_next(&ci) && - (STRING_CHUNK == (c = li_chunkiter_chunk(ci))->type || MEM_CHUNK == c->type) && + (STRING_CHUNK == (c = li_chunkiter_chunk(ci))->type || MEM_CHUNK == c->type || BUFFER_CHUNK == c->type) && chunks->len < UIO_MAXIOV); while (-1 == (r = writev(fd, (struct iovec*) chunks->data, chunks->len))) { @@ -116,6 +119,8 @@ liNetworkStatus li_network_write_writev(liVRequest *vr, int fd, liChunkQueue *cq do { switch (li_chunkqueue_first_chunk(cq)->type) { case STRING_CHUNK: + case MEM_CHUNK: + case BUFFER_CHUNK: LI_NETWORK_FALLBACK(li_network_backend_writev, write_max); break; case FILE_CHUNK: