~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000-2004 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
/* Test av locking */
17
18
#ifndef __NETWARE__
19
20
#include "myisam.h"
21
#include <sys/types.h>
22
#ifdef HAVE_SYS_WAIT_H
23
# include <sys/wait.h>
24
#endif
25
#ifndef WEXITSTATUS
26
# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
27
#endif
28
#ifndef WIFEXITED
29
# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
30
#endif
31
32
33
#if defined(HAVE_LRAND48)
34
#define rnd(X) (lrand48() % X)
35
#define rnd_init(X) srand48(X)
36
#else
37
#define rnd(X) (random() % X)
38
#define rnd_init(X) srandom(X)
39
#endif
40
41
42
const char *filename= "test3";
43
uint tests=10,forks=10,key_cacheing=0,use_log=0;
44
45
static void get_options(int argc, char *argv[]);
46
void start_test(int id);
47
int test_read(MI_INFO *,int),test_write(MI_INFO *,int,int),
48
    test_update(MI_INFO *,int,int),test_rrnd(MI_INFO *,int);
49
50
struct record {
51
  uchar id[8];
52
  uchar nr[4];
53
  uchar text[10];
54
} record;
55
56
57
int main(int argc,char **argv)
58
{
59
  int status,wait_ret;
60
  uint i=0;
61
  MI_KEYDEF keyinfo[10];
62
  MI_COLUMNDEF recinfo[10];
63
  HA_KEYSEG keyseg[10][2];
64
  MY_INIT(argv[0]);
65
  get_options(argc,argv);
66
67
  bzero((char*) keyinfo,sizeof(keyinfo));
68
  bzero((char*) recinfo,sizeof(recinfo));
69
  bzero((char*) keyseg,sizeof(keyseg));
70
  keyinfo[0].seg= &keyseg[0][0];
71
  keyinfo[0].seg[0].start=0;
72
  keyinfo[0].seg[0].length=8;
73
  keyinfo[0].seg[0].type=HA_KEYTYPE_TEXT;
74
  keyinfo[0].seg[0].flag=HA_SPACE_PACK;
75
  keyinfo[0].key_alg=HA_KEY_ALG_BTREE;
76
  keyinfo[0].keysegs=1;
77
  keyinfo[0].flag = (uint8) HA_PACK_KEY;
78
  keyinfo[0].block_length= 0;                   /* Default block length */
79
  keyinfo[1].seg= &keyseg[1][0];
80
  keyinfo[1].seg[0].start=8;
81
  keyinfo[1].seg[0].length=4;		/* Long is always 4 in myisam */
82
  keyinfo[1].seg[0].type=HA_KEYTYPE_LONG_INT;
83
  keyinfo[1].seg[0].flag=0;
84
  keyinfo[1].key_alg=HA_KEY_ALG_BTREE;
85
  keyinfo[1].keysegs=1;
86
  keyinfo[1].flag =HA_NOSAME;
87
  keyinfo[1].block_length= 0;                   /* Default block length */
88
89
  recinfo[0].type=0;
90
  recinfo[0].length=sizeof(record.id);
91
  recinfo[1].type=0;
92
  recinfo[1].length=sizeof(record.nr);
93
  recinfo[2].type=0;
94
  recinfo[2].length=sizeof(record.text);
95
96
  puts("- Creating myisam-file");
97
  my_delete(filename,MYF(0));		/* Remove old locks under gdb */
98
  if (mi_create(filename,2,&keyinfo[0],2,&recinfo[0],0,(MI_UNIQUEDEF*) 0,
99
		(MI_CREATE_INFO*) 0,0))
100
    exit(1);
101
102
  rnd_init(0);
103
  printf("- Starting %d processes\n",forks); fflush(stdout);
104
  for (i=0 ; i < forks; i++)
105
  {
106
    if (!fork())
107
    {
108
      start_test(i+1);
109
      sleep(1);
110
      return 0;
111
    }
112
    VOID(rnd(1));
113
  }
114
115
  for (i=0 ; i < forks ; i++)
116
    while ((wait_ret=wait(&status)) && wait_ret == -1);
117
  return 0;
118
}
119
120
121
static void get_options(int argc, char **argv)
122
{
123
  char *pos,*progname;
124
125
  progname= argv[0];
126
127
  while (--argc >0 && *(pos = *(++argv)) == '-' ) {
128
    switch(*++pos) {
129
    case 'l':
130
      use_log=1;
131
      break;
132
    case 'f':
133
      forks=atoi(++pos);
134
      break;
135
    case 't':
136
      tests=atoi(++pos);
137
      break;
138
    case 'K':				/* Use key cacheing */
139
      key_cacheing=1;
140
      break;
141
    case 'A':				/* All flags */
142
      use_log=key_cacheing=1;
143
      break;
144
   case '?':
145
    case 'I':
146
    case 'V':
147
      printf("%s  Ver 1.0 for %s at %s\n",progname,SYSTEM_TYPE,MACHINE_TYPE);
148
      puts("By Monty, for your professional use\n");
149
      puts("Test av locking with threads\n");
150
      printf("Usage: %s [-?lKA] [-f#] [-t#]\n",progname);
151
      exit(0);
152
    case '#':
153
      DBUG_PUSH (++pos);
154
      break;
155
    default:
156
      printf("Illegal option: '%c'\n",*pos);
157
      break;
158
    }
159
  }
160
  return;
161
}
162
163
164
void start_test(int id)
165
{
166
  uint i;
167
  int error,lock_type;
168
  MI_ISAMINFO isam_info;
169
  MI_INFO *file,*file1,*file2=0,*lock;
170
171
  if (use_log)
172
    mi_log(1);
173
  if (!(file1=mi_open(filename,O_RDWR,HA_OPEN_WAIT_IF_LOCKED)) ||
174
      !(file2=mi_open(filename,O_RDWR,HA_OPEN_WAIT_IF_LOCKED)))
175
  {
176
    fprintf(stderr,"Can't open isam-file: %s\n",filename);
177
    exit(1);
178
  }
179
  if (key_cacheing && rnd(2) == 0)
180
    init_key_cache(dflt_key_cache, KEY_CACHE_BLOCK_SIZE, 65536L, 0, 0);
181
  printf("Process %d, pid: %d\n",id,getpid()); fflush(stdout);
182
183
  for (error=i=0 ; i < tests && !error; i++)
184
  {
185
    file= (rnd(2) == 1) ? file1 : file2;
186
    lock=0 ; lock_type=0;
187
    if (rnd(10) == 0)
188
    {
189
      if (mi_lock_database(lock=(rnd(2) ? file1 : file2),
190
			   lock_type=(rnd(2) == 0 ? F_RDLCK : F_WRLCK)))
191
      {
192
	fprintf(stderr,"%2d: start: Can't lock table %d\n",id,my_errno);
193
	error=1;
194
	break;
195
      }
196
    }
197
    switch (rnd(4)) {
198
    case 0: error=test_read(file,id); break;
199
    case 1: error=test_rrnd(file,id); break;
200
    case 2: error=test_write(file,id,lock_type); break;
201
    case 3: error=test_update(file,id,lock_type); break;
202
    }
203
    if (lock)
204
      mi_lock_database(lock,F_UNLCK);
205
  }
206
  if (!error)
207
  {
208
    mi_status(file1,&isam_info,HA_STATUS_VARIABLE);
209
    printf("%2d: End of test.  Records:  %ld  Deleted:  %ld\n",
210
	   id,(long) isam_info.records, (long) isam_info.deleted);
211
    fflush(stdout);
212
  }
213
214
  mi_close(file1);
215
  mi_close(file2);
216
  if (use_log)
217
    mi_log(0);
218
  if (error)
219
  {
220
    printf("%2d: Aborted\n",id); fflush(stdout);
221
    exit(1);
222
  }
223
}
224
225
226
int test_read(MI_INFO *file,int id)
227
{
228
  uint i,lock,found,next,prev;
229
  ulong find;
230
231
  lock=0;
232
  if (rnd(2) == 0)
233
  {
234
    lock=1;
235
    if (mi_lock_database(file,F_RDLCK))
236
    {
237
      fprintf(stderr,"%2d: Can't lock table %d\n",id,my_errno);
238
      return 1;
239
    }
240
  }
241
242
  found=next=prev=0;
243
  for (i=0 ; i < 100 ; i++)
244
  {
245
    find=rnd(100000);
246
    if (!mi_rkey(file,record.id,1,(uchar*) &find, HA_WHOLE_KEY,
247
                 HA_READ_KEY_EXACT))
248
      found++;
249
    else
250
    {
251
      if (my_errno != HA_ERR_KEY_NOT_FOUND)
252
      {
253
	fprintf(stderr,"%2d: Got error %d from read in read\n",id,my_errno);
254
	return 1;
255
      }
256
      else if (!mi_rnext(file,record.id,1))
257
	next++;
258
      else
259
      {
260
	if (my_errno != HA_ERR_END_OF_FILE)
261
	{
262
	  fprintf(stderr,"%2d: Got error %d from rnext in read\n",id,my_errno);
263
	  return 1;
264
	}
265
	else if (!mi_rprev(file,record.id,1))
266
	  prev++;
267
	else
268
	{
269
	  if (my_errno != HA_ERR_END_OF_FILE)
270
	  {
271
	    fprintf(stderr,"%2d: Got error %d from rnext in read\n",
272
		    id,my_errno);
273
	    return 1;
274
	  }
275
	}
276
      }
277
    }
278
  }
279
  if (lock)
280
  {
281
    if (mi_lock_database(file,F_UNLCK))
282
    {
283
      fprintf(stderr,"%2d: Can't unlock table\n",id);
284
      return 1;
285
    }
286
  }
287
  printf("%2d: read:   found: %5d  next: %5d   prev: %5d\n",
288
	 id,found,next,prev);
289
  fflush(stdout);
290
  return 0;
291
}
292
293
294
int test_rrnd(MI_INFO *file,int id)
295
{
296
  uint count,lock;
297
298
  lock=0;
299
  if (rnd(2) == 0)
300
  {
301
    lock=1;
302
    if (mi_lock_database(file,F_RDLCK))
303
    {
304
      fprintf(stderr,"%2d: Can't lock table (%d)\n",id,my_errno);
305
      mi_close(file);
306
      return 1;
307
    }
308
    if (rnd(2) == 0)
309
      mi_extra(file,HA_EXTRA_CACHE,0);
310
  }
311
312
  count=0;
313
  if (mi_rrnd(file,record.id,0L))
314
  {
315
    if (my_errno == HA_ERR_END_OF_FILE)
316
      goto end;
317
    fprintf(stderr,"%2d: Can't read first record (%d)\n",id,my_errno);
318
    return 1;
319
  }
320
  for (count=1 ; !mi_rrnd(file,record.id,HA_OFFSET_ERROR) ;count++) ;
321
  if (my_errno != HA_ERR_END_OF_FILE)
322
  {
323
    fprintf(stderr,"%2d: Got error %d from rrnd\n",id,my_errno);
324
    return 1;
325
  }
326
327
end:
328
  if (lock)
329
  {
330
    mi_extra(file,HA_EXTRA_NO_CACHE,0);
331
    if (mi_lock_database(file,F_UNLCK))
332
    {
333
      fprintf(stderr,"%2d: Can't unlock table\n",id);
334
      exit(0);
335
    }
336
  }
337
  printf("%2d: rrnd:   %5d\n",id,count); fflush(stdout);
338
  return 0;
339
}
340
341
342
int test_write(MI_INFO *file,int id,int lock_type)
343
{
344
  uint i,tries,count,lock;
345
346
  lock=0;
347
  if (rnd(2) == 0 || lock_type == F_RDLCK)
348
  {
349
    lock=1;
350
    if (mi_lock_database(file,F_WRLCK))
351
    {
352
      if (lock_type == F_RDLCK && my_errno == EDEADLK)
353
      {
354
	printf("%2d: write:  deadlock\n",id); fflush(stdout);
355
	return 0;
356
      }
357
      fprintf(stderr,"%2d: Can't lock table (%d)\n",id,my_errno);
358
      mi_close(file);
359
      return 1;
360
    }
361
    if (rnd(2) == 0)
362
      mi_extra(file,HA_EXTRA_WRITE_CACHE,0);
363
  }
364
365
  sprintf((char*) record.id,"%7d",getpid());
366
  strnmov((char*) record.text,"Testing...", sizeof(record.text));
367
368
  tries=(uint) rnd(100)+10;
369
  for (i=count=0 ; i < tries ; i++)
370
  {
371
    uint32 tmp=rnd(80000)+20000;
372
    int4store(record.nr,tmp);
373
    if (!mi_write(file,record.id))
374
      count++;
375
    else
376
    {
377
      if (my_errno != HA_ERR_FOUND_DUPP_KEY)
378
      {
379
	fprintf(stderr,"%2d: Got error %d (errno %d) from write\n",id,my_errno,
380
		errno);
381
	return 1;
382
      }
383
    }
384
  }
385
  if (lock)
386
  {
387
    mi_extra(file,HA_EXTRA_NO_CACHE,0);
388
    if (mi_lock_database(file,F_UNLCK))
389
    {
390
      fprintf(stderr,"%2d: Can't unlock table\n",id);
391
      exit(0);
392
    }
393
  }
394
  printf("%2d: write:  %5d\n",id,count); fflush(stdout);
395
  return 0;
396
}
397
398
399
int test_update(MI_INFO *file,int id,int lock_type)
400
{
401
  uint i,lock,found,next,prev,update;
402
  uint32 tmp;
403
  char find[4];
404
  struct record new_record;
405
406
  lock=0;
407
  if (rnd(2) == 0 || lock_type == F_RDLCK)
408
  {
409
    lock=1;
410
    if (mi_lock_database(file,F_WRLCK))
411
    {
412
      if (lock_type == F_RDLCK && my_errno == EDEADLK)
413
      {
414
	printf("%2d: write:  deadlock\n",id); fflush(stdout);
415
	return 0;
416
      }
417
      fprintf(stderr,"%2d: Can't lock table (%d)\n",id,my_errno);
418
      return 1;
419
    }
420
  }
421
  bzero((char*) &new_record,sizeof(new_record));
422
  strmov((char*) new_record.text,"Updated");
423
424
  found=next=prev=update=0;
425
  for (i=0 ; i < 100 ; i++)
426
  {
427
    tmp=rnd(100000);
428
    int4store(find,tmp);
429
    if (!mi_rkey(file,record.id,1,(uchar*) find, HA_WHOLE_KEY,
430
                 HA_READ_KEY_EXACT))
431
      found++;
432
    else
433
    {
434
      if (my_errno != HA_ERR_KEY_NOT_FOUND)
435
      {
436
	fprintf(stderr,"%2d: Got error %d from read in update\n",id,my_errno);
437
	return 1;
438
      }
439
      else if (!mi_rnext(file,record.id,1))
440
	next++;
441
      else
442
      {
443
	if (my_errno != HA_ERR_END_OF_FILE)
444
	{
445
	  fprintf(stderr,"%2d: Got error %d from rnext in update\n",
446
		  id,my_errno);
447
	  return 1;
448
	}
449
	else if (!mi_rprev(file,record.id,1))
450
	  prev++;
451
	else
452
	{
453
	  if (my_errno != HA_ERR_END_OF_FILE)
454
	  {
455
	    fprintf(stderr,"%2d: Got error %d from rnext in update\n",
456
		    id,my_errno);
457
	    return 1;
458
	  }
459
	  continue;
460
	}
461
      }
462
    }
463
    memcpy_fixed(new_record.id,record.id,sizeof(record.id));
464
    tmp=rnd(20000)+40000;
465
    int4store(new_record.nr,tmp);
466
    if (!mi_update(file,record.id,new_record.id))
467
      update++;
468
    else
469
    {
470
      if (my_errno != HA_ERR_RECORD_CHANGED &&
471
	  my_errno != HA_ERR_RECORD_DELETED &&
472
	  my_errno != HA_ERR_FOUND_DUPP_KEY)
473
      {
474
	fprintf(stderr,"%2d: Got error %d from update\n",id,my_errno);
475
	return 1;
476
      }
477
    }
478
  }
479
  if (lock)
480
  {
481
    if (mi_lock_database(file,F_UNLCK))
482
    {
483
      fprintf(stderr,"Can't unlock table,id, error%d\n",my_errno);
484
      return 1;
485
    }
486
  }
487
  printf("%2d: update: %5d\n",id,update); fflush(stdout);
488
  return 0;
489
}
490
491
#else /* __NETWARE__ */
492
493
#include <stdio.h>
494
495
main()
496
{
497
	fprintf(stderr,"this test has not been ported to NetWare\n");
498
	return 0;
499
}
500
501
#endif /* __NETWARE__ */
502
503
#include "mi_extrafunc.h"