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 02110-1335 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 
42 const char *filename= "test3";
43 uint tests=10,forks=10,pagecacheing=0;
44 
45 static void get_options(int argc, char *argv[]);
46 void start_test(int id);
47 int test_read(MARIA_HA *,int),test_write(MARIA_HA *,int,int),
48     test_update(MARIA_HA *,int,int),test_rrnd(MARIA_HA *,int);
49 
50 struct record {
51   uchar id[8];
52   uchar nr[4];
53   uchar text[10];
54 } record;
55 
56 
main(int argc,char ** argv)57 int 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 
get_options(int argc,char ** argv)127 static 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 
start_test(int id)167 void 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 
test_read(MARIA_HA * file,int id)226 int 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 
test_rrnd(MARIA_HA * file,int id)294 int 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 
327 end:
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 
test_write(MARIA_HA * file,int id,int lock_type)342 int 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   my_snprintf((char*) record.id, sizeof(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 
test_update(MARIA_HA * file,int id,int lock_type)399 int 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 
main()497 int main()
498 {
499 	fprintf(stderr,"this test has not been ported to Windows\n");
500 	return 0;
501 }
502 
503 #endif /* _WIN32 */
504 
505