diff options
-rw-r--r-- | libglusterfs/src/Makefile.am | 4 | ||||
-rw-r--r-- | libglusterfs/src/glusterfs.h | 1 | ||||
-rw-r--r-- | libglusterfs/src/iobuf.c | 394 | ||||
-rw-r--r-- | libglusterfs/src/iobuf.h | 97 |
4 files changed, 494 insertions, 2 deletions
diff --git a/libglusterfs/src/Makefile.am b/libglusterfs/src/Makefile.am index 982c4d69d..8ff35fbb2 100644 --- a/libglusterfs/src/Makefile.am +++ b/libglusterfs/src/Makefile.am @@ -6,9 +6,9 @@ libglusterfs_la_LIBADD = @LEXLIB@ lib_LTLIBRARIES = libglusterfs.la -libglusterfs_la_SOURCES = dict.c spec.lex.c y.tab.c xlator.c logging.c hashfn.c defaults.c scheduler.c common-utils.c transport.c timer.c inode.c call-stub.c compat.c authenticate.c fd.c compat-errno.c event.c mem-pool.c gf-dirent.c syscall.c +libglusterfs_la_SOURCES = dict.c spec.lex.c y.tab.c xlator.c logging.c hashfn.c defaults.c scheduler.c common-utils.c transport.c timer.c inode.c call-stub.c compat.c authenticate.c fd.c compat-errno.c event.c mem-pool.c gf-dirent.c syscall.c iobuf.c -noinst_HEADERS = common-utils.h defaults.h dict.h glusterfs.h hashfn.h logging.h protocol.h scheduler.h xlator.h transport.h stack.h timer.h list.h inode.h call-stub.h compat.h authenticate.h fd.h revision.h compat-errno.h event.h mem-pool.h byte-order.h gf-dirent.h locking.h syscall.h +noinst_HEADERS = common-utils.h defaults.h dict.h glusterfs.h hashfn.h logging.h protocol.h scheduler.h xlator.h transport.h stack.h timer.h list.h inode.h call-stub.h compat.h authenticate.h fd.h revision.h compat-errno.h event.h mem-pool.h byte-order.h gf-dirent.h locking.h syscall.h iobuf.h EXTRA_DIST = spec.l spec.y diff --git a/libglusterfs/src/glusterfs.h b/libglusterfs/src/glusterfs.h index 604b41d14..529f54397 100644 --- a/libglusterfs/src/glusterfs.h +++ b/libglusterfs/src/glusterfs.h @@ -260,6 +260,7 @@ struct _glusterfs_ctx { void *graph; void *top; /* either fuse or server protocol */ void *event_pool; + void *iobuf_pool; pthread_mutex_t lock; int xl_count; uint32_t volfile_checksum; diff --git a/libglusterfs/src/iobuf.c b/libglusterfs/src/iobuf.c new file mode 100644 index 000000000..5d1f37c03 --- /dev/null +++ b/libglusterfs/src/iobuf.c @@ -0,0 +1,394 @@ +/* + Copyright (c) 2009 Z RESEARCH, Inc. <http://www.zresearch.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + + +#include "iobuf.h" +#include <stdio.h> + + +/* + TODO: implement destroy margins and prefetching of arenas +*/ + +void +__iobuf_arena_init_iobufs (struct iobuf_arena *iobuf_arena) +{ + size_t arena_size = 0; + size_t page_size = 0; + int iobuf_cnt = 0; + struct iobuf *iobuf = NULL; + int offset = 0; + int i = 0; + + arena_size = iobuf_arena->iobuf_pool->arena_size; + page_size = iobuf_arena->iobuf_pool->page_size; + iobuf_cnt = arena_size / page_size; + + iobuf_arena->iobufs = CALLOC (sizeof (*iobuf), iobuf_cnt); + if (!iobuf_arena->iobufs) + return; + + iobuf = iobuf_arena->iobufs; + for (i = 0; i < iobuf_cnt; i++) { + INIT_LIST_HEAD (&iobuf->list); + LOCK_INIT (&iobuf->lock); + + iobuf->iobuf_arena = iobuf_arena; + + iobuf->ptr = iobuf_arena->mem_base + offset; + + list_add (&iobuf->list, &iobuf_arena->passive.list); + iobuf_arena->passive_cnt++; + + offset += page_size; + iobuf++; + } +} + + +void +__iobuf_arena_destroy_iobufs (struct iobuf_arena *iobuf_arena) +{ + size_t arena_size = 0; + size_t page_size = 0; + int iobuf_cnt = 0; + struct iobuf *iobuf = NULL; + int i = 0; + + arena_size = iobuf_arena->iobuf_pool->arena_size; + page_size = iobuf_arena->iobuf_pool->page_size; + iobuf_cnt = arena_size / page_size; + + iobuf = iobuf_arena->iobufs; + for (i = 0; i < iobuf_cnt; i++) { + assert (iobuf->ref == 0); + + list_del_init (&iobuf->list); + iobuf++; + } +} + + +void +__iobuf_arena_destroy (struct iobuf_arena *iobuf_arena) +{ + if (!iobuf_arena) + return; + + __iobuf_arena_destroy_iobufs (iobuf_arena); + + if (iobuf_arena->mem_base) + FREE (iobuf_arena->mem_base); + + FREE (iobuf_arena); +} + + +struct iobuf_arena * +__iobuf_arena_alloc (struct iobuf_pool *iobuf_pool) +{ + struct iobuf_arena *iobuf_arena = NULL; + size_t arena_size = 0; + + iobuf_arena = CALLOC (sizeof (*iobuf_pool), 1); + if (!iobuf_arena) + goto err; + + INIT_LIST_HEAD (&iobuf_arena->list); + INIT_LIST_HEAD (&iobuf_arena->active.list); + INIT_LIST_HEAD (&iobuf_arena->passive.list); + iobuf_arena->iobuf_pool = iobuf_pool; + + arena_size = iobuf_pool->arena_size; + iobuf_arena->mem_base = mmap (NULL, arena_size, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + if (iobuf_arena->mem_base == ((void *) -1)) + goto err; + + __iobuf_arena_init_iobufs (iobuf_arena); + if (!iobuf_arena->iobufs) + goto err; + + return iobuf_arena; + +err: + __iobuf_arena_destroy (iobuf_arena); + return NULL; +} + + +struct iobuf_arena * +__iobuf_pool_add_arena (struct iobuf_pool *iobuf_pool) +{ + struct iobuf_arena *iobuf_arena = NULL; + + iobuf_arena = __iobuf_arena_alloc (iobuf_pool); + + if (!iobuf_arena) + return NULL; + + list_add_tail (&iobuf_arena->list, &iobuf_pool->arenas.list); + iobuf_pool->arena_cnt++; + + return iobuf_arena; +} + + +struct iobuf_arena * +iobuf_pool_add_arena (struct iobuf_pool *iobuf_pool) +{ + struct iobuf_arena *iobuf_arena = NULL; + + pthread_mutex_lock (&iobuf_pool->mutex); + { + iobuf_arena = __iobuf_pool_add_arena (iobuf_pool); + } + pthread_mutex_unlock (&iobuf_pool->mutex); + + return iobuf_arena; +} + + +void +iobuf_pool_destroy (struct iobuf_pool *iobuf_pool) +{ + struct iobuf_arena *iobuf_arena = NULL; + struct iobuf_arena *tmp = NULL; + + if (!iobuf_pool) + return; + + list_for_each_entry_safe (iobuf_arena, tmp, &iobuf_pool->arenas.list, + list) { + + list_del_init (&iobuf_arena->list); + iobuf_pool->arena_cnt--; + + __iobuf_arena_destroy (iobuf_arena); + } +} + + +struct iobuf_pool * +iobuf_pool_new (size_t arena_size, size_t page_size) +{ + struct iobuf_pool *iobuf_pool = NULL; + + if (arena_size < page_size) + return NULL; + + iobuf_pool = CALLOC (sizeof (*iobuf_pool), 1); + if (!iobuf_pool) + return NULL; + + pthread_mutex_init (&iobuf_pool->mutex, NULL); + INIT_LIST_HEAD (&iobuf_pool->arenas.list); + + iobuf_pool->arena_size = arena_size; + iobuf_pool->page_size = page_size; + + iobuf_pool_add_arena (iobuf_pool); + + return iobuf_pool; +} + + + +void +__iobuf_pool_prune (struct iobuf_pool *iobuf_pool) +{ + struct iobuf_arena *iobuf_arena = NULL; + struct iobuf_arena *tmp = NULL; + + list_for_each_entry_safe (iobuf_arena, tmp, &iobuf_pool->arenas.list, + list) { + if (iobuf_arena->active_cnt) + continue; + + list_del_init (&iobuf_arena->list); + iobuf_pool->arena_cnt--; + + __iobuf_arena_destroy (iobuf_arena); + } +} + + +void +iobuf_pool_prune (struct iobuf_pool *iobuf_pool) +{ + pthread_mutex_lock (&iobuf_pool->mutex); + { + __iobuf_pool_prune (iobuf_pool); + } + pthread_mutex_unlock (&iobuf_pool->mutex); +} + + +struct iobuf_arena * +__iobuf_select_arena (struct iobuf_pool *iobuf_pool) +{ + struct iobuf_arena *iobuf_arena = NULL; + + /* look for unused iobuf from the head-most arena */ + list_for_each_entry (iobuf_arena, &iobuf_pool->arenas.list, list) { + if (iobuf_arena->passive_cnt) + break; + } + + if (!iobuf_arena) { + /* all arenas were full */ + iobuf_arena = iobuf_pool_add_arena (iobuf_pool); + } + + return iobuf_arena; +} + + +struct iobuf * +__iobuf_ref (struct iobuf *iobuf) +{ + iobuf->ref++; + + return iobuf; +} + + +struct iobuf * +__iobuf_unref (struct iobuf *iobuf) +{ + iobuf->ref--; + + return iobuf; +} + + +struct iobuf * +__iobuf_get (struct iobuf_arena *iobuf_arena) +{ + struct iobuf *iobuf = NULL; + + list_for_each_entry (iobuf, &iobuf_arena->passive.list, list) + break; + + list_del (&iobuf->list); + iobuf_arena->passive_cnt--; + + list_add (&iobuf->list, &iobuf_arena->active.list); + iobuf_arena->active_cnt++; + + return iobuf; +} + + +struct iobuf * +iobuf_get (struct iobuf_pool *iobuf_pool) +{ + struct iobuf *iobuf = NULL; + struct iobuf_arena *iobuf_arena = NULL; + + pthread_mutex_lock (&iobuf_pool->mutex); + { + /* most eligible arena for picking an iobuf */ + iobuf_arena = __iobuf_select_arena (iobuf_pool); + if (!iobuf_arena) + goto unlock; + + iobuf = __iobuf_get (iobuf_arena); + if (!iobuf) + goto unlock; + + __iobuf_ref (iobuf); + } +unlock: + pthread_mutex_unlock (&iobuf_pool->mutex); + + return iobuf; +} + + +void +__iobuf_put (struct iobuf *iobuf, struct iobuf_arena *iobuf_arena) +{ + list_del_init (&iobuf->list); + iobuf_arena->active_cnt--; + + list_add (&iobuf->list, &iobuf_arena->passive.list); + iobuf_arena->passive_cnt++; +} + + +void +iobuf_put (struct iobuf *iobuf) +{ + struct iobuf_arena *iobuf_arena = NULL; + struct iobuf_pool *iobuf_pool = NULL; + + if (!iobuf) + return; + + iobuf_arena = iobuf->iobuf_arena; + if (!iobuf_arena) + return; + + iobuf_pool = iobuf_arena->iobuf_pool; + if (!iobuf_pool) + return; + + pthread_mutex_lock (&iobuf_pool->mutex); + { + __iobuf_put (iobuf, iobuf_arena); + } + pthread_mutex_unlock (&iobuf_pool->mutex); +} + + +void +iobuf_unref (struct iobuf *iobuf) +{ + int ref = 0; + + if (!iobuf) + return; + + LOCK (&iobuf->lock); + { + __iobuf_unref (iobuf); + ref = iobuf->ref; + } + UNLOCK (&iobuf->lock); + + if (!ref) + iobuf_put (iobuf); +} + + +struct iobuf * +iobuf_ref (struct iobuf *iobuf) +{ + if (!iobuf) + return NULL; + + LOCK (&iobuf->lock); + { + __iobuf_ref (iobuf); + } + UNLOCK (&iobuf->lock); + + return iobuf; +} diff --git a/libglusterfs/src/iobuf.h b/libglusterfs/src/iobuf.h new file mode 100644 index 000000000..8a854db8f --- /dev/null +++ b/libglusterfs/src/iobuf.h @@ -0,0 +1,97 @@ +/* + Copyright (c) 2009 Z RESEARCH, Inc. <http://www.zresearch.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#ifndef _IOBUF_H_ +#define _IOBUF_H_ + +#include "list.h" +#include "common-utils.h" +#include <pthread.h> +#include <sys/mman.h> + +/* one allocatable unit for the consumers of the IOBUF API */ +/* each unit hosts @page_size bytes of memory */ +struct iobuf; + +/* one region of memory MMAPed from the operating system */ +/* each region MMAPs @arena_size bytes of memory */ +/* each arena hosts @arena_size / @page_size IOBUFs */ +struct iobuf_arena; + +/* expandable and contractable pool of memory, internally broken into arenas */ +struct iobuf_pool; + + +struct iobuf { + union { + struct list_head list; + struct { + struct iobuf *next; + struct iobuf *prev; + }; + }; + struct iobuf_arena *iobuf_arena; + + gf_lock_t lock; /* for ->ptr and ->ref */ + int ref; /* 0 == passive, >0 == active */ + + void *ptr; /* usable memory region by the consumer */ +}; + + +struct iobuf_arena { + union { + struct list_head list; + struct { + struct iobuf_arena *next; + struct iobuf_arena *prev; + }; + }; + struct iobuf_pool *iobuf_pool; + + void *mem_base; + struct iobuf *iobufs; /* allocated iobufs list */ + + int active_cnt; + struct iobuf active; /* head node iobuf + (unused by itself) */ + int passive_cnt; + struct iobuf passive; /* head node iobuf + (unused by itself) */ +}; + + +struct iobuf_pool { + pthread_mutex_t mutex; + size_t page_size; /* size of all iobufs in this pool */ + size_t arena_size; /* size of memory region in arena */ + + int arena_cnt; + struct iobuf_arena arenas; /* head node arena + (unused by itself) */ +}; + + + + +struct iobuf_pool *iobuf_pool_new (size_t arena_size, size_t page_size); +struct iobuf *iobuf_get (struct iobuf_pool *iobuf_pool); +void iobuf_unref (struct iobuf *iobuf); + +#endif /* !_IOBUF_H_ */ |