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