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" |