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 02111-1301 USA */
15
16/* Test av isam-databas: stor test */
17
18#ifndef USE_MY_FUNC /* We want to be able to dbug this !! */
19#define USE_MY_FUNC
20#endif
21#include "maria_def.h"
22#include "trnman.h"
23#include <m_ctype.h>
24#include <my_bit.h>
25#include "ma_checkpoint.h"
26
27#define STANDARD_LENGTH 37
28#define MARIA_KEYS 6
29#define MAX_PARTS 4
30
31static void get_options(int argc, char *argv[]);
32static uint rnd(uint max_value);
33static void fix_length(uchar *record,uint length);
34static void put_blob_in_record(uchar *blob_pos,char **blob_buffer,
35 ulong *length);
36static void copy_key(MARIA_HA *info, uint inx, uchar *record, uchar *key);
37
38static int verbose= 0, testflag= 0, first_key= 0, async_io= 0, pagecacheing= 0;
39static int write_cacheing= 0, do_locking= 0, rec_pointer_size= 0;
40static int silent= 0, opt_quick_mode= 0, transactional= 0, skip_update= 0;
41static int die_in_middle_of_transaction= 0, pack_fields= 1;
42static int pack_seg= HA_SPACE_PACK, pack_type= HA_PACK_KEY, remove_count= -1;
43static int create_flag= 0, srand_arg= 0, checkpoint= 0;
44static my_bool opt_versioning= 0;
45static uint use_blob= 0, update_count= 0;
46static ulong pagecache_size=8192*32;
47static enum data_file_type record_type= DYNAMIC_RECORD;
48
49static uint keys=MARIA_KEYS,recant=1000;
50static uint16 key1[1001],key3[5001];
51static uchar record[300],record2[300],key[100],key2[100];
52static uchar read_record[300],read_record2[300],read_record3[300];
53static HA_KEYSEG glob_keyseg[MARIA_KEYS][MAX_PARTS];
54
55 /* Test program */
56
57int main(int argc, char *argv[])
58{
59 uint i;
60 int j,n1,n2,n3,error,k;
61 uint write_count,update,dupp_keys,opt_delete,start,length,blob_pos,
62 reclength,ant,found_parts;
63 my_off_t lastpos;
64 ha_rows range_records,records;
65 MARIA_HA *file;
66 MARIA_KEYDEF keyinfo[10];
67 MARIA_COLUMNDEF recinfo[10];
68 MARIA_INFO info;
69 char *blob_buffer;
70 MARIA_CREATE_INFO create_info;
71 char filename[FN_REFLEN];
72
73#ifdef SAFE_MUTEX
74 safe_mutex_deadlock_detector= 1;
75#endif
76 MY_INIT(argv[0]);
77
78 maria_data_root= (char *)".";
79 get_options(argc,argv);
80 fn_format(filename, "test2", maria_data_root, "", MYF(0));
81
82 if (! async_io)
83 my_disable_async_io=1;
84
85 /* If we sync or not have no affect on this test */
86 my_disable_sync= 1;
87
88 /* Maria requires that we always have a page cache */
89 if (maria_init() ||
90 (init_pagecache(maria_pagecache, pagecache_size, 0, 0,
91 maria_block_size, 0, MY_WME) == 0) ||
92 ma_control_file_open(TRUE, TRUE) ||
93 (init_pagecache(maria_log_pagecache,
94 TRANSLOG_PAGECACHE_SIZE, 0, 0,
95 TRANSLOG_PAGE_SIZE, 0, MY_WME) == 0) ||
96 translog_init(maria_data_root, TRANSLOG_FILE_SIZE,
97 0, 0, maria_log_pagecache,
98 TRANSLOG_DEFAULT_FLAGS, 0) ||
99 (transactional && (trnman_init(0) || ma_checkpoint_init(0))))
100 {
101 fprintf(stderr, "Error in initialization");
102 exit(1);
103 }
104 if (opt_versioning)
105 init_thr_lock();
106
107 reclength=STANDARD_LENGTH+60+(use_blob ? 8 : 0);
108 blob_pos=STANDARD_LENGTH+60;
109 keyinfo[0].seg= &glob_keyseg[0][0];
110 keyinfo[0].seg[0].start=0;
111 keyinfo[0].seg[0].length=6;
112 keyinfo[0].seg[0].type=HA_KEYTYPE_TEXT;
113 keyinfo[0].seg[0].language= default_charset_info->number;
114 keyinfo[0].seg[0].flag=(uint8) pack_seg;
115 keyinfo[0].seg[0].null_bit=0;
116 keyinfo[0].seg[0].null_pos=0;
117 keyinfo[0].key_alg=HA_KEY_ALG_BTREE;
118 keyinfo[0].keysegs=1;
119 keyinfo[0].flag = pack_type;
120 keyinfo[0].block_length= 0; /* Default block length */
121 keyinfo[1].seg= &glob_keyseg[1][0];
122 keyinfo[1].seg[0].start=7;
123 keyinfo[1].seg[0].length=6;
124 keyinfo[1].seg[0].type=HA_KEYTYPE_BINARY;
125 keyinfo[1].seg[0].flag=0;
126 keyinfo[1].seg[0].null_bit=0;
127 keyinfo[1].seg[0].null_pos=0;
128 keyinfo[1].seg[1].start=0; /* two part key */
129 keyinfo[1].seg[1].length=6;
130 keyinfo[1].seg[1].type=HA_KEYTYPE_NUM;
131 keyinfo[1].seg[1].flag=HA_REVERSE_SORT;
132 keyinfo[1].seg[1].null_bit=0;
133 keyinfo[1].seg[1].null_pos=0;
134 keyinfo[1].key_alg=HA_KEY_ALG_BTREE;
135 keyinfo[1].keysegs=2;
136 keyinfo[1].flag =0;
137 keyinfo[1].block_length= MARIA_MIN_KEY_BLOCK_LENGTH; /* Diff blocklength */
138 keyinfo[2].seg= &glob_keyseg[2][0];
139 keyinfo[2].seg[0].start=12;
140 keyinfo[2].seg[0].length=8;
141 keyinfo[2].seg[0].type=HA_KEYTYPE_BINARY;
142 keyinfo[2].seg[0].flag=HA_REVERSE_SORT;
143 keyinfo[2].seg[0].null_bit=0;
144 keyinfo[2].seg[0].null_pos=0;
145 keyinfo[2].key_alg=HA_KEY_ALG_BTREE;
146 keyinfo[2].keysegs=1;
147 keyinfo[2].flag =HA_NOSAME;
148 keyinfo[2].block_length= 0; /* Default block length */
149 keyinfo[3].seg= &glob_keyseg[3][0];
150 keyinfo[3].seg[0].start=0;
151 keyinfo[3].seg[0].length=reclength-(use_blob ? 8 : 0);
152 keyinfo[3].seg[0].type=HA_KEYTYPE_TEXT;
153 keyinfo[3].seg[0].language=default_charset_info->number;
154 keyinfo[3].seg[0].flag=(uint8) pack_seg;
155 keyinfo[3].seg[0].null_bit=0;
156 keyinfo[3].seg[0].null_pos=0;
157 keyinfo[3].key_alg=HA_KEY_ALG_BTREE;
158 keyinfo[3].keysegs=1;
159 keyinfo[3].flag = pack_type;
160 keyinfo[3].block_length= 0; /* Default block length */
161 keyinfo[4].seg= &glob_keyseg[4][0];
162 keyinfo[4].seg[0].start=0;
163 keyinfo[4].seg[0].length=5;
164 keyinfo[4].seg[0].type=HA_KEYTYPE_TEXT;
165 keyinfo[4].seg[0].language=default_charset_info->number;
166 keyinfo[4].seg[0].flag=0;
167 keyinfo[4].seg[0].null_bit=0;
168 keyinfo[4].seg[0].null_pos=0;
169 keyinfo[4].key_alg=HA_KEY_ALG_BTREE;
170 keyinfo[4].keysegs=1;
171 keyinfo[4].flag = pack_type;
172 keyinfo[4].block_length= 0; /* Default block length */
173 keyinfo[5].seg= &glob_keyseg[5][0];
174 keyinfo[5].seg[0].start=0;
175 keyinfo[5].seg[0].length=4;
176 keyinfo[5].seg[0].type=HA_KEYTYPE_TEXT;
177 keyinfo[5].seg[0].language=default_charset_info->number;
178 keyinfo[5].seg[0].flag=pack_seg;
179 keyinfo[5].seg[0].null_bit=0;
180 keyinfo[5].seg[0].null_pos=0;
181 keyinfo[5].key_alg=HA_KEY_ALG_BTREE;
182 keyinfo[5].keysegs=1;
183 keyinfo[5].flag = pack_type;
184 keyinfo[5].block_length= 0; /* Default block length */
185
186 recinfo[0].type=pack_fields ? FIELD_SKIP_PRESPACE : 0;
187 recinfo[0].length=7;
188 recinfo[0].null_bit=0;
189 recinfo[0].null_pos=0;
190 recinfo[1].type=pack_fields ? FIELD_SKIP_PRESPACE : 0;
191 recinfo[1].length=5;
192 recinfo[1].null_bit=0;
193 recinfo[1].null_pos=0;
194 recinfo[2].type=pack_fields ? FIELD_SKIP_PRESPACE : 0;
195 recinfo[2].length=9;
196 recinfo[2].null_bit=0;
197 recinfo[2].null_pos=0;
198 recinfo[3].type=FIELD_NORMAL;
199 recinfo[3].length=STANDARD_LENGTH-7-5-9-4;
200 recinfo[3].null_bit=0;
201 recinfo[3].null_pos=0;
202 recinfo[4].type=pack_fields ? FIELD_SKIP_ZERO : 0;
203 recinfo[4].length=4;
204 recinfo[4].null_bit=0;
205 recinfo[4].null_pos=0;
206 recinfo[5].type=pack_fields ? FIELD_SKIP_ENDSPACE : 0;
207 recinfo[5].length=60;
208 recinfo[5].null_bit=0;
209 recinfo[5].null_pos=0;
210 if (use_blob)
211 {
212 recinfo[6].type=FIELD_BLOB;
213 recinfo[6].length=4+portable_sizeof_char_ptr;
214 recinfo[6].null_bit=0;
215 recinfo[6].null_pos=0;
216 }
217
218 write_count=update=dupp_keys=opt_delete=0;
219 blob_buffer=0;
220
221 for (i=1000 ; i>0 ; i--) key1[i]=0;
222 for (i=5000 ; i>0 ; i--) key3[i]=0;
223
224 if (!silent)
225 printf("- Creating maria-file\n");
226 file= 0;
227 bzero((char*) &create_info,sizeof(create_info));
228 create_info.max_rows=(ha_rows) (rec_pointer_size ?
229 (1L << (rec_pointer_size*8))/
230 reclength : 0);
231 create_info.reloc_rows=(ha_rows) 100;
232 create_info.transactional= transactional;
233 if (maria_create(filename, record_type, keys,&keyinfo[first_key],
234 use_blob ? 7 : 6, &recinfo[0],
235 0,(MARIA_UNIQUEDEF*) 0,
236 &create_info,create_flag))
237 goto err;
238 if (!(file=maria_open(filename,2,HA_OPEN_ABORT_IF_LOCKED)))
239 goto err;
240 maria_begin(file);
241 if (opt_versioning)
242 maria_versioning(file, 1);
243 if (testflag == 1)
244 goto end;
245 if (checkpoint == 1 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
246 goto err;
247 if (!silent)
248 printf("- Writing key:s\n");
249 if (do_locking)
250 maria_lock_database(file,F_WRLCK);
251 if (write_cacheing)
252 maria_extra(file,HA_EXTRA_WRITE_CACHE,0);
253 if (opt_quick_mode)
254 maria_extra(file,HA_EXTRA_QUICK,0);
255
256 for (i=0 ; i < recant ; i++)
257 {
258 ulong blob_length;
259 n1=rnd(1000); n2=rnd(100); n3=rnd(5000);
260 sprintf((char*) record,"%6d:%4d:%8d:Pos: %4d ",n1,n2,n3,write_count);
261 int4store(record+STANDARD_LENGTH-4,(long) i);
262 fix_length(record,(uint) STANDARD_LENGTH+rnd(60));
263 put_blob_in_record(record+blob_pos,&blob_buffer, &blob_length);
264 DBUG_PRINT("test",("record: %d blob_length: %lu", i, blob_length));
265
266 if (maria_write(file,record))
267 {
268 if (my_errno != HA_ERR_FOUND_DUPP_KEY || key3[n3] == 0)
269 {
270 printf("Error: %d in write at record: %d\n",my_errno,i);
271 goto err;
272 }
273 if (verbose) printf(" Double key: %d at record# %d\n", n3, i);
274 }
275 else
276 {
277 if (key3[n3] == 1 && first_key <3 && first_key+keys >= 3)
278 {
279 printf("Error: Didn't get error when writing second key: '%8d'\n",n3);
280 goto err2;
281 }
282 write_count++; key1[n1]++; key3[n3]=1;
283 }
284
285 /* Check if we can find key without flushing database */
286 if (i % 10 == 0)
287 {
288 for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ;
289 if (!j)
290 for (j=999 ; j>0 && key1[j] == 0 ; j--) ;
291 sprintf((char*) key,"%6d",j);
292 if (maria_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT))
293 {
294 printf("Test in loop: Can't find key: \"%s\"\n",key);
295 goto err;
296 }
297 }
298 }
299 if (checkpoint == 2 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
300 goto err;
301
302 if (write_cacheing)
303 {
304 if (maria_extra(file,HA_EXTRA_NO_CACHE,0))
305 {
306 puts("got error from maria_extra(HA_EXTRA_NO_CACHE)");
307 goto err;
308 }
309 }
310
311 if (testflag == 2)
312 goto end;
313
314#ifdef REMOVE_WHEN_WE_HAVE_RESIZE
315 if (pagecacheing)
316 resize_pagecache(maria_pagecache, maria_block_size,
317 pagecache_size * 2, 0, 0);
318#endif
319 if (!silent)
320 printf("- Delete\n");
321 if (srand_arg)
322 srand(srand_arg);
323 if (!update_count)
324 update_count= recant/10;
325
326 for (i=0 ; i < update_count ; i++)
327 {
328 for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ;
329 if (j != 0)
330 {
331 sprintf((char*) key,"%6d",j);
332 if (maria_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT))
333 {
334 printf("can't find key1: \"%s\"\n",key);
335 goto err;
336 }
337 if (bcmp(read_record+keyinfo[0].seg[0].start,
338 key, keyinfo[0].seg[0].length))
339 {
340 printf("Found wrong record when searching for key: \"%s\"\n",key);
341 goto err2;
342 }
343 if (opt_delete == (uint) remove_count) /* While testing */
344 goto end;
345 if (maria_delete(file,read_record))
346 {
347 printf("error: %d; can't delete record: \"%s\"\n", my_errno,read_record);
348 goto err;
349 }
350 opt_delete++;
351 key1[atoi((char*) read_record+keyinfo[0].seg[0].start)]--;
352 key3[atoi((char*) read_record+keyinfo[2].seg[0].start)]=0;
353 }
354 else
355 {
356 puts("Warning: Skipping delete test because no dupplicate keys");
357 break;
358 }
359 }
360 if (testflag == 3)
361 goto end;
362 if (checkpoint == 3 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
363 goto err;
364
365 if (!silent)
366 printf("- Update\n");
367 if (srand_arg)
368 srand(srand_arg);
369 if (!update_count)
370 update_count= recant/10;
371
372 for (i=0 ; i < update_count ; i++)
373 {
374 n1=rnd(1000); n2=rnd(100); n3=rnd(5000);
375 sprintf((char*) record2,"%6d:%4d:%8d:XXX: %4d ",n1,n2,n3,update);
376 int4store(record2+STANDARD_LENGTH-4,(long) i);
377 fix_length(record2,(uint) STANDARD_LENGTH+rnd(60));
378
379 for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ;
380 if (j != 0)
381 {
382 sprintf((char*) key,"%6d",j);
383 if (maria_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT))
384 {
385 printf("can't find key1: \"%s\"\n", (char*) key);
386 goto err;
387 }
388 if (bcmp(read_record+keyinfo[0].seg[0].start,
389 key, keyinfo[0].seg[0].length))
390 {
391 printf("Found wrong record when searching for key: \"%s\"; Found \"%.*s\"\n",
392 key, keyinfo[0].seg[0].length,
393 read_record+keyinfo[0].seg[0].start);
394 goto err2;
395 }
396 if (use_blob)
397 {
398 ulong blob_length;
399 if (i & 1)
400 put_blob_in_record(record2+blob_pos,&blob_buffer, &blob_length);
401 else
402 bmove(record2+blob_pos, read_record+blob_pos, 4 + sizeof(char*));
403 }
404 if (skip_update)
405 continue;
406 if (maria_update(file,read_record,record2))
407 {
408 if (my_errno != HA_ERR_FOUND_DUPP_KEY || key3[n3] == 0)
409 {
410 printf("error: %d; can't update:\nFrom: \"%s\"\nTo: \"%s\"\n",
411 my_errno,read_record,record2);
412 goto err;
413 }
414 if (verbose)
415 printf("Double key when tried to update:\nFrom: \"%s\"\nTo: \"%s\"\n",record,record2);
416 }
417 else
418 {
419 key1[atoi((char*) read_record+keyinfo[0].seg[0].start)]--;
420 key3[atoi((char*) read_record+keyinfo[2].seg[0].start)]=0;
421 key1[n1]++; key3[n3]=1;
422 update++;
423 }
424 }
425 }
426 if (testflag == 4)
427 goto end;
428 if (checkpoint == 4 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
429 goto err;
430
431 for (i=999, dupp_keys=j=0 ; i>0 ; i--)
432 {
433 if (key1[i] > dupp_keys)
434 {
435 dupp_keys=key1[i]; j=i;
436 }
437 }
438 sprintf((char*) key,"%6d",j);
439 start=keyinfo[0].seg[0].start;
440 length=keyinfo[0].seg[0].length;
441 if (dupp_keys)
442 {
443 if (!silent)
444 printf("- Same key: first - next -> last - prev -> first\n");
445 DBUG_PRINT("progpos",("first - next -> last - prev -> first"));
446 if (verbose) printf(" Using key: \"%s\" Keys: %d\n",key,dupp_keys);
447
448 if (maria_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT))
449 goto err;
450 if (maria_rsame(file,read_record2,-1))
451 goto err;
452 if (memcmp(read_record,read_record2,reclength) != 0)
453 {
454 printf("maria_rsame didn't find same record\n");
455 goto err2;
456 }
457 info.recpos=maria_position(file);
458 if (maria_rfirst(file,read_record2,0) ||
459 maria_rsame_with_pos(file,read_record2,0,info.recpos) ||
460 memcmp(read_record,read_record2,reclength) != 0)
461 {
462 printf("maria_rsame_with_pos didn't find same record\n");
463 goto err2;
464 }
465 {
466 int skr;
467 info.recpos= maria_position(file);
468 skr= maria_rnext(file,read_record2,0);
469 if ((skr && my_errno != HA_ERR_END_OF_FILE) ||
470 maria_rprev(file,read_record2,0) ||
471 memcmp(read_record,read_record2,reclength) != 0 ||
472 info.recpos != maria_position(file))
473 {
474 printf("maria_rsame_with_pos lost position\n");
475 goto err;
476 }
477 }
478 ant=1;
479 while (maria_rnext(file,read_record2,0) == 0 &&
480 memcmp(read_record2+start,key,length) == 0) ant++;
481 if (ant != dupp_keys)
482 {
483 printf("next: Found: %d keys of %d\n",ant,dupp_keys);
484 goto err2;
485 }
486 ant=0;
487 while (maria_rprev(file,read_record3,0) == 0 &&
488 bcmp(read_record3+start,key,length) == 0) ant++;
489 if (ant != dupp_keys)
490 {
491 printf("prev: Found: %d records of %d\n",ant,dupp_keys);
492 goto err2;
493 }
494
495 /* Check of maria_rnext_same */
496 if (maria_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT))
497 goto err;
498 ant=1;
499 while (!maria_rnext_same(file,read_record3) && ant < dupp_keys+10)
500 ant++;
501 if (ant != dupp_keys || my_errno != HA_ERR_END_OF_FILE)
502 {
503 printf("maria_rnext_same: Found: %d records of %d\n",ant,dupp_keys);
504 goto err2;
505 }
506 }
507
508 if (!silent)
509 printf("- All keys: first - next -> last - prev -> first\n");
510 DBUG_PRINT("progpos",("All keys: first - next -> last - prev -> first"));
511 ant=1;
512 if (maria_rfirst(file,read_record,0))
513 {
514 printf("Can't find first record\n");
515 goto err;
516 }
517 while ((error=maria_rnext(file,read_record3,0)) == 0 && ant < write_count+10)
518 ant++;
519 if (ant != write_count - opt_delete || error != HA_ERR_END_OF_FILE)
520 {
521 printf("next: I found: %d records of %d (error: %d)\n",
522 ant, write_count - opt_delete, error);
523 goto err;
524 }
525 if (maria_rlast(file,read_record2,0) ||
526 bcmp(read_record2,read_record3,reclength))
527 {
528 printf("Can't find last record\n");
529 DBUG_DUMP("record2", read_record2, reclength);
530 DBUG_DUMP("record3", read_record3, reclength);
531 goto err2;
532 }
533 ant=1;
534 while (maria_rprev(file,read_record3,0) == 0 && ant < write_count+10)
535 ant++;
536 if (ant != write_count - opt_delete)
537 {
538 printf("prev: I found: %d records of %d\n",ant,write_count);
539 goto err2;
540 }
541 if (bcmp(read_record,read_record3,reclength))
542 {
543 printf("Can't find first record\n");
544 goto err2;
545 }
546
547 if (!silent)
548 printf("- Test if: Read first - next - prev - prev - next == first\n");
549 DBUG_PRINT("progpos",("- Read first - next - prev - prev - next == first"));
550 if (maria_rfirst(file,read_record,0) ||
551 maria_rnext(file,read_record3,0) ||
552 maria_rprev(file,read_record3,0) ||
553 maria_rprev(file,read_record3,0) == 0 ||
554 maria_rnext(file,read_record3,0))
555 goto err;
556 if (bcmp(read_record,read_record3,reclength) != 0)
557 printf("Can't find first record\n");
558
559 if (!silent)
560 printf("- Test if: Read last - prev - next - next - prev == last\n");
561 DBUG_PRINT("progpos",("Read last - prev - next - next - prev == last"));
562 if (maria_rlast(file,read_record2,0) ||
563 maria_rprev(file,read_record3,0) ||
564 maria_rnext(file,read_record3,0) ||
565 maria_rnext(file,read_record3,0) == 0 ||
566 maria_rprev(file,read_record3,0))
567 goto err;
568 if (bcmp(read_record2,read_record3,reclength))
569 printf("Can't find last record\n");
570#ifdef NOT_ANYMORE
571 if (!silent)
572 puts("- Test read key-part");
573 strmov(key2,key);
574 for(i=strlen(key2) ; i-- > 1 ;)
575 {
576 key2[i]=0;
577
578 /* The following row is just to catch some bugs in the key code */
579 bzero((char*) file->lastkey,file->s->base.max_key_length*2);
580 if (maria_rkey(file,read_record,0,key2,(uint) i,HA_READ_PREFIX))
581 goto err;
582 if (bcmp(read_record+start,key,(uint) i))
583 {
584 puts("Didn't find right record");
585 goto err2;
586 }
587 }
588#endif
589 if (dupp_keys > 2)
590 {
591 if (!silent)
592 printf("- Read key (first) - next - delete - next -> last\n");
593 DBUG_PRINT("progpos",("first - next - delete - next -> last"));
594 if (maria_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT))
595 goto err;
596 if (maria_rnext(file,read_record3,0)) goto err;
597 if (maria_delete(file,read_record3)) goto err;
598 opt_delete++;
599 ant=1;
600 while (maria_rnext(file,read_record3,0) == 0 &&
601 bcmp(read_record3+start,key,length) == 0) ant++;
602 if (ant != dupp_keys-1)
603 {
604 printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-1);
605 goto err2;
606 }
607 }
608 if (dupp_keys>4)
609 {
610 if (!silent)
611 printf("- Read last of key - prev - delete - prev -> first\n");
612 DBUG_PRINT("progpos",("last - prev - delete - prev -> first"));
613 if (maria_rprev(file,read_record3,0)) goto err;
614 if (maria_rprev(file,read_record3,0)) goto err;
615 if (maria_delete(file,read_record3)) goto err;
616 opt_delete++;
617 ant=1;
618 while (maria_rprev(file,read_record3,0) == 0 &&
619 bcmp(read_record3+start,key,length) == 0) ant++;
620 if (ant != dupp_keys-2)
621 {
622 printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-2);
623 goto err2;
624 }
625 }
626 if (dupp_keys > 6)
627 {
628 if (!silent)
629 printf("- Read first - delete - next -> last\n");
630 DBUG_PRINT("progpos",("first - delete - next -> last"));
631 if (maria_rkey(file,read_record3,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT))
632 goto err;
633 if (maria_delete(file,read_record3)) goto err;
634 opt_delete++;
635 ant=1;
636 if (maria_rnext(file,read_record,0))
637 goto err; /* Skall finnas poster */
638 while (maria_rnext(file,read_record3,0) == 0 &&
639 bcmp(read_record3+start,key,length) == 0) ant++;
640 if (ant != dupp_keys-3)
641 {
642 printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-3);
643 goto err2;
644 }
645
646 if (!silent)
647 printf("- Read last - delete - prev -> first\n");
648 DBUG_PRINT("progpos",("last - delete - prev -> first"));
649 if (maria_rprev(file,read_record3,0)) goto err;
650 if (maria_delete(file,read_record3)) goto err;
651 opt_delete++;
652 ant=0;
653 while (maria_rprev(file,read_record3,0) == 0 &&
654 bcmp(read_record3+start,key,length) == 0) ant++;
655 if (ant != dupp_keys-4)
656 {
657 printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-4);
658 goto err2;
659 }
660 }
661
662 if (!silent)
663 puts("- Test if: Read rrnd - same");
664 DBUG_PRINT("progpos",("Read rrnd - same"));
665 maria_scan_init(file);
666 for (i=0 ; i < write_count ; i++)
667 {
668 int tmp;
669 if ((tmp= maria_scan(file,read_record)) &&
670 tmp != HA_ERR_END_OF_FILE &&
671 tmp != HA_ERR_RECORD_DELETED)
672 {
673 printf("Got error %d when scanning table\n", tmp);
674 break;
675 }
676 if (!tmp)
677 {
678 /* Remember position to last found row */
679 info.recpos= maria_position(file);
680 bmove(read_record2,read_record,reclength);
681 }
682 }
683 maria_scan_end(file);
684 if (i != write_count && i != write_count - opt_delete)
685 {
686 printf("Found wrong number of rows while scanning table\n");
687 goto err2;
688 }
689
690 if (maria_rsame_with_pos(file,read_record,0,info.recpos))
691 goto err;
692 if (bcmp(read_record,read_record2,reclength) != 0)
693 {
694 printf("maria_rsame_with_pos didn't find same record\n");
695 goto err2;
696 }
697
698 for (i=MY_MIN(2,keys) ; i-- > 0 ;)
699 {
700 if (maria_rsame(file,read_record2,(int) i)) goto err;
701 if (bcmp(read_record,read_record2,reclength) != 0)
702 {
703 printf("maria_rsame didn't find same record\n");
704 goto err2;
705 }
706 }
707 if (!silent)
708 puts("- Test maria_records_in_range");
709 maria_status(file,&info,HA_STATUS_VARIABLE);
710 for (i=0 ; i < info.keys ; i++)
711 {
712 key_range min_key, max_key;
713 if (maria_rfirst(file,read_record,(int) i) ||
714 maria_rlast(file,read_record2,(int) i))
715 goto err;
716 copy_key(file,(uint) i, read_record, key);
717 copy_key(file,(uint) i, read_record2, key2);
718 min_key.key= key;
719 min_key.keypart_map= HA_WHOLE_KEY;
720 min_key.flag= HA_READ_KEY_EXACT;
721 max_key.key= key2;
722 max_key.keypart_map= HA_WHOLE_KEY;
723 max_key.flag= HA_READ_AFTER_KEY;
724
725 range_records= maria_records_in_range(file,(int) i, &min_key, &max_key);
726 if (range_records < info.records*8/10 ||
727 range_records > info.records*12/10)
728 {
729 printf("maria_records_range returned %ld; Should be about %ld\n",
730 (long) range_records,(long) info.records);
731 goto err2;
732 }
733 if (verbose)
734 {
735 printf("maria_records_range returned %ld; Exact is %ld (diff: %4.2g %%)\n",
736 (long) range_records, (long) info.records,
737 labs((long) range_records - (long) info.records)*100.0/
738 info.records);
739 }
740 }
741 for (i=0 ; i < 5 ; i++)
742 {
743 for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ;
744 for (k=rnd(1000)+1 ; k>0 && key1[k] == 0 ; k--) ;
745 if (j != 0 && k != 0)
746 {
747 key_range min_key, max_key;
748 if (j > k)
749 swap_variables(int, j, k);
750 sprintf((char*) key,"%6d",j);
751 sprintf((char*) key2,"%6d",k);
752
753 min_key.key= key;
754 min_key.keypart_map= HA_WHOLE_KEY;
755 min_key.flag= HA_READ_AFTER_KEY;
756 max_key.key= key2;
757 max_key.keypart_map= HA_WHOLE_KEY;
758 max_key.flag= HA_READ_BEFORE_KEY;
759 range_records= maria_records_in_range(file, 0, &min_key, &max_key);
760 records=0;
761 for (j++ ; j < k ; j++)
762 records+=key1[j];
763 if ((long) range_records < (long) records*6/10-2 ||
764 (long) range_records > (long) records*14/10+2)
765 {
766 printf("maria_records_range for key: %d returned %lu; Should be about %lu\n",
767 i, (ulong) range_records, (ulong) records);
768 goto err2;
769 }
770 if (verbose && records)
771 {
772 printf("maria_records_range returned %lu; Exact is %lu (diff: %4.2g %%)\n",
773 (ulong) range_records, (ulong) records,
774 labs((long) range_records-(long) records)*100.0/records);
775
776 }
777 }
778 }
779
780 if (!silent)
781 printf("- maria_info\n");
782 maria_status(file,&info,HA_STATUS_VARIABLE | HA_STATUS_CONST);
783 if (info.records != write_count-opt_delete ||
784 info.deleted > opt_delete + update || info.keys != keys)
785 {
786 puts("Wrong info from maria_info");
787 printf("Got: records: %lu delete: %lu i_keys: %d\n",
788 (ulong) info.records, (ulong) info.deleted, info.keys);
789 goto err2;
790 }
791 if (verbose)
792 {
793 char buff[80];
794 get_date(buff,3,info.create_time);
795 printf("info: Created %s\n",buff);
796 get_date(buff,3,info.check_time);
797 printf("info: checked %s\n",buff);
798 get_date(buff,3,info.update_time);
799 printf("info: Modified %s\n",buff);
800 }
801
802 maria_panic(HA_PANIC_WRITE);
803 maria_panic(HA_PANIC_READ);
804 if (maria_is_changed(file))
805 puts("Warning: maria_is_changed reported that datafile was changed");
806
807 if (!silent)
808 printf("- maria_extra(CACHE) + maria_rrnd.... + maria_extra(NO_CACHE)\n");
809 if (maria_reset(file) || maria_extra(file,HA_EXTRA_CACHE,0))
810 {
811 if (do_locking || (!use_blob && !pack_fields))
812 {
813 puts("got error from maria_extra(HA_EXTRA_CACHE)");
814 goto err;
815 }
816 }
817 ant=0;
818 maria_scan_init(file);
819 while ((error= maria_scan(file,record)) != HA_ERR_END_OF_FILE &&
820 ant < write_count + 10)
821 ant+= error ? 0 : 1;
822 maria_scan_end(file);
823 if (ant != write_count-opt_delete)
824 {
825 printf("scan with cache: I can only find: %d records of %d\n",
826 ant,write_count-opt_delete);
827 maria_scan_end(file);
828 goto err2;
829 }
830 if (maria_extra(file,HA_EXTRA_NO_CACHE,0))
831 {
832 puts("got error from maria_extra(HA_EXTRA_NO_CACHE)");
833 maria_scan_end(file);
834 goto err;
835 }
836 maria_scan_end(file);
837
838 ant=0;
839 maria_scan_init(file);
840 while ((error=maria_scan(file,record)) != HA_ERR_END_OF_FILE &&
841 ant < write_count + 10)
842 ant+= error ? 0 : 1;
843 if (ant != write_count-opt_delete)
844 {
845 printf("scan with cache: I can only find: %d records of %d\n",
846 ant,write_count-opt_delete);
847 maria_scan_end(file);
848 goto err2;
849 }
850 maria_scan_end(file);
851
852 if (testflag == 5)
853 goto end;
854 if (checkpoint == 5 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
855 goto err;
856
857 if (!silent)
858 printf("- Removing keys\n");
859 DBUG_PRINT("progpos",("Removing keys"));
860 lastpos = HA_OFFSET_ERROR;
861 /* DBUG_POP(); */
862 maria_reset(file);
863 found_parts=0;
864 maria_scan_init(file);
865 while ((error= maria_scan(file,read_record)) != HA_ERR_END_OF_FILE)
866 {
867 info.recpos=maria_position(file);
868 if (lastpos >= info.recpos && lastpos != HA_OFFSET_ERROR)
869 {
870 printf("maria_rrnd didn't advance filepointer; old: %ld, new: %ld\n",
871 (long) lastpos, (long) info.recpos);
872 goto err2;
873 }
874 lastpos=info.recpos;
875 if (error == 0)
876 {
877 if (opt_delete == (uint) remove_count) /* While testing */
878 goto end;
879 if (rnd(2) == 1 && maria_rsame(file,read_record,-1))
880 {
881 printf("can't find record %lx\n",(long) info.recpos);
882 goto err;
883 }
884 if (use_blob)
885 {
886 ulong blob_length,pos;
887 uchar *ptr;
888 memcpy(&ptr, read_record+blob_pos+4, sizeof(ptr));
889 blob_length= uint4korr(read_record+blob_pos);
890 for (pos=0 ; pos < blob_length ; pos++)
891 {
892 if (ptr[pos] != (uchar) (blob_length+pos))
893 {
894 printf("Found blob with wrong info at %ld\n",(long) lastpos);
895 maria_scan_end(file);
896 my_errno= 0;
897 goto err2;
898 }
899 }
900 }
901 if (maria_delete(file,read_record))
902 {
903 printf("can't delete record: %6.6s, delete_count: %d\n",
904 read_record, opt_delete);
905 maria_scan_end(file);
906 goto err;
907 }
908 opt_delete++;
909 }
910 else
911 found_parts++;
912 }
913 if (my_errno != HA_ERR_END_OF_FILE && my_errno != HA_ERR_RECORD_DELETED)
914 printf("error: %d from maria_rrnd\n",my_errno);
915 if (write_count != opt_delete)
916 {
917 printf("Deleted only %d of %d records (%d parts)\n",opt_delete,write_count,
918 found_parts);
919 maria_scan_end(file);
920 goto err2;
921 }
922 if (testflag == 6)
923 goto end;
924 if (checkpoint == 6 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
925 goto err;
926
927end:
928 maria_scan_end(file);
929 if (die_in_middle_of_transaction)
930 {
931 /* As commit record is not done, UNDO entries needs to be rolled back */
932 switch (die_in_middle_of_transaction) {
933 case 1:
934 /*
935 Flush changed data and index pages go to disk
936 That will also flush log. Recovery will skip REDOs and apply UNDOs.
937 */
938 _ma_flush_table_files(file, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
939 FLUSH_RELEASE, FLUSH_RELEASE);
940 break;
941 case 2:
942 /*
943 Just flush log. Pages are likely to not be on disk. Recovery will
944 then execute REDOs and UNDOs.
945 */
946 if (translog_flush(file->trn->undo_lsn))
947 goto err;
948 break;
949 case 3:
950 /*
951 Flush nothing. Pages and log are likely to not be on disk. Recovery
952 will then do nothing.
953 */
954 break;
955 case 4:
956 /*
957 Flush changed data pages go to disk. Changed index pages are not
958 flushed. Recovery will skip some REDOs and apply UNDOs.
959 */
960 _ma_flush_table_files(file, MARIA_FLUSH_DATA, FLUSH_RELEASE,
961 FLUSH_RELEASE);
962 /*
963 We have to flush log separately as the redo for the last key page
964 may not be flushed
965 */
966 if (translog_flush(file->trn->undo_lsn))
967 goto err;
968 break;
969 }
970 printf("Dying on request without maria_commit()/maria_close()\n");
971 sf_leaking_memory= 1; /* no memory leak reports here */
972 exit(0);
973 }
974 if (maria_commit(file))
975 goto err;
976 if (maria_close(file))
977 {
978 file= 0;
979 goto err;
980 }
981 file= 0;
982 maria_panic(HA_PANIC_CLOSE); /* Should close log */
983 if (!silent)
984 {
985 printf("\nFollowing test have been made:\n");
986 printf("Write records: %d\nUpdate records: %d\nSame-key-read: %d\nDelete records: %d\n", write_count,update,dupp_keys,opt_delete);
987 if (rec_pointer_size)
988 printf("Record pointer size: %d\n",rec_pointer_size);
989 printf("maria_block_size: %lu\n", maria_block_size);
990 if (write_cacheing)
991 puts("Key cache resized");
992 if (write_cacheing)
993 puts("Write cacheing used");
994 if (write_cacheing)
995 puts("quick mode");
996 if (async_io && do_locking)
997 puts("Asyncron io with locking used");
998 else if (do_locking)
999 puts("Locking used");
1000 if (use_blob)
1001 puts("blobs used");
1002 printf("key cache status: \n\
1003blocks used:%10lu\n\
1004not flushed:%10lu\n\
1005w_requests: %10lu\n\
1006writes: %10lu\n\
1007r_requests: %10lu\n\
1008reads: %10lu\n",
1009 (ulong) maria_pagecache->blocks_used,
1010 (ulong) maria_pagecache->global_blocks_changed,
1011 (ulong) maria_pagecache->global_cache_w_requests,
1012 (ulong) maria_pagecache->global_cache_write,
1013 (ulong) maria_pagecache->global_cache_r_requests,
1014 (ulong) maria_pagecache->global_cache_read);
1015 }
1016 maria_end();
1017 my_free(blob_buffer);
1018 my_uuid_end();
1019 my_end(silent ? MY_CHECK_ERROR : MY_CHECK_ERROR | MY_GIVE_INFO);
1020 return(0);
1021err:
1022 printf("got error: %d when using MARIA-database\n",my_errno);
1023err2:
1024 if (file)
1025 {
1026 if (maria_commit(file))
1027 printf("got error: %d when using MARIA-database\n",my_errno);
1028 maria_close(file);
1029 }
1030 maria_end();
1031 my_uuid_end();
1032 my_end(0);
1033 return(1);
1034} /* main */
1035
1036
1037/* Read options */
1038
1039static void get_options(int argc, char **argv)
1040{
1041 char *pos,*progname;
1042
1043 progname= argv[0];
1044
1045 while (--argc >0 && *(pos = *(++argv)) == '-' ) {
1046 switch(*++pos) {
1047 case 'B':
1048 pack_type= HA_BINARY_PACK_KEY;
1049 break;
1050 case 'b':
1051 use_blob= 1000;
1052 if (*++pos)
1053 use_blob= atol(pos);
1054 break;
1055 case 'K': /* Use key cacheing */
1056 pagecacheing=1;
1057 if (*++pos)
1058 pagecache_size=atol(pos);
1059 break;
1060 case 'W': /* Use write cacheing */
1061 write_cacheing=1;
1062 if (*++pos)
1063 my_default_record_cache_size=atoi(pos);
1064 break;
1065 case 'd':
1066 remove_count= atoi(++pos);
1067 break;
1068 case 'i':
1069 if (*++pos)
1070 srand(srand_arg= atoi(pos));
1071 break;
1072 case 'L':
1073 do_locking=1;
1074 break;
1075 case 'a': /* use asyncron io */
1076 async_io=1;
1077 if (*++pos)
1078 my_default_record_cache_size=atoi(pos);
1079 break;
1080 case 'v': /* verbose */
1081 verbose=1;
1082 break;
1083 case 'm': /* records */
1084 if ((recant=atoi(++pos)) < 10 && testflag > 2)
1085 {
1086 fprintf(stderr,"record count must be >= 10 (if testflag > 2)\n");
1087 exit(1);
1088 }
1089 break;
1090 case 'e': /* maria_block_length */
1091 case 'E':
1092 if ((maria_block_size= atoi(++pos)) < MARIA_MIN_KEY_BLOCK_LENGTH ||
1093 maria_block_size > MARIA_MAX_KEY_BLOCK_LENGTH)
1094 {
1095 fprintf(stderr,"Wrong maria_block_length\n");
1096 exit(1);
1097 }
1098 maria_block_size= my_round_up_to_next_power(maria_block_size);
1099 break;
1100 case 'f':
1101 if ((first_key=atoi(++pos)) < 0 || first_key >= MARIA_KEYS)
1102 first_key=0;
1103 break;
1104 case 'H':
1105 checkpoint= atoi(++pos);
1106 break;
1107 case 'h':
1108 maria_data_root= ++pos;
1109 break;
1110 case 'k':
1111 if ((keys=(uint) atoi(++pos)) < 1 ||
1112 keys > (uint) (MARIA_KEYS-first_key))
1113 keys=MARIA_KEYS-first_key;
1114 break;
1115 case 'M':
1116 record_type= BLOCK_RECORD;
1117 break;
1118 case 'P':
1119 pack_type=0; /* Don't use DIFF_LENGTH */
1120 pack_seg=0;
1121 break;
1122 case 'R': /* Length of record pointer */
1123 rec_pointer_size=atoi(++pos);
1124 if (rec_pointer_size > 7)
1125 rec_pointer_size=0;
1126 break;
1127 case 'S':
1128 pack_fields=0; /* Static-length-records */
1129 record_type= STATIC_RECORD;
1130 break;
1131 case 's':
1132 silent=1;
1133 break;
1134 case 't':
1135 testflag=atoi(++pos); /* testmod */
1136 break;
1137 case 'T':
1138 transactional= 1;
1139 break;
1140 case 'A':
1141 die_in_middle_of_transaction= atoi(++pos);
1142 break;
1143 case 'u':
1144 update_count=atoi(++pos);
1145 if (!update_count)
1146 skip_update= 1;
1147 break;
1148 case 'q':
1149 opt_quick_mode=1;
1150 break;
1151 case 'c':
1152 create_flag|= HA_CREATE_CHECKSUM | HA_CREATE_PAGE_CHECKSUM;
1153 break;
1154 case 'D':
1155 create_flag|=HA_CREATE_DELAY_KEY_WRITE;
1156 break;
1157 case 'g':
1158 skip_update= TRUE;
1159 break;
1160 case 'C':
1161 opt_versioning= 1;
1162 break;
1163 case '?':
1164 case 'I':
1165 case 'V':
1166 printf("%s Ver 1.2 for %s at %s\n",progname,SYSTEM_TYPE,MACHINE_TYPE);
1167 puts("By Monty, for testing Maria\n");
1168 printf("Usage: %s [-?AbBcCDIKLPRqSsTVWltv] [-k#] [-f#] [-m#] [-e#] [-E#] [-t#]\n",
1169 progname);
1170 exit(0);
1171 case '#':
1172 DBUG_PUSH (++pos);
1173 break;
1174 default:
1175 printf("Illegal option: '%c'\n",*pos);
1176 break;
1177 }
1178 }
1179 return;
1180} /* get options */
1181
1182 /* Get a random value 0 <= x <= n */
1183
1184static uint rnd(uint max_value)
1185{
1186 return (uint) ((rand() & 32767)/32767.0*max_value);
1187} /* rnd */
1188
1189
1190 /* Create a variable length record */
1191
1192static void fix_length(uchar *rec, uint length)
1193{
1194 bmove(rec+STANDARD_LENGTH,
1195 "0123456789012345678901234567890123456789012345678901234567890",
1196 length-STANDARD_LENGTH);
1197 strfill((char*) rec+length,STANDARD_LENGTH+60-length,' ');
1198} /* fix_length */
1199
1200
1201/* Put maybe a blob in record */
1202
1203static int first_entry;
1204
1205static void put_blob_in_record(uchar *blob_pos, char **blob_buffer,
1206 ulong *blob_length)
1207{
1208 ulong i,length;
1209 *blob_length= 0;
1210 if (use_blob)
1211 {
1212 if (! *blob_buffer &&
1213 !(*blob_buffer=my_malloc((uint) use_blob,MYF(MY_WME))))
1214 {
1215 use_blob= 0;
1216 return;
1217 }
1218 if (rnd(10) == 0)
1219 {
1220 if (first_entry++ == 0)
1221 {
1222 /* Ensure we have at least one blob of max length in file */
1223 length= use_blob;
1224 }
1225 else
1226 length=rnd(use_blob);
1227 for (i=0 ; i < length ; i++)
1228 (*blob_buffer)[i]=(char) (length+i);
1229 int4store(blob_pos,length);
1230 memcpy(blob_pos+4, blob_buffer, sizeof(char*));
1231 *blob_length= length;
1232 }
1233 else
1234 {
1235 int4store(blob_pos,0);
1236 }
1237 }
1238 return;
1239}
1240
1241
1242static void copy_key(MARIA_HA *info,uint inx,uchar *rec,uchar *key_buff)
1243{
1244 HA_KEYSEG *keyseg;
1245
1246 for (keyseg=info->s->keyinfo[inx].seg ; keyseg->type ; keyseg++)
1247 {
1248 memcpy(key_buff,rec+keyseg->start,(size_t) keyseg->length);
1249 key_buff+=keyseg->length;
1250 }
1251 return;
1252}
1253
1254#include "ma_check_standalone.h"
1255
1256