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