920 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C++
		
	
	
			
		
		
	
	
			920 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C++
		
	
	
| /* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
 | |
| 
 | |
|    This program is free software; you can redistribute it and/or modify
 | |
|    it under the terms of the GNU General Public License, version 2.0,
 | |
|    as published by the Free Software Foundation.
 | |
| 
 | |
|    This program is also distributed with certain software (including
 | |
|    but not limited to OpenSSL) that is licensed under separate terms,
 | |
|    as designated in a particular file or component or in included license
 | |
|    documentation.  The authors of MySQL hereby grant you an additional
 | |
|    permission to link the program and your derivative works with the
 | |
|    separately licensed software that they have included with MySQL.
 | |
| 
 | |
|    This program is distributed in the hope that it will be useful,
 | |
|    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|    GNU General Public License, version 2.0, for more details.
 | |
| 
 | |
|    You should have received a copy of the GNU General Public License
 | |
|    along with this program; if not, write to the Free Software
 | |
|    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
 | |
| 
 | |
| /* Test av isam-databas: stor test */
 | |
| 
 | |
| #ifdef DBUG_OFF
 | |
| #undef DBUG_OFF
 | |
| #endif
 | |
| #include <m_ctype.h>
 | |
| #include <my_bit.h>
 | |
| #include "my_byteorder.h"
 | |
| #include "myisamdef.h"
 | |
| #include "sql/field.h"
 | |
| 
 | |
| #define STANDARD_LENGTH 37
 | |
| #define MYISAM_KEYS 6
 | |
| #define MAX_PARTS 4
 | |
| #if !defined(labs)
 | |
| #define labs(a) abs(a)
 | |
| #endif
 | |
| 
 | |
| static void get_options(int argc, char *argv[]);
 | |
| static uint rnd(uint max_value);
 | |
| static void fix_length(uchar *record, uint length);
 | |
| static void put_blob_in_record(uchar *blob_pos, char **blob_buffer);
 | |
| static void copy_key(MI_INFO *info, uint inx, uchar *record, uchar *key);
 | |
| 
 | |
| static int verbose = 0, testflag = 0, first_key = 0, async_io = 0,
 | |
|            key_cacheing = 0, locking = 0, rec_pointer_size = 0, pack_fields = 1,
 | |
|            use_log = 0, silent = 0, opt_quick_mode = 0;
 | |
| static int pack_seg = HA_SPACE_PACK, pack_type = HA_PACK_KEY, remove_count = -1,
 | |
|            create_flag = 0;
 | |
| static ulong key_cache_size = IO_SIZE * 16;
 | |
| static uint key_cache_block_size = KEY_CACHE_BLOCK_SIZE;
 | |
| 
 | |
| static uint keys = MYISAM_KEYS, recant = 1000;
 | |
| static uint use_blob = 0;
 | |
| static uint16 key1[1001], key3[5000];
 | |
| static uchar record[300], record2[300], key[100], key2[100];
 | |
| static uchar read_record[300], read_record2[300], read_record3[300];
 | |
| static HA_KEYSEG glob_keyseg[MYISAM_KEYS][MAX_PARTS];
 | |
| 
 | |
| /* Test program */
 | |
| 
 | |
| int main(int argc, char *argv[]) {
 | |
|   uint i;
 | |
|   int j, n1, n2, n3, error, k;
 | |
|   uint write_count, update, dupp_keys, opt_delete, start, length, blob_pos,
 | |
|       reclength, ant, found_parts;
 | |
|   my_off_t lastpos;
 | |
|   ha_rows range_records, records;
 | |
|   MI_INFO *file;
 | |
|   MI_KEYDEF keyinfo[10];
 | |
|   MI_COLUMNDEF recinfo[10];
 | |
|   MI_ISAMINFO info;
 | |
|   const char *filename;
 | |
|   char *blob_buffer;
 | |
|   MI_CREATE_INFO create_info;
 | |
|   MY_INIT(argv[0]);
 | |
| 
 | |
|   filename = "test2";
 | |
|   get_options(argc, argv);
 | |
| 
 | |
|   reclength = STANDARD_LENGTH + 60 + (use_blob ? 8 : 0);
 | |
|   blob_pos = STANDARD_LENGTH + 60;
 | |
|   keyinfo[0].seg = &glob_keyseg[0][0];
 | |
|   keyinfo[0].seg[0].start = 0;
 | |
|   keyinfo[0].seg[0].length = 6;
 | |
|   keyinfo[0].seg[0].type = HA_KEYTYPE_TEXT;
 | |
|   keyinfo[0].seg[0].language = default_charset_info->number;
 | |
|   keyinfo[0].seg[0].flag = (uint8)pack_seg;
 | |
|   keyinfo[0].seg[0].null_bit = 0;
 | |
|   keyinfo[0].seg[0].null_pos = 0;
 | |
|   keyinfo[0].key_alg = HA_KEY_ALG_BTREE;
 | |
|   keyinfo[0].keysegs = 1;
 | |
|   keyinfo[0].flag = pack_type;
 | |
|   keyinfo[0].block_length = 0; /* Default block length */
 | |
|   keyinfo[1].seg = &glob_keyseg[1][0];
 | |
|   keyinfo[1].seg[0].start = 7;
 | |
|   keyinfo[1].seg[0].length = 6;
 | |
|   keyinfo[1].seg[0].type = HA_KEYTYPE_BINARY;
 | |
|   keyinfo[1].seg[0].flag = 0;
 | |
|   keyinfo[1].seg[0].null_bit = 0;
 | |
|   keyinfo[1].seg[0].null_pos = 0;
 | |
|   keyinfo[1].seg[1].start = 0; /* two part key */
 | |
|   keyinfo[1].seg[1].length = 6;
 | |
|   keyinfo[1].seg[1].type = HA_KEYTYPE_NUM;
 | |
|   keyinfo[1].seg[1].flag = HA_REVERSE_SORT;
 | |
|   keyinfo[1].seg[1].null_bit = 0;
 | |
|   keyinfo[1].seg[1].null_pos = 0;
 | |
|   keyinfo[1].key_alg = HA_KEY_ALG_BTREE;
 | |
|   keyinfo[1].keysegs = 2;
 | |
|   keyinfo[1].flag = 0;
 | |
|   keyinfo[1].block_length = MI_MIN_KEY_BLOCK_LENGTH; /* Diff blocklength */
 | |
|   keyinfo[2].seg = &glob_keyseg[2][0];
 | |
|   keyinfo[2].seg[0].start = 12;
 | |
|   keyinfo[2].seg[0].length = 8;
 | |
|   keyinfo[2].seg[0].type = HA_KEYTYPE_BINARY;
 | |
|   keyinfo[2].seg[0].flag = HA_REVERSE_SORT;
 | |
|   keyinfo[2].seg[0].null_bit = 0;
 | |
|   keyinfo[2].seg[0].null_pos = 0;
 | |
|   keyinfo[2].key_alg = HA_KEY_ALG_BTREE;
 | |
|   keyinfo[2].keysegs = 1;
 | |
|   keyinfo[2].flag = HA_NOSAME;
 | |
|   keyinfo[2].block_length = 0; /* Default block length */
 | |
|   keyinfo[3].seg = &glob_keyseg[3][0];
 | |
|   keyinfo[3].seg[0].start = 0;
 | |
|   keyinfo[3].seg[0].length = reclength - (use_blob ? 8 : 0);
 | |
|   keyinfo[3].seg[0].type = HA_KEYTYPE_TEXT;
 | |
|   keyinfo[3].seg[0].language = default_charset_info->number;
 | |
|   keyinfo[3].seg[0].flag = (uint8)pack_seg;
 | |
|   keyinfo[3].seg[0].null_bit = 0;
 | |
|   keyinfo[3].seg[0].null_pos = 0;
 | |
|   keyinfo[3].key_alg = HA_KEY_ALG_BTREE;
 | |
|   keyinfo[3].keysegs = 1;
 | |
|   keyinfo[3].flag = pack_type;
 | |
|   keyinfo[3].block_length = 0; /* Default block length */
 | |
|   keyinfo[4].seg = &glob_keyseg[4][0];
 | |
|   keyinfo[4].seg[0].start = 0;
 | |
|   keyinfo[4].seg[0].length = 5;
 | |
|   keyinfo[4].seg[0].type = HA_KEYTYPE_TEXT;
 | |
|   keyinfo[4].seg[0].language = default_charset_info->number;
 | |
|   keyinfo[4].seg[0].flag = 0;
 | |
|   keyinfo[4].seg[0].null_bit = 0;
 | |
|   keyinfo[4].seg[0].null_pos = 0;
 | |
|   keyinfo[4].key_alg = HA_KEY_ALG_BTREE;
 | |
|   keyinfo[4].keysegs = 1;
 | |
|   keyinfo[4].flag = pack_type;
 | |
|   keyinfo[4].block_length = 0; /* Default block length */
 | |
|   keyinfo[5].seg = &glob_keyseg[5][0];
 | |
|   keyinfo[5].seg[0].start = 0;
 | |
|   keyinfo[5].seg[0].length = 4;
 | |
|   keyinfo[5].seg[0].type = HA_KEYTYPE_TEXT;
 | |
|   keyinfo[5].seg[0].language = default_charset_info->number;
 | |
|   keyinfo[5].seg[0].flag = pack_seg;
 | |
|   keyinfo[5].seg[0].null_bit = 0;
 | |
|   keyinfo[5].seg[0].null_pos = 0;
 | |
|   keyinfo[5].key_alg = HA_KEY_ALG_BTREE;
 | |
|   keyinfo[5].keysegs = 1;
 | |
|   keyinfo[5].flag = pack_type;
 | |
|   keyinfo[5].block_length = 0; /* Default block length */
 | |
| 
 | |
|   recinfo[0].type = pack_fields ? FIELD_SKIP_PRESPACE : 0;
 | |
|   recinfo[0].length = 7;
 | |
|   recinfo[0].null_bit = 0;
 | |
|   recinfo[0].null_pos = 0;
 | |
|   recinfo[1].type = pack_fields ? FIELD_SKIP_PRESPACE : 0;
 | |
|   recinfo[1].length = 5;
 | |
|   recinfo[1].null_bit = 0;
 | |
|   recinfo[1].null_pos = 0;
 | |
|   recinfo[2].type = pack_fields ? FIELD_SKIP_PRESPACE : 0;
 | |
|   recinfo[2].length = 9;
 | |
|   recinfo[2].null_bit = 0;
 | |
|   recinfo[2].null_pos = 0;
 | |
|   recinfo[3].type = FIELD_NORMAL;
 | |
|   recinfo[3].length = STANDARD_LENGTH - 7 - 5 - 9 - 4;
 | |
|   recinfo[3].null_bit = 0;
 | |
|   recinfo[3].null_pos = 0;
 | |
|   recinfo[4].type = pack_fields ? FIELD_SKIP_ZERO : 0;
 | |
|   recinfo[4].length = 4;
 | |
|   recinfo[4].null_bit = 0;
 | |
|   recinfo[4].null_pos = 0;
 | |
|   recinfo[5].type = pack_fields ? FIELD_SKIP_ENDSPACE : 0;
 | |
|   recinfo[5].length = 60;
 | |
|   recinfo[5].null_bit = 0;
 | |
|   recinfo[5].null_pos = 0;
 | |
|   if (use_blob) {
 | |
|     recinfo[6].type = FIELD_BLOB;
 | |
|     recinfo[6].length = 4 + portable_sizeof_char_ptr;
 | |
|     recinfo[6].null_bit = 0;
 | |
|     recinfo[6].null_pos = 0;
 | |
|   }
 | |
| 
 | |
|   write_count = update = dupp_keys = opt_delete = 0;
 | |
|   blob_buffer = 0;
 | |
| 
 | |
|   for (i = 1000; i > 0; i--) key1[i] = 0;
 | |
|   for (i = 4999; i > 0; i--) key3[i] = 0;
 | |
| 
 | |
|   if (!silent) printf("- Creating isam-file\n");
 | |
|   /*  DBUG_PUSH(""); */
 | |
|   /* my_delete(filename,MYF(0)); */ /* Remove old locks under gdb */
 | |
|   file = 0;
 | |
|   memset(&create_info, 0, sizeof(create_info));
 | |
|   create_info.max_rows = (ha_rows)(
 | |
|       rec_pointer_size ? (1L << (rec_pointer_size * 8)) / reclength : 0);
 | |
|   create_info.reloc_rows = (ha_rows)100;
 | |
|   if (mi_create(filename, keys, &keyinfo[first_key], use_blob ? 7 : 6,
 | |
|                 &recinfo[0], 0, (MI_UNIQUEDEF *)0, &create_info, create_flag))
 | |
|     goto err;
 | |
|   if (use_log) mi_log(1);
 | |
|   if (!(file = mi_open(filename, 2, HA_OPEN_ABORT_IF_LOCKED))) goto err;
 | |
|   if (!silent) printf("- Writing key:s\n");
 | |
|   if (key_cacheing)
 | |
|     init_key_cache(dflt_key_cache, key_cache_block_size, key_cache_size, 0, 0);
 | |
|   if (locking) mi_lock_database(file, F_WRLCK);
 | |
|   if (opt_quick_mode) mi_extra(file, HA_EXTRA_QUICK, 0);
 | |
| 
 | |
|   for (i = 0; i < recant; i++) {
 | |
|     n1 = rnd(1000);
 | |
|     n2 = rnd(100);
 | |
|     n3 = rnd(5000);
 | |
|     sprintf((char *)record, "%6d:%4d:%8d:Pos: %4d    ", n1, n2, n3,
 | |
|             write_count);
 | |
|     int4store(record + STANDARD_LENGTH - 4, (long)i);
 | |
|     fix_length(record, (uint)STANDARD_LENGTH + rnd(60));
 | |
|     put_blob_in_record(record + blob_pos, &blob_buffer);
 | |
|     DBUG_PRINT("test", ("record: %d", i));
 | |
| 
 | |
|     if (mi_write(file, record)) {
 | |
|       if (my_errno != HA_ERR_FOUND_DUPP_KEY || key3[n3] == 0) {
 | |
|         printf("Error: %d in write at record: %d\n", my_errno, i);
 | |
|         goto err;
 | |
|       }
 | |
|       if (verbose) printf("   Double key: %d\n", n3);
 | |
|     } else {
 | |
|       if (key3[n3] == 1 && first_key < 3 && first_key + keys >= 3) {
 | |
|         printf("Error: Didn't get error when writing second key: '%8d'\n", n3);
 | |
|         goto err;
 | |
|       }
 | |
|       write_count++;
 | |
|       key1[n1]++;
 | |
|       key3[n3] = 1;
 | |
|     }
 | |
| 
 | |
|     /* Check if we can find key without flushing database */
 | |
|     if (i == recant / 2) {
 | |
|       for (j = rnd(1000) + 1; j > 0 && key1[j] == 0; j--)
 | |
|         ;
 | |
|       if (!j)
 | |
|         for (j = 999; j > 0 && key1[j] == 0; j--)
 | |
|           ;
 | |
|       sprintf((char *)key, "%6d", j);
 | |
|       if (mi_rkey(file, read_record, 0, key, HA_WHOLE_KEY, HA_READ_KEY_EXACT)) {
 | |
|         printf("Test in loop: Can't find key: \"%s\"\n", key);
 | |
|         goto err;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   if (testflag == 1) goto end;
 | |
| 
 | |
|   if (key_cacheing)
 | |
|     resize_key_cache(dflt_key_cache, key_cache_block_size, key_cache_size * 2,
 | |
|                      0, 0);
 | |
| 
 | |
|   if (!silent) printf("- Delete\n");
 | |
|   for (i = 0; i < recant / 10; i++) {
 | |
|     for (j = rnd(1000) + 1; j > 0 && key1[j] == 0; j--)
 | |
|       ;
 | |
|     if (j != 0) {
 | |
|       sprintf((char *)key, "%6d", j);
 | |
|       if (mi_rkey(file, read_record, 0, key, HA_WHOLE_KEY, HA_READ_KEY_EXACT)) {
 | |
|         printf("can't find key1: \"%s\"\n", key);
 | |
|         goto err;
 | |
|       }
 | |
|       if (opt_delete == (uint)remove_count) /* While testing */
 | |
|         goto end;
 | |
|       if (mi_delete(file, read_record)) {
 | |
|         printf("error: %d; can't delete record: \"%s\"\n", my_errno,
 | |
|                read_record);
 | |
|         goto err;
 | |
|       }
 | |
|       opt_delete++;
 | |
|       key1[atoi((char *)read_record + keyinfo[0].seg[0].start)]--;
 | |
|       key3[atoi((char *)read_record + keyinfo[2].seg[0].start)] = 0;
 | |
|     } else
 | |
|       puts("Warning: Skipping delete test because no dupplicate keys");
 | |
|   }
 | |
|   if (testflag == 2) goto end;
 | |
| 
 | |
|   if (!silent) printf("- Update\n");
 | |
|   for (i = 0; i < recant / 10; i++) {
 | |
|     n1 = rnd(1000);
 | |
|     n2 = rnd(100);
 | |
|     n3 = rnd(5000);
 | |
|     sprintf((char *)record2, "%6d:%4d:%8d:XXX: %4d     ", n1, n2, n3, update);
 | |
|     int4store(record2 + STANDARD_LENGTH - 4, (long)i);
 | |
|     fix_length(record2, (uint)STANDARD_LENGTH + rnd(60));
 | |
| 
 | |
|     for (j = rnd(1000) + 1; j > 0 && key1[j] == 0; j--)
 | |
|       ;
 | |
|     if (j != 0) {
 | |
|       sprintf((char *)key, "%6d", j);
 | |
|       if (mi_rkey(file, read_record, 0, key, HA_WHOLE_KEY, HA_READ_KEY_EXACT)) {
 | |
|         printf("can't find key1: \"%s\"\n", (char *)key);
 | |
|         goto err;
 | |
|       }
 | |
|       if (use_blob) {
 | |
|         if (i & 1)
 | |
|           put_blob_in_record(record + blob_pos, &blob_buffer);
 | |
|         else
 | |
|           memmove(record + blob_pos, read_record + blob_pos, 8);
 | |
|       }
 | |
|       if (mi_update(file, read_record, record2)) {
 | |
|         if (my_errno != HA_ERR_FOUND_DUPP_KEY || key3[n3] == 0) {
 | |
|           printf("error: %d; can't update:\nFrom: \"%s\"\nTo:   \"%s\"\n",
 | |
|                  my_errno, read_record, record2);
 | |
|           goto err;
 | |
|         }
 | |
|         if (verbose)
 | |
|           printf(
 | |
|               "Double key when tried to update:\nFrom: \"%s\"\nTo:   \"%s\"\n",
 | |
|               record, record2);
 | |
|       } else {
 | |
|         key1[atoi((char *)read_record + keyinfo[0].seg[0].start)]--;
 | |
|         key3[atoi((char *)read_record + keyinfo[2].seg[0].start)] = 0;
 | |
|         key1[n1]++;
 | |
|         key3[n3] = 1;
 | |
|         update++;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   if (testflag == 3) goto end;
 | |
| 
 | |
|   for (i = 999, dupp_keys = j = 0; i > 0; i--) {
 | |
|     if (key1[i] > dupp_keys) {
 | |
|       dupp_keys = key1[i];
 | |
|       j = i;
 | |
|     }
 | |
|   }
 | |
|   sprintf((char *)key, "%6d", j);
 | |
|   start = keyinfo[0].seg[0].start;
 | |
|   length = keyinfo[0].seg[0].length;
 | |
|   if (dupp_keys) {
 | |
|     if (!silent) printf("- Same key: first - next -> last - prev -> first\n");
 | |
|     DBUG_PRINT("progpos", ("first - next -> last - prev -> first"));
 | |
|     if (verbose) {
 | |
|       printf("	 Using key: \"%s\"  Keys: %d\n", key, dupp_keys);
 | |
|     }
 | |
| 
 | |
|     if (mi_rkey(file, read_record, 0, key, HA_WHOLE_KEY, HA_READ_KEY_EXACT))
 | |
|       goto err;
 | |
|     if (mi_rsame(file, read_record2, -1)) goto err;
 | |
|     if (memcmp(read_record, read_record2, reclength) != 0) {
 | |
|       printf("mi_rsame didn't find same record\n");
 | |
|       goto end;
 | |
|     }
 | |
|     info.recpos = mi_position(file);
 | |
|     if (mi_rfirst(file, read_record2, 0) ||
 | |
|         mi_rsame_with_pos(file, read_record2, 0, info.recpos) ||
 | |
|         memcmp(read_record, read_record2, reclength) != 0) {
 | |
|       printf("mi_rsame_with_pos didn't find same record\n");
 | |
|       goto end;
 | |
|     }
 | |
|     {
 | |
|       int skr = mi_rnext(file, read_record2, 0);
 | |
|       if ((skr && my_errno != HA_ERR_END_OF_FILE) ||
 | |
|           mi_rprev(file, read_record2, -1) ||
 | |
|           memcmp(read_record, read_record2, reclength) != 0) {
 | |
|         printf("mi_rsame_with_pos lost position\n");
 | |
|         goto end;
 | |
|       }
 | |
|     }
 | |
|     ant = 1;
 | |
|     while (mi_rnext(file, read_record2, 0) == 0 &&
 | |
|            memcmp(read_record2 + start, key, length) == 0)
 | |
|       ant++;
 | |
|     if (ant != dupp_keys) {
 | |
|       printf("next: Found: %d keys of %d\n", ant, dupp_keys);
 | |
|       goto end;
 | |
|     }
 | |
|     ant = 0;
 | |
|     while (mi_rprev(file, read_record3, 0) == 0 &&
 | |
|            memcmp(read_record3 + start, key, length) == 0)
 | |
|       ant++;
 | |
|     if (ant != dupp_keys) {
 | |
|       printf("prev: Found: %d records of %d\n", ant, dupp_keys);
 | |
|       goto end;
 | |
|     }
 | |
| 
 | |
|     /* Check of mi_rnext_same */
 | |
|     if (mi_rkey(file, read_record, 0, key, HA_WHOLE_KEY, HA_READ_KEY_EXACT))
 | |
|       goto err;
 | |
|     ant = 1;
 | |
|     while (!mi_rnext_same(file, read_record3) && ant < dupp_keys + 10) ant++;
 | |
|     if (ant != dupp_keys || my_errno != HA_ERR_END_OF_FILE) {
 | |
|       printf("mi_rnext_same: Found: %d records of %d\n", ant, dupp_keys);
 | |
|       goto end;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!silent) printf("- All keys: first - next -> last - prev -> first\n");
 | |
|   DBUG_PRINT("progpos", ("All keys: first - next -> last - prev -> first"));
 | |
|   ant = 1;
 | |
|   if (mi_rfirst(file, read_record, 0)) {
 | |
|     printf("Can't find first record\n");
 | |
|     goto end;
 | |
|   }
 | |
|   while ((error = mi_rnext(file, read_record3, 0)) == 0 &&
 | |
|          ant < write_count + 10)
 | |
|     ant++;
 | |
|   if (ant != write_count - opt_delete || error != HA_ERR_END_OF_FILE) {
 | |
|     printf("next: I found: %d records of %d (error: %d)\n", ant,
 | |
|            write_count - opt_delete, error);
 | |
|     goto end;
 | |
|   }
 | |
|   if (mi_rlast(file, read_record2, 0) ||
 | |
|       memcmp(read_record2, read_record3, reclength)) {
 | |
|     printf("Can't find last record\n");
 | |
|     DBUG_DUMP("record2", (uchar *)read_record2, reclength);
 | |
|     DBUG_DUMP("record3", (uchar *)read_record3, reclength);
 | |
|     goto end;
 | |
|   }
 | |
|   ant = 1;
 | |
|   while (mi_rprev(file, read_record3, 0) == 0 && ant < write_count + 10) ant++;
 | |
|   if (ant != write_count - opt_delete) {
 | |
|     printf("prev: I found: %d records of %d\n", ant, write_count);
 | |
|     goto end;
 | |
|   }
 | |
|   if (memcmp(read_record, read_record3, reclength)) {
 | |
|     printf("Can't find first record\n");
 | |
|     goto end;
 | |
|   }
 | |
| 
 | |
|   if (!silent)
 | |
|     printf("- Test if: Read first - next - prev - prev - next == first\n");
 | |
|   DBUG_PRINT("progpos", ("- Read first - next - prev - prev - next == first"));
 | |
|   if (mi_rfirst(file, read_record, 0) || mi_rnext(file, read_record3, 0) ||
 | |
|       mi_rprev(file, read_record3, 0) || mi_rprev(file, read_record3, 0) == 0 ||
 | |
|       mi_rnext(file, read_record3, 0))
 | |
|     goto err;
 | |
|   if (memcmp(read_record, read_record3, reclength) != 0)
 | |
|     printf("Can't find first record\n");
 | |
| 
 | |
|   if (!silent)
 | |
|     printf("- Test if: Read last - prev - next - next - prev == last\n");
 | |
|   DBUG_PRINT("progpos", ("Read last - prev - next - next - prev == last"));
 | |
|   if (mi_rlast(file, read_record2, 0) || mi_rprev(file, read_record3, 0) ||
 | |
|       mi_rnext(file, read_record3, 0) || mi_rnext(file, read_record3, 0) == 0 ||
 | |
|       mi_rprev(file, read_record3, 0))
 | |
|     goto err;
 | |
|   if (memcmp(read_record2, read_record3, reclength))
 | |
|     printf("Can't find last record\n");
 | |
|   if (dupp_keys > 2) {
 | |
|     if (!silent) printf("- Read key (first) - next - delete - next -> last\n");
 | |
|     DBUG_PRINT("progpos", ("first - next - delete - next -> last"));
 | |
|     if (mi_rkey(file, read_record, 0, key, HA_WHOLE_KEY, HA_READ_KEY_EXACT))
 | |
|       goto err;
 | |
|     if (mi_rnext(file, read_record3, 0)) goto err;
 | |
|     if (mi_delete(file, read_record3)) goto err;
 | |
|     opt_delete++;
 | |
|     ant = 1;
 | |
|     while (mi_rnext(file, read_record3, 0) == 0 &&
 | |
|            memcmp(read_record3 + start, key, length) == 0)
 | |
|       ant++;
 | |
|     if (ant != dupp_keys - 1) {
 | |
|       printf("next: I can only find: %d keys of %d\n", ant, dupp_keys - 1);
 | |
|       goto end;
 | |
|     }
 | |
|   }
 | |
|   if (dupp_keys > 4) {
 | |
|     if (!silent) printf("- Read last of key - prev - delete - prev -> first\n");
 | |
|     DBUG_PRINT("progpos", ("last - prev - delete - prev -> first"));
 | |
|     if (mi_rprev(file, read_record3, 0)) goto err;
 | |
|     if (mi_rprev(file, read_record3, 0)) goto err;
 | |
|     if (mi_delete(file, read_record3)) goto err;
 | |
|     opt_delete++;
 | |
|     ant = 1;
 | |
|     while (mi_rprev(file, read_record3, 0) == 0 &&
 | |
|            memcmp(read_record3 + start, key, length) == 0)
 | |
|       ant++;
 | |
|     if (ant != dupp_keys - 2) {
 | |
|       printf("next: I can only find: %d keys of %d\n", ant, dupp_keys - 2);
 | |
|       goto end;
 | |
|     }
 | |
|   }
 | |
|   if (dupp_keys > 6) {
 | |
|     if (!silent) printf("- Read first - delete - next -> last\n");
 | |
|     DBUG_PRINT("progpos", ("first - delete - next -> last"));
 | |
|     if (mi_rkey(file, read_record3, 0, key, HA_WHOLE_KEY, HA_READ_KEY_EXACT))
 | |
|       goto err;
 | |
|     if (mi_delete(file, read_record3)) goto err;
 | |
|     opt_delete++;
 | |
|     ant = 1;
 | |
|     if (mi_rnext(file, read_record, 0)) goto err; /* Skall finnas poster */
 | |
|     while (mi_rnext(file, read_record3, 0) == 0 &&
 | |
|            memcmp(read_record3 + start, key, length) == 0)
 | |
|       ant++;
 | |
|     if (ant != dupp_keys - 3) {
 | |
|       printf("next: I can only find: %d keys of %d\n", ant, dupp_keys - 3);
 | |
|       goto end;
 | |
|     }
 | |
| 
 | |
|     if (!silent) printf("- Read last - delete - prev -> first\n");
 | |
|     DBUG_PRINT("progpos", ("last - delete - prev -> first"));
 | |
|     if (mi_rprev(file, read_record3, 0)) goto err;
 | |
|     if (mi_delete(file, read_record3)) goto err;
 | |
|     opt_delete++;
 | |
|     ant = 0;
 | |
|     while (mi_rprev(file, read_record3, 0) == 0 &&
 | |
|            memcmp(read_record3 + start, key, length) == 0)
 | |
|       ant++;
 | |
|     if (ant != dupp_keys - 4) {
 | |
|       printf("next: I can only find: %d keys of %d\n", ant, dupp_keys - 4);
 | |
|       goto end;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!silent) puts("- Test if: Read rrnd - same");
 | |
|   DBUG_PRINT("progpos", ("Read rrnd - same"));
 | |
|   for (i = 0; i < write_count; i++) {
 | |
|     if (mi_rrnd(file, read_record, i == 0 ? 0L : HA_OFFSET_ERROR) == 0) break;
 | |
|   }
 | |
|   if (i == write_count) goto err;
 | |
| 
 | |
|   memmove(read_record2, read_record, reclength);
 | |
|   for (i = min(2, keys); i-- > 0;) {
 | |
|     if (mi_rsame(file, read_record2, (int)i)) goto err;
 | |
|     if (memcmp(read_record, read_record2, reclength) != 0) {
 | |
|       printf("is_rsame didn't find same record\n");
 | |
|       goto end;
 | |
|     }
 | |
|   }
 | |
|   if (!silent) puts("- Test mi_records_in_range");
 | |
|   mi_status(file, &info, HA_STATUS_VARIABLE);
 | |
|   for (i = 0; i < info.keys; i++) {
 | |
|     key_range min_key, max_key;
 | |
|     if (mi_rfirst(file, read_record, (int)i) ||
 | |
|         mi_rlast(file, read_record2, (int)i))
 | |
|       goto err;
 | |
|     copy_key(file, (uint)i, (uchar *)read_record, (uchar *)key);
 | |
|     copy_key(file, (uint)i, (uchar *)read_record2, (uchar *)key2);
 | |
|     min_key.key = key;
 | |
|     min_key.keypart_map = HA_WHOLE_KEY;
 | |
|     min_key.flag = HA_READ_KEY_EXACT;
 | |
|     max_key.key = key2;
 | |
|     max_key.keypart_map = HA_WHOLE_KEY;
 | |
|     max_key.flag = HA_READ_AFTER_KEY;
 | |
| 
 | |
|     range_records = mi_records_in_range(file, (int)i, &min_key, &max_key);
 | |
|     if (range_records < info.records * 8 / 10 ||
 | |
|         range_records > info.records * 12 / 10) {
 | |
|       printf("mi_records_range returned %ld; Should be about %ld\n",
 | |
|              (long)range_records, (long)info.records);
 | |
|       goto end;
 | |
|     }
 | |
|     if (verbose) {
 | |
|       printf("mi_records_range returned %ld;  Exact is %ld  (diff: %4.2g %%)\n",
 | |
|              (long)range_records, (long)info.records,
 | |
|              labs((long)range_records - (long)info.records) * 100.0 /
 | |
|                  info.records);
 | |
|     }
 | |
|   }
 | |
|   for (i = 0; i < 5; i++) {
 | |
|     for (j = rnd(1000) + 1; j > 0 && key1[j] == 0; j--)
 | |
|       ;
 | |
|     for (k = rnd(1000) + 1; k > 0 && key1[k] == 0; k--)
 | |
|       ;
 | |
|     if (j != 0 && k != 0) {
 | |
|       key_range min_key, max_key;
 | |
|       if (j > k) swap_variables(int, j, k);
 | |
|       sprintf((char *)key, "%6d", j);
 | |
|       sprintf((char *)key2, "%6d", k);
 | |
| 
 | |
|       min_key.key = key;
 | |
|       min_key.length = USE_WHOLE_KEY;
 | |
|       min_key.flag = HA_READ_AFTER_KEY;
 | |
|       max_key.key = key2;
 | |
|       max_key.length = USE_WHOLE_KEY;
 | |
|       max_key.flag = HA_READ_BEFORE_KEY;
 | |
|       range_records = mi_records_in_range(file, 0, &min_key, &max_key);
 | |
|       records = 0;
 | |
|       for (j++; j < k; j++) records += key1[j];
 | |
|       if ((long)range_records < (long)records * 7 / 10 - 2 ||
 | |
|           (long)range_records > (long)records * 14 / 10 + 2) {
 | |
|         printf(
 | |
|             "mi_records_range for key: %d returned %lu; Should be about %lu\n",
 | |
|             i, (ulong)range_records, (ulong)records);
 | |
|         goto end;
 | |
|       }
 | |
|       if (verbose && records) {
 | |
|         printf(
 | |
|             "mi_records_range returned %lu;  Exact is %lu  (diff: %4.2g %%)\n",
 | |
|             (ulong)range_records, (ulong)records,
 | |
|             labs((long)range_records - (long)records) * 100.0 / records);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!silent) printf("- mi_info\n");
 | |
|   mi_status(file, &info, HA_STATUS_VARIABLE | HA_STATUS_CONST);
 | |
|   if (info.records != write_count - opt_delete ||
 | |
|       info.deleted > opt_delete + update || info.keys != keys) {
 | |
|     puts("Wrong info from mi_info");
 | |
|     printf("Got: records: %lu  delete: %lu  i_keys: %d\n", (ulong)info.records,
 | |
|            (ulong)info.deleted, info.keys);
 | |
|   }
 | |
|   if (verbose) {
 | |
|     char buff[80];
 | |
|     get_date(buff, 3, info.create_time);
 | |
|     printf("info: Created %s\n", buff);
 | |
|     get_date(buff, 3, info.check_time);
 | |
|     printf("info: checked %s\n", buff);
 | |
|     get_date(buff, 3, info.update_time);
 | |
|     printf("info: Modified %s\n", buff);
 | |
|   }
 | |
| 
 | |
|   mi_panic(HA_PANIC_WRITE);
 | |
|   mi_panic(HA_PANIC_READ);
 | |
|   if (mi_is_changed(file))
 | |
|     puts("Warning: mi_is_changed reported that datafile was changed");
 | |
| 
 | |
|   if (!silent) printf("- mi_extra(CACHE) + mi_rrnd.... + mi_extra(NO_CACHE)\n");
 | |
|   if (mi_reset(file)) {
 | |
|     if (locking || (!use_blob && !pack_fields)) {
 | |
|       puts("got error from mi_reset()");
 | |
|       goto end;
 | |
|     }
 | |
|   }
 | |
|   ant = 0;
 | |
|   while ((error = mi_rrnd(file, record, HA_OFFSET_ERROR)) !=
 | |
|              HA_ERR_END_OF_FILE &&
 | |
|          ant < write_count + 10)
 | |
|     ant += error ? 0 : 1;
 | |
|   if (ant != write_count - opt_delete) {
 | |
|     printf("rrnd with cache: I can only find: %d records of %d\n", ant,
 | |
|            write_count - opt_delete);
 | |
|     goto end;
 | |
|   }
 | |
| 
 | |
|   ant = 0;
 | |
|   mi_scan_init(file);
 | |
|   while ((error = mi_scan(file, record)) != HA_ERR_END_OF_FILE &&
 | |
|          ant < write_count + 10)
 | |
|     ant += error ? 0 : 1;
 | |
|   if (ant != write_count - opt_delete) {
 | |
|     printf("scan with cache: I can only find: %d records of %d\n", ant,
 | |
|            write_count - opt_delete);
 | |
|     goto end;
 | |
|   }
 | |
| 
 | |
|   if (testflag == 4) goto end;
 | |
| 
 | |
|   if (!silent) printf("- Removing keys\n");
 | |
|   DBUG_PRINT("progpos", ("Removing keys"));
 | |
|   lastpos = HA_OFFSET_ERROR;
 | |
|   /* DBUG_POP(); */
 | |
|   mi_reset(file);
 | |
|   found_parts = 0;
 | |
|   while ((error = mi_rrnd(file, read_record, HA_OFFSET_ERROR)) !=
 | |
|          HA_ERR_END_OF_FILE) {
 | |
|     info.recpos = mi_position(file);
 | |
|     if (lastpos >= info.recpos && lastpos != HA_OFFSET_ERROR) {
 | |
|       printf("mi_rrnd didn't advance filepointer; old: %ld, new: %ld\n",
 | |
|              (long)lastpos, (long)info.recpos);
 | |
|       goto err;
 | |
|     }
 | |
|     lastpos = info.recpos;
 | |
|     if (error == 0) {
 | |
|       if (opt_delete == (uint)remove_count) /* While testing */
 | |
|         goto end;
 | |
|       if (mi_rsame(file, read_record, -1)) {
 | |
|         printf("can't find record %lx\n", (long)info.recpos);
 | |
|         goto err;
 | |
|       }
 | |
|       if (use_blob) {
 | |
|         ulong blob_length, pos;
 | |
|         uchar *ptr;
 | |
|         longget(blob_length, read_record + blob_pos + 4);
 | |
|         ptr = (uchar *)blob_length;
 | |
|         longget(blob_length, read_record + blob_pos);
 | |
|         for (pos = 0; pos < blob_length; pos++) {
 | |
|           if (ptr[pos] != (uchar)(blob_length + pos)) {
 | |
|             printf("found blob with wrong info at %ld\n", (long)lastpos);
 | |
|             use_blob = 0;
 | |
|             break;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       if (mi_delete(file, read_record)) {
 | |
|         printf("can't delete record: %6.6s,  delete_count: %d\n", read_record,
 | |
|                opt_delete);
 | |
|         goto err;
 | |
|       }
 | |
|       opt_delete++;
 | |
|     } else
 | |
|       found_parts++;
 | |
|   }
 | |
|   if (my_errno != HA_ERR_END_OF_FILE && my_errno != HA_ERR_RECORD_DELETED)
 | |
|     printf("error: %d from mi_rrnd\n", my_errno);
 | |
|   if (write_count != opt_delete) {
 | |
|     printf("Deleted only %d of %d records (%d parts)\n", opt_delete,
 | |
|            write_count, found_parts);
 | |
|     goto err;
 | |
|   }
 | |
| end:
 | |
|   if (mi_close(file)) goto err;
 | |
|   mi_panic(HA_PANIC_CLOSE); /* Should close log */
 | |
|   if (!silent) {
 | |
|     printf("\nFollowing test have been made:\n");
 | |
|     printf(
 | |
|         "Write records: %d\nUpdate records: %d\nSame-key-read: %d\nDelete "
 | |
|         "records: %d\n",
 | |
|         write_count, update, dupp_keys, opt_delete);
 | |
|     if (rec_pointer_size)
 | |
|       printf("Record pointer size:  %d\n", rec_pointer_size);
 | |
|     printf("myisam_block_size:    %lu\n", myisam_block_size);
 | |
|     if (key_cacheing) {
 | |
|       puts("Key cache used");
 | |
|       printf("key_cache_block_size: %u\n", key_cache_block_size);
 | |
|     }
 | |
|     if (async_io && locking)
 | |
|       puts("Asyncron io with locking used");
 | |
|     else if (locking)
 | |
|       puts("Locking used");
 | |
|     if (use_blob) puts("blobs used");
 | |
|     printf(
 | |
|         "key cache status: \n\
 | |
| blocks used:%10lu\n\
 | |
| not flushed:%10lu\n\
 | |
| w_requests: %10lu\n\
 | |
| writes:     %10lu\n\
 | |
| r_requests: %10lu\n\
 | |
| reads:      %10lu\n",
 | |
|         dflt_key_cache->blocks_used, dflt_key_cache->global_blocks_changed,
 | |
|         (ulong)dflt_key_cache->global_cache_w_requests,
 | |
|         (ulong)dflt_key_cache->global_cache_write,
 | |
|         (ulong)dflt_key_cache->global_cache_r_requests,
 | |
|         (ulong)dflt_key_cache->global_cache_read);
 | |
|   }
 | |
|   end_key_cache(dflt_key_cache, 1);
 | |
|   if (blob_buffer) my_free(blob_buffer);
 | |
|   my_end(silent ? MY_CHECK_ERROR : MY_CHECK_ERROR | MY_GIVE_INFO);
 | |
|   return (0);
 | |
| err:
 | |
|   printf("got error: %d when using MyISAM-database\n", my_errno);
 | |
|   if (file) (void)mi_close(file);
 | |
|   return (1);
 | |
| } /* main */
 | |
| 
 | |
| /* l{ser optioner */
 | |
| /* OBS! intierar endast DEBUG - ingen debuggning h{r ! */
 | |
| 
 | |
| static void get_options(int argc, char **argv) {
 | |
|   char *pos, *progname;
 | |
| 
 | |
|   progname = argv[0];
 | |
| 
 | |
|   while (--argc > 0 && *(pos = *(++argv)) == '-') {
 | |
|     switch (*++pos) {
 | |
|       case 'B':
 | |
|         pack_type = HA_BINARY_PACK_KEY;
 | |
|         break;
 | |
|       case 'b':
 | |
|         use_blob = 1;
 | |
|         break;
 | |
|       case 'K': /* Use key cacheing */
 | |
|         key_cacheing = 1;
 | |
|         if (*++pos) key_cache_size = atol(pos);
 | |
|         break;
 | |
|       case 'W': /* Use write cacheing */
 | |
|         // Now ignored, but accept the option for copmatibility.
 | |
|         if (*++pos) my_default_record_cache_size = atoi(pos);
 | |
|         break;
 | |
|       case 'd':
 | |
|         remove_count = atoi(++pos);
 | |
|         break;
 | |
|       case 'i':
 | |
|         if (*++pos) srand(atoi(pos));
 | |
|         break;
 | |
|       case 'l':
 | |
|         use_log = 1;
 | |
|         break;
 | |
|       case 'L':
 | |
|         locking = 1;
 | |
|         break;
 | |
|       case 'A': /* use asyncron io */
 | |
|         async_io = 1;
 | |
|         if (*++pos) my_default_record_cache_size = atoi(pos);
 | |
|         break;
 | |
|       case 'v': /* verbose */
 | |
|         verbose = 1;
 | |
|         break;
 | |
|       case 'm': /* records */
 | |
|         if ((recant = atoi(++pos)) < 10) {
 | |
|           fprintf(stderr, "record count must be >= 10\n");
 | |
|           exit(1);
 | |
|         }
 | |
|         break;
 | |
|       case 'e': /* myisam_block_length */
 | |
|         if ((myisam_block_size = atoi(++pos)) < MI_MIN_KEY_BLOCK_LENGTH ||
 | |
|             myisam_block_size > MI_MAX_KEY_BLOCK_LENGTH) {
 | |
|           fprintf(stderr, "Wrong myisam_block_length\n");
 | |
|           exit(1);
 | |
|         }
 | |
|         myisam_block_size = my_round_up_to_next_power(myisam_block_size);
 | |
|         break;
 | |
|       case 'E': /* myisam_block_length */
 | |
|         if ((key_cache_block_size = atoi(++pos)) < MI_MIN_KEY_BLOCK_LENGTH ||
 | |
|             key_cache_block_size > MI_MAX_KEY_BLOCK_LENGTH) {
 | |
|           fprintf(stderr, "Wrong key_cache_block_size\n");
 | |
|           exit(1);
 | |
|         }
 | |
|         key_cache_block_size = my_round_up_to_next_power(key_cache_block_size);
 | |
|         break;
 | |
|       case 'f':
 | |
|         if ((first_key = atoi(++pos)) < 0 || first_key >= MYISAM_KEYS)
 | |
|           first_key = 0;
 | |
|         break;
 | |
|       case 'k':
 | |
|         if ((keys = (uint)atoi(++pos)) < 1 ||
 | |
|             keys > (uint)(MYISAM_KEYS - first_key))
 | |
|           keys = MYISAM_KEYS - first_key;
 | |
|         break;
 | |
|       case 'P':
 | |
|         pack_type = 0; /* Don't use DIFF_LENGTH */
 | |
|         pack_seg = 0;
 | |
|         break;
 | |
|       case 'R': /* Length of record pointer */
 | |
|         rec_pointer_size = atoi(++pos);
 | |
|         if (rec_pointer_size > 7) rec_pointer_size = 0;
 | |
|         break;
 | |
|       case 'S':
 | |
|         pack_fields = 0; /* Static-length-records */
 | |
|         break;
 | |
|       case 's':
 | |
|         silent = 1;
 | |
|         break;
 | |
|       case 't':
 | |
|         testflag = atoi(++pos); /* testmod */
 | |
|         break;
 | |
|       case 'q':
 | |
|         opt_quick_mode = 1;
 | |
|         break;
 | |
|       case 'c':
 | |
|         create_flag |= HA_CREATE_CHECKSUM;
 | |
|         break;
 | |
|       case 'D':
 | |
|         create_flag |= HA_CREATE_DELAY_KEY_WRITE;
 | |
|         break;
 | |
|       case '?':
 | |
|       case 'I':
 | |
|       case 'V':
 | |
|         printf("%s  Ver 1.2 for %s at %s\n", progname, SYSTEM_TYPE,
 | |
|                MACHINE_TYPE);
 | |
|         puts("By Monty, for your professional use\n");
 | |
|         printf(
 | |
|             "Usage: %s [-?AbBcDIKLPRqSsVWltv] [-k#] [-f#] [-m#] [-e#] [-E#] "
 | |
|             "[-t#]\n",
 | |
|             progname);
 | |
|         exit(0);
 | |
|       case '#':
 | |
|         DBUG_PUSH(++pos);
 | |
|         break;
 | |
|       default:
 | |
|         printf("Illegal option: '%c'\n", *pos);
 | |
|         break;
 | |
|     }
 | |
|   }
 | |
|   return;
 | |
| } /* get options */
 | |
| 
 | |
| /* Get a random value 0 <= x <= n */
 | |
| 
 | |
| static uint rnd(uint max_value) {
 | |
|   return (uint)((rand() & 32767) / 32767.0 * max_value);
 | |
| } /* rnd */
 | |
| 
 | |
| /* Create a variable length record */
 | |
| 
 | |
| static void fix_length(uchar *rec, uint length) {
 | |
|   memmove(rec + STANDARD_LENGTH,
 | |
|           "0123456789012345678901234567890123456789012345678901234567890",
 | |
|           length - STANDARD_LENGTH);
 | |
|   strfill((char *)rec + length, STANDARD_LENGTH + 60 - length, ' ');
 | |
| } /* fix_length */
 | |
| 
 | |
| /* Put maybe a blob in record */
 | |
| 
 | |
| static void put_blob_in_record(uchar *blob_pos, char **blob_buffer) {
 | |
|   ulong i, length;
 | |
|   if (use_blob) {
 | |
|     if (rnd(10) == 0) {
 | |
|       if (!*blob_buffer &&
 | |
|           !(*blob_buffer = my_malloc((uint)use_blob, MYF(MY_WME)))) {
 | |
|         use_blob = 0;
 | |
|         return;
 | |
|       }
 | |
|       length = rnd(use_blob);
 | |
|       for (i = 0; i < length; i++) (*blob_buffer)[i] = (char)(length + i);
 | |
|       int4store(blob_pos, length);
 | |
|       memcpy(blob_pos + 4, blob_buffer, sizeof(char *));
 | |
|     } else {
 | |
|       int4store(blob_pos, 0);
 | |
|     }
 | |
|   }
 | |
|   return;
 | |
| }
 | |
| 
 | |
| static void copy_key(MI_INFO *info, uint inx, uchar *rec, uchar *key_buff) {
 | |
|   HA_KEYSEG *keyseg;
 | |
| 
 | |
|   for (keyseg = info->s->keyinfo[inx].seg; keyseg->type; keyseg++) {
 | |
|     memcpy(key_buff, rec + keyseg->start, (size_t)keyseg->length);
 | |
|     key_buff += keyseg->length;
 | |
|   }
 | |
|   return;
 | |
| }
 | |
| 
 | |
| #include "mi_extrafunc.h"
 |