~jlukas79/+junk/mysql-server

« back to all changes in this revision

Viewing changes to storage/maria/unittest/lockman1-t.c

manual merge 6.0-main --> 6.0-bka-review

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2006 MySQL AB
 
2
 
 
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.
 
6
 
 
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.
 
11
 
 
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 */
 
15
 
 
16
/*
 
17
  lockman for row locks, tablockman for table locks
 
18
*/
 
19
 
 
20
/* #define EXTRA_VERBOSE */
 
21
 
 
22
#include <tap.h>
 
23
 
 
24
#include <my_global.h>
 
25
#include <my_sys.h>
 
26
#include <my_atomic.h>
 
27
#include <lf.h>
 
28
#include "../lockman.h"
 
29
#include "../tablockman.h"
 
30
 
 
31
#define Nlos 100
 
32
#define Ntbls 10
 
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];
 
38
LOCKMAN lockman;
 
39
TABLOCKMAN tablockman;
 
40
 
 
41
#ifndef EXTRA_VERBOSE
 
42
#define print_lo1(X)       /* no-op */
 
43
#define DIAG(X)            /* no-op */
 
44
#else
 
45
#define DIAG(X) diag X
 
46
#endif
 
47
 
 
48
LOCK_OWNER *loid2lo(uint16 loid)
 
49
{
 
50
  return loarray+loid-1;
 
51
}
 
52
TABLE_LOCK_OWNER *loid2lo1(uint16 loid)
 
53
{
 
54
  return loarray1+loid-1;
 
55
}
 
56
 
 
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), &ltarray[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);
 
71
 
 
72
void test_tablockman_simple()
 
73
{
 
74
  /* simple */
 
75
  lock_ok_a(1, 1, S);
 
76
  lock_ok_i(2, 2, IS);
 
77
  lock_ok_i(1, 2, IX);
 
78
  /* lock escalation */
 
79
  lock_ok_a(1, 1, X);
 
80
  lock_ok_i(2, 2, IX);
 
81
  /* failures */
 
82
  lock_conflict(2, 1, X);
 
83
  unlock_all(2);
 
84
  lock_ok_a(1, 2, S);
 
85
  lock_ok_a(1, 2, IS);
 
86
  lock_ok_a(1, 2, LS);
 
87
  lock_ok_i(1, 3, IX);
 
88
  lock_ok_a(2, 3, LS);
 
89
  lock_ok_i(1, 3, IX);
 
90
  lock_ok_l(2, 3, IS);
 
91
  unlock_all(1);
 
92
  unlock_all(2);
 
93
 
 
94
  lock_ok_i(1, 1, IX);
 
95
  lock_conflict(2, 1, S);
 
96
  lock_ok_a(1, 1, LS);
 
97
  unlock_all(1);
 
98
  unlock_all(2);
 
99
 
 
100
  lock_ok_i(1, 1, IX);
 
101
  lock_ok_a(2, 1, LS);
 
102
  lock_ok_a(1, 1, LS);
 
103
  lock_ok_i(1, 1, IX);
 
104
  lock_ok_i(3, 1, IS);
 
105
  unlock_all(1);
 
106
  unlock_all(2);
 
107
  unlock_all(3);
 
108
 
 
109
  lock_ok_i(1, 4, IS);
 
110
  lock_ok_i(2, 4, IS);
 
111
  lock_ok_i(3, 4, IS);
 
112
  lock_ok_a(3, 4, LS);
 
113
  lock_ok_i(4, 4, IS);
 
114
  lock_conflict(4, 4, IX);
 
115
  lock_conflict(2, 4, IX);
 
116
  lock_ok_a(1, 4, LS);
 
117
  unlock_all(1);
 
118
  unlock_all(2);
 
119
  unlock_all(3);
 
120
  unlock_all(4);
 
121
 
 
122
  lock_ok_i(1, 1, IX);
 
123
  lock_ok_i(2, 1, IX);
 
124
  lock_conflict(1, 1, S);
 
125
  lock_conflict(2, 1, X);
 
126
  unlock_all(1);
 
127
  unlock_all(2);
 
128
}
 
129
 
 
130
int rt_num_threads;
 
131
int litmus;
 
132
int thread_number= 0, timeouts= 0;
 
133
void run_test(const char *test, pthread_handler handler, int n, int m)
 
134
{
 
135
  pthread_t *threads;
 
136
  ulonglong now= my_getsystime();
 
137
  int i;
 
138
 
 
139
  thread_number= timeouts= 0;
 
140
  litmus= 0;
 
141
 
 
142
  threads= (pthread_t *)my_malloc(sizeof(void *)*n, MYF(0));
 
143
  if (!threads)
 
144
  {
 
145
    diag("Out of memory");
 
146
    abort();
 
147
  }
 
148
 
 
149
  diag("Running %s with %d threads, %d iterations... ", test, n, m);
 
150
  rt_num_threads= n;
 
151
  for (i= 0; i < n ; i++)
 
152
    if (pthread_create(threads+i, 0, handler, &m))
 
153
    {
 
154
      diag("Could not create thread");
 
155
      abort();
 
156
    }
 
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));
 
162
}
 
163
 
 
164
pthread_mutex_t rt_mutex;
 
165
int Nrows= 100;
 
166
int Ntables= 10;
 
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"};
 
170
char *res2str[]= {
 
171
  "DIDN'T GET THE LOCK",
 
172
  "OUT OF MEMORY",
 
173
  "DEADLOCK",
 
174
  "LOCK TIMEOUT",
 
175
  "GOT 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)
 
179
{
 
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);
 
183
 
 
184
  pthread_mutex_lock(&rt_mutex);
 
185
  loid= ++thread_number;
 
186
  pthread_mutex_unlock(&rt_mutex);
 
187
  lo= loid2lo(loid); lo1= loid2lo1(loid);
 
188
 
 
189
  for (x= ((int)(intptr)(&m)); m > 0; m--)
 
190
  {
 
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)
 
196
    { /* table lock */
 
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)
 
201
      {
 
202
        lockman_release_locks(&lockman, lo); tablockman_release_locks(&tablockman, lo1);
 
203
        DIAG(("loid %2d, release all locks", loid));
 
204
        timeout++;
 
205
        continue;
 
206
      }
 
207
      DBUG_ASSERT(res == GOT_THE_LOCK);
 
208
    }
 
209
    else
 
210
    { /* row lock */
 
211
      locklevel&= 1;
 
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]));
 
215
      switch (res)
 
216
      {
 
217
      case GOT_THE_LOCK:
 
218
        continue;
 
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)
 
226
        {
 
227
          lockman_release_locks(&lockman, lo);
 
228
          tablockman_release_locks(&tablockman, lo1);
 
229
          DIAG(("loid %2d, release all locks", loid));
 
230
          timeout++;
 
231
          continue;
 
232
        }
 
233
        DBUG_ASSERT(res == GOT_THE_LOCK);
 
234
        continue;
 
235
      default:
 
236
        lockman_release_locks(&lockman, lo); tablockman_release_locks(&tablockman, lo1);
 
237
        DIAG(("loid %2d, release all locks", loid));
 
238
        timeout++;
 
239
        continue;
 
240
      }
 
241
    }
 
242
  }
 
243
 
 
244
  lockman_release_locks(&lockman, lo);
 
245
  tablockman_release_locks(&tablockman, lo1);
 
246
 
 
247
  pthread_mutex_lock(&rt_mutex);
 
248
  rt_num_threads--;
 
249
  timeouts+= timeout;
 
250
  if (!rt_num_threads)
 
251
    diag("number of timeouts: %d", timeouts);
 
252
  pthread_mutex_unlock(&rt_mutex);
 
253
 
 
254
  return 0;
 
255
}
 
256
 
 
257
int main()
 
258
{
 
259
  int i;
 
260
 
 
261
  my_init();
 
262
  pthread_mutex_init(&rt_mutex, 0);
 
263
 
 
264
  plan(35);
 
265
 
 
266
  if (my_atomic_initialize())
 
267
    return exit_status();
 
268
 
 
269
 
 
270
  lockman_init(&lockman, &loid2lo, 50);
 
271
  tablockman_init(&tablockman, &loid2lo1, 50);
 
272
 
 
273
  for (i= 0; i < Nlos; i++)
 
274
  {
 
275
    pthread_mutex_init(&mutexes[i], MY_MUTEX_INIT_FAST);
 
276
    pthread_cond_init (&conds[i], 0);
 
277
 
 
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;
 
284
 
 
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;
 
291
  }
 
292
 
 
293
  for (i= 0; i < Ntbls; i++)
 
294
  {
 
295
    tablockman_init_locked_table(ltarray+i, Nlos);
 
296
  }
 
297
 
 
298
  test_tablockman_simple();
 
299
 
 
300
#define CYCLES 10000
 
301
#define THREADS Nlos /* don't change this line */
 
302
 
 
303
  /* mixed load, stress-test with random locks */
 
304
  Nrows= 100;
 
305
  Ntables= 10;
 
306
  table_lock_ratio= 10;
 
307
  run_test("\"random lock\" stress test", test_lockman, THREADS, CYCLES);
 
308
 
 
309
  /* "real-life" simulation - many rows, no table locks */
 
310
  Nrows= 1000000;
 
311
  Ntables= 10;
 
312
  table_lock_ratio= 0;
 
313
  run_test("\"real-life\" simulation test", test_lockman, THREADS, CYCLES*10);
 
314
 
 
315
  for (i= 0; i < Nlos; i++)
 
316
  {
 
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);
 
321
  }
 
322
 
 
323
  {
 
324
    ulonglong now= my_getsystime();
 
325
    lockman_destroy(&lockman);
 
326
    now= my_getsystime()-now;
 
327
    diag("lockman_destroy: %g secs", ((double)now)/1e7);
 
328
  }
 
329
 
 
330
  pthread_mutex_destroy(&rt_mutex);
 
331
  my_end(0);
 
332
  return exit_status();
 
333
}
 
334