1 /* Copyright (c) 2000, 2021, Oracle and/or its affiliates.
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, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 /* Test av locking */
24
25 #include "myisam.h"
26 #include <sys/types.h>
27 #ifdef HAVE_SYS_WAIT_H
28 # include <sys/wait.h>
29 #endif
30 #ifndef WEXITSTATUS
31 # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
32 #endif
33 #ifndef WIFEXITED
34 # define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
35 #endif
36
37
38 #if defined(HAVE_LRAND48)
39 #define rnd(X) (lrand48() % X)
40 #define rnd_init(X) srand48(X)
41 #else
42 #define rnd(X) (random() % X)
43 #define rnd_init(X) srandom(X)
44 #endif
45
46
47 const char *filename= "test3";
48 uint tests=10,forks=10,key_cacheing=0,use_log=0;
49
50 static void get_options(int argc, char *argv[]);
51 void start_test(int id);
52 int test_read(MI_INFO *,int),test_write(MI_INFO *,int,int),
53 test_update(MI_INFO *,int,int),test_rrnd(MI_INFO *,int);
54
55 struct record {
56 uchar id[8];
57 uchar nr[4];
58 uchar text[10];
59 } record;
60
61
main(int argc,char ** argv)62 int main(int argc,char **argv)
63 {
64 int status,wait_ret;
65 uint i=0;
66 MI_KEYDEF keyinfo[10];
67 MI_COLUMNDEF recinfo[10];
68 HA_KEYSEG keyseg[10][2];
69 MY_INIT(argv[0]);
70 get_options(argc,argv);
71
72 memset(keyinfo, 0, sizeof(keyinfo));
73 memset(recinfo, 0, sizeof(recinfo));
74 memset(keyseg, 0, 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 myisam */
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 myisam-file");
102 my_delete(filename,MYF(0)); /* Remove old locks under gdb */
103 if (mi_create(filename,2,&keyinfo[0],2,&recinfo[0],0,(MI_UNIQUEDEF*) 0,
104 (MI_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 return 0;
123 }
124
125
get_options(int argc,char ** argv)126 static void get_options(int argc, char **argv)
127 {
128 char *pos,*progname;
129
130 progname= argv[0];
131
132 while (--argc >0 && *(pos = *(++argv)) == '-' ) {
133 switch(*++pos) {
134 case 'l':
135 use_log=1;
136 break;
137 case 'f':
138 forks=atoi(++pos);
139 break;
140 case 't':
141 tests=atoi(++pos);
142 break;
143 case 'K': /* Use key cacheing */
144 key_cacheing=1;
145 break;
146 case 'A': /* All flags */
147 use_log=key_cacheing=1;
148 break;
149 case '?':
150 case 'I':
151 case 'V':
152 printf("%s Ver 1.0 for %s at %s\n",progname,SYSTEM_TYPE,MACHINE_TYPE);
153 puts("By Monty, for your professional use\n");
154 puts("Test av locking with threads\n");
155 printf("Usage: %s [-?lKA] [-f#] [-t#]\n",progname);
156 exit(0);
157 case '#':
158 DBUG_PUSH (++pos);
159 break;
160 default:
161 printf("Illegal option: '%c'\n",*pos);
162 break;
163 }
164 }
165 return;
166 }
167
168
start_test(int id)169 void start_test(int id)
170 {
171 uint i;
172 int error,lock_type;
173 MI_ISAMINFO isam_info;
174 MI_INFO *file,*file1,*file2=0,*lock;
175
176 if (use_log)
177 mi_log(1);
178 if (!(file1=mi_open(filename,O_RDWR,HA_OPEN_WAIT_IF_LOCKED)) ||
179 !(file2=mi_open(filename,O_RDWR,HA_OPEN_WAIT_IF_LOCKED)))
180 {
181 fprintf(stderr,"Can't open isam-file: %s\n",filename);
182 exit(1);
183 }
184 if (key_cacheing && rnd(2) == 0)
185 init_key_cache(dflt_key_cache, KEY_CACHE_BLOCK_SIZE, 65536L, 0, 0);
186 printf("Process %d, pid: %d\n",id,getpid()); fflush(stdout);
187
188 for (error=i=0 ; i < tests && !error; i++)
189 {
190 file= (rnd(2) == 1) ? file1 : file2;
191 lock=0 ; lock_type=0;
192 if (rnd(10) == 0)
193 {
194 if (mi_lock_database(lock=(rnd(2) ? file1 : file2),
195 lock_type=(rnd(2) == 0 ? F_RDLCK : F_WRLCK)))
196 {
197 fprintf(stderr,"%2d: start: Can't lock table %d\n",id,my_errno);
198 error=1;
199 break;
200 }
201 }
202 switch (rnd(4)) {
203 case 0: error=test_read(file,id); break;
204 case 1: error=test_rrnd(file,id); break;
205 case 2: error=test_write(file,id,lock_type); break;
206 case 3: error=test_update(file,id,lock_type); break;
207 }
208 if (lock)
209 mi_lock_database(lock,F_UNLCK);
210 }
211 if (!error)
212 {
213 mi_status(file1,&isam_info,HA_STATUS_VARIABLE);
214 printf("%2d: End of test. Records: %ld Deleted: %ld\n",
215 id,(long) isam_info.records, (long) isam_info.deleted);
216 fflush(stdout);
217 }
218
219 mi_close(file1);
220 mi_close(file2);
221 if (use_log)
222 mi_log(0);
223 if (error)
224 {
225 printf("%2d: Aborted\n",id); fflush(stdout);
226 exit(1);
227 }
228 }
229
230
test_read(MI_INFO * file,int id)231 int test_read(MI_INFO *file,int id)
232 {
233 uint i,lock,found,next,prev;
234 ulong find;
235
236 lock=0;
237 if (rnd(2) == 0)
238 {
239 lock=1;
240 if (mi_lock_database(file,F_RDLCK))
241 {
242 fprintf(stderr,"%2d: Can't lock table %d\n",id,my_errno);
243 return 1;
244 }
245 }
246
247 found=next=prev=0;
248 for (i=0 ; i < 100 ; i++)
249 {
250 find=rnd(100000);
251 if (!mi_rkey(file,record.id,1,(uchar*) &find, HA_WHOLE_KEY,
252 HA_READ_KEY_EXACT))
253 found++;
254 else
255 {
256 if (my_errno != HA_ERR_KEY_NOT_FOUND)
257 {
258 fprintf(stderr,"%2d: Got error %d from read in read\n",id,my_errno);
259 return 1;
260 }
261 else if (!mi_rnext(file,record.id,1))
262 next++;
263 else
264 {
265 if (my_errno != HA_ERR_END_OF_FILE)
266 {
267 fprintf(stderr,"%2d: Got error %d from rnext in read\n",id,my_errno);
268 return 1;
269 }
270 else if (!mi_rprev(file,record.id,1))
271 prev++;
272 else
273 {
274 if (my_errno != HA_ERR_END_OF_FILE)
275 {
276 fprintf(stderr,"%2d: Got error %d from rnext in read\n",
277 id,my_errno);
278 return 1;
279 }
280 }
281 }
282 }
283 }
284 if (lock)
285 {
286 if (mi_lock_database(file,F_UNLCK))
287 {
288 fprintf(stderr,"%2d: Can't unlock table\n",id);
289 return 1;
290 }
291 }
292 printf("%2d: read: found: %5d next: %5d prev: %5d\n",
293 id,found,next,prev);
294 fflush(stdout);
295 return 0;
296 }
297
298
test_rrnd(MI_INFO * file,int id)299 int test_rrnd(MI_INFO *file,int id)
300 {
301 uint count,lock;
302
303 lock=0;
304 if (rnd(2) == 0)
305 {
306 lock=1;
307 if (mi_lock_database(file,F_RDLCK))
308 {
309 fprintf(stderr,"%2d: Can't lock table (%d)\n",id,my_errno);
310 mi_close(file);
311 return 1;
312 }
313 if (rnd(2) == 0)
314 mi_extra(file,HA_EXTRA_CACHE,0);
315 }
316
317 count=0;
318 if (mi_rrnd(file,record.id,0L))
319 {
320 if (my_errno == HA_ERR_END_OF_FILE)
321 goto end;
322 fprintf(stderr,"%2d: Can't read first record (%d)\n",id,my_errno);
323 return 1;
324 }
325 for (count=1 ; !mi_rrnd(file,record.id,HA_OFFSET_ERROR) ;count++) ;
326 if (my_errno != HA_ERR_END_OF_FILE)
327 {
328 fprintf(stderr,"%2d: Got error %d from rrnd\n",id,my_errno);
329 return 1;
330 }
331
332 end:
333 if (lock)
334 {
335 mi_extra(file,HA_EXTRA_NO_CACHE,0);
336 if (mi_lock_database(file,F_UNLCK))
337 {
338 fprintf(stderr,"%2d: Can't unlock table\n",id);
339 exit(0);
340 }
341 }
342 printf("%2d: rrnd: %5d\n",id,count); fflush(stdout);
343 return 0;
344 }
345
346
test_write(MI_INFO * file,int id,int lock_type)347 int test_write(MI_INFO *file,int id,int lock_type)
348 {
349 uint i,tries,count,lock;
350
351 lock=0;
352 if (rnd(2) == 0 || lock_type == F_RDLCK)
353 {
354 lock=1;
355 if (mi_lock_database(file,F_WRLCK))
356 {
357 if (lock_type == F_RDLCK && my_errno == EDEADLK)
358 {
359 printf("%2d: write: deadlock\n",id); fflush(stdout);
360 return 0;
361 }
362 fprintf(stderr,"%2d: Can't lock table (%d)\n",id,my_errno);
363 mi_close(file);
364 return 1;
365 }
366 if (rnd(2) == 0)
367 mi_extra(file,HA_EXTRA_WRITE_CACHE,0);
368 }
369
370 sprintf((char*) record.id,"%7d",getpid());
371 my_stpnmov((char*) record.text,"Testing...", sizeof(record.text));
372
373 tries=(uint) rnd(100)+10;
374 for (i=count=0 ; i < tries ; i++)
375 {
376 uint32 tmp=rnd(80000)+20000;
377 int4store(record.nr,tmp);
378 if (!mi_write(file,record.id))
379 count++;
380 else
381 {
382 if (my_errno != HA_ERR_FOUND_DUPP_KEY)
383 {
384 fprintf(stderr,"%2d: Got error %d (errno %d) from write\n",id,my_errno,
385 errno);
386 return 1;
387 }
388 }
389 }
390 if (lock)
391 {
392 mi_extra(file,HA_EXTRA_NO_CACHE,0);
393 if (mi_lock_database(file,F_UNLCK))
394 {
395 fprintf(stderr,"%2d: Can't unlock table\n",id);
396 exit(0);
397 }
398 }
399 printf("%2d: write: %5d\n",id,count); fflush(stdout);
400 return 0;
401 }
402
403
test_update(MI_INFO * file,int id,int lock_type)404 int test_update(MI_INFO *file,int id,int lock_type)
405 {
406 uint i,lock,found,next,prev,update;
407 uint32 tmp;
408 char find[4];
409 struct record new_record;
410
411 lock=0;
412 if (rnd(2) == 0 || lock_type == F_RDLCK)
413 {
414 lock=1;
415 if (mi_lock_database(file,F_WRLCK))
416 {
417 if (lock_type == F_RDLCK && my_errno == EDEADLK)
418 {
419 printf("%2d: write: deadlock\n",id); fflush(stdout);
420 return 0;
421 }
422 fprintf(stderr,"%2d: Can't lock table (%d)\n",id,my_errno);
423 return 1;
424 }
425 }
426 memset(&new_record, 0, sizeof(new_record));
427 my_stpcpy((char*) new_record.text,"Updated");
428
429 found=next=prev=update=0;
430 for (i=0 ; i < 100 ; i++)
431 {
432 tmp=rnd(100000);
433 int4store(find,tmp);
434 if (!mi_rkey(file,record.id,1,(uchar*) find, HA_WHOLE_KEY,
435 HA_READ_KEY_EXACT))
436 found++;
437 else
438 {
439 if (my_errno != HA_ERR_KEY_NOT_FOUND)
440 {
441 fprintf(stderr,"%2d: Got error %d from read in update\n",id,my_errno);
442 return 1;
443 }
444 else if (!mi_rnext(file,record.id,1))
445 next++;
446 else
447 {
448 if (my_errno != HA_ERR_END_OF_FILE)
449 {
450 fprintf(stderr,"%2d: Got error %d from rnext in update\n",
451 id,my_errno);
452 return 1;
453 }
454 else if (!mi_rprev(file,record.id,1))
455 prev++;
456 else
457 {
458 if (my_errno != HA_ERR_END_OF_FILE)
459 {
460 fprintf(stderr,"%2d: Got error %d from rnext in update\n",
461 id,my_errno);
462 return 1;
463 }
464 continue;
465 }
466 }
467 }
468 memcpy(new_record.id, record.id, sizeof(record.id));
469 tmp=rnd(20000)+40000;
470 int4store(new_record.nr,tmp);
471 if (!mi_update(file,record.id,new_record.id))
472 update++;
473 else
474 {
475 if (my_errno != HA_ERR_RECORD_CHANGED &&
476 my_errno != HA_ERR_RECORD_DELETED &&
477 my_errno != HA_ERR_FOUND_DUPP_KEY)
478 {
479 fprintf(stderr,"%2d: Got error %d from update\n",id,my_errno);
480 return 1;
481 }
482 }
483 }
484 if (lock)
485 {
486 if (mi_lock_database(file,F_UNLCK))
487 {
488 fprintf(stderr,"Can't unlock table,id, error%d\n",my_errno);
489 return 1;
490 }
491 }
492 printf("%2d: update: %5d\n",id,update); fflush(stdout);
493 return 0;
494 }
495
496 #include "mi_extrafunc.h"
497