summaryrefslogtreecommitdiff
path: root/mysys/lf_dynarray.c
diff options
context:
space:
mode:
authorunknown <serg@janus.mylan>2006-08-10 19:19:47 +0200
committerunknown <serg@janus.mylan>2006-08-10 19:19:47 +0200
commitcd876fb11883f68f93027a70b5f3f99ad9234f27 (patch)
tree606c0ae70958f725f45d6d8f2bfbbf437a3873df /mysys/lf_dynarray.c
parentfe84903b15772782aa3bfbaa5fee60d480eaa4f2 (diff)
downloadmariadb-git-cd876fb11883f68f93027a70b5f3f99ad9234f27.tar.gz
amd64 atomic ops
lock-free alloc (WL#3229), lock-free hash (WL#3230) bit functions made inline include/Makefile.am: lf.h added mysys/Makefile.am: lf_hash.c lf_dynarray.c lf_alloc-pin.c include/atomic/nolock.h: amd64 atomic ops include/atomic/rwlock.h: s/rw_lock/mutex/g include/atomic/x86-gcc.h: amd64 atomic ops try PAUSE include/my_global.h: STATIC_INLINE mysys/mf_keycache.c: make bit functions inline mysys/my_atomic.c: STATIC_INLINE mysys/my_bitmap.c: make bit functions inline sql/ha_myisam.cc: make bit functions inline sql/item_func.cc: make bit functions inline include/my_atomic.h: STATIC_INLINE mysys/my_bit.c: make bit functions inline sql/sql_select.cc: make bit functions inline storage/myisam/mi_create.c: make bit functions inline storage/myisam/mi_test2.c: make bit functions inline storage/myisam/myisamchk.c: make bit functions inline mysys/my_init.c: thread_size moved to mysys sql/mysql_priv.h: thread_size moved to mysys sql/set_var.cc: thread_size moved to mysys include/my_sys.h: thread_size moved to mysys sql/mysqld.cc: thread_size moved to mysys sql/sql_parse.cc: thread_size moved to mysys sql/sql_test.cc: thread_size moved to mysys include/lf.h: dylf_dynarray refactored to remove 65536 elements limit mysys/lf_alloc-pin.c: dylf_dynarray refactored to remove 65536 elements limit mysys/lf_dynarray.c: dylf_dynarray refactored to remove 65536 elements limit mysys/lf_hash.c: dylf_dynarray refactored to remove 65536 elements limit unittest/mysys/my_atomic-t.c: fix to commit (remove debug code)
Diffstat (limited to 'mysys/lf_dynarray.c')
-rw-r--r--mysys/lf_dynarray.c186
1 files changed, 186 insertions, 0 deletions
diff --git a/mysys/lf_dynarray.c b/mysys/lf_dynarray.c
new file mode 100644
index 00000000000..dcf99163ca1
--- /dev/null
+++ b/mysys/lf_dynarray.c
@@ -0,0 +1,186 @@
+/* Copyright (C) 2000 MySQL AB
+
+ This program 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 2 of the License, or
+ (at your option) any later version.
+
+ This program 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Analog of DYNAMIC_ARRAY that never reallocs
+ (so no pointer into the array may ever become invalid).
+
+ Memory is allocated in non-contiguous chunks.
+ This data structure is not space efficient for sparce arrays.
+
+ The number of elements is limited to 2^16
+
+ Every element is aligned to sizeof(element) boundary
+ (to avoid false sharing if element is big enough).
+
+ Actually, it's wait-free, not lock-free ;-)
+*/
+
+#undef DBUG_OFF
+#include <my_global.h>
+#include <strings.h>
+#include <my_sys.h>
+#include <lf.h>
+
+void lf_dynarray_init(LF_DYNARRAY *array, uint element_size)
+{
+ bzero(array, sizeof(*array));
+ array->size_of_element=element_size;
+ my_atomic_rwlock_init(&array->lock);
+}
+
+static void recursive_free(void **alloc, int level)
+{
+ if (!alloc) return;
+
+ if (level)
+ {
+ int i;
+ for (i=0; i < LF_DYNARRAY_LEVEL_LENGTH; i++)
+ recursive_free(alloc[i], level-1);
+ my_free((void *)alloc, MYF(0));
+ }
+ else
+ my_free(alloc[-1], MYF(0));
+}
+
+void lf_dynarray_end(LF_DYNARRAY *array)
+{
+ int i;
+ for (i=0; i < LF_DYNARRAY_LEVELS; i++)
+ recursive_free(array->level[i], i);
+ my_atomic_rwlock_destroy(&array->lock);
+ bzero(array, sizeof(*array));
+}
+
+static const int dynarray_idxes_in_level[LF_DYNARRAY_LEVELS]=
+{
+ 0, /* +1 here to to avoid -1's below */
+ LF_DYNARRAY_LEVEL_LENGTH,
+ LF_DYNARRAY_LEVEL_LENGTH * LF_DYNARRAY_LEVEL_LENGTH,
+ LF_DYNARRAY_LEVEL_LENGTH * LF_DYNARRAY_LEVEL_LENGTH *
+ LF_DYNARRAY_LEVEL_LENGTH
+};
+
+void *_lf_dynarray_lvalue(LF_DYNARRAY *array, uint idx)
+{
+ void * ptr, * volatile * ptr_ptr=0;
+ int i;
+
+ for (i=3; i > 0; i--)
+ {
+ if (ptr_ptr || idx >= dynarray_idxes_in_level[i])
+ {
+ if (!ptr_ptr)
+ {
+ ptr_ptr=&array->level[i];
+ idx-= dynarray_idxes_in_level[i];
+ }
+ ptr=*ptr_ptr;
+ if (!ptr)
+ {
+ void *alloc=my_malloc(LF_DYNARRAY_LEVEL_LENGTH * sizeof(void *),
+ MYF(MY_WME|MY_ZEROFILL));
+ if (!alloc)
+ return(NULL);
+ if (my_atomic_casptr(ptr_ptr, &ptr, alloc))
+ ptr= alloc;
+ else
+ my_free(alloc, MYF(0));
+ }
+ ptr_ptr=((void **)ptr) + idx / dynarray_idxes_in_level[i];
+ idx%= dynarray_idxes_in_level[i];
+ }
+ }
+ if (!ptr_ptr)
+ ptr_ptr=&array->level[0];
+ ptr=*ptr_ptr;
+ if (!ptr)
+ {
+ void *alloc, *data;
+ alloc=my_malloc(LF_DYNARRAY_LEVEL_LENGTH * array->size_of_element +
+ max(array->size_of_element, sizeof(void *)),
+ MYF(MY_WME|MY_ZEROFILL));
+ if (!alloc)
+ return(NULL);
+ /* reserve the space for free() address */
+ data= alloc + sizeof(void *);
+ { /* alignment */
+ intptr mod= ((intptr)data) % array->size_of_element;
+ if (mod)
+ data+= array->size_of_element - mod;
+ }
+ ((void **)data)[-1]=alloc; /* free() will need the original pointer */
+ if (my_atomic_casptr(ptr_ptr, &ptr, data))
+ ptr= data;
+ else
+ my_free(alloc, MYF(0));
+ }
+ return ptr + array->size_of_element * idx;
+}
+
+void *_lf_dynarray_value(LF_DYNARRAY *array, uint idx)
+{
+ void * ptr, * volatile * ptr_ptr=0;
+ int i;
+
+ for (i=3; i > 0; i--)
+ {
+ if (ptr_ptr || idx >= dynarray_idxes_in_level[i])
+ {
+ if (!ptr_ptr)
+ {
+ ptr_ptr=&array->level[i];
+ idx-= dynarray_idxes_in_level[i];
+ }
+ ptr=*ptr_ptr;
+ if (!ptr)
+ return(NULL);
+ ptr_ptr=((void **)ptr) + idx / dynarray_idxes_in_level[i];
+ idx %= dynarray_idxes_in_level[i];
+ }
+ }
+ if (!ptr_ptr)
+ ptr_ptr=&array->level[0];
+ ptr=*ptr_ptr;
+ if (!ptr)
+ return(NULL);
+ return ptr + array->size_of_element * idx;
+}
+
+static int recursive_iterate(LF_DYNARRAY *array, void *ptr, int level,
+ lf_dynarray_func func, void *arg)
+{
+ int res, i;
+ if (!ptr)
+ return 0;
+ if (!level)
+ return func(ptr, arg);
+ for (i=0; i < LF_DYNARRAY_LEVEL_LENGTH; i++)
+ if ((res=recursive_iterate(array, ((void **)ptr)[i], level-1, func, arg)))
+ return res;
+ return 0;
+}
+
+int _lf_dynarray_iterate(LF_DYNARRAY *array, lf_dynarray_func func, void *arg)
+{
+ int i, res;
+ for (i=0; i < LF_DYNARRAY_LEVELS; i++)
+ if ((res=recursive_iterate(array, array->level[i], i, func, arg)))
+ return res;
+ return 0;
+}
+