1/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
15
16/* Test av locking */
17
18#ifndef _WIN32 /*no fork() in Windows*/
19
20#include "maria_def.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
42const char *filename= "test3";
43uint tests=10,forks=10,pagecacheing=0;
44
45static void get_options(int argc, char *argv[]);
46void start_test(int id);
47int test_read(MARIA_HA *,int),test_write(MARIA_HA *,int,int),
48 test_update(MARIA_HA *,int,int),test_rrnd(MARIA_HA *,int);
49
50struct record {
51 uchar id[8];
52 uchar nr[4];
53 uchar text[10];
54} record;
55
56
57int main(int argc,char **argv)
58{
59 int status,wait_ret;
60 uint i=0;
61 MARIA_KEYDEF keyinfo[10];
62 MARIA_COLUMNDEF recinfo[10];
63 HA_KEYSEG keyseg[10][2];
64 MY_INIT(argv[0]);
65 get_options(argc,argv);
66
67 fprintf(stderr, "WARNING! this program is to test 'external locking'"
68 " (when several processes share a table through file locking)"
69 " which is not supported by Maria at all; expect errors."
70 " We may soon remove this program.\n");
71 maria_init();
72 bzero((char*) keyinfo,sizeof(keyinfo));
73 bzero((char*) recinfo,sizeof(recinfo));
74 bzero((char*) keyseg,sizeof(keyseg));
75 keyinfo[0].seg= &keyseg[0][0];
76 keyinfo[0].seg[0].start=0;
77 keyinfo[0].seg[0].length=8;
78 keyinfo[0].seg[0].type=HA_KEYTYPE_TEXT;
79 keyinfo[0].seg[0].flag=HA_SPACE_PACK;
80 keyinfo[0].key_alg=HA_KEY_ALG_BTREE;
81 keyinfo[0].keysegs=1;
82 keyinfo[0].flag = (uint8) HA_PACK_KEY;
83 keyinfo[0].block_length= 0; /* Default block length */
84 keyinfo[1].seg= &keyseg[1][0];
85 keyinfo[1].seg[0].start=8;
86 keyinfo[1].seg[0].length=4; /* Long is always 4 in maria */
87 keyinfo[1].seg[0].type=HA_KEYTYPE_LONG_INT;
88 keyinfo[1].seg[0].flag=0;
89 keyinfo[1].key_alg=HA_KEY_ALG_BTREE;
90 keyinfo[1].keysegs=1;
91 keyinfo[1].flag =HA_NOSAME;
92 keyinfo[1].block_length= 0; /* Default block length */
93
94 recinfo[0].type=0;
95 recinfo[0].length=sizeof(record.id);
96 recinfo[1].type=0;
97 recinfo[1].length=sizeof(record.nr);
98 recinfo[2].type=0;
99 recinfo[2].length=sizeof(record.text);
100
101 puts("- Creating maria-file");
102 my_delete(filename,MYF(0)); /* Remove old locks under gdb */
103 if (maria_create(filename,BLOCK_RECORD, 2, &keyinfo[0],2,&recinfo[0],0,
104 (MARIA_UNIQUEDEF*) 0, (MARIA_CREATE_INFO*) 0,0))
105 exit(1);
106
107 rnd_init(0);
108 printf("- Starting %d processes\n",forks); fflush(stdout);
109 for (i=0 ; i < forks; i++)
110 {
111 if (!fork())
112 {
113 start_test(i+1);
114 sleep(1);
115 return 0;
116 }
117 (void)rnd(1);
118 }
119
120 for (i=0 ; i < forks ; i++)
121 while ((wait_ret=wait(&status)) && wait_ret == -1);
122 maria_end();
123 return 0;
124}
125
126
127static void get_options(int argc, char **argv)
128{
129 char *pos,*progname;
130
131 progname= argv[0];
132
133 while (--argc >0 && *(pos = *(++argv)) == '-' ) {
134 switch(*++pos) {
135 case 'f':
136 forks=atoi(++pos);
137 break;
138 case 't':
139 tests=atoi(++pos);
140 break;
141 case 'K': /* Use key cacheing */
142 pagecacheing=1;
143 break;
144 case 'A': /* All flags */
145 pagecacheing=1;
146 break;
147 case '?':
148 case 'I':
149 case 'V':
150 printf("%s Ver 1.0 for %s at %s\n",progname,SYSTEM_TYPE,MACHINE_TYPE);
151 puts("By Monty, for your professional use\n");
152 puts("Test av locking with threads\n");
153 printf("Usage: %s [-?lKA] [-f#] [-t#]\n",progname);
154 exit(0);
155 case '#':
156 DBUG_PUSH (++pos);
157 break;
158 default:
159 printf("Illegal option: '%c'\n",*pos);
160 break;
161 }
162 }
163 return;
164}
165
166
167void start_test(int id)
168{
169 uint i;
170 int error,lock_type;
171 MARIA_INFO isam_info;
172 MARIA_HA *file,*file1,*file2=0,*lock;
173
174 if (!(file1=maria_open(filename,O_RDWR,HA_OPEN_WAIT_IF_LOCKED)) ||
175 !(file2=maria_open(filename,O_RDWR,HA_OPEN_WAIT_IF_LOCKED)))
176 {
177 fprintf(stderr,"Can't open isam-file: %s\n",filename);
178 exit(1);
179 }
180 if (pagecacheing && rnd(2) == 0)
181 init_pagecache(maria_pagecache, 65536L, 0, 0, MARIA_KEY_BLOCK_LENGTH, 0,
182 MY_WME);
183 printf("Process %d, pid: %ld\n",id,(long) getpid()); fflush(stdout);
184
185 for (error=i=0 ; i < tests && !error; i++)
186 {
187 file= (rnd(2) == 1) ? file1 : file2;
188 lock=0 ; lock_type=0;
189 if (rnd(10) == 0)
190 {
191 if (maria_lock_database(lock=(rnd(2) ? file1 : file2),
192 lock_type=(rnd(2) == 0 ? F_RDLCK : F_WRLCK)))
193 {
194 fprintf(stderr,"%2d: start: Can't lock table %d\n",id,my_errno);
195 error=1;
196 break;
197 }
198 }
199 switch (rnd(4)) {
200 case 0: error=test_read(file,id); break;
201 case 1: error=test_rrnd(file,id); break;
202 case 2: error=test_write(file,id,lock_type); break;
203 case 3: error=test_update(file,id,lock_type); break;
204 }
205 if (lock)
206 maria_lock_database(lock,F_UNLCK);
207 }
208 if (!error)
209 {
210 maria_status(file1,&isam_info,HA_STATUS_VARIABLE);
211 printf("%2d: End of test. Records: %ld Deleted: %ld\n",
212 id,(long) isam_info.records, (long) isam_info.deleted);
213 fflush(stdout);
214 }
215
216 maria_close(file1);
217 maria_close(file2);
218 if (error)
219 {
220 printf("%2d: Aborted\n",id); fflush(stdout);
221 exit(1);
222 }
223}
224
225
226int test_read(MARIA_HA *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 (maria_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 (!maria_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 (!maria_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 (!maria_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 (maria_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
294int test_rrnd(MARIA_HA *file,int id)
295{
296 uint count,lock;
297
298 lock=0;
299 if (rnd(2) == 0)
300 {
301 lock=1;
302 if (maria_lock_database(file,F_RDLCK))
303 {
304 fprintf(stderr,"%2d: Can't lock table (%d)\n",id,my_errno);
305 maria_close(file);
306 return 1;
307 }
308 if (rnd(2) == 0)
309 maria_extra(file,HA_EXTRA_CACHE,0);
310 }
311
312 count=0;
313 if (maria_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 ; !maria_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
327end:
328 if (lock)
329 {
330 maria_extra(file,HA_EXTRA_NO_CACHE,0);
331 if (maria_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
342int test_write(MARIA_HA *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 (maria_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 maria_close(file);
359 return 1;
360 }
361 if (rnd(2) == 0)
362 maria_extra(file,HA_EXTRA_WRITE_CACHE,0);
363 }
364
365 sprintf((char*) record.id,"%7ld", (long) 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 (!maria_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 maria_extra(file,HA_EXTRA_NO_CACHE,0);
388 if (maria_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
399int test_update(MARIA_HA *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 (maria_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 (!maria_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 (!maria_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 (!maria_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(new_record.id,record.id,sizeof(record.id));
464 tmp=rnd(20000)+40000;
465 int4store(new_record.nr,tmp);
466 if (!maria_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 (maria_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#include "ma_check_standalone.h"
492
493#else /* _WIN32 */
494
495#include <stdio.h>
496
497int main()
498{
499 fprintf(stderr,"this test has not been ported to Windows\n");
500 return 0;
501}
502
503#endif /* _WIN32 */
504
505