1/* Copyright (c) 2000, 2002-2007 MySQL AB
2 Use is subject to license terms
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
16
17/* Check that heap-structure is ok */
18
19#include "heapdef.h"
20
21static int check_one_key(HP_KEYDEF *keydef, uint keynr, ulong records,
22 ulong blength, my_bool print_status);
23static int check_one_rb_key(HP_INFO *info, uint keynr, ulong records,
24 my_bool print_status);
25
26
27/*
28 Check if keys and rows are ok in a heap table
29
30 SYNOPSIS
31 heap_check_heap()
32 info Table handler
33 print_status Prints some extra status
34
35 NOTES
36 Doesn't change the state of the table handler
37
38 RETURN VALUES
39 0 ok
40 1 error
41*/
42
43int heap_check_heap(HP_INFO *info, my_bool print_status)
44{
45 int error;
46 uint key;
47 ulong records=0, deleted=0, pos, next_block;
48 HP_SHARE *share=info->s;
49 HP_INFO save_info= *info; /* Needed because scan_init */
50 DBUG_ENTER("heap_check_heap");
51
52 for (error=key= 0 ; key < share->keys ; key++)
53 {
54 if (share->keydef[key].algorithm == HA_KEY_ALG_BTREE)
55 error|= check_one_rb_key(info, key, share->records, print_status);
56 else
57 error|= check_one_key(share->keydef + key, key, share->records,
58 share->blength, print_status);
59 }
60 /*
61 This is basicly the same code as in hp_scan, but we repeat it here to
62 get shorter DBUG log file.
63 */
64 for (pos=next_block= 0 ; ; pos++)
65 {
66 if (pos < next_block)
67 {
68 info->current_ptr+= share->block.recbuffer;
69 }
70 else
71 {
72 next_block+= share->block.records_in_block;
73 if (next_block >= share->records+share->deleted)
74 {
75 next_block= share->records+share->deleted;
76 if (pos >= next_block)
77 break; /* End of file */
78 }
79 }
80 hp_find_record(info,pos);
81
82 if (!info->current_ptr[share->visible])
83 deleted++;
84 else
85 records++;
86 }
87
88 if (records != share->records || deleted != share->deleted)
89 {
90 DBUG_PRINT("error",("Found rows: %lu (%lu) deleted %lu (%lu)",
91 records, (ulong) share->records,
92 deleted, (ulong) share->deleted));
93 error= 1;
94 }
95 *info= save_info;
96 DBUG_RETURN(error);
97}
98
99
100static int check_one_key(HP_KEYDEF *keydef, uint keynr, ulong records,
101 ulong blength, my_bool print_status)
102{
103 int error;
104 ulong i,found,max_links,seek,links;
105 ulong rec_link; /* Only used with debugging */
106 ulong hash_buckets_found;
107 HASH_INFO *hash_info;
108
109 error=0;
110 hash_buckets_found= 0;
111 for (i=found=max_links=seek=0 ; i < records ; i++)
112 {
113 hash_info=hp_find_hash(&keydef->block,i);
114 if (hash_info->hash_of_key != hp_rec_hashnr(keydef, hash_info->ptr_to_rec))
115 {
116 DBUG_PRINT("error",
117 ("Found row with wrong hash_of_key at position %lu", i));
118 error= 1;
119 }
120 if (hp_mask(hash_info->hash_of_key, blength, records) == i)
121 {
122 found++;
123 seek++;
124 links=1;
125 while ((hash_info=hash_info->next_key) && found < records + 1)
126 {
127 seek+= ++links;
128 if ((rec_link= hp_mask(hash_info->hash_of_key, blength, records)) != i)
129 {
130 DBUG_PRINT("error",
131 ("Record in wrong link: Link %lu Record: %p Record-link %lu",
132 i, hash_info->ptr_to_rec, rec_link));
133 error=1;
134 }
135 else
136 found++;
137 }
138 if (links > max_links) max_links=links;
139 hash_buckets_found++;
140 }
141 }
142 if (found != records)
143 {
144 DBUG_PRINT("error",("Found %ld of %ld records", found, records));
145 error=1;
146 }
147 if (keydef->hash_buckets != hash_buckets_found)
148 {
149 DBUG_PRINT("error",("Found %ld buckets, stats shows %ld buckets",
150 hash_buckets_found, (long) keydef->hash_buckets));
151 error=1;
152 }
153 DBUG_PRINT("info",
154 ("key: %u records: %ld seeks: %lu max links: %lu "
155 "hitrate: %.2f buckets: %lu",
156 keynr, records,seek,max_links,
157 (float) seek / (float) (records ? records : 1),
158 hash_buckets_found));
159 if (print_status)
160 printf("Key: %u records: %ld seeks: %lu max links: %lu "
161 "hitrate: %.2f buckets: %lu\n",
162 keynr, records, seek, max_links,
163 (float) seek / (float) (records ? records : 1),
164 hash_buckets_found);
165 return error;
166}
167
168static int check_one_rb_key(HP_INFO *info, uint keynr, ulong records,
169 my_bool print_status)
170{
171 HP_KEYDEF *keydef= info->s->keydef + keynr;
172 int error= 0;
173 ulong found= 0;
174 uchar *key, *recpos;
175 uint key_length;
176 uint not_used[2];
177
178 if ((key= tree_search_edge(&keydef->rb_tree, info->parents,
179 &info->last_pos, offsetof(TREE_ELEMENT, left))))
180 {
181 do
182 {
183 memcpy(&recpos, key + (*keydef->get_key_length)(keydef,key), sizeof(uchar*));
184 key_length= hp_rb_make_key(keydef, info->recbuf, recpos, 0);
185 if (ha_key_cmp(keydef->seg, (uchar*) info->recbuf, (uchar*) key,
186 key_length, SEARCH_FIND | SEARCH_SAME, not_used))
187 {
188 error= 1;
189 DBUG_PRINT("error",("Record in wrong link: key: %u Record: %p\n",
190 keynr, recpos));
191 }
192 else
193 found++;
194 key= tree_search_next(&keydef->rb_tree, &info->last_pos,
195 offsetof(TREE_ELEMENT, left),
196 offsetof(TREE_ELEMENT, right));
197 } while (key);
198 }
199 if (found != records)
200 {
201 DBUG_PRINT("error",("Found %lu of %lu records", found, records));
202 error= 1;
203 }
204 if (print_status)
205 printf("Key: %d records: %ld\n", keynr, records);
206 return error;
207}
208