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
lockman for row locks, tablockman for table locks
20
/* #define EXTRA_VERBOSE */
24
#include <my_global.h>
26
#include <my_atomic.h>
28
#include "../lockman.h"
29
#include "../tablockman.h"
33
LOCK_OWNER loarray[Nlos];
34
TABLE_LOCK_OWNER loarray1[Nlos];
35
pthread_mutex_t mutexes[Nlos];
36
pthread_cond_t conds[Nlos];
37
LOCKED_TABLE ltarray[Ntbls];
39
TABLOCKMAN tablockman;
42
#define print_lo1(X) /* no-op */
43
#define DIAG(X) /* no-op */
45
#define DIAG(X) diag X
48
LOCK_OWNER *loid2lo(uint16 loid)
50
return loarray+loid-1;
52
TABLE_LOCK_OWNER *loid2lo1(uint16 loid)
54
return loarray1+loid-1;
57
#define unlock_all(O) diag("lo" #O "> release all locks"); \
58
tablockman_release_locks(&tablockman, loid2lo1(O));
59
#define test_lock(O, R, L, S, RES) \
60
ok(tablockman_getlock(&tablockman, loid2lo1(O), <array[R], L) == RES, \
61
"lo" #O "> " S "lock resource " #R " with " #L "-lock"); \
62
print_lo1(loid2lo1(O));
63
#define lock_ok_a(O, R, L) \
64
test_lock(O, R, L, "", GOT_THE_LOCK)
65
#define lock_ok_i(O, R, L) \
66
test_lock(O, R, L, "", GOT_THE_LOCK_NEED_TO_LOCK_A_SUBRESOURCE)
67
#define lock_ok_l(O, R, L) \
68
test_lock(O, R, L, "", GOT_THE_LOCK_NEED_TO_INSTANT_LOCK_A_SUBRESOURCE)
69
#define lock_conflict(O, R, L) \
70
test_lock(O, R, L, "cannot ", LOCK_TIMEOUT);
72
void test_tablockman_simple()
82
lock_conflict(2, 1, X);
95
lock_conflict(2, 1, S);
114
lock_conflict(4, 4, IX);
115
lock_conflict(2, 4, IX);
124
lock_conflict(1, 1, S);
125
lock_conflict(2, 1, X);
132
int thread_number= 0, timeouts= 0;
133
void run_test(const char *test, pthread_handler handler, int n, int m)
136
ulonglong now= my_getsystime();
139
thread_number= timeouts= 0;
142
threads= (pthread_t *)my_malloc(sizeof(void *)*n, MYF(0));
145
diag("Out of memory");
149
diag("Running %s with %d threads, %d iterations... ", test, n, m);
151
for (i= 0; i < n ; i++)
152
if (pthread_create(threads+i, 0, handler, &m))
154
diag("Could not create thread");
157
for (i= 0 ; i < n ; i++)
158
pthread_join(threads[i], 0);
159
now= my_getsystime()-now;
160
ok(litmus == 0, "Finished %s in %g secs (%d)", test, ((double)now)/1e7, litmus);
161
my_free((void*)threads, MYF(0));
164
pthread_mutex_t rt_mutex;
167
int table_lock_ratio= 10;
168
enum lockman_lock_type lock_array[6]= {S, X, LS, LX, IS, IX};
169
char *lock2str[6]= {"S", "X", "LS", "LX", "IS", "IX"};
171
"DIDN'T GET THE LOCK",
176
"GOT THE LOCK NEED TO LOCK A SUBRESOURCE",
177
"GOT THE LOCK NEED TO INSTANT LOCK A SUBRESOURCE"};
178
pthread_handler_t test_lockman(void *arg)
180
int m= (*(int *)arg);
181
uint x, loid, row, table, res, locklevel, timeout= 0;
182
LOCK_OWNER *lo; TABLE_LOCK_OWNER *lo1; DBUG_ASSERT(Ntables <= Ntbls);
184
pthread_mutex_lock(&rt_mutex);
185
loid= ++thread_number;
186
pthread_mutex_unlock(&rt_mutex);
187
lo= loid2lo(loid); lo1= loid2lo1(loid);
189
for (x= ((int)(intptr)(&m)); m > 0; m--)
191
x= (x*3628273133 + 1500450271) % 9576890767; /* three prime numbers */
192
row= x % Nrows + Ntables;
193
table= row % Ntables;
194
locklevel= (x/Nrows) & 3;
195
if (table_lock_ratio && (x/Nrows/4) % table_lock_ratio == 0)
197
res= tablockman_getlock(&tablockman, lo1, ltarray+table, lock_array[locklevel]);
198
DIAG(("loid %2d, table %d, lock %s, res %s", loid, table,
199
lock2str[locklevel], res2str[res]));
200
if (res < GOT_THE_LOCK)
202
lockman_release_locks(&lockman, lo); tablockman_release_locks(&tablockman, lo1);
203
DIAG(("loid %2d, release all locks", loid));
207
DBUG_ASSERT(res == GOT_THE_LOCK);
212
res= tablockman_getlock(&tablockman, lo1, ltarray+table, lock_array[locklevel + 4]);
213
DIAG(("loid %2d, row %d, lock %s, res %s", loid, row,
214
lock2str[locklevel+4], res2str[res]));
219
case GOT_THE_LOCK_NEED_TO_INSTANT_LOCK_A_SUBRESOURCE:
220
/* not implemented, so take a regular lock */
221
case GOT_THE_LOCK_NEED_TO_LOCK_A_SUBRESOURCE:
222
res= lockman_getlock(&lockman, lo, row, lock_array[locklevel]);
223
DIAG(("loid %2d, ROW %d, lock %s, res %s", loid, row,
224
lock2str[locklevel], res2str[res]));
225
if (res == DIDNT_GET_THE_LOCK)
227
lockman_release_locks(&lockman, lo);
228
tablockman_release_locks(&tablockman, lo1);
229
DIAG(("loid %2d, release all locks", loid));
233
DBUG_ASSERT(res == GOT_THE_LOCK);
236
lockman_release_locks(&lockman, lo); tablockman_release_locks(&tablockman, lo1);
237
DIAG(("loid %2d, release all locks", loid));
244
lockman_release_locks(&lockman, lo);
245
tablockman_release_locks(&tablockman, lo1);
247
pthread_mutex_lock(&rt_mutex);
251
diag("number of timeouts: %d", timeouts);
252
pthread_mutex_unlock(&rt_mutex);
262
pthread_mutex_init(&rt_mutex, 0);
266
if (my_atomic_initialize())
267
return exit_status();
270
lockman_init(&lockman, &loid2lo, 50);
271
tablockman_init(&tablockman, &loid2lo1, 50);
273
for (i= 0; i < Nlos; i++)
275
pthread_mutex_init(&mutexes[i], MY_MUTEX_INIT_FAST);
276
pthread_cond_init (&conds[i], 0);
278
loarray[i].pins= lf_alloc_get_pins(&lockman.alloc);
279
loarray[i].all_locks= 0;
280
loarray[i].waiting_for= 0;
281
loarray[i].mutex= &mutexes[i];
282
loarray[i].cond= &conds[i];
283
loarray[i].loid= i+1;
285
loarray1[i].active_locks= 0;
286
loarray1[i].waiting_lock= 0;
287
loarray1[i].waiting_for= 0;
288
loarray1[i].mutex= &mutexes[i];
289
loarray1[i].cond= &conds[i];
290
loarray1[i].loid= i+1;
293
for (i= 0; i < Ntbls; i++)
295
tablockman_init_locked_table(ltarray+i, Nlos);
298
test_tablockman_simple();
301
#define THREADS Nlos /* don't change this line */
303
/* mixed load, stress-test with random locks */
306
table_lock_ratio= 10;
307
run_test("\"random lock\" stress test", test_lockman, THREADS, CYCLES);
309
/* "real-life" simulation - many rows, no table locks */
313
run_test("\"real-life\" simulation test", test_lockman, THREADS, CYCLES*10);
315
for (i= 0; i < Nlos; i++)
317
lockman_release_locks(&lockman, &loarray[i]);
318
pthread_mutex_destroy(loarray[i].mutex);
319
pthread_cond_destroy(loarray[i].cond);
320
lf_pinbox_put_pins(loarray[i].pins);
324
ulonglong now= my_getsystime();
325
lockman_destroy(&lockman);
326
now= my_getsystime()-now;
327
diag("lockman_destroy: %g secs", ((double)now)/1e7);
330
pthread_mutex_destroy(&rt_mutex);
332
return exit_status();