From: Liu Yuan <tailai.ly at taobao.com> Dbuffer is a dynamic buffer that can grow automatically. Maybe per thread buffer is a better idea than global one. But global one is simple to implement and use. Signed-off-by: Liu Yuan <tailai.ly at taobao.com> --- include/util.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ lib/Makefile.am | 2 +- lib/dbuffer.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ sheep/strbuf.h | 20 -------------------- 4 files changed, 90 insertions(+), 21 deletions(-) create mode 100644 lib/dbuffer.c diff --git a/include/util.h b/include/util.h index ff86a00..e56249f 100644 --- a/include/util.h +++ b/include/util.h @@ -69,4 +69,49 @@ extern ssize_t xwrite(int fd, const void *buf, size_t len); extern ssize_t xpread(int fd, void *buf, size_t count, off_t offset); extern ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset); +#define alloc_nr(x) (((x)+16)*3/2) + +/* + * Realloc the buffer pointed at by variable 'x' so that it can hold + * at least 'nr' entries; the number of entries currently allocated + * is 'alloc', using the standard growing factor alloc_nr() macro. + * + * DO NOT USE any expression with side-effect for 'x' or 'alloc'. + */ +#define ALLOC_GROW(x, nr, alloc) \ + do { \ + if ((nr) > alloc) { \ + if (alloc_nr(alloc) < (nr)) \ + alloc = (nr); \ + else \ + alloc = alloc_nr(alloc); \ + x = xrealloc((x), alloc * sizeof(*(x))); \ + } \ + } while(0) + +/* dbuffer.c */ +struct dbuffer { + char *buffer; /* data buffer */ + size_t capacity; /* initial maximum number of items in the buffer */ + size_t count; /* number of items in the buffer */ + size_t sz; /* size of each item in the buffer */ + pthread_spinlock_t lock; /* be thread-safe */ +}; + +#define BUF_ADDR(dbuf, idx) (dbuf->buffer + idx * dbuf->sz) +/* Caller is responsible for index check */ +static inline void dbuffer_get_item(struct dbuffer *dbuf, void *item, size_t idx) +{ + memcpy(item, BUF_ADDR(dbuf, idx), dbuf->sz); +} + +static inline size_t dbuffer_size(struct dbuffer *dbuf) +{ + return dbuf->count * dbuf->sz; +} + +void dbuffer_put_item(struct dbuffer *dbuf, const void *item); +void dbuffer_destroy(struct dbuffer *dbuf); +int dbuffer_create(struct dbuffer *dbuf, size_t capacity, size_t item_size); + #endif diff --git a/lib/Makefile.am b/lib/Makefile.am index c4fb3af..3d08739 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -4,4 +4,4 @@ INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include noinst_LIBRARIES = libsheepdog.a -libsheepdog_a_SOURCES = event.c logger.c net.c util.c coroutine.c +libsheepdog_a_SOURCES = event.c logger.c net.c util.c coroutine.c dbuffer.c diff --git a/lib/dbuffer.c b/lib/dbuffer.c new file mode 100644 index 0000000..3b90acc --- /dev/null +++ b/lib/dbuffer.c @@ -0,0 +1,44 @@ +#include <pthread.h> +#include <stdlib.h> + +#include "util.h" +#include "logger.h" + +notrace int dbuffer_create(struct dbuffer *dbuf, size_t capacity, size_t sz) +{ + if (capacity) + dbuf->buffer = xmalloc(capacity * sz); + else + dbuf->buffer = NULL; + dbuf->capacity = capacity; + dbuf->count = 0; + dbuf->sz = sz; + if (pthread_spin_init(&dbuf->lock, 0) != 0) { + return -1; + } + return 0; +} + +notrace void dbuffer_destroy(struct dbuffer *dbuf) +{ + free(dbuf->buffer); + pthread_spin_destroy(&dbuf->lock); +} + +notrace static void dbuffer_try_grow(struct dbuffer *dbuf, size_t extra) +{ + size_t len = dbuf->count * dbuf->sz; + if (len + extra + 1 <= len) + panic("you want to use way too much memory"); + ALLOC_GROW(dbuf->buffer, len + extra + 1, dbuf->capacity); +} + +/* Put the item to the tail of the buffer */ +notrace void dbuffer_put_item(struct dbuffer *dbuf, const void *item) +{ + pthread_spin_lock(&dbuf->lock); + dbuffer_try_grow(dbuf, dbuf->sz); + memcpy(BUF_ADDR(dbuf, dbuf->count), item, dbuf->sz); + dbuf->count++; + pthread_spin_unlock(&dbuf->lock); +} diff --git a/sheep/strbuf.h b/sheep/strbuf.h index 573784b..3033209 100644 --- a/sheep/strbuf.h +++ b/sheep/strbuf.h @@ -17,26 +17,6 @@ struct strbuf { char *buf; }; -#define alloc_nr(x) (((x)+16)*3/2) - -/* - * Realloc the buffer pointed at by variable 'x' so that it can hold - * at least 'nr' entries; the number of entries currently allocated - * is 'alloc', using the standard growing factor alloc_nr() macro. - * - * DO NOT USE any expression with side-effect for 'x' or 'alloc'. - */ -#define ALLOC_GROW(x, nr, alloc) \ - do { \ - if ((nr) > alloc) { \ - if (alloc_nr(alloc) < (nr)) \ - alloc = (nr); \ - else \ - alloc = alloc_nr(alloc); \ - x = xrealloc((x), alloc * sizeof(*(x))); \ - } \ - } while(0) - #define STRBUF_INIT { 0, 0, 0, NULL } /*----- strbuf life cycle -----*/ -- 1.7.8.2 |