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 02110-1335 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 
31 static void get_options(int argc, char *argv[]);
32 static uint rnd(uint max_value);
33 static void fix_length(uchar *record,uint length);
34 static void put_blob_in_record(uchar *blob_pos,char **blob_buffer,
35                                ulong *length);
36 static void copy_key(MARIA_HA *info, uint inx, uchar *record, uchar *key);
37 
38 static int verbose= 0, testflag= 0, first_key= 0, async_io= 0, pagecacheing= 0;
39 static int write_cacheing= 0, do_locking= 0, rec_pointer_size= 0;
40 static int silent= 0, opt_quick_mode= 0, transactional= 0, skip_update= 0;
41 static int die_in_middle_of_transaction= 0, pack_fields= 1;
42 static int pack_seg= HA_SPACE_PACK, pack_type= HA_PACK_KEY, remove_count= -1;
43 static int create_flag= 0, srand_arg= 0, checkpoint= 0;
44 static my_bool opt_versioning= 0;
45 static uint use_blob= 0, update_count= 0;
46 static ulong pagecache_size=8192*32;
47 static enum data_file_type record_type= DYNAMIC_RECORD;
48 
49 static uint keys=MARIA_KEYS,recant=1000;
50 static uint16 key1[1001],key3[5001];
51 static uchar record[300],record2[300],key[100],key2[100];
52 static uchar read_record[300],read_record2[300],read_record3[300];
53 static HA_KEYSEG glob_keyseg[MARIA_KEYS][MAX_PARTS];
54 
55 		/* Test program */
56 
main(int argc,char * argv[])57 int 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 
927 end:
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\
1003 blocks used:%10lu\n\
1004 not flushed:%10lu\n\
1005 w_requests: %10lu\n\
1006 writes:     %10lu\n\
1007 r_requests: %10lu\n\
1008 reads:      %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);
1021 err:
1022   printf("got error: %d when using MARIA-database\n",my_errno);
1023 err2:
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 
get_options(int argc,char ** argv)1039 static 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 
rnd(uint max_value)1184 static 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 
fix_length(uchar * rec,uint length)1192 static 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 
1203 static int first_entry;
1204 
put_blob_in_record(uchar * blob_pos,char ** blob_buffer,ulong * blob_length)1205 static 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 
copy_key(MARIA_HA * info,uint inx,uchar * rec,uchar * key_buff)1242 static 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