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 /* Testing of the basic functions of a MARIA rtree table */
17 /* Written by Alex Barkov who has a shared copyright to this code */
18
19
20 #include "maria_def.h"
21 #include "ma_control_file.h"
22 #include "ma_loghandler.h"
23 #include "ma_checkpoint.h"
24 #include "trnman.h"
25 #include <my_getopt.h>
26
27 #ifdef HAVE_RTREE_KEYS
28
29 #include "ma_rt_index.h"
30
31 #define MAX_REC_LENGTH 1024
32 #define ndims 2
33 #define KEYALG HA_KEY_ALG_RTREE
34
35 static int read_with_pos(MARIA_HA * file);
36 static void create_record(uchar *record,uint rownr);
37 static void create_record1(uchar *record,uint rownr);
38 static void print_record(uchar * record,my_off_t offs,const char * tail);
39 static int run_test(const char *filename);
40 static void get_options(int argc, char *argv[]);
41 static void usage();
42
43 static double rt_data[]=
44 {
45 /*1*/ 0,10,0,10,
46 /*2*/ 5,15,0,10,
47 /*3*/ 0,10,5,15,
48 /*4*/ 10,20,10,20,
49 /*5*/ 0,10,0,10,
50 /*6*/ 5,15,0,10,
51 /*7*/ 0,10,5,15,
52 /*8*/ 10,20,10,20,
53 /*9*/ 0,10,0,10,
54 /*10*/ 5,15,0,10,
55 /*11*/ 0,10,5,15,
56 /*12*/ 10,20,10,20,
57 /*13*/ 0,10,0,10,
58 /*14*/ 5,15,0,10,
59 /*15*/ 0,10,5,15,
60 /*16*/ 10,20,10,20,
61 /*17*/ 5,15,0,10,
62 /*18*/ 0,10,5,15,
63 /*19*/ 10,20,10,20,
64 /*20*/ 0,10,0,10,
65
66 /*1*/ 100,110,0,10,
67 /*2*/ 105,115,0,10,
68 /*3*/ 100,110,5,15,
69 /*4*/ 110,120,10,20,
70 /*5*/ 100,110,0,10,
71 /*6*/ 105,115,0,10,
72 /*7*/ 100,110,5,15,
73 /*8*/ 110,120,10,20,
74 /*9*/ 100,110,0,10,
75 /*10*/ 105,115,0,10,
76 /*11*/ 100,110,5,15,
77 /*12*/ 110,120,10,20,
78 /*13*/ 100,110,0,10,
79 /*14*/ 105,115,0,10,
80 /*15*/ 100,110,5,15,
81 /*16*/ 110,120,10,20,
82 /*17*/ 105,115,0,10,
83 /*18*/ 100,110,5,15,
84 /*19*/ 110,120,10,20,
85 /*20*/ 100,110,0,10,
86 -1
87 };
88
89 static int testflag, checkpoint, create_flag;
90 static my_bool silent, transactional, die_in_middle_of_transaction,
91 opt_versioning;
92 static enum data_file_type record_type= DYNAMIC_RECORD;
93
main(int argc,char * argv[])94 int main(int argc, char *argv[])
95 {
96 char buff[FN_REFLEN];
97 MY_INIT(argv[0]);
98 maria_data_root= ".";
99 get_options(argc, argv);
100 /* Maria requires that we always have a page cache */
101 if (maria_init() ||
102 (init_pagecache(maria_pagecache, maria_block_size * 16, 0, 0,
103 maria_block_size, 0, MY_WME) == 0) ||
104 ma_control_file_open(TRUE, TRUE, TRUE) ||
105 (init_pagecache(maria_log_pagecache,
106 TRANSLOG_PAGECACHE_SIZE, 0, 0,
107 TRANSLOG_PAGE_SIZE, 0, MY_WME) == 0) ||
108 translog_init(maria_data_root, TRANSLOG_FILE_SIZE,
109 0, 0, maria_log_pagecache,
110 TRANSLOG_DEFAULT_FLAGS, 0) ||
111 (transactional && (trnman_init(0) || ma_checkpoint_init(0))))
112 {
113 fprintf(stderr, "Error in initialization\n");
114 exit(1);
115 }
116
117 exit(run_test(fn_format(buff, "test1", maria_data_root, "", MYF(0))));
118 }
119
120
run_test(const char * filename)121 static int run_test(const char *filename)
122 {
123 MARIA_HA *file;
124 MARIA_UNIQUEDEF uniquedef;
125 MARIA_CREATE_INFO create_info;
126 MARIA_COLUMNDEF recinfo[20];
127 MARIA_KEYDEF keyinfo[20];
128 HA_KEYSEG keyseg[20];
129 key_range range;
130
131 int opt_unique=0;
132 int key_type=HA_KEYTYPE_DOUBLE;
133 int key_length=8;
134 int null_fields=0;
135 int nrecords=sizeof(rt_data)/(sizeof(double)*4);/* 40 */
136 int uniques=0;
137 int i, max_i;
138 int error;
139 int row_count=0;
140 uchar record[MAX_REC_LENGTH];
141 uchar read_record[MAX_REC_LENGTH];
142 int upd= 10;
143 ha_rows hrows;
144 page_range pages;
145
146 bzero(&uniquedef, sizeof(uniquedef));
147 bzero(&create_info, sizeof(create_info));
148 bzero(recinfo, sizeof(recinfo));
149 bzero(keyinfo, sizeof(keyinfo));
150 bzero(keyseg, sizeof(keyseg));
151
152 /* Define a column for NULLs and DEL markers*/
153
154 recinfo[0].type=FIELD_NORMAL;
155 recinfo[0].length=1; /* For NULL bits */
156
157 /* Define 2*ndims columns for coordinates*/
158
159 for (i=1; i<=2*ndims ;i++)
160 {
161 recinfo[i].type=FIELD_NORMAL;
162 recinfo[i].length=key_length;
163 }
164
165 /* Define a key with 2*ndims segments */
166
167 keyinfo[0].seg=keyseg;
168 keyinfo[0].keysegs=2*ndims;
169 keyinfo[0].flag=0;
170 keyinfo[0].key_alg=KEYALG;
171
172 for (i=0; i<2*ndims; i++)
173 {
174 keyinfo[0].seg[i].type= key_type;
175 keyinfo[0].seg[i].flag=0; /* Things like HA_REVERSE_SORT */
176 keyinfo[0].seg[i].start= (key_length*i)+1;
177 keyinfo[0].seg[i].length=key_length;
178 keyinfo[0].seg[i].null_bit= null_fields ? 2 : 0;
179 keyinfo[0].seg[i].null_pos=0;
180 keyinfo[0].seg[i].language=default_charset_info->number;
181 }
182
183 if (!silent)
184 printf("- Creating isam-file\n");
185
186 create_info.max_rows=10000000;
187 create_info.transactional= transactional;
188
189 if (maria_create(filename,
190 record_type,
191 1, /* keys */
192 keyinfo,
193 1+2*ndims+opt_unique, /* columns */
194 recinfo,uniques,&uniquedef,&create_info,create_flag))
195 goto err;
196
197 if (!silent)
198 printf("- Open isam-file\n");
199
200 if (!(file=maria_open(filename,2,HA_OPEN_ABORT_IF_LOCKED,0)))
201 goto err;
202 maria_begin(file);
203 if (opt_versioning)
204 maria_versioning(file, 1);
205 if (testflag == 1)
206 goto end;
207 if (checkpoint == 1 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
208 goto err;
209 if (!silent)
210 printf("- Writing key:s\n");
211
212 for (i=0; i<nrecords; i++ )
213 {
214 create_record(record,i);
215 error=maria_write(file,record);
216 print_record(record,maria_position(file),"\n");
217 if (!error)
218 {
219 row_count++;
220 }
221 else
222 {
223 fprintf(stderr, "maria_write: %d\n", error);
224 goto err;
225 }
226 }
227
228 if (maria_scan_init(file))
229 {
230 fprintf(stderr, "maria_scan_init failed\n");
231 goto err;
232 }
233 if ((error=read_with_pos(file)))
234 goto err;
235 maria_scan_end(file);
236
237 if (!silent)
238 printf("- Reading rows with key\n");
239
240 for (i=0 ; i < nrecords ; i++)
241 {
242 my_errno=0;
243 create_record(record,i);
244
245 bzero((char*) read_record,MAX_REC_LENGTH);
246 error=maria_rkey(file,read_record,0,record+1,HA_WHOLE_KEY,HA_READ_MBR_EQUAL);
247
248 if (error && error!=HA_ERR_KEY_NOT_FOUND)
249 {
250 fprintf(stderr," maria_rkey: %3d errno: %3d\n",error,my_errno);
251 goto err;
252 }
253 if (error == HA_ERR_KEY_NOT_FOUND)
254 {
255 print_record(record,maria_position(file)," NOT FOUND\n");
256 continue;
257 }
258 print_record(read_record,maria_position(file),"\n");
259 }
260
261 if (checkpoint == 2 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
262 goto err;
263
264 if (testflag == 2)
265 goto end;
266
267 if (!silent)
268 printf("- Deleting rows\n");
269 if (maria_scan_init(file))
270 {
271 fprintf(stderr, "maria_scan_init failed\n");
272 goto err;
273 }
274
275 for (i=0; i < nrecords/4; i++)
276 {
277 my_errno=0;
278 bzero((char*) read_record,MAX_REC_LENGTH);
279 error=maria_scan(file,read_record);
280 if (error)
281 {
282 fprintf(stderr, "pos: %2d maria_rrnd: %3d errno: %3d\n", i, error,
283 my_errno);
284 goto err;
285 }
286 print_record(read_record,maria_position(file),"\n");
287
288 error=maria_delete(file,read_record);
289 if (error)
290 {
291 fprintf(stderr, "pos: %2d maria_delete: %3d errno: %3d\n", i, error,
292 my_errno);
293 goto err;
294 }
295 }
296 maria_scan_end(file);
297
298 if (testflag == 3)
299 goto end;
300 if (checkpoint == 3 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
301 goto err;
302
303 if (!silent)
304 printf("- Updating rows with position\n");
305 if (maria_scan_init(file))
306 {
307 fprintf(stderr, "maria_scan_init failed\n");
308 goto err;
309 }
310
311 /* We are looking for nrecords-necords/2 non-deleted records */
312 for (i=0, max_i= nrecords - nrecords/2; i < max_i ; i++)
313 {
314 my_errno=0;
315 bzero((char*) read_record,MAX_REC_LENGTH);
316 error=maria_scan(file,read_record);
317 if (error)
318 {
319 if (error==HA_ERR_RECORD_DELETED)
320 {
321 if (!silent)
322 printf("found deleted record\n");
323 /*
324 In BLOCK_RECORD format, maria_scan() never returns deleted records,
325 while in DYNAMIC format it can. Don't count such record:
326 */
327 max_i++;
328 continue;
329 }
330 fprintf(stderr, "pos: %2d maria_rrnd: %3d errno: %3d\n",i , error,
331 my_errno);
332 goto err;
333 }
334 print_record(read_record,maria_position(file),"");
335 create_record1(record,i+nrecords*upd);
336 if (!silent)
337 printf("\t-> ");
338 print_record(record,maria_position(file),"\n");
339 error=maria_update(file,read_record,record);
340 if (error)
341 {
342 fprintf(stderr, "pos: %2d maria_update: %3d errno: %3d\n",i, error,
343 my_errno);
344 goto err;
345 }
346 }
347
348 if (testflag == 4)
349 goto end;
350 if (checkpoint == 4 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
351 goto err;
352
353 if (maria_scan_init(file))
354 {
355 fprintf(stderr, "maria_scan_init failed\n");
356 goto err;
357 }
358 if ((error=read_with_pos(file)))
359 goto err;
360 maria_scan_end(file);
361
362 if (!silent)
363 printf("- Test maria_rkey then a sequence of maria_rnext_same\n");
364
365 create_record(record, nrecords*4/5);
366 print_record(record,0," search for\n");
367
368 if ((error=maria_rkey(file,read_record,0,record+1,HA_WHOLE_KEY,
369 HA_READ_MBR_INTERSECT)))
370 {
371 fprintf(stderr, "maria_rkey: %3d errno: %3d\n",error,my_errno);
372 goto err;
373 }
374 print_record(read_record,maria_position(file)," maria_rkey\n");
375 row_count=1;
376
377 for (;;)
378 {
379 if ((error=maria_rnext_same(file,read_record)))
380 {
381 if (error==HA_ERR_END_OF_FILE)
382 break;
383 fprintf(stderr, "maria_next: %3d errno: %3d\n",error,my_errno);
384 goto err;
385 }
386 print_record(read_record,maria_position(file)," maria_rnext_same\n");
387 row_count++;
388 }
389 if (!silent)
390 printf(" %d rows\n",row_count);
391
392 if (!silent)
393 printf("- Test maria_rfirst then a sequence of maria_rnext\n");
394
395 error=maria_rfirst(file,read_record,0);
396 if (error)
397 {
398 fprintf(stderr, "maria_rfirst: %3d errno: %3d\n",error,my_errno);
399 goto err;
400 }
401 row_count=1;
402 print_record(read_record,maria_position(file)," maria_frirst\n");
403
404 for (i=0;i<nrecords;i++)
405 {
406 if ((error=maria_rnext(file,read_record,0)))
407 {
408 if (error==HA_ERR_END_OF_FILE)
409 break;
410 fprintf(stderr, "maria_next: %3d errno: %3d\n",error,my_errno);
411 goto err;
412 }
413 print_record(read_record,maria_position(file)," maria_rnext\n");
414 row_count++;
415 }
416 if (!silent)
417 printf(" %d rows\n",row_count);
418
419 if (!silent)
420 printf("- Test maria_records_in_range()\n");
421
422 create_record1(record, nrecords*4/5);
423 print_record(record,0,"\n");
424
425 range.key= record+1;
426 range.length= 1000; /* Big enough */
427 range.flag= HA_READ_MBR_INTERSECT;
428 hrows= maria_records_in_range(file,0, &range, (key_range*) 0, &pages);
429 if (!silent)
430 printf(" %ld rows\n", (long) hrows);
431
432 end:
433 maria_scan_end(file);
434 if (die_in_middle_of_transaction)
435 {
436 /* see similar code in ma_test2.c for comments */
437 switch (die_in_middle_of_transaction) {
438 case 1:
439 _ma_flush_table_files(file, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
440 FLUSH_RELEASE, FLUSH_RELEASE);
441 break;
442 case 2:
443 if (translog_flush(file->trn->undo_lsn))
444 goto err;
445 break;
446 case 3:
447 break;
448 case 4:
449 _ma_flush_table_files(file, MARIA_FLUSH_DATA, FLUSH_RELEASE,
450 FLUSH_RELEASE);
451 if (translog_flush(file->trn->undo_lsn))
452 goto err;
453 break;
454 }
455 if (!silent)
456 printf("Dying on request without maria_commit()/maria_close()\n");
457 exit(0);
458 }
459 if (maria_commit(file))
460 goto err;
461 if (maria_close(file)) goto err;
462 maria_end();
463 my_end(MY_CHECK_ERROR);
464
465 return 0;
466
467 err:
468 fprintf(stderr, "got error: %3d when using maria-database\n",my_errno);
469 return 1; /* skip warning */
470 }
471
472
473
read_with_pos(MARIA_HA * file)474 static int read_with_pos (MARIA_HA * file)
475 {
476 int error;
477 int i;
478 uchar read_record[MAX_REC_LENGTH];
479
480 if (!silent)
481 printf("- Reading rows with position\n");
482 for (i=0;;i++)
483 {
484 my_errno=0;
485 bzero((char*) read_record,MAX_REC_LENGTH);
486 error=maria_scan(file,read_record);
487 if (error)
488 {
489 if (error==HA_ERR_END_OF_FILE)
490 break;
491 if (error==HA_ERR_RECORD_DELETED)
492 continue;
493 fprintf(stderr, "pos: %2d maria_rrnd: %3d errno: %3d\n", i, error,
494 my_errno);
495 return error;
496 }
497 print_record(read_record,maria_position(file),"\n");
498 }
499 return 0;
500 }
501
502
503 #ifdef NOT_USED
bprint_record(char * record,my_off_t offs,const char * tail)504 static void bprint_record(char * record,
505 my_off_t offs __attribute__((unused)),
506 const char * tail)
507 {
508 int i;
509 char * pos;
510 if (silent)
511 return;
512 i=(unsigned char)record[0];
513 printf("%02X ",i);
514
515 for( pos=record+1, i=0; i<32; i++,pos++){
516 int b=(unsigned char)*pos;
517 printf("%02X",b);
518 }
519 printf("%s",tail);
520 }
521 #endif
522
523
print_record(uchar * record,my_off_t offs,const char * tail)524 static void print_record(uchar *record,
525 my_off_t offs __attribute__((unused)),
526 const char * tail)
527 {
528 int i;
529 uchar *pos;
530 double c;
531
532 if (silent)
533 return;
534 printf(" rec=(%d)",(unsigned char)record[0]);
535 for ( pos=record+1, i=0; i<2*ndims; i++)
536 {
537 memcpy(&c,pos,sizeof(c));
538 float8get(c,pos);
539 printf(" %.14g ",c);
540 pos+=sizeof(c);
541 }
542 printf("pos=%ld",(long int)offs);
543 printf("%s",tail);
544 }
545
546
547
create_record1(uchar * record,uint rownr)548 static void create_record1(uchar *record, uint rownr)
549 {
550 int i;
551 uchar *pos;
552 double c=rownr+10;
553
554 bzero((char*) record,MAX_REC_LENGTH);
555 record[0]=0x01; /* DEL marker */
556
557 for ( pos=record+1, i=0; i<2*ndims; i++)
558 {
559 memcpy(pos,&c,sizeof(c));
560 float8store(pos,c);
561 pos+=sizeof(c);
562 }
563 }
564
565 #ifdef NOT_USED
566
create_record0(char * record,uint rownr)567 static void create_record0(char *record,uint rownr)
568 {
569 int i;
570 char * pos;
571 double c=rownr+10;
572 double c0=0;
573
574 bzero((char*) record,MAX_REC_LENGTH);
575 record[0]=0x01; /* DEL marker */
576
577 for ( pos=record+1, i=0; i<ndims; i++)
578 {
579 memcpy(pos,&c0,sizeof(c0));
580 float8store(pos,c0);
581 pos+=sizeof(c0);
582 memcpy(pos,&c,sizeof(c));
583 float8store(pos,c);
584 pos+=sizeof(c);
585 }
586 }
587
588 #endif
589
create_record(uchar * record,uint rownr)590 static void create_record(uchar *record, uint rownr)
591 {
592 int i;
593 uchar *pos;
594 double *data= rt_data+rownr*4;
595 record[0]=0x01; /* DEL marker */
596 for ( pos=record+1, i=0; i<ndims*2; i++)
597 {
598 float8store(pos,data[i]);
599 pos+=8;
600 }
601 }
602
603
604 static struct my_option my_long_options[] =
605 {
606 {"checkpoint", 'H', "Checkpoint at specified stage", (uchar**) &checkpoint,
607 (uchar**) &checkpoint, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
608 {"checksum", 'c', "Undocumented",
609 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
610 #ifndef DBUG_OFF
611 {"debug", '#', "Undocumented",
612 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
613 #endif
614 {"help", '?', "Display help and exit",
615 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
616 {"datadir", 'h', "Path to the database root.", (char**) &maria_data_root,
617 (char**) &maria_data_root, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
618 {"row-fixed-size", 'S', "Fixed size records",
619 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
620 {"rows-in-block", 'M', "Store rows in block format",
621 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
622 {"silent", 's', "Undocumented",
623 (uchar**) &silent, (uchar**) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
624 0, 0},
625 {"testflag", 't', "Stop test at specified stage", (uchar**) &testflag,
626 (uchar**) &testflag, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
627 {"test-undo", 'A',
628 "Abort hard. Used for testing recovery with undo",
629 (uchar**) &die_in_middle_of_transaction,
630 (uchar**) &die_in_middle_of_transaction,
631 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
632 {"transactional", 'T',
633 "Test in transactional mode. (Only works with block format)",
634 (uchar**) &transactional, (uchar**) &transactional, 0, GET_BOOL, NO_ARG,
635 0, 0, 0, 0, 0, 0},
636 {"versioning", 'C', "Use row versioning (only works with block format)",
637 (uchar**) &opt_versioning, (uchar**) &opt_versioning, 0, GET_BOOL,
638 NO_ARG, 0, 0, 0, 0, 0, 0},
639 { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
640 };
641
642
643 static my_bool
get_one_option(const struct my_option * opt,const char * argument,const char * filename)644 get_one_option(const struct my_option *opt,
645 const char *argument __attribute__((unused)),
646 const char *filename __attribute__((unused)))
647 {
648 switch(opt->id) {
649 case 'c':
650 create_flag|= HA_CREATE_CHECKSUM | HA_CREATE_PAGE_CHECKSUM;
651 break;
652 case 'M':
653 record_type= BLOCK_RECORD;
654 break;
655 case 'S':
656 record_type= STATIC_RECORD;
657 break;
658 case '#':
659 DBUG_PUSH(argument);
660 break;
661 case '?':
662 usage();
663 exit(1);
664 }
665 return 0;
666 }
667
668
669 /* Read options */
670
get_options(int argc,char * argv[])671 static void get_options(int argc, char *argv[])
672 {
673 int ho_error;
674
675 if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
676 exit(ho_error);
677
678 return;
679 } /* get options */
680
681
usage()682 static void usage()
683 {
684 printf("Usage: %s [options]\n\n", my_progname);
685 my_print_help(my_long_options);
686 my_print_variables(my_long_options);
687 }
688
689 #include "ma_check_standalone.h"
690
691 #else
main(int argc,char * argv[])692 int main(int argc __attribute__((unused)),char *argv[] __attribute__((unused)))
693 {
694 exit(0);
695 }
696 #endif /*HAVE_RTREE_KEYS*/
697