diff options
author | Anand V. Avati <avati@amp.gluster.com> | 2009-04-03 15:17:04 +0530 |
---|---|---|
committer | Anand V. Avati <avati@amp.gluster.com> | 2009-04-12 11:33:46 +0530 |
commit | 124fb0c752530322e6311dde668422afef6b2afe (patch) | |
tree | 712d29e4a66bad15f7deb25f9a8d455a970ac0bd /libglusterfs/src/iobuf.c | |
parent | a31e26f8df26b1229e9fbca60ff8bf462b234241 (diff) |
IOBUF support (to be used by transports and fuse)
Signed-off-by: Anand V. Avati <avati@amp.gluster.com>
Diffstat (limited to 'libglusterfs/src/iobuf.c')
-rw-r--r-- | libglusterfs/src/iobuf.c | 394 |
1 files changed, 394 insertions, 0 deletions
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; +} |