Commit aea73116 authored by unknown's avatar unknown

post-review fixes (style)


include/lf.h:
  comments
parent 12a55aea
/* Copyright (C) 2006 MySQL AB
/* This program is free software; you can redistribute it and/or modify
TODO it under the terms of the GNU General Public License as published by
1. copyright the Free Software Foundation; either version 2 of the License, or
6. reduce the number of memory barriers (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 */
#ifndef _lf_h #ifndef _lf_h
#define _lf_h #define _lf_h
...@@ -11,7 +20,8 @@ ...@@ -11,7 +20,8 @@
#include <my_atomic.h> #include <my_atomic.h>
/* /*
Generic helpers Helpers to define both func() and _func(), where
func() is a _func() protected by my_atomic_rwlock_wrlock()
*/ */
#define lock_wrap(f,t,proto_args, args, lock) \ #define lock_wrap(f,t,proto_args, args, lock) \
...@@ -49,7 +59,7 @@ static inline void f proto_args \ ...@@ -49,7 +59,7 @@ static inline void f proto_args \
} }
/* /*
dynamic array wait-free dynamic array, see lf_dynarray.c
4 levels of 256 elements each mean 4311810304 elements in an array - it 4 levels of 256 elements each mean 4311810304 elements in an array - it
should be enough for a while should be enough for a while
...@@ -68,14 +78,9 @@ typedef int (*lf_dynarray_func)(void *, void *); ...@@ -68,14 +78,9 @@ typedef int (*lf_dynarray_func)(void *, void *);
void lf_dynarray_init(LF_DYNARRAY *array, uint element_size); void lf_dynarray_init(LF_DYNARRAY *array, uint element_size);
void lf_dynarray_destroy(LF_DYNARRAY *array); void lf_dynarray_destroy(LF_DYNARRAY *array);
nolock_wrap(lf_dynarray_nr, int,
(LF_DYNARRAY *array, void *el),
(array,el));
nolock_wrap(lf_dynarray_value, void *, nolock_wrap(lf_dynarray_value, void *,
(LF_DYNARRAY *array, uint idx), (LF_DYNARRAY *array, uint idx),
(array,idx)); (array,idx));
lock_wrap(lf_dynarray_lvalue, void *, lock_wrap(lf_dynarray_lvalue, void *,
(LF_DYNARRAY *array, uint idx), (LF_DYNARRAY *array, uint idx),
(array,idx), (array,idx),
...@@ -85,7 +90,7 @@ nolock_wrap(lf_dynarray_iterate, int, ...@@ -85,7 +90,7 @@ nolock_wrap(lf_dynarray_iterate, int,
(array,func,arg)); (array,func,arg));
/* /*
pin manager for memory allocator pin manager for memory allocator, lf_alloc-pin.c
*/ */
#define LF_PINBOX_PINS 4 #define LF_PINBOX_PINS 4
...@@ -102,13 +107,13 @@ typedef struct { ...@@ -102,13 +107,13 @@ typedef struct {
uint32 volatile pins_in_stack; /* number of elements in array */ uint32 volatile pins_in_stack; /* number of elements in array */
} LF_PINBOX; } LF_PINBOX;
/* we want sizeof(LF_PINS) to be 128 to avoid false sharing */
typedef struct { typedef struct {
void * volatile pin[LF_PINBOX_PINS]; void * volatile pin[LF_PINBOX_PINS];
LF_PINBOX *pinbox; LF_PINBOX *pinbox;
void *purgatory; void *purgatory;
uint32 purgatory_count; uint32 purgatory_count;
uint32 volatile link; uint32 volatile link;
/* we want sizeof(LF_PINS) to be 128 to avoid false sharing */
char pad[128-sizeof(uint32)*2 char pad[128-sizeof(uint32)*2
-sizeof(void *)*(LF_PINBOX_PINS+2)]; -sizeof(void *)*(LF_PINBOX_PINS+2)];
} LF_PINS; } LF_PINS;
...@@ -160,19 +165,13 @@ lock_wrap_void(lf_pinbox_put_pins, ...@@ -160,19 +165,13 @@ lock_wrap_void(lf_pinbox_put_pins,
(LF_PINS *pins), (LF_PINS *pins),
(pins), (pins),
&pins->pinbox->pinstack.lock); &pins->pinbox->pinstack.lock);
#if 0
lock_wrap_void(lf_pinbox_real_free,
(LF_PINS *pins),
(pins),
&pins->pinbox->pinstack.lock);
#endif
lock_wrap_void(lf_pinbox_free, lock_wrap_void(lf_pinbox_free,
(LF_PINS *pins, void *addr), (LF_PINS *pins, void *addr),
(pins,addr), (pins,addr),
&pins->pinbox->pinstack.lock); &pins->pinbox->pinstack.lock);
/* /*
memory allocator memory allocator, lf_alloc-pin.c
*/ */
typedef struct st_lf_allocator { typedef struct st_lf_allocator {
...@@ -199,7 +198,7 @@ lock_wrap(lf_alloc_new, void *, ...@@ -199,7 +198,7 @@ lock_wrap(lf_alloc_new, void *,
&pins->pinbox->pinstack.lock); &pins->pinbox->pinstack.lock);
/* /*
extendible hash extendible hash, lf_hash.c
*/ */
#include <hash.h> #include <hash.h>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
different characteristics. long lists, few distinct resources - different characteristics. long lists, few distinct resources -
slow to scan, [possibly] high retry rate slow to scan, [possibly] high retry rate
*/ */
/* Copyright (C) 2000 MySQL AB /* Copyright (C) 2006 MySQL AB
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -272,7 +272,7 @@ retry: ...@@ -272,7 +272,7 @@ retry:
_lf_unpin(pins, 3); _lf_unpin(pins, 3);
do { do {
cursor->curr= PTR(*cursor->prev); cursor->curr= PTR(*cursor->prev);
_lf_pin(pins,1,cursor->curr); _lf_pin(pins, 1, cursor->curr);
} while(*cursor->prev != (intptr)cursor->curr && LF_BACKOFF); } while(*cursor->prev != (intptr)cursor->curr && LF_BACKOFF);
for (;;) for (;;)
{ {
...@@ -507,7 +507,7 @@ static int lockdelete(LOCK * volatile *head, LOCK *node, LF_PINS *pins) ...@@ -507,7 +507,7 @@ static int lockdelete(LOCK * volatile *head, LOCK *node, LF_PINS *pins)
void lockman_init(LOCKMAN *lm, loid_to_lo_func *func, uint timeout) void lockman_init(LOCKMAN *lm, loid_to_lo_func *func, uint timeout)
{ {
lf_alloc_init(&lm->alloc,sizeof(LOCK), offsetof(LOCK,lonext)); lf_alloc_init(&lm->alloc, sizeof(LOCK), offsetof(LOCK, lonext));
lf_dynarray_init(&lm->array, sizeof(LOCK **)); lf_dynarray_init(&lm->array, sizeof(LOCK **));
lm->size= 1; lm->size= 1;
lm->count= 0; lm->count= 0;
...@@ -744,7 +744,7 @@ static char *lock2str[]= ...@@ -744,7 +744,7 @@ static char *lock2str[]=
void print_lockhash(LOCKMAN *lm) void print_lockhash(LOCKMAN *lm)
{ {
LOCK *el= *(LOCK **)_lf_dynarray_lvalue(&lm->array, 0); LOCK *el= *(LOCK **)_lf_dynarray_lvalue(&lm->array, 0);
printf("hash: size=%u count=%u\n", lm->size, lm->count); printf("hash: size:%u count:%u\n", lm->size, lm->count);
while (el) while (el)
{ {
intptr next= el->link; intptr next= el->link;
......
/* Copyright (C) 2000 MySQL AB /* Copyright (C) 2006 MySQL AB
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
......
/* Copyright (C) 2000 MySQL AB /* Copyright (C) 2006 MySQL AB
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -20,21 +20,35 @@ ...@@ -20,21 +20,35 @@
#include <lf.h> #include <lf.h>
#include "trnman.h" #include "trnman.h"
/* status variables */
uint trnman_active_transactions, trnman_allocated_transactions; uint trnman_active_transactions, trnman_allocated_transactions;
static TRN active_list_min, active_list_max, /* list of active transactions in the trid order */
committed_list_min, committed_list_max, *pool; static TRN active_list_min, active_list_max;
/* list of committed transactions in the trid order */
static TRN committed_list_min, committed_list_max;
static pthread_mutex_t LOCK_trn_list; /* a counter, used to generate transaction ids */
static TrID global_trid_generator; static TrID global_trid_generator;
static LF_HASH trid_to_trn; /* the mutex for everything above */
static LOCKMAN maria_lockman; static pthread_mutex_t LOCK_trn_list;
/* LIFO pool of unused TRN structured for reuse */
static TRN *pool;
/* a hash for committed transactions that maps trid to a TRN structure */
static LF_HASH trid_to_committed_trn;
static TRN **short_trid_to_trn; /* an array that maps short_trid of an active transaction to a TRN structure */
static TRN **short_trid_to_active_trn;
/* locks for short_trid_to_active_trn and pool */
static my_atomic_rwlock_t LOCK_short_trid_to_trn, LOCK_pool; static my_atomic_rwlock_t LOCK_short_trid_to_trn, LOCK_pool;
static byte *trn_get_hash_key(const byte *trn,uint* len, my_bool unused) static LOCKMAN maria_lockman;
static byte *trn_get_hash_key(const byte *trn, uint* len, my_bool unused)
{ {
*len= sizeof(TrID); *len= sizeof(TrID);
return (byte *) & ((*((TRN **)trn))->trid); return (byte *) & ((*((TRN **)trn))->trid);
...@@ -44,7 +58,7 @@ static LOCK_OWNER *trnman_short_trid_to_TRN(uint16 short_trid) ...@@ -44,7 +58,7 @@ static LOCK_OWNER *trnman_short_trid_to_TRN(uint16 short_trid)
{ {
TRN *trn; TRN *trn;
my_atomic_rwlock_rdlock(&LOCK_short_trid_to_trn); my_atomic_rwlock_rdlock(&LOCK_short_trid_to_trn);
trn= my_atomic_loadptr((void **)&short_trid_to_trn[short_trid]); trn= my_atomic_loadptr((void **)&short_trid_to_active_trn[short_trid]);
my_atomic_rwlock_rdunlock(&LOCK_short_trid_to_trn); my_atomic_rwlock_rdunlock(&LOCK_short_trid_to_trn);
return (LOCK_OWNER *)trn; return (LOCK_OWNER *)trn;
} }
...@@ -52,39 +66,56 @@ static LOCK_OWNER *trnman_short_trid_to_TRN(uint16 short_trid) ...@@ -52,39 +66,56 @@ static LOCK_OWNER *trnman_short_trid_to_TRN(uint16 short_trid)
int trnman_init() int trnman_init()
{ {
pthread_mutex_init(&LOCK_trn_list, MY_MUTEX_INIT_FAST); pthread_mutex_init(&LOCK_trn_list, MY_MUTEX_INIT_FAST);
/*
Initialize lists.
active_list_max.min_read_from must be larger than any trid,
so that when an active list is empty we would could free
all committed list.
And committed_list_max itself can not be freed so
committed_list_max.commit_trid must not be smaller that
active_list_max.min_read_from
*/
active_list_max.trid= active_list_min.trid= 0; active_list_max.trid= active_list_min.trid= 0;
active_list_max.min_read_from= ~0; active_list_max.min_read_from= ~0;
active_list_max.next= active_list_min.prev= 0; active_list_max.next= active_list_min.prev= 0;
active_list_max.prev= &active_list_min; active_list_max.prev= &active_list_min;
active_list_min.next= &active_list_max; active_list_min.next= &active_list_max;
trnman_active_transactions= 0;
trnman_allocated_transactions= 0;
committed_list_max.commit_trid= ~0; committed_list_max.commit_trid= ~0;
committed_list_max.next= committed_list_min.prev= 0; committed_list_max.next= committed_list_min.prev= 0;
committed_list_max.prev= &committed_list_min; committed_list_max.prev= &committed_list_min;
committed_list_min.next= &committed_list_max; committed_list_min.next= &committed_list_max;
trnman_active_transactions= 0;
trnman_allocated_transactions= 0;
pool= 0; pool= 0;
global_trid_generator= 0; /* set later by recovery code */ global_trid_generator= 0; /* set later by the recovery code */
lf_hash_init(&trid_to_trn, sizeof(TRN*), LF_HASH_UNIQUE, lf_hash_init(&trid_to_committed_trn, sizeof(TRN*), LF_HASH_UNIQUE,
0, 0, trn_get_hash_key, 0); 0, 0, trn_get_hash_key, 0);
my_atomic_rwlock_init(&LOCK_short_trid_to_trn); my_atomic_rwlock_init(&LOCK_short_trid_to_trn);
my_atomic_rwlock_init(&LOCK_pool); my_atomic_rwlock_init(&LOCK_pool);
short_trid_to_trn= (TRN **)my_malloc(SHORT_TRID_MAX*sizeof(TRN*), short_trid_to_active_trn= (TRN **)my_malloc(SHORT_TRID_MAX*sizeof(TRN*),
MYF(MY_WME|MY_ZEROFILL)); MYF(MY_WME|MY_ZEROFILL));
if (!short_trid_to_trn) if (!short_trid_to_active_trn)
return 1; return 1;
short_trid_to_trn--; /* min short_trid is 1 */ short_trid_to_active_trn--; /* min short_trid is 1 */
lockman_init(&maria_lockman, &trnman_short_trid_to_TRN, 10000); lockman_init(&maria_lockman, &trnman_short_trid_to_TRN, 10000);
return 0; return 0;
} }
/*
NOTE
this could only be called in the "idle" state - no transaction can be
running. See asserts below.
*/
int trnman_destroy() int trnman_destroy()
{ {
DBUG_ASSERT(trid_to_trn.count == 0); DBUG_ASSERT(trid_to_committed_trn.count == 0);
DBUG_ASSERT(trnman_active_transactions == 0); DBUG_ASSERT(trnman_active_transactions == 0);
DBUG_ASSERT(active_list_max.prev == &active_list_min); DBUG_ASSERT(active_list_max.prev == &active_list_min);
DBUG_ASSERT(active_list_min.next == &active_list_max); DBUG_ASSERT(active_list_min.next == &active_list_max);
...@@ -98,14 +129,20 @@ int trnman_destroy() ...@@ -98,14 +129,20 @@ int trnman_destroy()
DBUG_ASSERT(trn->locks.cond == 0); DBUG_ASSERT(trn->locks.cond == 0);
my_free((void *)trn, MYF(0)); my_free((void *)trn, MYF(0));
} }
lf_hash_destroy(&trid_to_trn); lf_hash_destroy(&trid_to_committed_trn);
pthread_mutex_destroy(&LOCK_trn_list); pthread_mutex_destroy(&LOCK_trn_list);
my_atomic_rwlock_destroy(&LOCK_short_trid_to_trn); my_atomic_rwlock_destroy(&LOCK_short_trid_to_trn);
my_atomic_rwlock_destroy(&LOCK_pool); my_atomic_rwlock_destroy(&LOCK_pool);
my_free((void *)(short_trid_to_trn+1), MYF(0)); my_free((void *)(short_trid_to_active_trn+1), MYF(0));
lockman_destroy(&maria_lockman); lockman_destroy(&maria_lockman);
} }
/*
NOTE
TrID is limited to 6 bytes. Initial value of the generator
is set by the recovery code - being read from the last checkpoint
(or 1 on a first run).
*/
static TrID new_trid() static TrID new_trid()
{ {
DBUG_ASSERT(global_trid_generator < 0xffffffffffffLL); DBUG_ASSERT(global_trid_generator < 0xffffffffffffLL);
...@@ -120,8 +157,8 @@ static void set_short_trid(TRN *trn) ...@@ -120,8 +157,8 @@ static void set_short_trid(TRN *trn)
for ( ; ; i= i % SHORT_TRID_MAX + 1) /* the range is [1..SHORT_TRID_MAX] */ for ( ; ; i= i % SHORT_TRID_MAX + 1) /* the range is [1..SHORT_TRID_MAX] */
{ {
void *tmp= NULL; void *tmp= NULL;
if (short_trid_to_trn[i] == NULL && if (short_trid_to_active_trn[i] == NULL &&
my_atomic_casptr((void **)&short_trid_to_trn[i], &tmp, trn)) my_atomic_casptr((void **)&short_trid_to_active_trn[i], &tmp, trn))
break; break;
} }
my_atomic_rwlock_wrunlock(&LOCK_short_trid_to_trn); my_atomic_rwlock_wrunlock(&LOCK_short_trid_to_trn);
...@@ -138,38 +175,37 @@ TRN *trnman_new_trn(pthread_mutex_t *mutex, pthread_cond_t *cond) ...@@ -138,38 +175,37 @@ TRN *trnman_new_trn(pthread_mutex_t *mutex, pthread_cond_t *cond)
TRN *trn; TRN *trn;
/* /*
see trnman_end_trn to see why we need a mutex here we have a mutex, to do simple things under it - allocate a TRN,
increment trnman_active_transactions, set trn->min_read_from.
and as we have a mutex, we can as well do everything
under it - allocating a TRN, incrementing trnman_active_transactions,
setting trn->min_read_from.
Note that all the above is fast. generating short_trid may be slow, Note that all the above is fast. generating short_trid may be slow,
as it involves scanning a big array - so it's still done as it involves scanning a large array - so it's done outside of the
outside of the mutex. mutex.
*/ */
pthread_mutex_lock(&LOCK_trn_list); pthread_mutex_lock(&LOCK_trn_list);
trnman_active_transactions++;
/* Allocating a new TRN structure */
trn= pool; trn= pool;
/* popping an element from a stack */ /* Popping an unused TRN from the pool */
my_atomic_rwlock_wrlock(&LOCK_pool); my_atomic_rwlock_wrlock(&LOCK_pool);
while (trn && !my_atomic_casptr((void **)&pool, (void **)&trn, while (trn && !my_atomic_casptr((void **)&pool, (void **)&trn,
(void *)trn->next)) (void *)trn->next))
/* no-op */; /* no-op */;
my_atomic_rwlock_wrunlock(&LOCK_pool); my_atomic_rwlock_wrunlock(&LOCK_pool);
/* Nothing in the pool ? Allocate a new one */
if (!trn) if (!trn)
{ {
trn= (TRN *)my_malloc(sizeof(TRN), MYF(MY_WME)); trn= (TRN *)my_malloc(sizeof(TRN), MYF(MY_WME));
if (!trn) if (unlikely(!trn))
{ {
pthread_mutex_unlock(&LOCK_trn_list); pthread_mutex_unlock(&LOCK_trn_list);
return 0; return 0;
} }
trnman_allocated_transactions++; trnman_allocated_transactions++;
} }
trnman_active_transactions++;
trn->min_read_from= active_list_min.next->trid; trn->min_read_from= active_list_min.next->trid;
...@@ -181,36 +217,31 @@ TRN *trnman_new_trn(pthread_mutex_t *mutex, pthread_cond_t *cond) ...@@ -181,36 +217,31 @@ TRN *trnman_new_trn(pthread_mutex_t *mutex, pthread_cond_t *cond)
active_list_max.prev= trn->prev->next= trn; active_list_max.prev= trn->prev->next= trn;
pthread_mutex_unlock(&LOCK_trn_list); pthread_mutex_unlock(&LOCK_trn_list);
trn->pins= lf_hash_get_pins(&trid_to_trn); trn->pins= lf_hash_get_pins(&trid_to_committed_trn);
if (!trn->min_read_from) if (unlikely(!trn->min_read_from))
trn->min_read_from= trn->trid; trn->min_read_from= trn->trid;
trn->commit_trid= 0;
trn->locks.mutex= mutex; trn->locks.mutex= mutex;
trn->locks.cond= cond; trn->locks.cond= cond;
trn->commit_trid= 0;
trn->locks.waiting_for= 0; trn->locks.waiting_for= 0;
trn->locks.all_locks= 0; trn->locks.all_locks= 0;
trn->locks.pins= lf_alloc_get_pins(&maria_lockman.alloc); trn->locks.pins= lf_alloc_get_pins(&maria_lockman.alloc);
set_short_trid(trn); /* this must be the last! */ /*
only after the following function TRN is considered initialized,
so it must be done the last
*/
set_short_trid(trn);
return trn; return trn;
} }
/* /*
remove a trn from the active list, remove a trn from the active list.
move to committed list, if necessary - move to committed list and set commit_trid
set commit_trid
TODO
integrate with 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 ???) XXX - why did I think it must be done atomically ?
trid_to_trn, active_list_*, and committed_list_* can be
updated asyncronously.
*/ */
void trnman_end_trn(TRN *trn, my_bool commit) void trnman_end_trn(TRN *trn, my_bool commit)
{ {
...@@ -224,7 +255,11 @@ void trnman_end_trn(TRN *trn, my_bool commit) ...@@ -224,7 +255,11 @@ void trnman_end_trn(TRN *trn, my_bool commit)
trn->next->prev= trn->prev; trn->next->prev= trn->prev;
trn->prev->next= trn->next; trn->prev->next= trn->next;
/* if this transaction was the oldest - clean up committed list */ /*
if trn was the oldest active transaction, now that it goes away there
may be committed transactions in the list which no active transaction
needs to bother about - clean up the committed list
*/
if (trn->prev == &active_list_min) if (trn->prev == &active_list_min)
{ {
TRN *t; TRN *t;
...@@ -232,6 +267,7 @@ void trnman_end_trn(TRN *trn, my_bool commit) ...@@ -232,6 +267,7 @@ void trnman_end_trn(TRN *trn, my_bool commit)
t->commit_trid < active_list_min.next->min_read_from; t->commit_trid < active_list_min.next->min_read_from;
t= t->next) /* no-op */; t= t->next) /* no-op */;
/* found transactions committed before the oldest active one */
if (t != committed_list_min.next) if (t != committed_list_min.next)
{ {
free_me= committed_list_min.next; free_me= committed_list_min.next;
...@@ -241,7 +277,10 @@ void trnman_end_trn(TRN *trn, my_bool commit) ...@@ -241,7 +277,10 @@ void trnman_end_trn(TRN *trn, my_bool commit)
} }
} }
/* add transaction to the committed list (for read-from relations) */ /*
if transaction is committed and it was not the only active transaction -
add it to the committed list (which is used for read-from relation)
*/
if (commit && active_list_min.next != &active_list_max) if (commit && active_list_min.next != &active_list_max)
{ {
trn->commit_trid= global_trid_generator; trn->commit_trid= global_trid_generator;
...@@ -250,10 +289,10 @@ void trnman_end_trn(TRN *trn, my_bool commit) ...@@ -250,10 +289,10 @@ void trnman_end_trn(TRN *trn, my_bool commit)
trn->prev= committed_list_max.prev; trn->prev= committed_list_max.prev;
committed_list_max.prev= trn->prev->next= trn; committed_list_max.prev= trn->prev->next= trn;
res= lf_hash_insert(&trid_to_trn, pins, &trn); res= lf_hash_insert(&trid_to_committed_trn, pins, &trn);
DBUG_ASSERT(res == 0); DBUG_ASSERT(res == 0);
} }
else /* or free it right away */ else /* otherwise free it right away */
{ {
trn->next= free_me; trn->next= free_me;
free_me= trn; free_me= trn;
...@@ -266,7 +305,7 @@ void trnman_end_trn(TRN *trn, my_bool commit) ...@@ -266,7 +305,7 @@ void trnman_end_trn(TRN *trn, my_bool commit)
trn->locks.mutex= 0; trn->locks.mutex= 0;
trn->locks.cond= 0; trn->locks.cond= 0;
my_atomic_rwlock_rdlock(&LOCK_short_trid_to_trn); my_atomic_rwlock_rdlock(&LOCK_short_trid_to_trn);
my_atomic_storeptr((void **)&short_trid_to_trn[trn->locks.loid], 0); my_atomic_storeptr((void **)&short_trid_to_active_trn[trn->locks.loid], 0);
my_atomic_rwlock_rdunlock(&LOCK_short_trid_to_trn); my_atomic_rwlock_rdunlock(&LOCK_short_trid_to_trn);
while (free_me) // XXX send them to the purge thread while (free_me) // XXX send them to the purge thread
...@@ -275,7 +314,7 @@ void trnman_end_trn(TRN *trn, my_bool commit) ...@@ -275,7 +314,7 @@ void trnman_end_trn(TRN *trn, my_bool commit)
TRN *t= free_me; TRN *t= free_me;
free_me= free_me->next; free_me= free_me->next;
res= lf_hash_delete(&trid_to_trn, pins, &t->trid, sizeof(TrID)); res= lf_hash_delete(&trid_to_committed_trn, pins, &t->trid, sizeof(TrID));
trnman_free_trn(t); trnman_free_trn(t);
} }
...@@ -331,7 +370,7 @@ my_bool trnman_can_read_from(TRN *trn, TrID trid) ...@@ -331,7 +370,7 @@ my_bool trnman_can_read_from(TRN *trn, TrID trid)
if (trid > trn->trid) if (trid > trn->trid)
return FALSE; /* cannot read */ return FALSE; /* cannot read */
found= lf_hash_search(&trid_to_trn, trn->pins, &trid, sizeof(trid)); found= lf_hash_search(&trid_to_committed_trn, trn->pins, &trid, sizeof(trid));
if (!found) if (!found)
return FALSE; /* not in the hash of committed transactions = cannot read */ return FALSE; /* not in the hash of committed transactions = cannot read */
......
/* Copyright (C) 2000 MySQL AB /* Copyright (C) 2006 MySQL AB
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
......
...@@ -48,10 +48,14 @@ LOCK_OWNER *loid2lo(uint16 loid) ...@@ -48,10 +48,14 @@ LOCK_OWNER *loid2lo(uint16 loid)
ok(lockman_getlock(&lockman, loid2lo(O), R, L) == RES, \ ok(lockman_getlock(&lockman, loid2lo(O), R, L) == RES, \
"lo" #O "> " S " lock resource " #R " with " #L "-lock"); \ "lo" #O "> " S " lock resource " #R " with " #L "-lock"); \
print_lockhash(&lockman) print_lockhash(&lockman)
#define lock_ok_a(O,R,L) test_lock(O,R,L,"",GOT_THE_LOCK) #define lock_ok_a(O, R, L) \
#define lock_ok_i(O,R,L) test_lock(O,R,L,"",GOT_THE_LOCK_NEED_TO_LOCK_A_SUBRESOURCE) test_lock(O, R, L, "", GOT_THE_LOCK)
#define lock_ok_l(O,R,L) test_lock(O,R,L,"",GOT_THE_LOCK_NEED_TO_INSTANT_LOCK_A_SUBRESOURCE) #define lock_ok_i(O, R, L) \
#define lock_conflict(O,R,L) test_lock(O,R,L,"cannot ",DIDNT_GET_THE_LOCK); test_lock(O, R, L, "", GOT_THE_LOCK_NEED_TO_LOCK_A_SUBRESOURCE)
#define lock_ok_l(O, R, L) \
test_lock(O, R, L, "", GOT_THE_LOCK_NEED_TO_INSTANT_LOCK_A_SUBRESOURCE)
#define lock_conflict(O, R, L) \
test_lock(O, R, L, "cannot ", DIDNT_GET_THE_LOCK);
void test_lockman_simple() void test_lockman_simple()
{ {
...@@ -63,41 +67,41 @@ void test_lockman_simple() ...@@ -63,41 +67,41 @@ void test_lockman_simple()
lock_ok_a(1, 1, X); lock_ok_a(1, 1, X);
lock_ok_i(2, 2, IX); lock_ok_i(2, 2, IX);
/* failures */ /* failures */
lock_conflict(2,1,X); lock_conflict(2, 1, X);
unlock_all(2); unlock_all(2);
lock_ok_a(1,2,S); lock_ok_a(1, 2, S);
lock_ok_a(1,2,IS); lock_ok_a(1, 2, IS);
lock_ok_a(1,2,LS); lock_ok_a(1, 2, LS);
lock_ok_i(1,3,IX); lock_ok_i(1, 3, IX);
lock_ok_a(2,3,LS); lock_ok_a(2, 3, LS);
lock_ok_i(1,3,IX); lock_ok_i(1, 3, IX);
lock_ok_l(2,3,IS); lock_ok_l(2, 3, IS);
unlock_all(1); unlock_all(1);
unlock_all(2); unlock_all(2);
lock_ok_i(1,1,IX); lock_ok_i(1, 1, IX);
lock_conflict(2,1,S); lock_conflict(2, 1, S);
lock_ok_a(1,1,LS); lock_ok_a(1, 1, LS);
unlock_all(1); unlock_all(1);
unlock_all(2); unlock_all(2);
lock_ok_i(1,1,IX); lock_ok_i(1, 1, IX);
lock_ok_a(2,1,LS); lock_ok_a(2, 1, LS);
lock_ok_a(1,1,LS); lock_ok_a(1, 1, LS);
lock_ok_i(1,1,IX); lock_ok_i(1, 1, IX);
lock_ok_i(3,1,IS); lock_ok_i(3, 1, IS);
unlock_all(1); unlock_all(1);
unlock_all(2); unlock_all(2);
unlock_all(3); unlock_all(3);
lock_ok_i(1,4,IS); lock_ok_i(1, 4, IS);
lock_ok_i(2,4,IS); lock_ok_i(2, 4, IS);
lock_ok_i(3,4,IS); lock_ok_i(3, 4, IS);
lock_ok_a(3,4,LS); lock_ok_a(3, 4, LS);
lock_ok_i(4,4,IS); lock_ok_i(4, 4, IS);
lock_conflict(4,4,IX); lock_conflict(4, 4, IX);
lock_conflict(2,4,IX); lock_conflict(2, 4, IX);
lock_ok_a(1,4,LS); lock_ok_a(1, 4, LS);
unlock_all(1); unlock_all(1);
unlock_all(2); unlock_all(2);
unlock_all(3); unlock_all(3);
...@@ -110,7 +114,7 @@ pthread_mutex_t rt_mutex; ...@@ -110,7 +114,7 @@ pthread_mutex_t rt_mutex;
pthread_cond_t rt_cond; pthread_cond_t rt_cond;
int rt_num_threads; int rt_num_threads;
int litmus; int litmus;
int thread_number= 0, timeouts=0; int thread_number= 0, timeouts= 0;
void run_test(const char *test, pthread_handler handler, int n, int m) void run_test(const char *test, pthread_handler handler, int n, int m)
{ {
pthread_t t; pthread_t t;
...@@ -121,7 +125,8 @@ void run_test(const char *test, pthread_handler handler, int n, int m) ...@@ -121,7 +125,8 @@ void run_test(const char *test, pthread_handler handler, int n, int m)
diag("Testing %s with %d threads, %d iterations... ", test, n, m); diag("Testing %s with %d threads, %d iterations... ", test, n, m);
for (rt_num_threads= n ; n ; n--) for (rt_num_threads= n ; n ; n--)
pthread_create(&t, &rt_attr, handler, &m); if (pthread_create(&t, &rt_attr, handler, &m))
abort();
pthread_mutex_lock(&rt_mutex); pthread_mutex_lock(&rt_mutex);
while (rt_num_threads) while (rt_num_threads)
pthread_cond_wait(&rt_cond, &rt_mutex); pthread_cond_wait(&rt_cond, &rt_mutex);
...@@ -133,9 +138,9 @@ void run_test(const char *test, pthread_handler handler, int n, int m) ...@@ -133,9 +138,9 @@ void run_test(const char *test, pthread_handler handler, int n, int m)
int Nrows= 100; int Nrows= 100;
int Ntables= 10; int Ntables= 10;
int table_lock_ratio= 10; int table_lock_ratio= 10;
enum lock_type lock_array[6]={S,X,LS,LX,IS,IX}; enum lock_type lock_array[6]= {S, X, LS, LX, IS, IX};
char *lock2str[6]={"S","X","LS","LX","IS","IX"}; char *lock2str[6]= {"S", "X", "LS", "LX", "IS", "IX"};
char *res2str[4]={ char *res2str[4]= {
"DIDN'T GET THE LOCK", "DIDN'T GET THE LOCK",
"GOT THE LOCK", "GOT THE LOCK",
"GOT THE LOCK NEED TO LOCK A SUBRESOURCE", "GOT THE LOCK NEED TO LOCK A SUBRESOURCE",
...@@ -160,12 +165,12 @@ pthread_handler_t test_lockman(void *arg) ...@@ -160,12 +165,12 @@ pthread_handler_t test_lockman(void *arg)
if (table_lock_ratio && (x/Nrows/4) % table_lock_ratio == 0) if (table_lock_ratio && (x/Nrows/4) % table_lock_ratio == 0)
{ /* table lock */ { /* table lock */
res= lockman_getlock(&lockman, lo, table, lock_array[locklevel]); res= lockman_getlock(&lockman, lo, table, lock_array[locklevel]);
DIAG(("loid=%2d, table %d lock %s, res=%s", loid, table, DIAG(("loid %2d, table %d, lock %s, res %s", loid, table,
lock2str[locklevel], res2str[res])); lock2str[locklevel], res2str[res]));
if (res == DIDNT_GET_THE_LOCK) if (res == DIDNT_GET_THE_LOCK)
{ {
lockman_release_locks(&lockman, lo); lockman_release_locks(&lockman, lo);
DIAG(("loid=%2d, release all locks", loid)); DIAG(("loid %2d, release all locks", loid));
timeout++; timeout++;
continue; continue;
} }
...@@ -175,13 +180,13 @@ pthread_handler_t test_lockman(void *arg) ...@@ -175,13 +180,13 @@ pthread_handler_t test_lockman(void *arg)
{ /* row lock */ { /* row lock */
locklevel&= 1; locklevel&= 1;
res= lockman_getlock(&lockman, lo, table, lock_array[locklevel + 4]); res= lockman_getlock(&lockman, lo, table, lock_array[locklevel + 4]);
DIAG(("loid=%2d, row %d lock %s, res=%s", loid, row, DIAG(("loid %2d, row %d, lock %s, res %s", loid, row,
lock2str[locklevel+4], res2str[res])); lock2str[locklevel+4], res2str[res]));
switch (res) switch (res)
{ {
case DIDNT_GET_THE_LOCK: case DIDNT_GET_THE_LOCK:
lockman_release_locks(&lockman, lo); lockman_release_locks(&lockman, lo);
DIAG(("loid=%2d, release all locks", loid)); DIAG(("loid %2d, release all locks", loid));
timeout++; timeout++;
continue; continue;
case GOT_THE_LOCK: case GOT_THE_LOCK:
...@@ -190,12 +195,12 @@ pthread_handler_t test_lockman(void *arg) ...@@ -190,12 +195,12 @@ pthread_handler_t test_lockman(void *arg)
/* not implemented, so take a regular lock */ /* not implemented, so take a regular lock */
case GOT_THE_LOCK_NEED_TO_LOCK_A_SUBRESOURCE: case GOT_THE_LOCK_NEED_TO_LOCK_A_SUBRESOURCE:
res= lockman_getlock(&lockman, lo, row, lock_array[locklevel]); res= lockman_getlock(&lockman, lo, row, lock_array[locklevel]);
DIAG(("loid=%2d, ROW %d lock %s, res=%s", loid, row, DIAG(("loid %2d, ROW %d, lock %s, res %s", loid, row,
lock2str[locklevel], res2str[res])); lock2str[locklevel], res2str[res]));
if (res == DIDNT_GET_THE_LOCK) if (res == DIDNT_GET_THE_LOCK)
{ {
lockman_release_locks(&lockman, lo); lockman_release_locks(&lockman, lo);
DIAG(("loid=%2d, release all locks", loid)); DIAG(("loid %2d, release all locks", loid));
timeout++; timeout++;
continue; continue;
} }
...@@ -234,7 +239,7 @@ int main() ...@@ -234,7 +239,7 @@ int main()
return exit_status(); return exit_status();
pthread_attr_init(&rt_attr); pthread_attr_init(&rt_attr);
pthread_attr_setdetachstate(&rt_attr,PTHREAD_CREATE_DETACHED); pthread_attr_setdetachstate(&rt_attr, PTHREAD_CREATE_DETACHED);
pthread_mutex_init(&rt_mutex, 0); pthread_mutex_init(&rt_mutex, 0);
pthread_cond_init(&rt_cond, 0); pthread_cond_init(&rt_cond, 0);
...@@ -261,13 +266,13 @@ int main() ...@@ -261,13 +266,13 @@ int main()
Nrows= 100; Nrows= 100;
Ntables= 10; Ntables= 10;
table_lock_ratio= 10; table_lock_ratio= 10;
run_test("lockman", test_lockman, THREADS,CYCLES); run_test("lockman", test_lockman, THREADS, CYCLES);
/* "real-life" simulation - many rows, no table locks */ /* "real-life" simulation - many rows, no table locks */
Nrows= 1000000; Nrows= 1000000;
Ntables= 10; Ntables= 10;
table_lock_ratio= 0; table_lock_ratio= 0;
run_test("lockman", test_lockman, THREADS,10000); run_test("lockman", test_lockman, THREADS, 10000);
for (i= 0; i < Nlos; i++) for (i= 0; i < Nlos; i++)
{ {
......
...@@ -41,7 +41,7 @@ pthread_handler_t test_trnman(void *arg) ...@@ -41,7 +41,7 @@ pthread_handler_t test_trnman(void *arg)
pthread_mutex_t mutexes[MAX_ITER]; pthread_mutex_t mutexes[MAX_ITER];
pthread_cond_t conds[MAX_ITER]; pthread_cond_t conds[MAX_ITER];
for (i=0; i < MAX_ITER; i++) for (i= 0; i < MAX_ITER; i++)
{ {
pthread_mutex_init(&mutexes[i], MY_MUTEX_INIT_FAST); pthread_mutex_init(&mutexes[i], MY_MUTEX_INIT_FAST);
pthread_cond_init(&conds[i], 0); pthread_cond_init(&conds[i], 0);
...@@ -60,7 +60,7 @@ pthread_handler_t test_trnman(void *arg) ...@@ -60,7 +60,7 @@ pthread_handler_t test_trnman(void *arg)
} }
} }
for (i=0; i < MAX_ITER; i++) for (i= 0; i < MAX_ITER; i++)
{ {
pthread_mutex_destroy(&mutexes[i]); pthread_mutex_destroy(&mutexes[i]);
pthread_cond_destroy(&conds[i]); pthread_cond_destroy(&conds[i]);
...@@ -84,7 +84,8 @@ void run_test(const char *test, pthread_handler handler, int n, int m) ...@@ -84,7 +84,8 @@ void run_test(const char *test, pthread_handler handler, int n, int m)
diag("Testing %s with %d threads, %d iterations... ", test, n, m); diag("Testing %s with %d threads, %d iterations... ", test, n, m);
for (rt_num_threads= n ; n ; n--) for (rt_num_threads= n ; n ; n--)
pthread_create(&t, &rt_attr, handler, &m); if (pthread_create(&t, &rt_attr, handler, &m))
abort();
pthread_mutex_lock(&rt_mutex); pthread_mutex_lock(&rt_mutex);
while (rt_num_threads) while (rt_num_threads)
pthread_cond_wait(&rt_cond, &rt_mutex); pthread_cond_wait(&rt_cond, &rt_mutex);
...@@ -94,11 +95,10 @@ void run_test(const char *test, pthread_handler handler, int n, int m) ...@@ -94,11 +95,10 @@ void run_test(const char *test, pthread_handler handler, int n, int m)
} }
#define ok_read_from(T1, T2, RES) \ #define ok_read_from(T1, T2, RES) \
i=trnman_can_read_from(trn[T1], trid[T2]); \ i= trnman_can_read_from(trn[T1], trn[T2]->trid); \
ok(i == RES, "trn" #T1 " %s read from trn" #T2, i ? "can" : "cannot") ok(i == RES, "trn" #T1 " %s read from trn" #T2, i ? "can" : "cannot")
#define start_transaction(T) \ #define start_transaction(T) \
trn[T]= trnman_new_trn(&mutexes[T], &conds[T]); \ trn[T]= trnman_new_trn(&mutexes[T], &conds[T])
trid[T]= trn[T]->trid
#define commit(T) trnman_commit_trn(trn[T]) #define commit(T) trnman_commit_trn(trn[T])
#define abort(T) trnman_abort_trn(trn[T]) #define abort(T) trnman_abort_trn(trn[T])
...@@ -106,12 +106,11 @@ void run_test(const char *test, pthread_handler handler, int n, int m) ...@@ -106,12 +106,11 @@ void run_test(const char *test, pthread_handler handler, int n, int m)
void test_trnman_read_from() void test_trnman_read_from()
{ {
TRN *trn[Ntrns]; TRN *trn[Ntrns];
TrID trid[Ntrns];
pthread_mutex_t mutexes[Ntrns]; pthread_mutex_t mutexes[Ntrns];
pthread_cond_t conds[Ntrns]; pthread_cond_t conds[Ntrns];
int i; int i;
for (i=0; i < Ntrns; i++) for (i= 0; i < Ntrns; i++)
{ {
pthread_mutex_init(&mutexes[i], MY_MUTEX_INIT_FAST); pthread_mutex_init(&mutexes[i], MY_MUTEX_INIT_FAST);
pthread_cond_init(&conds[i], 0); pthread_cond_init(&conds[i], 0);
...@@ -119,19 +118,19 @@ void test_trnman_read_from() ...@@ -119,19 +118,19 @@ void test_trnman_read_from()
start_transaction(0); /* start trn1 */ start_transaction(0); /* start trn1 */
start_transaction(1); /* start trn2 */ start_transaction(1); /* start trn2 */
ok_read_from(1,0,0); ok_read_from(1, 0, 0);
commit(0); /* commit trn1 */ commit(0); /* commit trn1 */
start_transaction(2); /* start trn4 */ start_transaction(2); /* start trn4 */
abort(2); /* abort trn4 */ abort(2); /* abort trn4 */
start_transaction(3); /* start trn5 */ start_transaction(3); /* start trn5 */
ok_read_from(3,0,1); ok_read_from(3, 0, 1);
ok_read_from(3,1,0); ok_read_from(3, 1, 0);
ok_read_from(3,2,0); ok_read_from(3, 2, 0);
commit(1); /* commit trn2 */ commit(1); /* commit trn2 */
ok_read_from(3,1,0); ok_read_from(3, 1, 0);
commit(3); /* commit trn5 */ commit(3); /* commit trn5 */
for (i=0; i < Ntrns; i++) for (i= 0; i < Ntrns; i++)
{ {
pthread_mutex_destroy(&mutexes[i]); pthread_mutex_destroy(&mutexes[i]);
pthread_cond_destroy(&conds[i]); pthread_cond_destroy(&conds[i]);
...@@ -148,7 +147,7 @@ int main() ...@@ -148,7 +147,7 @@ int main()
return exit_status(); return exit_status();
pthread_attr_init(&rt_attr); pthread_attr_init(&rt_attr);
pthread_attr_setdetachstate(&rt_attr,PTHREAD_CREATE_DETACHED); pthread_attr_setdetachstate(&rt_attr, PTHREAD_CREATE_DETACHED);
pthread_mutex_init(&rt_mutex, 0); pthread_mutex_init(&rt_mutex, 0);
pthread_cond_init(&rt_cond, 0); pthread_cond_init(&rt_cond, 0);
...@@ -158,7 +157,7 @@ int main() ...@@ -158,7 +157,7 @@ int main()
trnman_init(); trnman_init();
test_trnman_read_from(); test_trnman_read_from();
run_test("trnman", test_trnman, THREADS,CYCLES); run_test("trnman", test_trnman, THREADS, CYCLES);
diag("mallocs: %d", trnman_allocated_transactions); diag("mallocs: %d", trnman_allocated_transactions);
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment