1/* Copyright (c) 2000, 2011, Oracle and/or its affiliates.
2 Copyright (c) 2010, 2011, Monty Program Ab
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
16
17/* Test av isam-databas: stor test */
18
19#include "heapdef.h" /* Because of hp_find_block */
20#include <signal.h>
21
22#define MAX_RECORDS 100000
23#define MAX_KEYS 4
24
25static int get_options(int argc, char *argv[]);
26static int rnd(int max_value);
27static sig_handler endprog(int sig_number);
28
29static uint flag=0,verbose=0,testflag=0,recant=10000,silent=0;
30static uint keys=MAX_KEYS;
31static uint16 key1[1001];
32static my_bool key3[MAX_RECORDS];
33static int reclength=39;
34
35
36static int calc_check(uchar *buf,uint length);
37static void make_record(uchar *record, uint n1, uint n2, uint n3,
38 const char *mark, uint count);
39
40/* Main program */
41
42int main(int argc, char *argv[])
43{
44 register uint i,j;
45 uint ant,n1,n2,n3;
46 uint write_count,update,opt_delete,check2,dupp_keys,found_key;
47 int error;
48 ulong pos;
49 unsigned long key_check;
50 uchar record[128],record2[128],record3[128],key[10];
51 const char *filename,*filename2;
52 HP_INFO *file,*file2;
53 HP_SHARE *tmp_share;
54 HP_KEYDEF keyinfo[MAX_KEYS];
55 HA_KEYSEG keyseg[MAX_KEYS*5];
56 HEAP_PTR UNINIT_VAR(position);
57 HP_CREATE_INFO hp_create_info;
58 CHARSET_INFO *cs= &my_charset_latin1;
59 my_bool unused;
60 MY_INIT(argv[0]); /* init my_sys library & pthreads */
61
62 filename= "test2";
63 filename2= "test2_2";
64 file=file2=0;
65 get_options(argc,argv);
66
67 bzero(&hp_create_info, sizeof(hp_create_info));
68 hp_create_info.max_table_size= 2*1024L*1024L;
69 hp_create_info.keys= keys;
70 hp_create_info.keydef= keyinfo;
71 hp_create_info.reclength= reclength;
72 hp_create_info.max_records= (ulong) flag*100000L;
73 hp_create_info.min_records= (ulong) recant/2;
74
75 write_count=update=opt_delete=0;
76 key_check=0;
77
78 keyinfo[0].seg=keyseg;
79 keyinfo[0].keysegs=1;
80 keyinfo[0].flag= 0;
81 keyinfo[0].algorithm= HA_KEY_ALG_HASH;
82 keyinfo[0].seg[0].type=HA_KEYTYPE_BINARY;
83 keyinfo[0].seg[0].start=0;
84 keyinfo[0].seg[0].length=6;
85 keyinfo[0].seg[0].null_bit=0;
86 keyinfo[0].seg[0].charset=cs;
87 keyinfo[1].seg=keyseg+1;
88 keyinfo[1].keysegs=2;
89 keyinfo[1].flag=0;
90 keyinfo[1].algorithm= HA_KEY_ALG_HASH;
91 keyinfo[1].seg[0].type=HA_KEYTYPE_BINARY;
92 keyinfo[1].seg[0].start=7;
93 keyinfo[1].seg[0].length=6;
94 keyinfo[1].seg[0].null_bit=0;
95 keyinfo[1].seg[0].charset=cs;
96 keyinfo[1].seg[1].type=HA_KEYTYPE_TEXT;
97 keyinfo[1].seg[1].start=0; /* key in two parts */
98 keyinfo[1].seg[1].length=6;
99 keyinfo[1].seg[1].null_bit=0;
100 keyinfo[1].seg[1].charset=cs;
101 keyinfo[2].seg=keyseg+3;
102 keyinfo[2].keysegs=1;
103 keyinfo[2].flag=HA_NOSAME;
104 keyinfo[2].algorithm= HA_KEY_ALG_HASH;
105 keyinfo[2].seg[0].type=HA_KEYTYPE_BINARY;
106 keyinfo[2].seg[0].start=12;
107 keyinfo[2].seg[0].length=8;
108 keyinfo[2].seg[0].null_bit=0;
109 keyinfo[2].seg[0].charset=cs;
110 keyinfo[3].seg=keyseg+4;
111 keyinfo[3].keysegs=1;
112 keyinfo[3].flag=HA_NOSAME;
113 keyinfo[3].algorithm= HA_KEY_ALG_HASH;
114 keyinfo[3].seg[0].type=HA_KEYTYPE_BINARY;
115 keyinfo[3].seg[0].start=37;
116 keyinfo[3].seg[0].length=1;
117 keyinfo[3].seg[0].null_bit=1;
118 keyinfo[3].seg[0].null_pos=38;
119 keyinfo[3].seg[0].charset=cs;
120
121 bzero((char*) key1,sizeof(key1));
122 bzero((char*) key3,sizeof(key3));
123
124 printf("- Creating heap-file\n");
125 if (heap_create(filename, &hp_create_info, &tmp_share, &unused) ||
126 !(file= heap_open(filename, 2)))
127 goto err;
128 signal(SIGINT,endprog);
129
130 printf("- Writing records:s\n");
131 strmov((char*) record," ..... key");
132
133 for (i=0 ; i < recant ; i++)
134 {
135 n1=rnd(1000); n2=rnd(100); n3=rnd(MY_MIN(recant*5,MAX_RECORDS));
136 make_record(record,n1,n2,n3,"Pos",write_count);
137
138 if (heap_write(file,record))
139 {
140 if (my_errno != HA_ERR_FOUND_DUPP_KEY || key3[n3] == 0)
141 {
142 printf("Error: %d in write at record: %d\n",my_errno,i);
143 goto err;
144 }
145 if (verbose) printf(" Double key: %d\n",n3);
146 }
147 else
148 {
149 if (key3[n3] == 1)
150 {
151 printf("Error: Didn't get error when writing second key: '%8d'\n",n3);
152 goto err;
153 }
154 write_count++; key1[n1]++; key3[n3]=1;
155 key_check+=n1;
156 }
157 if (testflag == 1 && heap_check_heap(file,0))
158 {
159 puts("Heap keys crashed");
160 goto err;
161 }
162 }
163 if (testflag == 1)
164 goto end;
165 if (heap_check_heap(file,0))
166 {
167 puts("Heap keys crashed");
168 goto err;
169 }
170
171 printf("- Delete\n");
172 for (i=0 ; i < write_count/10 ; i++)
173 {
174 for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ;
175 if (j != 0)
176 {
177 sprintf((char*) key,"%6d",j);
178 if (heap_rkey(file,record,0,key,6, HA_READ_KEY_EXACT))
179 {
180 printf("can't find key1: \"%s\"\n",(char*) key);
181 goto err;
182 }
183 if (heap_delete(file,record))
184 {
185 printf("error: %d; can't delete record: \"%s\"\n", my_errno,(char*) record);
186 goto err;
187 }
188 opt_delete++;
189 key1[atoi((char*) record+keyinfo[0].seg[0].start)]--;
190 key3[atoi((char*) record+keyinfo[2].seg[0].start)]=0;
191 key_check-=atoi((char*) record);
192 if (testflag == 2 && heap_check_heap(file,0))
193 {
194 puts("Heap keys crashed");
195 goto err;
196 }
197 }
198 else
199 puts("Warning: Skipping delete test because no dupplicate keys");
200 }
201 if (testflag==2) goto end;
202 if (heap_check_heap(file,0))
203 {
204 puts("Heap keys crashed");
205 goto err;
206 }
207
208 printf("- Update\n");
209 for (i=0 ; i < write_count/10 ; i++)
210 {
211 n1=rnd(1000); n2=rnd(100); n3=rnd(MY_MIN(recant*2,MAX_RECORDS));
212 make_record(record2, n1, n2, n3, "XXX", update);
213 if (rnd(2) == 1)
214 {
215 if (heap_scan_init(file))
216 goto err;
217 j=rnd(write_count-opt_delete);
218 while ((error=heap_scan(file,record) == HA_ERR_RECORD_DELETED) ||
219 (!error && j))
220 {
221 if (!error)
222 j--;
223 }
224 if (error)
225 goto err;
226 }
227 else
228 {
229 for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ;
230 if (!key1[j])
231 continue;
232 sprintf((char*) key,"%6d",j);
233 if (heap_rkey(file,record,0,key,6, HA_READ_KEY_EXACT))
234 {
235 printf("can't find key1: \"%s\"\n",(char*) key);
236 goto err;
237 }
238 }
239 if (heap_update(file,record,record2))
240 {
241 if (my_errno != HA_ERR_FOUND_DUPP_KEY || key3[n3] == 0)
242 {
243 printf("error: %d; can't update:\nFrom: \"%s\"\nTo: \"%s\"\n",
244 my_errno,(char*) record, (char*) record2);
245 goto err;
246 }
247 if (verbose)
248 printf("Double key when tried to update:\nFrom: \"%s\"\nTo: \"%s\"\n",
249 (char*) record, (char*) record2);
250 }
251 else
252 {
253 key1[atoi((char*) record+keyinfo[0].seg[0].start)]--;
254 key3[atoi((char*) record+keyinfo[2].seg[0].start)]=0;
255 key1[n1]++; key3[n3]=1;
256 update++;
257 key_check=key_check-atoi((char*) record)+n1;
258 }
259 if (testflag == 3 && heap_check_heap(file,0))
260 {
261 puts("Heap keys crashed");
262 goto err;
263 }
264 }
265 if (testflag == 3) goto end;
266 if (heap_check_heap(file,0))
267 {
268 puts("Heap keys crashed");
269 goto err;
270 }
271
272 for (i=999, dupp_keys=found_key=0 ; i>0 ; i--)
273 {
274 if (key1[i] > dupp_keys) { dupp_keys=key1[i]; found_key=i; }
275 sprintf((char*) key,"%6d",found_key);
276 }
277
278 if (dupp_keys > 3)
279 {
280 if (!silent)
281 printf("- Read first key - next - delete - next -> last\n");
282 DBUG_PRINT("progpos",("first - next - delete - next -> last"));
283
284 if (heap_rkey(file,record,0,key,6, HA_READ_KEY_EXACT))
285 goto err;
286 if (heap_rnext(file,record3)) goto err;
287 if (heap_delete(file,record3)) goto err;
288 key_check-=atoi((char*) record3);
289 key1[atoi((char*) record+keyinfo[0].seg[0].start)]--;
290 key3[atoi((char*) record+keyinfo[2].seg[0].start)]=0;
291 opt_delete++;
292 ant=2;
293 while ((error=heap_rnext(file,record3)) == 0 ||
294 error == HA_ERR_RECORD_DELETED)
295 if (! error)
296 ant++;
297 if (ant != dupp_keys)
298 {
299 printf("next: I can only find: %d records of %d\n",
300 ant,dupp_keys);
301 goto end;
302 }
303 dupp_keys--;
304 if (heap_check_heap(file,0))
305 {
306 puts("Heap keys crashed");
307 goto err;
308 }
309
310 if (!silent)
311 printf("- Read last key - delete - prev - prev - opt_delete - prev -> first\n");
312
313 if (heap_rprev(file,record))
314 goto err;
315 if (heap_delete(file,record3)) goto err;
316 key_check-=atoi((char*) record3);
317 key1[atoi((char*) record+keyinfo[0].seg[0].start)]--;
318 key3[atoi((char*) record+keyinfo[2].seg[0].start)]=0;
319 opt_delete++;
320 if (heap_rprev(file,record3) || heap_rprev(file,record3))
321 goto err;
322 if (heap_delete(file,record3)) goto err;
323 key_check-=atoi((char*) record3);
324 key1[atoi((char*) record+keyinfo[0].seg[0].start)]--;
325 key3[atoi((char*) record+keyinfo[2].seg[0].start)]=0;
326 opt_delete++;
327 ant=3;
328 while ((error=heap_rprev(file,record3)) == 0 ||
329 error == HA_ERR_RECORD_DELETED)
330 {
331 if (! error)
332 ant++;
333 }
334 if (ant != dupp_keys)
335 {
336 printf("next: I can only find: %d records of %d\n",
337 ant,dupp_keys);
338 goto end;
339 }
340 dupp_keys-=2;
341 if (heap_check_heap(file,0))
342 {
343 puts("Heap keys crashed");
344 goto err;
345 }
346 }
347 else
348 puts("Warning: Not enough duplicated keys: Skipping delete key check");
349
350 if (!silent)
351 printf("- Read (first) - next - delete - next -> last\n");
352 DBUG_PRINT("progpos",("first - next - delete - next -> last"));
353
354 if (heap_scan_init(file))
355 goto err;
356 while ((error=heap_scan(file,record3) == HA_ERR_RECORD_DELETED)) ;
357 if (error)
358 goto err;
359 if (heap_delete(file,record3)) goto err;
360 key_check-=atoi((char*) record3);
361 opt_delete++;
362 key1[atoi((char*) record+keyinfo[0].seg[0].start)]--;
363 key3[atoi((char*) record+keyinfo[2].seg[0].start)]=0;
364 ant=0;
365 while ((error=heap_scan(file,record3)) == 0 ||
366 error == HA_ERR_RECORD_DELETED)
367 if (! error)
368 ant++;
369 if (ant != write_count-opt_delete)
370 {
371 printf("next: Found: %d records of %d\n",ant,write_count-opt_delete);
372 goto end;
373 }
374 if (heap_check_heap(file,0))
375 {
376 puts("Heap keys crashed");
377 goto err;
378 }
379
380 puts("- Test if: Read rrnd - same - rkey - same");
381 DBUG_PRINT("progpos",("Read rrnd - same"));
382 pos=rnd(write_count-opt_delete-5)+5;
383 heap_scan_init(file);
384 i=5;
385 while ((error=heap_scan(file,record)) == HA_ERR_RECORD_DELETED ||
386 (error == 0 && pos))
387 {
388 if (!error)
389 pos--;
390 if (i-- == 0)
391 {
392 bmove(record3,record,reclength);
393 position=heap_position(file);
394 }
395 }
396 if (error)
397 goto err;
398 bmove(record2,record,reclength);
399 if (heap_rsame(file,record,-1) || heap_rsame(file,record2,2))
400 goto err;
401 if (memcmp(record2,record,reclength))
402 {
403 puts("heap_rsame didn't find right record");
404 goto end;
405 }
406
407 puts("- Test of read through position");
408 if (heap_rrnd(file,record,position))
409 goto err;
410 if (memcmp(record3,record,reclength))
411 {
412 puts("heap_frnd didn't find right record");
413 goto end;
414 }
415
416 printf("- heap_info\n");
417 {
418 HEAPINFO info;
419 heap_info(file,&info,0);
420 /* We have to test with opt_delete +1 as this may be the case if the last
421 inserted row was a duplicate key */
422 if (info.records != write_count-opt_delete ||
423 (info.deleted != opt_delete && info.deleted != opt_delete+1))
424 {
425 puts("Wrong info from heap_info");
426 printf("Got: records: %ld(%d) deleted: %ld(%d)\n",
427 info.records,write_count-opt_delete,info.deleted,opt_delete);
428 }
429 }
430
431 printf("- Read through all records with scan\n");
432 if (heap_reset(file) || heap_extra(file,HA_EXTRA_CACHE))
433 {
434 puts("got error from heap_extra");
435 goto end;
436 }
437 ant=check2=0;
438 heap_scan_init(file);
439 while ((error=heap_scan(file,record)) != HA_ERR_END_OF_FILE &&
440 ant < write_count + 10)
441 {
442 if (!error)
443 {
444 ant++;
445 check2+=calc_check(record,reclength);
446 }
447 }
448 if (ant != write_count-opt_delete)
449 {
450 printf("scan: I can only find: %d records of %d\n", ant,
451 write_count-opt_delete);
452 goto end;
453 }
454
455 if (heap_extra(file,HA_EXTRA_NO_CACHE))
456 {
457 puts("got error from heap_extra(HA_EXTRA_NO_CACHE)");
458 goto end;
459 }
460
461 for (i=999, dupp_keys=found_key=0 ; i>0 ; i--)
462 {
463 if (key1[i] > dupp_keys) { dupp_keys=key1[i]; found_key=i; }
464 sprintf((char*) key,"%6d",found_key);
465 }
466 printf("- Read through all keys with first-next-last-prev\n");
467 ant=0;
468 for (error=heap_rkey(file,record,0,key,6, HA_READ_KEY_EXACT);
469 ! error ;
470 error=heap_rnext(file,record))
471 ant++;
472 if (ant != dupp_keys)
473 {
474 printf("first-next: I can only find: %d records of %d\n", ant,
475 dupp_keys);
476 goto end;
477 }
478
479 ant=0;
480 for (error=heap_rprev(file,record) ;
481 ! error ;
482 error=heap_rprev(file,record))
483 {
484 ant++;
485 check2+=calc_check(record,reclength);
486 }
487 if (ant != dupp_keys)
488 {
489 printf("last-prev: I can only find: %d records of %d\n", ant,
490 dupp_keys);
491 goto end;
492 }
493
494 if (testflag == 4) goto end;
495
496 printf("- Reading through all rows through keys\n");
497 if (!(file2=heap_open(filename, 2)))
498 goto err;
499 if (heap_scan_init(file))
500 goto err;
501 while ((error=heap_scan(file,record)) != HA_ERR_END_OF_FILE)
502 {
503 if (error == 0)
504 {
505 if (heap_rkey(file2,record2,2,record+keyinfo[2].seg[0].start,8,
506 HA_READ_KEY_EXACT))
507 {
508 printf("can't find key3: \"%.8s\"\n",
509 record+keyinfo[2].seg[0].start);
510 goto err;
511 }
512 }
513 }
514 heap_close(file2);
515
516 printf("- Creating output heap-file 2\n");
517 hp_create_info.keys= 1;
518 hp_create_info.max_records= 0;
519 hp_create_info.min_records= 0;
520 if (heap_create(filename2, &hp_create_info, &tmp_share, &unused) ||
521 !(file2= heap_open_from_share_and_register(tmp_share, 2)))
522 goto err;
523
524 printf("- Copying and removing records\n");
525 if (heap_scan_init(file))
526 goto err;
527 while ((error=heap_scan(file,record)) != HA_ERR_END_OF_FILE)
528 {
529 if (error == 0)
530 {
531 if (heap_write(file2,record))
532 goto err;
533 key_check-=atoi((char*) record);
534 write_count++;
535 if (heap_delete(file,record))
536 goto err;
537 opt_delete++;
538 }
539 pos++;
540 }
541 printf("- Checking heap tables\n");
542 if (heap_check_heap(file,1) || heap_check_heap(file2,1))
543 {
544 puts("Heap keys crashed");
545 goto err;
546 }
547
548 if (my_errno != HA_ERR_END_OF_FILE)
549 printf("error: %d from heap_rrnd\n",my_errno);
550 if (key_check)
551 printf("error: Some read got wrong: check is %ld\n",(long) key_check);
552
553end:
554 printf("\nFollowing test have been made:\n");
555 printf("Write records: %d\nUpdate records: %d\nDelete records: %d\n", write_count,update,opt_delete);
556 heap_clear(file);
557 if (heap_close(file) || (file2 && heap_close(file2)))
558 goto err;
559 heap_delete_table(filename2);
560 hp_panic(HA_PANIC_CLOSE);
561 my_end(MY_GIVE_INFO);
562 return(0);
563err:
564 printf("Got error: %d when using heap-database\n",my_errno);
565 (void) heap_close(file);
566 return(1);
567} /* main */
568
569
570 /* Read options */
571
572static int get_options(int argc,char *argv[])
573{
574 char *pos,*progname;
575
576 progname= argv[0];
577
578 while (--argc >0 && *(pos = *(++argv)) == '-' ) {
579 switch(*++pos) {
580 case 'B': /* Big file */
581 flag=1;
582 break;
583 case 'v': /* verbose */
584 verbose=1;
585 break;
586 case 'm': /* records */
587 recant=atoi(++pos);
588 break;
589 case 's':
590 silent=1;
591 break;
592 case 't':
593 testflag=atoi(++pos); /* testmod */
594 break;
595 case 'V':
596 case 'I':
597 case '?':
598 printf("%s Ver 1.2 for %s at %s\n",progname,SYSTEM_TYPE,MACHINE_TYPE);
599 puts("TCX Datakonsult AB, by Monty, for your professional use\n");
600 printf("Usage: %s [-?ABIKLsWv] [-m#] [-t#]\n",progname);
601 exit(0);
602 case '#':
603 DBUG_PUSH (++pos);
604 break;
605 }
606 }
607 return 0;
608} /* get options */
609
610 /* Generate a random value in intervall 0 <=x <= n */
611
612static int rnd(int max_value)
613{
614 return (int) ((rand() & 32767)/32767.0*max_value);
615} /* rnd */
616
617
618static sig_handler endprog(int sig_number __attribute__((unused)))
619{
620 {
621 hp_panic(HA_PANIC_CLOSE);
622 my_end(1);
623 exit(1);
624 }
625}
626
627static int calc_check(uchar *buf, uint length)
628{
629 int check=0;
630 while (length--)
631 check+= (int) (uchar) *(buf++);
632 return check;
633}
634
635static void make_record(uchar *record, uint n1, uint n2, uint n3,
636 const char *mark, uint count)
637{
638 bfill(record,reclength,' ');
639 sprintf((char*) record,"%6d:%4d:%8d:%3.3s: %4d",
640 n1,n2,n3,mark,count);
641 record[37]='A'; /* Store A in null key */
642 record[38]=1; /* set as null */
643}
644