Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
aea73116
Commit
aea73116
authored
Oct 19, 2006
by
unknown
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
post-review fixes (style)
include/lf.h: comments
parent
12a55aea
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
186 additions
and
144 deletions
+186
-144
include/lf.h
include/lf.h
+21
-22
storage/maria/lockman.c
storage/maria/lockman.c
+4
-4
storage/maria/lockman.h
storage/maria/lockman.h
+1
-1
storage/maria/trnman.c
storage/maria/trnman.c
+93
-54
storage/maria/trnman.h
storage/maria/trnman.h
+1
-1
storage/maria/unittest/lockman-t.c
storage/maria/unittest/lockman-t.c
+51
-46
storage/maria/unittest/trnman-t.c
storage/maria/unittest/trnman-t.c
+15
-16
No files found.
include/lf.h
View file @
aea73116
/* Copyright (C) 2006 MySQL AB
/*
TODO
1. copyright
6. reduce the number of memory barriers
*/
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 */
#ifndef _lf_h
#define _lf_h
...
...
@@ -11,7 +20,8 @@
#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) \
...
...
@@ -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
should be enough for a while
...
...
@@ -68,14 +78,9 @@ typedef int (*lf_dynarray_func)(void *, void *);
void
lf_dynarray_init
(
LF_DYNARRAY
*
array
,
uint
element_size
);
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
*
,
(
LF_DYNARRAY
*
array
,
uint
idx
),
(
array
,
idx
));
lock_wrap
(
lf_dynarray_lvalue
,
void
*
,
(
LF_DYNARRAY
*
array
,
uint
idx
),
(
array
,
idx
),
...
...
@@ -85,7 +90,7 @@ nolock_wrap(lf_dynarray_iterate, int,
(
array
,
func
,
arg
));
/*
pin manager for memory allocator
pin manager for memory allocator
, lf_alloc-pin.c
*/
#define LF_PINBOX_PINS 4
...
...
@@ -102,13 +107,13 @@ typedef struct {
uint32
volatile
pins_in_stack
;
/* number of elements in array */
}
LF_PINBOX
;
/* we want sizeof(LF_PINS) to be 128 to avoid false sharing */
typedef
struct
{
void
*
volatile
pin
[
LF_PINBOX_PINS
];
LF_PINBOX
*
pinbox
;
void
*
purgatory
;
uint32
purgatory_count
;
uint32
volatile
link
;
/* we want sizeof(LF_PINS) to be 128 to avoid false sharing */
char
pad
[
128
-
sizeof
(
uint32
)
*
2
-
sizeof
(
void
*
)
*
(
LF_PINBOX_PINS
+
2
)];
}
LF_PINS
;
...
...
@@ -160,19 +165,13 @@ lock_wrap_void(lf_pinbox_put_pins,
(
LF_PINS
*
pins
),
(
pins
),
&
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
,
(
LF_PINS
*
pins
,
void
*
addr
),
(
pins
,
addr
),
&
pins
->
pinbox
->
pinstack
.
lock
);
/*
memory allocator
memory allocator
, lf_alloc-pin.c
*/
typedef
struct
st_lf_allocator
{
...
...
@@ -199,7 +198,7 @@ lock_wrap(lf_alloc_new, void *,
&
pins
->
pinbox
->
pinstack
.
lock
);
/*
extendible hash
extendible hash
, lf_hash.c
*/
#include <hash.h>
...
...
storage/maria/lockman.c
View file @
aea73116
...
...
@@ -5,7 +5,7 @@
different characteristics. long lists, few distinct resources -
slow to scan, [possibly] high retry rate
*/
/* Copyright (C) 200
0
MySQL AB
/* Copyright (C) 200
6
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
...
...
@@ -272,7 +272,7 @@ retry:
_lf_unpin
(
pins
,
3
);
do
{
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
);
for
(;;)
{
...
...
@@ -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
)
{
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
**
));
lm
->
size
=
1
;
lm
->
count
=
0
;
...
...
@@ -744,7 +744,7 @@ static char *lock2str[]=
void
print_lockhash
(
LOCKMAN
*
lm
)
{
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
)
{
intptr
next
=
el
->
link
;
...
...
storage/maria/lockman.h
View file @
aea73116
/* Copyright (C) 200
0
MySQL AB
/* Copyright (C) 200
6
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
...
...
storage/maria/trnman.c
View file @
aea73116
/* Copyright (C) 200
0
MySQL AB
/* Copyright (C) 200
6
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
...
...
@@ -20,21 +20,35 @@
#include <lf.h>
#include "trnman.h"
/* status variables */
uint
trnman_active_transactions
,
trnman_allocated_transactions
;
static
TRN
active_list_min
,
active_list_max
,
committed_list_min
,
committed_list_max
,
*
pool
;
/* list of active transactions in the trid order */
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
LF_HASH
trid_to_trn
;
static
LOCKMAN
maria_lockman
;
/* the mutex for everything above */
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
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
);
return
(
byte
*
)
&
((
*
((
TRN
**
)
trn
))
->
trid
);
...
...
@@ -44,7 +58,7 @@ static LOCK_OWNER *trnman_short_trid_to_TRN(uint16 short_trid)
{
TRN
*
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
);
return
(
LOCK_OWNER
*
)
trn
;
}
...
...
@@ -52,39 +66,56 @@ static LOCK_OWNER *trnman_short_trid_to_TRN(uint16 short_trid)
int
trnman_init
()
{
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
.
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
;
trnman_active_transactions
=
0
;
trnman_allocated_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
;
trnman_active_transactions
=
0
;
trnman_allocated_transactions
=
0
;
pool
=
0
;
global_trid_generator
=
0
;
/* set later by recovery code */
lf_hash_init
(
&
trid_to_trn
,
sizeof
(
TRN
*
),
LF_HASH_UNIQUE
,
global_trid_generator
=
0
;
/* set later by
the
recovery code */
lf_hash_init
(
&
trid_to_
committed_
trn
,
sizeof
(
TRN
*
),
LF_HASH_UNIQUE
,
0
,
0
,
trn_get_hash_key
,
0
);
my_atomic_rwlock_init
(
&
LOCK_short_trid_to_trn
);
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
));
if
(
!
short_trid_to_trn
)
if
(
!
short_trid_to_
active_
trn
)
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
);
return
0
;
}
/*
NOTE
this could only be called in the "idle" state - no transaction can be
running. See asserts below.
*/
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
(
active_list_max
.
prev
==
&
active_list_min
);
DBUG_ASSERT
(
active_list_min
.
next
==
&
active_list_max
);
...
...
@@ -98,14 +129,20 @@ int trnman_destroy()
DBUG_ASSERT
(
trn
->
locks
.
cond
==
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
);
my_atomic_rwlock_destroy
(
&
LOCK_short_trid_to_trn
);
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
);
}
/*
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
()
{
DBUG_ASSERT
(
global_trid_generator
<
0xffffffffffffLL
);
...
...
@@ -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] */
{
void
*
tmp
=
NULL
;
if
(
short_trid_to_trn
[
i
]
==
NULL
&&
my_atomic_casptr
((
void
**
)
&
short_trid_to_trn
[
i
],
&
tmp
,
trn
))
if
(
short_trid_to_
active_
trn
[
i
]
==
NULL
&&
my_atomic_casptr
((
void
**
)
&
short_trid_to_
active_
trn
[
i
],
&
tmp
,
trn
))
break
;
}
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)
TRN
*
trn
;
/*
see trnman_end_trn to see why we need a mutex here
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.
we have a mutex, to do simple things under it - allocate a TRN,
increment trnman_active_transactions, set trn->min_read_from.
Note that all the above is fast. generating short_trid may be slow,
as it involves scanning a
big array - so it's still don
e
outside of the
mutex.
as it involves scanning a
large array - so it's done outside of th
e
mutex.
*/
pthread_mutex_lock
(
&
LOCK_trn_list
);
trnman_active_transactions
++
;
/* Allocating a new TRN structure */
trn
=
pool
;
/*
popping an element from a stack
*/
/*
Popping an unused TRN from the pool
*/
my_atomic_rwlock_wrlock
(
&
LOCK_pool
);
while
(
trn
&&
!
my_atomic_casptr
((
void
**
)
&
pool
,
(
void
**
)
&
trn
,
(
void
*
)
trn
->
next
))
/* no-op */
;
my_atomic_rwlock_wrunlock
(
&
LOCK_pool
);
/* Nothing in the pool ? Allocate a new one */
if
(
!
trn
)
{
trn
=
(
TRN
*
)
my_malloc
(
sizeof
(
TRN
),
MYF
(
MY_WME
));
if
(
!
trn
)
if
(
unlikely
(
!
trn
)
)
{
pthread_mutex_unlock
(
&
LOCK_trn_list
);
return
0
;
}
trnman_allocated_transactions
++
;
}
trnman_active_transactions
++
;
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)
active_list_max
.
prev
=
trn
->
prev
->
next
=
trn
;
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
->
commit_trid
=
0
;
trn
->
locks
.
mutex
=
mutex
;
trn
->
locks
.
cond
=
cond
;
trn
->
commit_trid
=
0
;
trn
->
locks
.
waiting_for
=
0
;
trn
->
locks
.
all_locks
=
0
;
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
;
}
/*
remove a trn from the active list,
move to committed list,
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.
remove a trn from the active list.
if necessary - move to committed list and set commit_trid
*/
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
->
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
)
{
TRN
*
t
;
...
...
@@ -232,6 +267,7 @@ void trnman_end_trn(TRN *trn, my_bool commit)
t
->
commit_trid
<
active_list_min
.
next
->
min_read_from
;
t
=
t
->
next
)
/* no-op */
;
/* found transactions committed before the oldest active one */
if
(
t
!=
committed_list_min
.
next
)
{
free_me
=
committed_list_min
.
next
;
...
...
@@ -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
)
{
trn
->
commit_trid
=
global_trid_generator
;
...
...
@@ -250,10 +289,10 @@ void trnman_end_trn(TRN *trn, my_bool commit)
trn
->
prev
=
committed_list_max
.
prev
;
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
);
}
else
/* o
r
free it right away */
else
/* o
therwise
free it right away */
{
trn
->
next
=
free_me
;
free_me
=
trn
;
...
...
@@ -266,7 +305,7 @@ void trnman_end_trn(TRN *trn, my_bool commit)
trn
->
locks
.
mutex
=
0
;
trn
->
locks
.
cond
=
0
;
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
);
while
(
free_me
)
// XXX send them to the purge thread
...
...
@@ -275,7 +314,7 @@ void trnman_end_trn(TRN *trn, my_bool commit)
TRN
*
t
=
free_me
;
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
);
}
...
...
@@ -331,7 +370,7 @@ my_bool trnman_can_read_from(TRN *trn, TrID trid)
if
(
trid
>
trn
->
trid
)
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
)
return
FALSE
;
/* not in the hash of committed transactions = cannot read */
...
...
storage/maria/trnman.h
View file @
aea73116
/* Copyright (C) 200
0
MySQL AB
/* Copyright (C) 200
6
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
...
...
storage/maria/unittest/lockman-t.c
View file @
aea73116
...
...
@@ -42,16 +42,20 @@ LOCK_OWNER *loid2lo(uint16 loid)
return
loarray
+
loid
-
1
;
}
#define unlock_all(O) diag("lo" #O "> release all locks"); \
#define unlock_all(O) diag("lo" #O "> release all locks");
\
lockman_release_locks(&lockman, loid2lo(O));print_lockhash(&lockman)
#define test_lock(O, R, L, S, RES) \
ok(lockman_getlock(&lockman, loid2lo(O), R, L) == RES, \
"lo" #O "> " S " lock resource " #R " with " #L "-lock"); \
#define test_lock(O, R, L, S, RES)
\
ok(lockman_getlock(&lockman, loid2lo(O), R, L) == RES,
\
"lo" #O "> " S " lock resource " #R " with " #L "-lock");
\
print_lockhash(&lockman)
#define lock_ok_a(O,R,L) test_lock(O,R,L,"",GOT_THE_LOCK)
#define lock_ok_i(O,R,L) 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);
#define lock_ok_a(O, R, L) \
test_lock(O, R, L, "", GOT_THE_LOCK)
#define lock_ok_i(O, R, L) \
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
()
{
...
...
@@ -63,41 +67,41 @@ void test_lockman_simple()
lock_ok_a
(
1
,
1
,
X
);
lock_ok_i
(
2
,
2
,
IX
);
/* failures */
lock_conflict
(
2
,
1
,
X
);
lock_conflict
(
2
,
1
,
X
);
unlock_all
(
2
);
lock_ok_a
(
1
,
2
,
S
);
lock_ok_a
(
1
,
2
,
IS
);
lock_ok_a
(
1
,
2
,
LS
);
lock_ok_i
(
1
,
3
,
IX
);
lock_ok_a
(
2
,
3
,
LS
);
lock_ok_i
(
1
,
3
,
IX
);
lock_ok_l
(
2
,
3
,
IS
);
lock_ok_a
(
1
,
2
,
S
);
lock_ok_a
(
1
,
2
,
IS
);
lock_ok_a
(
1
,
2
,
LS
);
lock_ok_i
(
1
,
3
,
IX
);
lock_ok_a
(
2
,
3
,
LS
);
lock_ok_i
(
1
,
3
,
IX
);
lock_ok_l
(
2
,
3
,
IS
);
unlock_all
(
1
);
unlock_all
(
2
);
lock_ok_i
(
1
,
1
,
IX
);
lock_conflict
(
2
,
1
,
S
);
lock_ok_a
(
1
,
1
,
LS
);
lock_ok_i
(
1
,
1
,
IX
);
lock_conflict
(
2
,
1
,
S
);
lock_ok_a
(
1
,
1
,
LS
);
unlock_all
(
1
);
unlock_all
(
2
);
lock_ok_i
(
1
,
1
,
IX
);
lock_ok_a
(
2
,
1
,
LS
);
lock_ok_a
(
1
,
1
,
LS
);
lock_ok_i
(
1
,
1
,
IX
);
lock_ok_i
(
3
,
1
,
IS
);
lock_ok_i
(
1
,
1
,
IX
);
lock_ok_a
(
2
,
1
,
LS
);
lock_ok_a
(
1
,
1
,
LS
);
lock_ok_i
(
1
,
1
,
IX
);
lock_ok_i
(
3
,
1
,
IS
);
unlock_all
(
1
);
unlock_all
(
2
);
unlock_all
(
3
);
lock_ok_i
(
1
,
4
,
IS
);
lock_ok_i
(
2
,
4
,
IS
);
lock_ok_i
(
3
,
4
,
IS
);
lock_ok_a
(
3
,
4
,
LS
);
lock_ok_i
(
4
,
4
,
IS
);
lock_conflict
(
4
,
4
,
IX
);
lock_conflict
(
2
,
4
,
IX
);
lock_ok_a
(
1
,
4
,
LS
);
lock_ok_i
(
1
,
4
,
IS
);
lock_ok_i
(
2
,
4
,
IS
);
lock_ok_i
(
3
,
4
,
IS
);
lock_ok_a
(
3
,
4
,
LS
);
lock_ok_i
(
4
,
4
,
IS
);
lock_conflict
(
4
,
4
,
IX
);
lock_conflict
(
2
,
4
,
IX
);
lock_ok_a
(
1
,
4
,
LS
);
unlock_all
(
1
);
unlock_all
(
2
);
unlock_all
(
3
);
...
...
@@ -110,7 +114,7 @@ pthread_mutex_t rt_mutex;
pthread_cond_t
rt_cond
;
int
rt_num_threads
;
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
)
{
pthread_t
t
;
...
...
@@ -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
);
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
);
while
(
rt_num_threads
)
pthread_cond_wait
(
&
rt_cond
,
&
rt_mutex
);
...
...
@@ -133,9 +138,9 @@ void run_test(const char *test, pthread_handler handler, int n, int m)
int
Nrows
=
100
;
int
Ntables
=
10
;
int
table_lock_ratio
=
10
;
enum
lock_type
lock_array
[
6
]
=
{
S
,
X
,
LS
,
LX
,
IS
,
IX
};
char
*
lock2str
[
6
]
=
{
"S"
,
"X"
,
"LS"
,
"LX"
,
"IS"
,
"IX"
};
char
*
res2str
[
4
]
=
{
enum
lock_type
lock_array
[
6
]
=
{
S
,
X
,
LS
,
LX
,
IS
,
IX
};
char
*
lock2str
[
6
]
=
{
"S"
,
"X"
,
"LS"
,
"LX"
,
"IS"
,
"IX"
};
char
*
res2str
[
4
]
=
{
"DIDN'T GET THE LOCK"
,
"GOT THE LOCK"
,
"GOT THE LOCK NEED TO LOCK A SUBRESOURCE"
,
...
...
@@ -160,12 +165,12 @@ pthread_handler_t test_lockman(void *arg)
if
(
table_lock_ratio
&&
(
x
/
Nrows
/
4
)
%
table_lock_ratio
==
0
)
{
/* table lock */
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
]));
if
(
res
==
DIDNT_GET_THE_LOCK
)
{
lockman_release_locks
(
&
lockman
,
lo
);
DIAG
((
"loid
=
%2d, release all locks"
,
loid
));
DIAG
((
"loid
%2d, release all locks"
,
loid
));
timeout
++
;
continue
;
}
...
...
@@ -175,13 +180,13 @@ pthread_handler_t test_lockman(void *arg)
{
/* row lock */
locklevel
&=
1
;
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
]));
switch
(
res
)
{
case
DIDNT_GET_THE_LOCK
:
lockman_release_locks
(
&
lockman
,
lo
);
DIAG
((
"loid
=
%2d, release all locks"
,
loid
));
DIAG
((
"loid
%2d, release all locks"
,
loid
));
timeout
++
;
continue
;
case
GOT_THE_LOCK
:
...
...
@@ -190,12 +195,12 @@ pthread_handler_t test_lockman(void *arg)
/* not implemented, so take a regular lock */
case
GOT_THE_LOCK_NEED_TO_LOCK_A_SUBRESOURCE
:
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
]));
if
(
res
==
DIDNT_GET_THE_LOCK
)
{
lockman_release_locks
(
&
lockman
,
lo
);
DIAG
((
"loid
=
%2d, release all locks"
,
loid
));
DIAG
((
"loid
%2d, release all locks"
,
loid
));
timeout
++
;
continue
;
}
...
...
@@ -234,7 +239,7 @@ int main()
return
exit_status
();
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_cond_init
(
&
rt_cond
,
0
);
...
...
@@ -261,13 +266,13 @@ int main()
Nrows
=
100
;
Ntables
=
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 */
Nrows
=
1000000
;
Ntables
=
10
;
table_lock_ratio
=
0
;
run_test
(
"lockman"
,
test_lockman
,
THREADS
,
10000
);
run_test
(
"lockman"
,
test_lockman
,
THREADS
,
10000
);
for
(
i
=
0
;
i
<
Nlos
;
i
++
)
{
...
...
storage/maria/unittest/trnman-t.c
View file @
aea73116
...
...
@@ -41,7 +41,7 @@ pthread_handler_t test_trnman(void *arg)
pthread_mutex_t
mutexes
[
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_cond_init
(
&
conds
[
i
],
0
);
...
...
@@ -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_cond_destroy
(
&
conds
[
i
]);
...
...
@@ -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
);
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
);
while
(
rt_num_threads
)
pthread_cond_wait
(
&
rt_cond
,
&
rt_mutex
);
...
...
@@ -94,11 +95,10 @@ void run_test(const char *test, pthread_handler handler, int n, int m)
}
#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")
#define start_transaction(T) \
trn[T]= trnman_new_trn(&mutexes[T], &conds[T]); \
trid[T]= trn[T]->trid
trn[T]= trnman_new_trn(&mutexes[T], &conds[T])
#define commit(T) trnman_commit_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)
void
test_trnman_read_from
()
{
TRN
*
trn
[
Ntrns
];
TrID
trid
[
Ntrns
];
pthread_mutex_t
mutexes
[
Ntrns
];
pthread_cond_t
conds
[
Ntrns
];
int
i
;
for
(
i
=
0
;
i
<
Ntrns
;
i
++
)
for
(
i
=
0
;
i
<
Ntrns
;
i
++
)
{
pthread_mutex_init
(
&
mutexes
[
i
],
MY_MUTEX_INIT_FAST
);
pthread_cond_init
(
&
conds
[
i
],
0
);
...
...
@@ -119,19 +118,19 @@ void test_trnman_read_from()
start_transaction
(
0
);
/* start trn1 */
start_transaction
(
1
);
/* start trn2 */
ok_read_from
(
1
,
0
,
0
);
ok_read_from
(
1
,
0
,
0
);
commit
(
0
);
/* commit trn1 */
start_transaction
(
2
);
/* start trn4 */
abort
(
2
);
/* abort trn4 */
start_transaction
(
3
);
/* start trn5 */
ok_read_from
(
3
,
0
,
1
);
ok_read_from
(
3
,
1
,
0
);
ok_read_from
(
3
,
2
,
0
);
ok_read_from
(
3
,
0
,
1
);
ok_read_from
(
3
,
1
,
0
);
ok_read_from
(
3
,
2
,
0
);
commit
(
1
);
/* commit trn2 */
ok_read_from
(
3
,
1
,
0
);
ok_read_from
(
3
,
1
,
0
);
commit
(
3
);
/* commit trn5 */
for
(
i
=
0
;
i
<
Ntrns
;
i
++
)
for
(
i
=
0
;
i
<
Ntrns
;
i
++
)
{
pthread_mutex_destroy
(
&
mutexes
[
i
]);
pthread_cond_destroy
(
&
conds
[
i
]);
...
...
@@ -148,7 +147,7 @@ int main()
return
exit_status
();
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_cond_init
(
&
rt_cond
,
0
);
...
...
@@ -158,7 +157,7 @@ int main()
trnman_init
();
test_trnman_read_from
();
run_test
(
"trnman"
,
test_trnman
,
THREADS
,
CYCLES
);
run_test
(
"trnman"
,
test_trnman
,
THREADS
,
CYCLES
);
diag
(
"mallocs: %d"
,
trnman_allocated_transactions
);
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment