diff options
author | unknown <serg@janus.mylan> | 2006-08-17 15:20:58 +0200 |
---|---|---|
committer | unknown <serg@janus.mylan> | 2006-08-17 15:20:58 +0200 |
commit | 74d050d000ff9db79e36931988386fe7988f8dd2 (patch) | |
tree | c1314972c00652cda1f4feaca6bee4aeaf330fb7 | |
parent | d1a8a2c7345847fc750c2d36908913dedb052c9c (diff) | |
download | mariadb-git-74d050d000ff9db79e36931988386fe7988f8dd2.tar.gz |
maria transaction manager with unit tests
include/lf.h:
few lf API changes
mysys/lf_alloc-pin.c:
few lf API changes
mysys/lf_dynarray.c:
few lf API changes
mysys/lf_hash.c:
few lf API changes
storage/maria/Makefile.am:
transaction manager
unittest/Makefile.am:
maria transaction manager
unittest/mysys/my_atomic-t.c:
ensure that values are positive
storage/maria/trxman.h:
New BitKeeper file ``storage/maria/trxman.h''
unittest/maria/Makefile.am:
New BitKeeper file ``unittest/maria/Makefile.am''
unittest/maria/trxman-t.c:
New BitKeeper file ``unittest/maria/trxman-t.c''
storage/maria/trxman.c:
comment clarified
-rw-r--r-- | configure.in | 2 | ||||
-rw-r--r-- | include/lf.h | 16 | ||||
-rw-r--r-- | mysys/lf_alloc-pin.c | 8 | ||||
-rw-r--r-- | mysys/lf_dynarray.c | 2 | ||||
-rw-r--r-- | mysys/lf_hash.c | 78 | ||||
-rw-r--r-- | storage/maria/Makefile.am | 6 | ||||
-rw-r--r-- | storage/maria/trxman.c | 261 | ||||
-rw-r--r-- | storage/maria/trxman.h | 28 | ||||
-rw-r--r-- | unittest/Makefile.am | 4 | ||||
-rw-r--r-- | unittest/maria/Makefile.am | 12 | ||||
-rw-r--r-- | unittest/maria/trxman-t.c | 138 | ||||
-rw-r--r-- | unittest/mysys/my_atomic-t.c | 17 |
12 files changed, 495 insertions, 77 deletions
diff --git a/configure.in b/configure.in index e984f1524da..d518760ca74 100644 --- a/configure.in +++ b/configure.in @@ -2537,7 +2537,7 @@ AC_SUBST(MAKE_BINARY_DISTRIBUTION_OPTIONS) # Output results AC_CONFIG_FILES(Makefile extra/Makefile mysys/Makefile dnl unittest/Makefile unittest/mytap/Makefile unittest/mytap/t/Makefile dnl - unittest/mysys/Makefile unittest/examples/Makefile dnl + unittest/mysys/Makefile unittest/examples/Makefile unittest/maria/Makefile dnl strings/Makefile regex/Makefile storage/Makefile dnl man/Makefile BUILD/Makefile vio/Makefile dnl libmysql/Makefile client/Makefile dnl diff --git a/include/lf.h b/include/lf.h index 299b4e07aa5..6a5047f6052 100644 --- a/include/lf.h +++ b/include/lf.h @@ -66,7 +66,7 @@ typedef struct { typedef int (*lf_dynarray_func)(void *, void *); void lf_dynarray_init(LF_DYNARRAY *array, uint element_size); -void lf_dynarray_end(LF_DYNARRAY *array); +void lf_dynarray_destroy(LF_DYNARRAY *array); nolock_wrap(lf_dynarray_nr, int, (LF_DYNARRAY *array, void *el), @@ -139,15 +139,15 @@ typedef struct { #define _lf_unpin(PINS, PIN) _lf_pin(PINS, PIN, NULL) #define lf_pin(PINS, PIN, ADDR) \ do { \ - lf_lock_pins(PINS); \ + lf_lock_by_pins(PINS); \ _lf_pin(PINS, PIN, ADDR); \ - lf_unlock_pins(PINS); \ + lf_unlock_by_pins(PINS); \ } while (0) #define lf_unpin(PINS, PIN) lf_pin(PINS, PIN, NULL) void lf_pinbox_init(LF_PINBOX *pinbox, lf_pinbox_free_func *free_func, void * free_func_arg); -void lf_pinbox_end(LF_PINBOX *pinbox); +void lf_pinbox_destroy(LF_PINBOX *pinbox); lock_wrap(lf_pinbox_get_pins, LF_PINS *, (LF_PINBOX *pinbox), @@ -180,7 +180,7 @@ typedef struct st_lf_allocator { } LF_ALLOCATOR; void lf_alloc_init(LF_ALLOCATOR *allocator, uint size); -void lf_alloc_end(LF_ALLOCATOR *allocator); +void lf_alloc_destroy(LF_ALLOCATOR *allocator); uint lf_alloc_in_pool(LF_ALLOCATOR *allocator); #define _lf_alloc_free(PINS, PTR) _lf_pinbox_free((PINS), (PTR)) #define lf_alloc_free(PINS, PTR) lf_pinbox_free((PINS), (PTR)) @@ -216,10 +216,10 @@ typedef struct { void lf_hash_init(LF_HASH *hash, uint element_size, uint flags, uint key_offset, uint key_length, hash_get_key get_key, CHARSET_INFO *charset); -void lf_hash_end(LF_HASH *hash); +void lf_hash_destroy(LF_HASH *hash); int lf_hash_insert(LF_HASH *hash, LF_PINS *pins, const void *data); -int lf_hash_search(LF_HASH *hash, LF_PINS *pins, const uchar *key, uint keylen); -int lf_hash_delete(LF_HASH *hash, LF_PINS *pins, const uchar *key, uint keylen); +void *lf_hash_search(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen); +int lf_hash_delete(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen); #define _lf_hash_get_pins(HASH) _lf_alloc_get_pins(&(HASH)->alloc) #define lf_hash_get_pins(HASH) lf_alloc_get_pins(&(HASH)->alloc) #define _lf_hash_put_pins(PINS) _lf_pinbox_put_pins(PINS) diff --git a/mysys/lf_alloc-pin.c b/mysys/lf_alloc-pin.c index a9ea1802c03..cf1612b73d1 100644 --- a/mysys/lf_alloc-pin.c +++ b/mysys/lf_alloc-pin.c @@ -54,9 +54,9 @@ void lf_pinbox_init(LF_PINBOX *pinbox, lf_pinbox_free_func *free_func, pinbox->free_func_arg=free_func_arg; } -void lf_pinbox_end(LF_PINBOX *pinbox) +void lf_pinbox_destroy(LF_PINBOX *pinbox) { - lf_dynarray_end(&pinbox->pinstack); + lf_dynarray_destroy(&pinbox->pinstack); } LF_PINS *_lf_pinbox_get_pins(LF_PINBOX *pinbox) @@ -292,7 +292,7 @@ void lf_alloc_init(LF_ALLOCATOR *allocator, uint size) DBUG_ASSERT(size >= (int)sizeof(void *)); } -void lf_alloc_end(LF_ALLOCATOR *allocator) +void lf_alloc_destroy(LF_ALLOCATOR *allocator) { void *el=allocator->top; while (el) @@ -301,7 +301,7 @@ void lf_alloc_end(LF_ALLOCATOR *allocator) my_free(el, MYF(0)); el=tmp; } - lf_pinbox_end(&allocator->pinbox); + lf_pinbox_destroy(&allocator->pinbox); allocator->top=0; } diff --git a/mysys/lf_dynarray.c b/mysys/lf_dynarray.c index dcf99163ca1..0fa04ab095c 100644 --- a/mysys/lf_dynarray.c +++ b/mysys/lf_dynarray.c @@ -57,7 +57,7 @@ static void recursive_free(void **alloc, int level) my_free(alloc[-1], MYF(0)); } -void lf_dynarray_end(LF_DYNARRAY *array) +void lf_dynarray_destroy(LF_DYNARRAY *array) { int i; for (i=0; i < LF_DYNARRAY_LEVELS; i++) diff --git a/mysys/lf_hash.c b/mysys/lf_hash.c index 6d3d30ebc3f..57936ea7b1f 100644 --- a/mysys/lf_hash.c +++ b/mysys/lf_hash.c @@ -228,14 +228,14 @@ void lf_hash_init(LF_HASH *hash, uint element_size, uint flags, hash->count=0; hash->element_size=element_size; hash->flags=flags; - hash->charset=charset; + hash->charset=charset ? charset : &my_charset_bin; hash->key_offset=key_offset; hash->key_length=key_length; hash->get_key=get_key; DBUG_ASSERT(get_key ? !key_offset && !key_length : key_length); } -void lf_hash_end(LF_HASH *hash) +void lf_hash_destroy(LF_HASH *hash) { LF_SLIST *el=*(LF_SLIST **)_lf_dynarray_lvalue(&hash->array, 0); while (el) @@ -244,109 +244,89 @@ void lf_hash_end(LF_HASH *hash) lf_alloc_real_free(&hash->alloc, el); el=(LF_SLIST *)next; } - lf_alloc_end(&hash->alloc); - lf_dynarray_end(&hash->array); + lf_alloc_destroy(&hash->alloc); + lf_dynarray_destroy(&hash->array); } /* + RETURN + 0 - inserted + 1 - didn't (unique key conflict) NOTE - see linsert() for pin usage + see linsert() for pin usage notes */ int lf_hash_insert(LF_HASH *hash, LF_PINS *pins, const void *data) { - uint csize, bucket, hashnr, keylen; + uint csize, bucket, hashnr; LF_SLIST *node, * volatile *el; - const uchar *key; - key= hash_key(hash, data, &keylen); - hashnr= calc_hash(hash, key, keylen); - bucket= hashnr % hash->size; lf_lock_by_pins(pins); node=(LF_SLIST *)_lf_alloc_new(pins); memcpy(node+1, data, hash->element_size); + node->key= hash_key(hash, node+1, &node->keylen); + hashnr= calc_hash(hash, node->key, node->keylen); + bucket= hashnr % hash->size; el=_lf_dynarray_lvalue(&hash->array, bucket); if (*el == NULL) initialize_bucket(hash, el, bucket, pins); node->hashnr=my_reverse_bits(hashnr) | 1; - node->key=((char *)(node+1))+(key-(uchar *)data); - node->keylen=keylen; if (linsert(el, node, pins, hash->flags)) { _lf_alloc_free(pins, node); lf_unlock_by_pins(pins); - return 0; + return 1; } csize= hash->size; if ((my_atomic_add32(&hash->count, 1)+1.0) / csize > MAX_LOAD) my_atomic_cas32(&hash->size, &csize, csize*2); -#if 0 - node=*(LF_SLIST **)_lf_dynarray_lvalue(&hash->array, 0); - hashnr=0; - while (node) - { - assert (node->hashnr >= hashnr); - hashnr=node->hashnr; - node=(LF_SLIST *)node->link; - } -#endif lf_unlock_by_pins(pins); - return 1; + return 0; } /* + RETURN + 0 - deleted + 1 - didn't (not found) NOTE - see ldelete() for pin usage + see ldelete() for pin usage notes */ -int lf_hash_delete(LF_HASH *hash, LF_PINS *pins, const uchar *key, uint keylen) +int lf_hash_delete(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen) { LF_SLIST * volatile *el; - uint bucket, hashnr=calc_hash(hash, key, keylen); + uint bucket, hashnr=calc_hash(hash, (uchar *)key, keylen); bucket= hashnr % hash->size; lf_lock_by_pins(pins); el=_lf_dynarray_lvalue(&hash->array, bucket); if (*el == NULL) initialize_bucket(hash, el, bucket, pins); - if (ldelete(el, my_reverse_bits(hashnr) | 1, key, keylen, pins)) + if (ldelete(el, my_reverse_bits(hashnr) | 1, (uchar *)key, keylen, pins)) { lf_unlock_by_pins(pins); - return 0; + return 1; } my_atomic_add32(&hash->count, -1); -#if 0 - { - LF_SLIST *node=*(LF_SLIST **)_lf_dynarray_lvalue(&hash->array, 0); - hashnr=0; - while (node) - { - assert (node->hashnr >= hashnr); - hashnr=node->hashnr; - node=(LF_SLIST *)node->link; - } - } -#endif lf_unlock_by_pins(pins); - return 1; + return 0; } /* NOTE - see lsearch() for pin usage + see lsearch() for pin usage notes */ -int lf_hash_search(LF_HASH *hash, LF_PINS *pins, const uchar *key, uint keylen) +void *lf_hash_search(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen) { - int res; - LF_SLIST * volatile *el; - uint bucket, hashnr=calc_hash(hash, key, keylen); + LF_SLIST * volatile *el, *found; + uint bucket, hashnr=calc_hash(hash, (uchar *)key, keylen); bucket= hashnr % hash->size; lf_lock_by_pins(pins); el=_lf_dynarray_lvalue(&hash->array, bucket); if (*el == NULL) initialize_bucket(hash, el, bucket, pins); - res=NULL != lsearch(el, my_reverse_bits(hashnr) | 1, key, keylen, pins); + found= lsearch(el, my_reverse_bits(hashnr) | 1, (uchar *)key, keylen, pins); lf_unlock_by_pins(pins); - return res; + return found+1; } static void initialize_bucket(LF_HASH *hash, LF_SLIST * volatile *node, diff --git a/storage/maria/Makefile.am b/storage/maria/Makefile.am index d4315b4d446..cacfa5dbcdc 100644 --- a/storage/maria/Makefile.am +++ b/storage/maria/Makefile.am @@ -28,7 +28,9 @@ bin_PROGRAMS = maria_chk maria_pack maria_ftdump maria_chk_DEPENDENCIES= $(LIBRARIES) maria_pack_DEPENDENCIES=$(LIBRARIES) noinst_PROGRAMS = ma_test1 ma_test2 ma_test3 ma_rt_test ma_sp_test -noinst_HEADERS = maria_def.h ma_rt_index.h ma_rt_key.h ma_rt_mbr.h ma_sp_defs.h ma_fulltext.h ma_ftdefs.h ma_ft_test1.h ma_ft_eval.h +noinst_HEADERS = maria_def.h ma_rt_index.h ma_rt_key.h ma_rt_mbr.h \ + ma_sp_defs.h ma_fulltext.h ma_ftdefs.h ma_ft_test1.h \ + ma_ft_eval.h trxman.h ma_test1_DEPENDENCIES= $(LIBRARIES) ma_test2_DEPENDENCIES= $(LIBRARIES) ma_test3_DEPENDENCIES= $(LIBRARIES) @@ -53,7 +55,7 @@ libmaria_a_SOURCES = ma_init.c ma_open.c ma_extra.c ma_info.c ma_rkey.c \ ma_ft_update.c ma_ft_boolean_search.c \ ma_ft_nlq_search.c ft_maria.c ma_sort.c \ ma_rt_index.c ma_rt_key.c ma_rt_mbr.c ma_rt_split.c \ - ma_sp_key.c + ma_sp_key.c trxman.c CLEANFILES = test?.MA? FT?.MA? isam.log ma_test_all ma_rt_test.MA? sp_test.MA? DEFS = diff --git a/storage/maria/trxman.c b/storage/maria/trxman.c new file mode 100644 index 00000000000..3c64d93183a --- /dev/null +++ b/storage/maria/trxman.c @@ -0,0 +1,261 @@ + +#include <my_global.h> +#include <my_sys.h> +#include <lf.h> +#include "trxman.h" + +TRX active_list_min, active_list_max, + committed_list_min, committed_list_max, *pool; + +pthread_mutex_t LOCK_trx_list; +uint active_transactions; +TrID global_trid_generator; + +TRX **short_id_to_trx; +my_atomic_rwlock_t LOCK_short_id_to_trx; + +LF_HASH trid_to_trx; + +static byte *trx_get_hash_key(const byte *trx,uint* len, my_bool unused) +{ + *len= sizeof(TrID); + return (byte *) & ((*((TRX **)trx))->trid); +} + +int trxman_init() +{ + pthread_mutex_init(&LOCK_trx_list, MY_MUTEX_INIT_FAST); + active_list_max.trid= active_list_min.trid= 0; + active_list_max.min_read_from=~0; + active_list_max.next= active_list_min.prev= 0; + active_list_max.prev= &active_list_min; + active_list_min.next= &active_list_max; + active_transactions= 0; + + committed_list_max.commit_trid= ~0; + committed_list_max.next= committed_list_min.prev= 0; + committed_list_max.prev= &committed_list_min; + committed_list_min.next= &committed_list_max; + + pool=0; + global_trid_generator=0; /* set later by recovery code */ + lf_hash_init(&trid_to_trx, sizeof(TRX*), LF_HASH_UNIQUE, + 0, 0, trx_get_hash_key, 0); + my_atomic_rwlock_init(&LOCK_short_id_to_trx); + short_id_to_trx=(TRX **)my_malloc(SHORT_ID_MAX*sizeof(TRX*), + MYF(MY_WME|MY_ZEROFILL)); + if (!short_id_to_trx) + return 1; + short_id_to_trx--; /* min short_id is 1 */ + + return 0; +} + +int trxman_destroy() +{ + DBUG_ASSERT(trid_to_trx.count == 0); + DBUG_ASSERT(active_transactions == 0); + DBUG_ASSERT(active_list_max.prev == &active_list_min); + DBUG_ASSERT(active_list_min.next == &active_list_max); + DBUG_ASSERT(committed_list_max.prev == &committed_list_min); + DBUG_ASSERT(committed_list_min.next == &committed_list_max); + while (pool) + { + TRX *tmp=pool->next; + my_free(pool, MYF(0)); + pool=tmp; + } + lf_hash_destroy(&trid_to_trx); + pthread_mutex_destroy(&LOCK_trx_list); + my_atomic_rwlock_destroy(&LOCK_short_id_to_trx); + my_free((void *)(short_id_to_trx+1), MYF(0)); +} + +static TrID new_trid() +{ + DBUG_ASSERT(global_trid_generator < 0xffffffffffffLL); + safe_mutex_assert_owner(&LOCK_trx_list); + return ++global_trid_generator; +} + +static void set_short_id(TRX *trx) +{ + int i= (global_trid_generator + (intptr)trx) * 312089 % SHORT_ID_MAX; + my_atomic_rwlock_wrlock(&LOCK_short_id_to_trx); + for ( ; ; i= i % SHORT_ID_MAX + 1) /* the range is [1..SHORT_ID_MAX] */ + { + void *tmp=NULL; + if (short_id_to_trx[i] == NULL && + my_atomic_casptr((void **)&short_id_to_trx[i], &tmp, trx)) + break; + } + my_atomic_rwlock_wrunlock(&LOCK_short_id_to_trx); + trx->short_id= i; +} + +extern int global_malloc; +TRX *trxman_new_trx() +{ + TRX *trx; + + my_atomic_add32(&active_transactions, 1); + + /* + we need a mutex here to ensure that + transactions in the active list are ordered by the trid. + So, incrementing global_trid_generator and + adding to the list must be atomic. + + and as we have a mutex, we can as well do everything + under it - allocating a TRX, incrementing active_transactions, + setting trx->min_read_from. + + Note that all the above is fast. generating short_id may be slow, + as it involves scanning a big array - so it's still done + outside of the mutex. + */ + + pthread_mutex_lock(&LOCK_trx_list); + trx=pool; + while (trx && !my_atomic_casptr((void **)&pool, (void **)&trx, trx->next)) + /* no-op */; + + if (!trx) + { + trx=(TRX *)my_malloc(sizeof(TRX), MYF(MY_WME)); + global_malloc++; + } + if (!trx) + return 0; + + trx->min_read_from= active_list_min.next->trid; + + trx->trid= new_trid(); + trx->short_id= 0; + + trx->next= &active_list_max; + trx->prev= active_list_max.prev; + active_list_max.prev= trx->prev->next= trx; + pthread_mutex_unlock(&LOCK_trx_list); + + trx->pins=lf_hash_get_pins(&trid_to_trx); + + if (!trx->min_read_from) + trx->min_read_from= trx->trid; + + trx->commit_trid=0; + + set_short_id(trx); /* this must be the last! */ + + + return trx; +} + +/* + remove a trx from the active list, + move to committed list, + set commit_trid + + TODO + integrate with lock manager, log manager. That means: + a common "commit" mutex - forcing the log and setting commit_trid + must be done atomically (QQ how the heck it could be done with + group commit ???) + + trid_to_trx, active_list_*, and committed_list_* can be + updated asyncronously. +*/ +void trxman_end_trx(TRX *trx, my_bool commit) +{ + int res; + TRX *free_me= 0; + LF_PINS *pins= trx->pins; + + pthread_mutex_lock(&LOCK_trx_list); + trx->next->prev= trx->prev; + trx->prev->next= trx->next; + + if (trx->prev == &active_list_min) + { + TRX *t; + for (t= committed_list_min.next; + t->commit_trid < active_list_min.next->min_read_from; + t= t->next) /* no-op */; + + if (t != committed_list_min.next) + { + free_me= committed_list_min.next; + committed_list_min.next= t; + t->prev->next=0; + t->prev= &committed_list_min; + } + } + + my_atomic_rwlock_wrlock(&LOCK_short_id_to_trx); + my_atomic_storeptr((void **)&short_id_to_trx[trx->short_id], 0); + my_atomic_rwlock_wrunlock(&LOCK_short_id_to_trx); + + if (commit && active_list_min.next != &active_list_max) + { + trx->commit_trid= global_trid_generator; + + trx->next= &committed_list_max; + trx->prev= committed_list_max.prev; + committed_list_max.prev= trx->prev->next= trx; + + res= lf_hash_insert(&trid_to_trx, pins, &trx); + DBUG_ASSERT(res == 0); + } + else + { + trx->next=free_me; + free_me=trx; + } + pthread_mutex_unlock(&LOCK_trx_list); + + my_atomic_add32(&active_transactions, -1); + + while (free_me) + { + int res; + TRX *t= free_me; + free_me= free_me->next; + + res= lf_hash_delete(&trid_to_trx, pins, &t->trid, sizeof(TrID)); + + trxman_free_trx(t); + } + + lf_hash_put_pins(pins); +} + +/* free a trx (add to the pool, that is */ +void trxman_free_trx(TRX *trx) +{ + TRX *tmp=pool; + + do + { + trx->next=tmp; + } while (!my_atomic_casptr((void **)&pool, (void **)&tmp, trx)); +} + +my_bool trx_can_read_from(TRX *trx, TrID trid) +{ + TRX *found; + my_bool can; + + if (trid < trx->min_read_from) + return TRUE; + if (trid > trx->trid) + return FALSE; + + found= lf_hash_search(&trid_to_trx, trx->pins, &trid, sizeof(trid)); + if (!found) + return FALSE; /* not in the hash = cannot read */ + + can= found->commit_trid < trx->trid; + lf_unpin(trx->pins, 2); + return can; +} + diff --git a/storage/maria/trxman.h b/storage/maria/trxman.h new file mode 100644 index 00000000000..ae794470a47 --- /dev/null +++ b/storage/maria/trxman.h @@ -0,0 +1,28 @@ + +typedef uint64 TrID; /* our TrID is 6 bytes */ + +typedef struct st_transaction +{ + TrID trid, min_read_from, commit_trid; + struct st_transaction *next, *prev; + /* Note! if short_id is 0, trx is NOT initialized */ + uint16 short_id; + LF_PINS *pins; +} TRX; + +#define SHORT_ID_MAX 65535 + +extern uint active_transactions; + +extern TRX **short_id_to_trx; +extern my_atomic_rwlock_t LOCK_short_id_to_trx; + +int trxman_init(); +int trxman_end(); +TRX *trxman_new_trx(); +void trxman_end_trx(TRX *trx, my_bool commit); +#define trxman_commit_trx(T) trxman_end_trx(T, TRUE) +#define trxman_abort_trx(T) trxman_end_trx(T, FALSE) +void trxman_free_trx(TRX *trx); +my_bool trx_can_read_from(TRX *trx, TrID trid); + diff --git a/unittest/Makefile.am b/unittest/Makefile.am index ca3291efde0..295ecd7186f 100644 --- a/unittest/Makefile.am +++ b/unittest/Makefile.am @@ -1,10 +1,10 @@ -SUBDIRS = mytap . mysys examples +SUBDIRS = mytap mysys maria examples noinst_SCRIPTS = unit EXTRA_DIST = unit.pl CLEANFILES = unit -unittests = mytap mysys +unittests = mytap mysys maria test: unit ./unit run $(unittests) diff --git a/unittest/maria/Makefile.am b/unittest/maria/Makefile.am new file mode 100644 index 00000000000..667d1e09a07 --- /dev/null +++ b/unittest/maria/Makefile.am @@ -0,0 +1,12 @@ + +AM_CPPFLAGS = @ZLIB_INCLUDES@ -I$(top_builddir)/include +AM_CPPFLAGS += -I$(top_srcdir)/include -I$(top_srcdir)/unittest/mytap + +LDADD = $(top_builddir)/unittest/mytap/libmytap.a \ + $(top_builddir)/storage/maria/libmaria.a \ + $(top_builddir)/mysys/libmysys.a \ + $(top_builddir)/dbug/libdbug.a \ + $(top_builddir)/strings/libmystrings.a + +noinst_PROGRAMS = trxman-t + diff --git a/unittest/maria/trxman-t.c b/unittest/maria/trxman-t.c new file mode 100644 index 00000000000..a29bf5abc8e --- /dev/null +++ b/unittest/maria/trxman-t.c @@ -0,0 +1,138 @@ +/* Copyright (C) 2006 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 */ + +#include <tap.h> + +#include <my_global.h> +#include <my_sys.h> +#include <my_atomic.h> +#include <lf.h> +#include "../../storage/maria/trxman.h" + +pthread_attr_t rt_attr; +pthread_mutex_t rt_mutex; +pthread_cond_t rt_cond; +int rt_num_threads; + +int litmus; + +/* template for a test: the goal is to have litmus==0 if the test passed + +#define ITER nnn +pthread_handler_t test_XXXXXXXX(void *arg) +{ + int m=(*(int *)arg)/ITER, x; + + for (x=((int)(intptr)(&m)); m ; m--) + { + // do something with litmus + } + // do something more with litmus + + pthread_mutex_lock(&rt_mutex); + rt_num_threads--; + if (!rt_num_threads) + { + diag("whatever diagnostics we want", blabla, foobar); + pthread_cond_signal(&rt_cond); + } + pthread_mutex_unlock(&rt_mutex); + return 0; +} +#undef ITER + +*/ + +/* + create and end (commit or rollback) transactions randomly +*/ +#define MAX_ITER 100 +pthread_handler_t test_trxman(void *arg) +{ + int m=(*(int *)arg); + uint x, y, i, j, n; + TRX *trx[MAX_ITER]; + + for (x=((int)(intptr)(&m)); m > 0; ) + { + y= x= (x*3628273133 + 1500450271) % 9576890767; /* three prime numbers */ + m-= n= x % MAX_ITER; + for (i=0; i < n; i++) + trx[i]=trxman_new_trx(); + for (i=0; i < n; i++) + { + y=(y*19 + 7) % 31; + trxman_end_trx(trx[i], y & 1); + } + } + + pthread_mutex_lock(&rt_mutex); + rt_num_threads--; + if (!rt_num_threads) + pthread_cond_signal(&rt_cond); + pthread_mutex_unlock(&rt_mutex); + return 0; +} +#undef MAX_ITER + +void run_test(const char *test, pthread_handler handler, int n, int m) +{ + pthread_t t; + ulonglong now=my_getsystime(); + + litmus= 0; + + diag("Testing %s with %d threads, %d iterations... ", test, n, m); + for (rt_num_threads=n ; n ; n--) + pthread_create(&t, &rt_attr, handler, &m); + pthread_mutex_lock(&rt_mutex); + while (rt_num_threads) + pthread_cond_wait(&rt_cond, &rt_mutex); + pthread_mutex_unlock(&rt_mutex); + now=my_getsystime()-now; + ok(litmus == 0, "tested %s in %g secs (%d)", test, ((double)now)/1e7, litmus); +} + +int global_malloc=0; +int main() +{ + plan(1); + + if (my_atomic_initialize()) + return exit_status(); + + my_init(); + + pthread_attr_init(&rt_attr); + pthread_attr_setdetachstate(&rt_attr,PTHREAD_CREATE_DETACHED); + pthread_mutex_init(&rt_mutex, 0); + pthread_cond_init(&rt_cond, 0); + +#define CYCLES 10000 +#define THREADS 10 + + trxman_init(); + run_test("trxman", test_trxman, THREADS,CYCLES); + trxman_destroy(); + diag("mallocs: %d\n", global_malloc); + + pthread_mutex_destroy(&rt_mutex); + pthread_cond_destroy(&rt_cond); + pthread_attr_destroy(&rt_attr); + my_end(0); + return exit_status(); +} + diff --git a/unittest/mysys/my_atomic-t.c b/unittest/mysys/my_atomic-t.c index 1e7206441eb..8962131d45a 100644 --- a/unittest/mysys/my_atomic-t.c +++ b/unittest/mysys/my_atomic-t.c @@ -14,9 +14,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -//#define MY_ATOMIC_MODE_RWLOCKS -//#define MY_ATOMIC_MODE_DUMMY - #include <tap.h> #include <my_global.h> @@ -41,7 +38,7 @@ pthread_handler_t test_atomic_add_handler(void *arg) int32 x; for (x=((int)(intptr)(&m)); m ; m--) { - x=x*m+0x87654321; + x=(x*m+0x87654321) & INT_MAX32; my_atomic_rwlock_wrlock(&rwl); my_atomic_add32(&a32, x); my_atomic_rwlock_wrunlock(&rwl); @@ -111,7 +108,7 @@ pthread_handler_t test_atomic_cas_handler(void *arg) my_atomic_rwlock_wrlock(&rwl); y=my_atomic_load32(&a32); my_atomic_rwlock_wrunlock(&rwl); - x=x*m+0x87654321; + x=(x*m+0x87654321) & INT_MAX32; do { my_atomic_rwlock_wrlock(&rwl); ok=my_atomic_cas32(&a32, &y, y+x); @@ -171,7 +168,7 @@ pthread_handler_t test_lf_alloc(void *arg) for (x=((int)(intptr)(&m)); m ; m--) { TLA *node1, *node2; - x=x*m+0x87654321; + x=(x*m+0x87654321) & INT_MAX32; node1=(TLA *)lf_alloc_new(pins); node1->data=x; y+=node1->data; @@ -217,7 +214,7 @@ pthread_handler_t test_lf_hash(void *arg) y=x; for (i=0; i < N_TLH; i++) { - x=x*(m+i)+0x87654321; + x=(x*(m+i)+0x87654321) & INT_MAX32; z=(x<0) ? -x : x; if (lf_hash_insert(&lf_hash, pins, &z)) { @@ -227,7 +224,7 @@ pthread_handler_t test_lf_hash(void *arg) } for (i=0; i < N_TLH; i++) { - y=y*(m+i)+0x87654321; + y=(y*(m+i)+0x87654321) & INT_MAX32; z=(y<0) ? -y : y; if (lf_hash_delete(&lf_hash, pins, (uchar *)&z, sizeof(z))) sum-=z; @@ -307,8 +304,8 @@ int main() test_atomic("lf_alloc", test_lf_alloc, THREADS,CYCLES); test_atomic("lf_hash", test_lf_hash, THREADS,CYCLES); - lf_hash_end(&lf_hash); - lf_alloc_end(&lf_allocator); + lf_hash_destroy(&lf_hash); + lf_alloc_destroy(&lf_allocator); pthread_mutex_destroy(&mutex); pthread_cond_destroy(&cond); pthread_attr_destroy(&thr_attr); |