summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnand V. Avati <avati@amp.gluster.com>2009-04-03 15:17:04 +0530
committerAnand V. Avati <avati@amp.gluster.com>2009-04-12 11:33:46 +0530
commit124fb0c752530322e6311dde668422afef6b2afe (patch)
tree712d29e4a66bad15f7deb25f9a8d455a970ac0bd
parenta31e26f8df26b1229e9fbca60ff8bf462b234241 (diff)
IOBUF support (to be used by transports and fuse)
Signed-off-by: Anand V. Avati <avati@amp.gluster.com>
-rw-r--r--libglusterfs/src/Makefile.am4
-rw-r--r--libglusterfs/src/glusterfs.h1
-rw-r--r--libglusterfs/src/iobuf.c394
-rw-r--r--libglusterfs/src/iobuf.h97
4 files changed, 494 insertions, 2 deletions
diff --git a/libglusterfs/src/Makefile.am b/libglusterfs/src/Makefile.am
index 982c4d69de9..8ff35fbb27a 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 604b41d1488..529f5439728 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 00000000000..5d1f37c0391
--- /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 00000000000..8a854db8f41
--- /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_ */