Browse Source

add liBuffer: a reference-counted memory chunk (using mempool) for basic network data

personal/stbuehler/wip
Stefan Bühler 12 years ago
parent
commit
0c3ca6b13b
  1. 1
      include/lighttpd/base.h
  2. 22
      include/lighttpd/buffer.h
  3. 42
      include/lighttpd/chunk.h
  4. 1
      include/lighttpd/typedefs.h
  5. 1
      src/CMakeLists.txt
  6. 1
      src/common/Makefile.am
  7. 39
      src/common/buffer.c
  8. 1
      src/common/wscript
  9. 206
      src/main/chunk.c
  10. 13
      src/main/network.c
  11. 9
      src/main/network_sendfile.c
  12. 15
      src/main/network_writev.c

1
include/lighttpd/base.h

@ -30,6 +30,7 @@
#include <lighttpd/angel_data.h>
#include <lighttpd/angel_connection.h>
#include <lighttpd/buffer.h>
#include <lighttpd/chunk.h>
#include <lighttpd/chunk_parser.h>

22
include/lighttpd/buffer.h

@ -0,0 +1,22 @@
#ifndef _LIGHTTPD_BUFFER_H_
#define _LIGHTTPD_BUFFER_H_
#include <lighttpd/settings.h>
#include <lighttpd/mempool.h>
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

42
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 <n> 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 <n> 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;
}

1
include/lighttpd/typedefs.h

@ -45,7 +45,6 @@ typedef enum {
BACKEND_DEAD
} liBackendError;
/* chunk.h */
typedef struct liChunkFile liChunkFile;

1
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

1
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 \

39
src/common/buffer.c

@ -0,0 +1,39 @@
#include <lighttpd/buffer.h>
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);
}

1
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

206
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;

13
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);

9
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:

15
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:

Loading…
Cancel
Save