1
/* Copyright (C) 2006 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
17
tablockman for row and table locks
20
/* #define EXTRA_VERBOSE */
24
#include <my_global.h>
26
#include <my_atomic.h>
28
#include "../tablockman.h"
32
TABLE_LOCK_OWNER loarray1[Nlos];
33
pthread_mutex_t mutexes[Nlos];
34
pthread_cond_t conds[Nlos];
35
LOCKED_TABLE ltarray[Ntbls];
36
TABLOCKMAN tablockman;
39
#define print_lo1(X) /* no-op */
40
#define DIAG(X) /* no-op */
42
#define DIAG(X) diag X
45
TABLE_LOCK_OWNER *loid2lo1(uint16 loid)
47
return loarray1+loid-1;
50
#define unlock_all(O) diag("lo" #O "> release all locks"); \
51
tablockman_release_locks(&tablockman, loid2lo1(O));
52
#define test_lock(O, R, L, S, RES) \
53
ok(tablockman_getlock(&tablockman, loid2lo1(O), <array[R], L) == RES, \
54
"lo" #O "> " S "lock resource " #R " with " #L "-lock"); \
55
print_lo1(loid2lo1(O));
56
#define lock_ok_a(O, R, L) \
57
test_lock(O, R, L, "", GOT_THE_LOCK)
58
#define lock_ok_i(O, R, L) \
59
test_lock(O, R, L, "", GOT_THE_LOCK_NEED_TO_LOCK_A_SUBRESOURCE)
60
#define lock_ok_l(O, R, L) \
61
test_lock(O, R, L, "", GOT_THE_LOCK_NEED_TO_INSTANT_LOCK_A_SUBRESOURCE)
62
#define lock_conflict(O, R, L) \
63
test_lock(O, R, L, "cannot ", LOCK_TIMEOUT);
65
void test_tablockman_simple()
75
lock_conflict(2, 1, X);
88
lock_conflict(2, 1, S);
107
lock_conflict(4, 4, IX);
108
lock_conflict(2, 4, IX);
117
lock_conflict(1, 1, S);
118
lock_conflict(2, 1, X);
123
lock_conflict(2, 1, X);
124
lock_conflict(3, 1, IS);
130
lock_conflict(2, 1, IX);
131
lock_conflict(3, 1, IS);
139
int thread_number= 0, timeouts= 0;
140
void run_test(const char *test, pthread_handler handler, int n, int m)
143
ulonglong now= my_getsystime();
146
thread_number= timeouts= 0;
149
threads= (pthread_t *)my_malloc(sizeof(void *)*n, MYF(0));
152
diag("Out of memory");
156
diag("Running %s with %d threads, %d iterations... ", test, n, m);
158
for (i= 0; i < n ; i++)
159
if (pthread_create(threads+i, 0, handler, &m))
161
diag("Could not create thread");
164
for (i= 0 ; i < n ; i++)
165
pthread_join(threads[i], 0);
166
now= my_getsystime()-now;
167
ok(litmus == 0, "Finished %s in %g secs (%d)", test, ((double)now)/1e7, litmus);
168
my_free((void*)threads, MYF(0));
171
static void reinit_tlo(TABLOCKMAN *lm, TABLE_LOCK_OWNER *lo)
174
TABLE_LOCK_OWNER backup= *lo;
177
tablockman_release_locks(lm, lo);
179
pthread_mutex_destroy(lo->mutex);
180
pthread_cond_destroy(lo->cond);
181
bzero(lo, sizeof(*lo));
183
lo->mutex= backup.mutex;
184
lo->cond= backup.cond;
185
lo->loid= backup.loid;
186
pthread_mutex_init(lo->mutex, MY_MUTEX_INIT_FAST);
187
pthread_cond_init(lo->cond, 0);
191
pthread_mutex_t rt_mutex;
194
int table_lock_ratio= 10;
195
enum lockman_lock_type lock_array[6]= {S, X, LS, LX, IS, IX};
196
const char *lock2str[6]= {"S", "X", "LS", "LX", "IS", "IX"};
197
const char *res2str[]= {
203
"GOT THE LOCK NEED TO LOCK A SUBRESOURCE",
204
"GOT THE LOCK NEED TO INSTANT LOCK A SUBRESOURCE"};
206
pthread_handler_t test_lockman(void *arg)
208
int m= (*(int *)arg);
209
uint x, loid, row, table, res, locklevel, timeout= 0;
210
TABLE_LOCK_OWNER *lo1;
211
DBUG_ASSERT(Ntables <= Ntbls);
212
DBUG_ASSERT(Nrows + Ntables <= Ntbls);
214
pthread_mutex_lock(&rt_mutex);
215
loid= ++thread_number;
216
pthread_mutex_unlock(&rt_mutex);
219
for (x= ((int)(intptr)(&m)); m > 0; m--)
221
/* three prime numbers */
222
x= (uint) ((x*LL(3628273133) + LL(1500450271)) % LL(9576890767));
223
row= x % Nrows + Ntables;
224
table= row % Ntables;
225
locklevel= (x/Nrows) & 3;
226
if (table_lock_ratio && (x/Nrows/4) % table_lock_ratio == 0)
229
res= tablockman_getlock(&tablockman, lo1, ltarray+table,
230
lock_array[locklevel]);
231
DIAG(("loid %2d, table %d, lock %s, res %s", loid, table,
232
lock2str[locklevel], res2str[res]));
233
if (res < GOT_THE_LOCK)
235
reinit_tlo(&tablockman, lo1);
236
DIAG(("loid %2d, release all locks", loid));
240
DBUG_ASSERT(res == GOT_THE_LOCK);
245
res= tablockman_getlock(&tablockman, lo1, ltarray+table, lock_array[locklevel + 4]);
246
DIAG(("loid %2d, row %d, lock %s, res %s", loid, row,
247
lock2str[locklevel+4], res2str[res]));
252
case GOT_THE_LOCK_NEED_TO_INSTANT_LOCK_A_SUBRESOURCE:
253
/* not implemented, so take a regular lock */
254
case GOT_THE_LOCK_NEED_TO_LOCK_A_SUBRESOURCE:
255
res= tablockman_getlock(&tablockman, lo1, ltarray+row, lock_array[locklevel]);
256
DIAG(("loid %2d, ROW %d, lock %s, res %s", loid, row,
257
lock2str[locklevel], res2str[res]));
258
if (res < GOT_THE_LOCK)
260
reinit_tlo(&tablockman, lo1);
261
DIAG(("loid %2d, release all locks", loid));
265
DBUG_ASSERT(res == GOT_THE_LOCK);
268
reinit_tlo(&tablockman, lo1);
269
DIAG(("loid %2d, release all locks", loid));
276
reinit_tlo(&tablockman, lo1);
278
pthread_mutex_lock(&rt_mutex);
282
diag("number of timeouts: %d", timeouts);
283
pthread_mutex_unlock(&rt_mutex);
288
int main(int argc __attribute__((unused)), char **argv)
294
pthread_mutex_init(&rt_mutex, 0);
298
if (my_atomic_initialize())
299
return exit_status();
302
tablockman_init(&tablockman, &loid2lo1, 50);
304
for (i= 0; i < Nlos; i++)
306
pthread_mutex_init(&mutexes[i], MY_MUTEX_INIT_FAST);
307
pthread_cond_init (&conds[i], 0);
309
loarray1[i].active_locks= 0;
310
loarray1[i].waiting_lock= 0;
311
loarray1[i].waiting_for= 0;
312
loarray1[i].mutex= &mutexes[i];
313
loarray1[i].cond= &conds[i];
314
loarray1[i].loid= i+1;
317
for (i= 0; i < Ntbls; i++)
319
tablockman_init_locked_table(ltarray+i, Nlos);
322
test_tablockman_simple();
325
#define THREADS Nlos /* don't change this line */
327
/* mixed load, stress-test with random locks */
330
table_lock_ratio= 10;
331
run_test("\"random lock\" stress test", test_lockman, THREADS, CYCLES);
333
/* "real-life" simulation - many rows, no table locks */
337
run_test("\"real-life\" simulation test", test_lockman, THREADS, CYCLES*10);
339
for (i= 0; i < Nlos; i++)
341
tablockman_release_locks(&tablockman, &loarray1[i]);
342
pthread_mutex_destroy(loarray1[i].mutex);
343
pthread_cond_destroy(loarray1[i].cond);
347
ulonglong now= my_getsystime();
348
for (i= 0; i < Ntbls; i++)
350
tablockman_destroy_locked_table(ltarray+i);
352
tablockman_destroy(&tablockman);
353
now= my_getsystime()-now;
354
diag("lockman_destroy: %g secs", ((double)now)/1e7);
357
pthread_mutex_destroy(&rt_mutex);
359
return exit_status();