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 | |
21 | static int check_one_key(HP_KEYDEF *keydef, uint keynr, ulong records, |
22 | ulong blength, my_bool print_status); |
23 | static 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 | |
43 | int 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 | |
100 | static 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 | |
168 | static 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 | |