1
by brian
clean slate |
1 |
/* Copyright (C) 2000-2006 MySQL 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
15 |
||
16 |
/* Describe, check and repair of MyISAM tables */
|
|
17 |
||
18 |
/*
|
|
19 |
About checksum calculation.
|
|
20 |
||
21 |
There are two types of checksums. Table checksum and row checksum.
|
|
22 |
||
23 |
Row checksum is an additional byte at the end of dynamic length
|
|
24 |
records. It must be calculated if the table is configured for them.
|
|
25 |
Otherwise they must not be used. The variable
|
|
26 |
MYISAM_SHARE::calc_checksum determines if row checksums are used.
|
|
27 |
MI_INFO::checksum is used as temporary storage during row handling.
|
|
28 |
For parallel repair we must assure that only one thread can use this
|
|
29 |
variable. There is no problem on the write side as this is done by one
|
|
30 |
thread only. But when checking a record after read this could go
|
|
31 |
wrong. But since all threads read through a common read buffer, it is
|
|
32 |
sufficient if only one thread checks it.
|
|
33 |
||
34 |
Table checksum is an eight byte value in the header of the index file.
|
|
35 |
It can be calculated even if row checksums are not used. The variable
|
|
36 |
MI_CHECK::glob_crc is calculated over all records.
|
|
37 |
MI_SORT_PARAM::calc_checksum determines if this should be done. This
|
|
38 |
variable is not part of MI_CHECK because it must be set per thread for
|
|
39 |
parallel repair. The global glob_crc must be changed by one thread
|
|
40 |
only. And it is sufficient to calculate the checksum once only.
|
|
41 |
*/
|
|
42 |
||
76.1.1
by Brian Aker
Final removal of fulltext core from myisam. |
43 |
#include "myisamdef.h" |
612.2.13
by Monty Taylor
Work on removing global.h from headers that should be installed. |
44 |
#include <mystrings/m_string.h> |
1
by brian
clean slate |
45 |
#include <stdarg.h> |
212.5.21
by Monty Taylor
Moved my_getopt.h |
46 |
#include <mysys/my_getopt.h> |
1
by brian
clean slate |
47 |
#ifdef HAVE_SYS_VADVISE_H
|
48 |
#include <sys/vadvise.h> |
|
49 |
#endif
|
|
470
by Monty Taylor
Remove madvise decl. |
50 |
#ifdef HAVE_SYS_TYPES
|
51 |
#include <sys/types.h> |
|
52 |
#endif
|
|
1
by brian
clean slate |
53 |
#ifdef HAVE_SYS_MMAN_H
|
54 |
#include <sys/mman.h> |
|
55 |
#endif
|
|
492.1.7
by Monty Taylor
Moved test() to its own file. |
56 |
#include <drizzled/util/test.h> |
57 |
||
1
by brian
clean slate |
58 |
|
489.1.6
by Monty Taylor
Removed RAID garbage. |
59 |
/* Functions defined in this file */
|
1
by brian
clean slate |
60 |
|
482
by Brian Aker
Remove uint. |
61 |
static int check_k_link(MI_CHECK *param, MI_INFO *info,uint32_t nr); |
1
by brian
clean slate |
62 |
static int chk_index(MI_CHECK *param, MI_INFO *info,MI_KEYDEF *keyinfo, |
481
by Brian Aker
Remove all of uchar. |
63 |
my_off_t page, unsigned char *buff, ha_rows *keys, |
482
by Brian Aker
Remove uint. |
64 |
ha_checksum *key_checksum, uint32_t level); |
65 |
static uint32_t isam_key_length(MI_INFO *info,MI_KEYDEF *keyinfo); |
|
1
by brian
clean slate |
66 |
static ha_checksum calc_checksum(ha_rows count); |
67 |
static int writekeys(MI_SORT_PARAM *sort_param); |
|
68 |
static int sort_one_index(MI_CHECK *param, MI_INFO *info,MI_KEYDEF *keyinfo, |
|
69 |
my_off_t pagepos, File new_file); |
|
70 |
static int sort_key_read(MI_SORT_PARAM *sort_param,void *key); |
|
71 |
static int sort_get_next_record(MI_SORT_PARAM *sort_param); |
|
72 |
static int sort_key_cmp(MI_SORT_PARAM *sort_param, const void *a,const void *b); |
|
73 |
static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a); |
|
74 |
static my_off_t get_record_for_key(MI_INFO *info,MI_KEYDEF *keyinfo, |
|
481
by Brian Aker
Remove all of uchar. |
75 |
unsigned char *key); |
1
by brian
clean slate |
76 |
static int sort_insert_key(MI_SORT_PARAM *sort_param, |
77 |
register SORT_KEY_BLOCKS *key_block, |
|
481
by Brian Aker
Remove all of uchar. |
78 |
unsigned char *key, my_off_t prev_block); |
1
by brian
clean slate |
79 |
static int sort_delete_record(MI_SORT_PARAM *sort_param); |
80 |
/*static int flush_pending_blocks(MI_CHECK *param);*/
|
|
482
by Brian Aker
Remove uint. |
81 |
static SORT_KEY_BLOCKS *alloc_key_blocks(MI_CHECK *param, uint32_t blocks, |
82 |
uint32_t buffer_length); |
|
83 |
static ha_checksum mi_byte_checksum(const unsigned char *buf, uint32_t length); |
|
1
by brian
clean slate |
84 |
static void set_data_file_type(SORT_INFO *sort_info, MYISAM_SHARE *share); |
85 |
||
86 |
void myisamchk_init(MI_CHECK *param) |
|
87 |
{
|
|
212.6.12
by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove(). |
88 |
memset(param, 0, sizeof(*param)); |
1
by brian
clean slate |
89 |
param->opt_follow_links=1; |
151
by Brian Aker
Ulonglong to uint64_t |
90 |
param->keys_in_use= ~(uint64_t) 0; |
1
by brian
clean slate |
91 |
param->search_after_block=HA_OFFSET_ERROR; |
92 |
param->auto_increment_value= 0; |
|
93 |
param->use_buffers=USE_BUFFER_INIT; |
|
94 |
param->read_buffer_length=READ_BUFFER_INIT; |
|
95 |
param->write_buffer_length=READ_BUFFER_INIT; |
|
96 |
param->sort_buffer_length=SORT_BUFFER_INIT; |
|
97 |
param->sort_key_blocks=BUFFERS_WHEN_SORTING; |
|
98 |
param->tmpfile_createflag=O_RDWR | O_TRUNC | O_EXCL; |
|
99 |
param->myf_rw=MYF(MY_NABP | MY_WME | MY_WAIT_IF_FULL); |
|
100 |
param->start_check_pos=0; |
|
163
by Brian Aker
Merge Monty's code. |
101 |
param->max_record_length= INT64_MAX; |
1
by brian
clean slate |
102 |
param->key_cache_block_size= KEY_CACHE_BLOCK_SIZE; |
103 |
param->stats_method= MI_STATS_METHOD_NULLS_NOT_EQUAL; |
|
104 |
}
|
|
105 |
||
106 |
/* Check the status flags for the table */
|
|
107 |
||
108 |
int chk_status(MI_CHECK *param, register MI_INFO *info) |
|
109 |
{
|
|
110 |
MYISAM_SHARE *share=info->s; |
|
111 |
||
112 |
if (mi_is_crashed_on_repair(info)) |
|
113 |
mi_check_print_warning(param, |
|
114 |
"Table is marked as crashed and last repair failed"); |
|
115 |
else if (mi_is_crashed(info)) |
|
116 |
mi_check_print_warning(param, |
|
117 |
"Table is marked as crashed"); |
|
118 |
if (share->state.open_count != (uint) (info->s->global_changed ? 1 : 0)) |
|
119 |
{
|
|
120 |
/* Don't count this as a real warning, as check can correct this ! */
|
|
482
by Brian Aker
Remove uint. |
121 |
uint32_t save=param->warning_printed; |
1
by brian
clean slate |
122 |
mi_check_print_warning(param, |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
123 |
share->state.open_count==1 ? |
124 |
"%d client is using or hasn't closed the table properly" : |
|
1
by brian
clean slate |
125 |
"%d clients are using or haven't closed the table properly", |
126 |
share->state.open_count); |
|
127 |
/* If this will be fixed by the check, forget the warning */
|
|
128 |
if (param->testflag & T_UPDATE_STATE) |
|
129 |
param->warning_printed=save; |
|
130 |
}
|
|
131 |
return 0; |
|
132 |
}
|
|
133 |
||
134 |
/* Check delete links */
|
|
135 |
||
482
by Brian Aker
Remove uint. |
136 |
int chk_del(MI_CHECK *param, register MI_INFO *info, uint32_t test_flag) |
1
by brian
clean slate |
137 |
{
|
138 |
register ha_rows i; |
|
482
by Brian Aker
Remove uint. |
139 |
uint32_t delete_link_length; |
1
by brian
clean slate |
140 |
my_off_t empty, next_link, old_link= 0; |
141 |
char buff[22],buff2[22]; |
|
142 |
||
143 |
param->record_checksum=0; |
|
144 |
delete_link_length=((info->s->options & HA_OPTION_PACK_RECORD) ? 20 : |
|
145 |
info->s->rec_reflength+1); |
|
146 |
||
147 |
if (!(test_flag & T_SILENT)) |
|
148 |
puts("- check record delete-chain"); |
|
149 |
||
150 |
next_link=info->s->state.dellink; |
|
151 |
if (info->state->del == 0) |
|
152 |
{
|
|
153 |
if (test_flag & T_VERBOSE) |
|
154 |
{
|
|
155 |
puts("No recordlinks"); |
|
156 |
}
|
|
157 |
}
|
|
158 |
else
|
|
159 |
{
|
|
160 |
if (test_flag & T_VERBOSE) |
|
161 |
printf("Recordlinks: "); |
|
162 |
empty=0; |
|
163 |
for (i= info->state->del ; i > 0L && next_link != HA_OFFSET_ERROR ; i--) |
|
164 |
{
|
|
165 |
if (*killed_ptr(param)) |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
166 |
return(1); |
1
by brian
clean slate |
167 |
if (test_flag & T_VERBOSE) |
168 |
printf(" %9s",llstr(next_link,buff)); |
|
169 |
if (next_link >= info->state->data_file_length) |
|
170 |
goto wrong; |
|
481
by Brian Aker
Remove all of uchar. |
171 |
if (my_pread(info->dfile, (unsigned char*) buff,delete_link_length, |
1
by brian
clean slate |
172 |
next_link,MYF(MY_NABP))) |
173 |
{
|
|
174 |
if (test_flag & T_VERBOSE) puts(""); |
|
175 |
mi_check_print_error(param,"Can't read delete-link at filepos: %s", |
|
176 |
llstr(next_link,buff)); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
177 |
return(1); |
1
by brian
clean slate |
178 |
}
|
179 |
if (*buff != '\0') |
|
180 |
{
|
|
181 |
if (test_flag & T_VERBOSE) puts(""); |
|
182 |
mi_check_print_error(param,"Record at pos: %s is not remove-marked", |
|
183 |
llstr(next_link,buff)); |
|
184 |
goto wrong; |
|
185 |
}
|
|
186 |
if (info->s->options & HA_OPTION_PACK_RECORD) |
|
187 |
{
|
|
188 |
my_off_t prev_link=mi_sizekorr(buff+12); |
|
189 |
if (empty && prev_link != old_link) |
|
190 |
{
|
|
191 |
if (test_flag & T_VERBOSE) puts(""); |
|
192 |
mi_check_print_error(param,"Deleted block at %s doesn't point back at previous delete link",llstr(next_link,buff2)); |
|
193 |
goto wrong; |
|
194 |
}
|
|
195 |
old_link=next_link; |
|
196 |
next_link=mi_sizekorr(buff+4); |
|
197 |
empty+=mi_uint3korr(buff+1); |
|
198 |
}
|
|
199 |
else
|
|
200 |
{
|
|
201 |
param->record_checksum+=(ha_checksum) next_link; |
|
481
by Brian Aker
Remove all of uchar. |
202 |
next_link=_mi_rec_pos(info->s,(unsigned char*) buff+1); |
1
by brian
clean slate |
203 |
empty+=info->s->base.pack_reclength; |
204 |
}
|
|
205 |
}
|
|
206 |
if (test_flag & T_VERBOSE) |
|
207 |
puts("\n"); |
|
208 |
if (empty != info->state->empty) |
|
209 |
{
|
|
210 |
mi_check_print_warning(param, |
|
211 |
"Found %s deleted space in delete link chain. Should be %s", |
|
212 |
llstr(empty,buff2), |
|
213 |
llstr(info->state->empty,buff)); |
|
214 |
}
|
|
215 |
if (next_link != HA_OFFSET_ERROR) |
|
216 |
{
|
|
217 |
mi_check_print_error(param, |
|
218 |
"Found more than the expected %s deleted rows in delete link chain", |
|
219 |
llstr(info->state->del, buff)); |
|
220 |
goto wrong; |
|
221 |
}
|
|
222 |
if (i != 0) |
|
223 |
{
|
|
224 |
mi_check_print_error(param, |
|
225 |
"Found %s deleted rows in delete link chain. Should be %s", |
|
226 |
llstr(info->state->del - i, buff2), |
|
227 |
llstr(info->state->del, buff)); |
|
228 |
goto wrong; |
|
229 |
}
|
|
230 |
}
|
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
231 |
return(0); |
1
by brian
clean slate |
232 |
|
233 |
wrong: |
|
234 |
param->testflag|=T_RETRY_WITHOUT_QUICK; |
|
235 |
if (test_flag & T_VERBOSE) puts(""); |
|
236 |
mi_check_print_error(param,"record delete-link-chain corrupted"); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
237 |
return(1); |
1
by brian
clean slate |
238 |
} /* chk_del */ |
239 |
||
240 |
||
241 |
/* Check delete links in index file */
|
|
242 |
||
482
by Brian Aker
Remove uint. |
243 |
static int check_k_link(MI_CHECK *param, register MI_INFO *info, uint32_t nr) |
1
by brian
clean slate |
244 |
{
|
245 |
my_off_t next_link; |
|
482
by Brian Aker
Remove uint. |
246 |
uint32_t block_size=(nr+1)*MI_MIN_KEY_BLOCK_LENGTH; |
1
by brian
clean slate |
247 |
ha_rows records; |
248 |
char llbuff[21], llbuff2[21]; |
|
481
by Brian Aker
Remove all of uchar. |
249 |
unsigned char *buff; |
1
by brian
clean slate |
250 |
|
251 |
if (param->testflag & T_VERBOSE) |
|
252 |
printf("block_size %4u:", block_size); /* purecov: tested */ |
|
253 |
||
254 |
next_link=info->s->state.key_del[nr]; |
|
255 |
records= (ha_rows) (info->state->key_file_length / block_size); |
|
256 |
while (next_link != HA_OFFSET_ERROR && records > 0) |
|
257 |
{
|
|
258 |
if (*killed_ptr(param)) |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
259 |
return(1); |
1
by brian
clean slate |
260 |
if (param->testflag & T_VERBOSE) |
261 |
printf("%16s",llstr(next_link,llbuff)); |
|
262 |
||
263 |
/* Key blocks must lay within the key file length entirely. */
|
|
264 |
if (next_link + block_size > info->state->key_file_length) |
|
265 |
{
|
|
266 |
/* purecov: begin tested */
|
|
267 |
mi_check_print_error(param, "Invalid key block position: %s " |
|
268 |
"key block size: %u file_length: %s", |
|
269 |
llstr(next_link, llbuff), block_size, |
|
270 |
llstr(info->state->key_file_length, llbuff2)); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
271 |
return(1); |
1
by brian
clean slate |
272 |
/* purecov: end */
|
273 |
}
|
|
274 |
||
275 |
/* Key blocks must be aligned at MI_MIN_KEY_BLOCK_LENGTH. */
|
|
276 |
if (next_link & (MI_MIN_KEY_BLOCK_LENGTH - 1)) |
|
277 |
{
|
|
278 |
/* purecov: begin tested */
|
|
279 |
mi_check_print_error(param, "Mis-aligned key block: %s " |
|
280 |
"minimum key block length: %u", |
|
281 |
llstr(next_link, llbuff), MI_MIN_KEY_BLOCK_LENGTH); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
282 |
return(1); |
1
by brian
clean slate |
283 |
/* purecov: end */
|
284 |
}
|
|
285 |
||
286 |
/*
|
|
287 |
Read the key block with MI_MIN_KEY_BLOCK_LENGTH to find next link.
|
|
288 |
If the key cache block size is smaller than block_size, we can so
|
|
289 |
avoid unecessary eviction of cache block.
|
|
290 |
*/
|
|
291 |
if (!(buff=key_cache_read(info->s->key_cache, |
|
292 |
info->s->kfile, next_link, DFLT_INIT_HITS, |
|
481
by Brian Aker
Remove all of uchar. |
293 |
(unsigned char*) info->buff, MI_MIN_KEY_BLOCK_LENGTH, |
1
by brian
clean slate |
294 |
MI_MIN_KEY_BLOCK_LENGTH, 1))) |
295 |
{
|
|
296 |
/* purecov: begin tested */
|
|
297 |
mi_check_print_error(param, "key cache read error for block: %s", |
|
298 |
llstr(next_link,llbuff)); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
299 |
return(1); |
1
by brian
clean slate |
300 |
/* purecov: end */
|
301 |
}
|
|
302 |
next_link=mi_sizekorr(buff); |
|
303 |
records--; |
|
304 |
param->key_file_blocks+=block_size; |
|
305 |
}
|
|
306 |
if (param->testflag & T_VERBOSE) |
|
307 |
{
|
|
308 |
if (next_link != HA_OFFSET_ERROR) |
|
309 |
printf("%16s\n",llstr(next_link,llbuff)); |
|
310 |
else
|
|
311 |
puts(""); |
|
312 |
}
|
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
313 |
return (next_link != HA_OFFSET_ERROR); |
1
by brian
clean slate |
314 |
} /* check_k_link */ |
315 |
||
316 |
||
317 |
/* Check sizes of files */
|
|
318 |
||
319 |
int chk_size(MI_CHECK *param, register MI_INFO *info) |
|
320 |
{
|
|
321 |
int error=0; |
|
322 |
register my_off_t skr,size; |
|
323 |
char buff[22],buff2[22]; |
|
324 |
||
325 |
if (!(param->testflag & T_SILENT)) puts("- check file-size"); |
|
326 |
||
327 |
/* The following is needed if called externally (not from myisamchk) */
|
|
328 |
flush_key_blocks(info->s->key_cache, |
|
329 |
info->s->kfile, FLUSH_FORCE_WRITE); |
|
330 |
||
656.1.39
by Monty Taylor
Removed my_seek, my_tell, my_fwrite, my_fseek. |
331 |
size= lseek(info->s->kfile, 0, SEEK_END); |
1
by brian
clean slate |
332 |
if ((skr=(my_off_t) info->state->key_file_length) != size) |
333 |
{
|
|
334 |
/* Don't give error if file generated by myisampack */
|
|
335 |
if (skr > size && mi_is_any_key_active(info->s->state.key_map)) |
|
336 |
{
|
|
337 |
error=1; |
|
338 |
mi_check_print_error(param, |
|
339 |
"Size of indexfile is: %-8s Should be: %s", |
|
340 |
llstr(size,buff), llstr(skr,buff2)); |
|
341 |
}
|
|
342 |
else
|
|
343 |
mi_check_print_warning(param, |
|
344 |
"Size of indexfile is: %-8s Should be: %s", |
|
345 |
llstr(size,buff), llstr(skr,buff2)); |
|
346 |
}
|
|
347 |
if (!(param->testflag & T_VERY_SILENT) && |
|
348 |
! (info->s->options & HA_OPTION_COMPRESS_RECORD) && |
|
151
by Brian Aker
Ulonglong to uint64_t |
349 |
uint64_t2double(info->state->key_file_length) > |
350 |
uint64_t2double(info->s->base.margin_key_file_length)*0.9) |
|
1
by brian
clean slate |
351 |
mi_check_print_warning(param,"Keyfile is almost full, %10s of %10s used", |
352 |
llstr(info->state->key_file_length,buff), |
|
353 |
llstr(info->s->base.max_key_file_length-1,buff)); |
|
354 |
||
656.1.39
by Monty Taylor
Removed my_seek, my_tell, my_fwrite, my_fseek. |
355 |
size=lseek(info->dfile,0L,SEEK_END); |
1
by brian
clean slate |
356 |
skr=(my_off_t) info->state->data_file_length; |
357 |
if (info->s->options & HA_OPTION_COMPRESS_RECORD) |
|
358 |
skr+= MEMMAP_EXTRA_MARGIN; |
|
359 |
#ifdef USE_RELOC
|
|
360 |
if (info->data_file_type == STATIC_RECORD && |
|
361 |
skr < (my_off_t) info->s->base.reloc*info->s->base.min_pack_length) |
|
362 |
skr=(my_off_t) info->s->base.reloc*info->s->base.min_pack_length; |
|
363 |
#endif
|
|
364 |
if (skr != size) |
|
365 |
{
|
|
366 |
info->state->data_file_length=size; /* Skip other errors */ |
|
367 |
if (skr > size && skr != size + MEMMAP_EXTRA_MARGIN) |
|
368 |
{
|
|
369 |
error=1; |
|
370 |
mi_check_print_error(param,"Size of datafile is: %-9s Should be: %s", |
|
371 |
llstr(size,buff), llstr(skr,buff2)); |
|
372 |
param->testflag|=T_RETRY_WITHOUT_QUICK; |
|
373 |
}
|
|
374 |
else
|
|
375 |
{
|
|
376 |
mi_check_print_warning(param, |
|
377 |
"Size of datafile is: %-9s Should be: %s", |
|
378 |
llstr(size,buff), llstr(skr,buff2)); |
|
379 |
}
|
|
380 |
}
|
|
381 |
if (!(param->testflag & T_VERY_SILENT) && |
|
382 |
!(info->s->options & HA_OPTION_COMPRESS_RECORD) && |
|
151
by Brian Aker
Ulonglong to uint64_t |
383 |
uint64_t2double(info->state->data_file_length) > |
384 |
(uint64_t2double(info->s->base.max_data_file_length)*0.9)) |
|
1
by brian
clean slate |
385 |
mi_check_print_warning(param, "Datafile is almost full, %10s of %10s used", |
386 |
llstr(info->state->data_file_length,buff), |
|
387 |
llstr(info->s->base.max_data_file_length-1,buff2)); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
388 |
return(error); |
1
by brian
clean slate |
389 |
} /* chk_size */ |
390 |
||
391 |
||
392 |
/* Check keys */
|
|
393 |
||
394 |
int chk_key(MI_CHECK *param, register MI_INFO *info) |
|
395 |
{
|
|
482
by Brian Aker
Remove uint. |
396 |
uint32_t key,found_keys=0,full_text_keys=0,result=0; |
1
by brian
clean slate |
397 |
ha_rows keys; |
398 |
ha_checksum old_record_checksum,init_checksum; |
|
399 |
my_off_t all_keydata,all_totaldata,key_totlength,length; |
|
400 |
ulong *rec_per_key_part; |
|
401 |
MYISAM_SHARE *share=info->s; |
|
402 |
MI_KEYDEF *keyinfo; |
|
403 |
char buff[22],buff2[22]; |
|
404 |
||
405 |
if (!(param->testflag & T_SILENT)) |
|
406 |
puts("- check key delete-chain"); |
|
407 |
||
408 |
param->key_file_blocks=info->s->base.keystart; |
|
409 |
for (key=0 ; key < info->s->state.header.max_block_size_index ; key++) |
|
410 |
if (check_k_link(param,info,key)) |
|
411 |
{
|
|
412 |
if (param->testflag & T_VERBOSE) puts(""); |
|
413 |
mi_check_print_error(param,"key delete-link-chain corrupted"); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
414 |
return(-1); |
1
by brian
clean slate |
415 |
}
|
416 |
||
417 |
if (!(param->testflag & T_SILENT)) puts("- check index reference"); |
|
418 |
||
419 |
all_keydata=all_totaldata=key_totlength=0; |
|
420 |
old_record_checksum=0; |
|
421 |
init_checksum=param->record_checksum; |
|
422 |
if (!(share->options & |
|
423 |
(HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD))) |
|
424 |
old_record_checksum=calc_checksum(info->state->records+info->state->del-1)* |
|
425 |
share->base.pack_reclength; |
|
426 |
rec_per_key_part= param->rec_per_key_part; |
|
427 |
for (key= 0,keyinfo= &share->keyinfo[0]; key < share->base.keys ; |
|
428 |
rec_per_key_part+=keyinfo->keysegs, key++, keyinfo++) |
|
429 |
{
|
|
430 |
param->key_crc[key]=0; |
|
431 |
if (! mi_is_key_active(share->state.key_map, key)) |
|
432 |
{
|
|
433 |
/* Remember old statistics for key */
|
|
212.6.12
by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove(). |
434 |
assert(rec_per_key_part >= param->rec_per_key_part); |
435 |
memcpy(rec_per_key_part, |
|
436 |
(share->state.rec_per_key_part + |
|
437 |
(rec_per_key_part - param->rec_per_key_part)), |
|
1
by brian
clean slate |
438 |
keyinfo->keysegs*sizeof(*rec_per_key_part)); |
439 |
continue; |
|
440 |
}
|
|
441 |
found_keys++; |
|
442 |
||
443 |
param->record_checksum=init_checksum; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
444 |
|
212.6.12
by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove(). |
445 |
memset(¶m->unique_count, 0, sizeof(param->unique_count)); |
446 |
memset(¶m->notnull_count, 0, sizeof(param->notnull_count)); |
|
1
by brian
clean slate |
447 |
|
448 |
if ((!(param->testflag & T_SILENT))) |
|
449 |
printf ("- check data record references index: %d\n",key+1); |
|
249
by Brian Aker
Random key cleanup (it is a friday...) |
450 |
if (share->state.key_root[key] == HA_OFFSET_ERROR && (info->state->records == 0)) |
1
by brian
clean slate |
451 |
goto do_stat; |
452 |
if (!_mi_fetch_keypage(info,keyinfo,share->state.key_root[key], |
|
453 |
DFLT_INIT_HITS,info->buff,0)) |
|
454 |
{
|
|
455 |
mi_check_print_error(param,"Can't read indexpage from filepos: %s", |
|
456 |
llstr(share->state.key_root[key],buff)); |
|
457 |
if (!(param->testflag & T_INFO)) |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
458 |
return(-1); |
1
by brian
clean slate |
459 |
result= -1; |
460 |
continue; |
|
461 |
}
|
|
462 |
param->key_file_blocks+=keyinfo->block_length; |
|
463 |
keys=0; |
|
464 |
param->keydata=param->totaldata=0; |
|
465 |
param->key_blocks=0; |
|
466 |
param->max_level=0; |
|
467 |
if (chk_index(param,info,keyinfo,share->state.key_root[key],info->buff, |
|
468 |
&keys, param->key_crc+key,1)) |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
469 |
return(-1); |
249
by Brian Aker
Random key cleanup (it is a friday...) |
470 |
if(!(0)) |
1
by brian
clean slate |
471 |
{
|
472 |
if (keys != info->state->records) |
|
473 |
{
|
|
474 |
mi_check_print_error(param,"Found %s keys of %s",llstr(keys,buff), |
|
475 |
llstr(info->state->records,buff2)); |
|
476 |
if (!(param->testflag & T_INFO)) |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
477 |
return(-1); |
1
by brian
clean slate |
478 |
result= -1; |
479 |
continue; |
|
480 |
}
|
|
481 |
if (found_keys - full_text_keys == 1 && |
|
482 |
((share->options & |
|
483 |
(HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) || |
|
484 |
(param->testflag & T_DONT_CHECK_CHECKSUM))) |
|
485 |
old_record_checksum=param->record_checksum; |
|
486 |
else if (old_record_checksum != param->record_checksum) |
|
487 |
{
|
|
488 |
if (key) |
|
489 |
mi_check_print_error(param,"Key %u doesn't point at same records that key 1", |
|
490 |
key+1); |
|
491 |
else
|
|
492 |
mi_check_print_error(param,"Key 1 doesn't point at all records"); |
|
493 |
if (!(param->testflag & T_INFO)) |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
494 |
return(-1); |
1
by brian
clean slate |
495 |
result= -1; |
496 |
continue; |
|
497 |
}
|
|
498 |
}
|
|
499 |
if ((uint) share->base.auto_key -1 == key) |
|
500 |
{
|
|
501 |
/* Check that auto_increment key is bigger than max key value */
|
|
151
by Brian Aker
Ulonglong to uint64_t |
502 |
uint64_t auto_increment; |
1
by brian
clean slate |
503 |
info->lastinx=key; |
504 |
_mi_read_key_record(info, 0L, info->rec_buff); |
|
505 |
auto_increment= retrieve_auto_increment(info, info->rec_buff); |
|
506 |
if (auto_increment > info->s->state.auto_increment) |
|
507 |
{
|
|
508 |
mi_check_print_warning(param, "Auto-increment value: %s is smaller " |
|
509 |
"than max used value: %s", |
|
510 |
llstr(info->s->state.auto_increment,buff2), |
|
511 |
llstr(auto_increment, buff)); |
|
512 |
}
|
|
513 |
if (param->testflag & T_AUTO_INC) |
|
514 |
{
|
|
515 |
set_if_bigger(info->s->state.auto_increment, |
|
516 |
auto_increment); |
|
517 |
set_if_bigger(info->s->state.auto_increment, |
|
518 |
param->auto_increment_value); |
|
519 |
}
|
|
520 |
||
521 |
/* Check that there isn't a row with auto_increment = 0 in the table */
|
|
522 |
mi_extra(info,HA_EXTRA_KEYREAD,0); |
|
212.6.1
by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file. |
523 |
memset(info->lastkey, 0, keyinfo->seg->length); |
481
by Brian Aker
Remove all of uchar. |
524 |
if (!mi_rkey(info, info->rec_buff, key, (const unsigned char*) info->lastkey, |
1
by brian
clean slate |
525 |
(key_part_map)1, HA_READ_KEY_EXACT)) |
526 |
{
|
|
527 |
/* Don't count this as a real warning, as myisamchk can't correct it */
|
|
482
by Brian Aker
Remove uint. |
528 |
uint32_t save=param->warning_printed; |
1
by brian
clean slate |
529 |
mi_check_print_warning(param, "Found row where the auto_increment " |
530 |
"column has the value 0"); |
|
531 |
param->warning_printed=save; |
|
532 |
}
|
|
533 |
mi_extra(info,HA_EXTRA_NO_KEYREAD,0); |
|
534 |
}
|
|
535 |
||
536 |
length=(my_off_t) isam_key_length(info,keyinfo)*keys + param->key_blocks*2; |
|
537 |
if (param->testflag & T_INFO && param->totaldata != 0L && keys != 0L) |
|
538 |
printf("Key: %2d: Keyblocks used: %3d%% Packed: %4d%% Max levels: %2d\n", |
|
539 |
key+1, |
|
540 |
(int) (my_off_t2double(param->keydata)*100.0/my_off_t2double(param->totaldata)), |
|
541 |
(int) ((my_off_t2double(length) - my_off_t2double(param->keydata))*100.0/ |
|
542 |
my_off_t2double(length)), |
|
543 |
param->max_level); |
|
544 |
all_keydata+=param->keydata; all_totaldata+=param->totaldata; key_totlength+=length; |
|
545 |
||
546 |
do_stat: |
|
547 |
if (param->testflag & T_STATISTICS) |
|
548 |
update_key_parts(keyinfo, rec_per_key_part, param->unique_count, |
|
549 |
param->stats_method == MI_STATS_METHOD_IGNORE_NULLS? |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
550 |
param->notnull_count: NULL, |
151
by Brian Aker
Ulonglong to uint64_t |
551 |
(uint64_t)info->state->records); |
1
by brian
clean slate |
552 |
}
|
553 |
if (param->testflag & T_INFO) |
|
554 |
{
|
|
555 |
if (all_totaldata != 0L && found_keys > 0) |
|
556 |
printf("Total: Keyblocks used: %3d%% Packed: %4d%%\n\n", |
|
557 |
(int) (my_off_t2double(all_keydata)*100.0/ |
|
558 |
my_off_t2double(all_totaldata)), |
|
559 |
(int) ((my_off_t2double(key_totlength) - |
|
560 |
my_off_t2double(all_keydata))*100.0/ |
|
561 |
my_off_t2double(key_totlength))); |
|
562 |
else if (all_totaldata != 0L && mi_is_any_key_active(share->state.key_map)) |
|
563 |
puts(""); |
|
564 |
}
|
|
565 |
if (param->key_file_blocks != info->state->key_file_length && |
|
151
by Brian Aker
Ulonglong to uint64_t |
566 |
param->keys_in_use != ~(uint64_t) 0) |
1
by brian
clean slate |
567 |
mi_check_print_warning(param, "Some data are unreferenced in keyfile"); |
568 |
if (found_keys != full_text_keys) |
|
569 |
param->record_checksum=old_record_checksum-init_checksum; /* Remove delete links */ |
|
570 |
else
|
|
571 |
param->record_checksum=0; |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
572 |
return(result); |
1
by brian
clean slate |
573 |
} /* chk_key */ |
574 |
||
575 |
||
576 |
static int chk_index_down(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, |
|
481
by Brian Aker
Remove all of uchar. |
577 |
my_off_t page, unsigned char *buff, ha_rows *keys, |
482
by Brian Aker
Remove uint. |
578 |
ha_checksum *key_checksum, uint32_t level) |
1
by brian
clean slate |
579 |
{
|
580 |
char llbuff[22],llbuff2[22]; |
|
581 |
||
582 |
/* Key blocks must lay within the key file length entirely. */
|
|
583 |
if (page + keyinfo->block_length > info->state->key_file_length) |
|
584 |
{
|
|
585 |
/* purecov: begin tested */
|
|
586 |
/* Give it a chance to fit in the real file size. */
|
|
656.1.39
by Monty Taylor
Removed my_seek, my_tell, my_fwrite, my_fseek. |
587 |
my_off_t max_length= lseek(info->s->kfile, 0, SEEK_END); |
1
by brian
clean slate |
588 |
mi_check_print_error(param, "Invalid key block position: %s " |
589 |
"key block size: %u file_length: %s", |
|
590 |
llstr(page, llbuff), keyinfo->block_length, |
|
591 |
llstr(info->state->key_file_length, llbuff2)); |
|
592 |
if (page + keyinfo->block_length > max_length) |
|
593 |
goto err; |
|
594 |
/* Fix the remebered key file length. */
|
|
595 |
info->state->key_file_length= (max_length & |
|
596 |
~ (my_off_t) (keyinfo->block_length - 1)); |
|
597 |
/* purecov: end */
|
|
598 |
}
|
|
599 |
||
600 |
/* Key blocks must be aligned at MI_MIN_KEY_BLOCK_LENGTH. */
|
|
601 |
if (page & (MI_MIN_KEY_BLOCK_LENGTH - 1)) |
|
602 |
{
|
|
603 |
/* purecov: begin tested */
|
|
604 |
mi_check_print_error(param, "Mis-aligned key block: %s " |
|
605 |
"minimum key block length: %u", |
|
606 |
llstr(page, llbuff), MI_MIN_KEY_BLOCK_LENGTH); |
|
607 |
goto err; |
|
608 |
/* purecov: end */
|
|
609 |
}
|
|
610 |
||
611 |
if (!_mi_fetch_keypage(info,keyinfo,page, DFLT_INIT_HITS,buff,0)) |
|
612 |
{
|
|
613 |
mi_check_print_error(param,"Can't read key from filepos: %s", |
|
614 |
llstr(page,llbuff)); |
|
615 |
goto err; |
|
616 |
}
|
|
617 |
param->key_file_blocks+=keyinfo->block_length; |
|
618 |
if (chk_index(param,info,keyinfo,page,buff,keys,key_checksum,level)) |
|
619 |
goto err; |
|
620 |
||
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
621 |
return(0); |
1
by brian
clean slate |
622 |
|
623 |
/* purecov: begin tested */
|
|
624 |
err: |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
625 |
return(1); |
1
by brian
clean slate |
626 |
/* purecov: end */
|
627 |
}
|
|
628 |
||
629 |
||
630 |
/*
|
|
631 |
"Ignore NULLs" statistics collection method: process first index tuple.
|
|
632 |
||
633 |
SYNOPSIS
|
|
634 |
mi_collect_stats_nonulls_first()
|
|
635 |
keyseg IN Array of key part descriptions
|
|
636 |
notnull INOUT Array, notnull[i] = (number of {keypart1...keypart_i}
|
|
637 |
tuples that don't contain NULLs)
|
|
638 |
key IN Key values tuple
|
|
639 |
||
640 |
DESCRIPTION
|
|
641 |
Process the first index tuple - find out which prefix tuples don't
|
|
642 |
contain NULLs, and update the array of notnull counters accordingly.
|
|
643 |
*/
|
|
644 |
||
645 |
static
|
|
151
by Brian Aker
Ulonglong to uint64_t |
646 |
void mi_collect_stats_nonulls_first(HA_KEYSEG *keyseg, uint64_t *notnull, |
481
by Brian Aker
Remove all of uchar. |
647 |
unsigned char *key) |
1
by brian
clean slate |
648 |
{
|
482
by Brian Aker
Remove uint. |
649 |
uint32_t first_null, kp; |
1
by brian
clean slate |
650 |
first_null= ha_find_null(keyseg, key) - keyseg; |
651 |
/*
|
|
652 |
All prefix tuples that don't include keypart_{first_null} are not-null
|
|
653 |
tuples (and all others aren't), increment counters for them.
|
|
654 |
*/
|
|
655 |
for (kp= 0; kp < first_null; kp++) |
|
656 |
notnull[kp]++; |
|
657 |
}
|
|
658 |
||
659 |
||
660 |
/*
|
|
661 |
"Ignore NULLs" statistics collection method: process next index tuple.
|
|
662 |
||
663 |
SYNOPSIS
|
|
664 |
mi_collect_stats_nonulls_next()
|
|
665 |
keyseg IN Array of key part descriptions
|
|
666 |
notnull INOUT Array, notnull[i] = (number of {keypart1...keypart_i}
|
|
667 |
tuples that don't contain NULLs)
|
|
668 |
prev_key IN Previous key values tuple
|
|
669 |
last_key IN Next key values tuple
|
|
670 |
||
671 |
DESCRIPTION
|
|
672 |
Process the next index tuple:
|
|
673 |
1. Find out which prefix tuples of last_key don't contain NULLs, and
|
|
674 |
update the array of notnull counters accordingly.
|
|
675 |
2. Find the first keypart number where the prev_key and last_key tuples
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
676 |
are different(A), or last_key has NULL value(B), and return it, so the
|
677 |
caller can count number of unique tuples for each key prefix. We don't
|
|
678 |
need (B) to be counted, and that is compensated back in
|
|
1
by brian
clean slate |
679 |
update_key_parts().
|
680 |
||
681 |
RETURN
|
|
682 |
1 + number of first keypart where values differ or last_key tuple has NULL
|
|
683 |
*/
|
|
684 |
||
685 |
static
|
|
151
by Brian Aker
Ulonglong to uint64_t |
686 |
int mi_collect_stats_nonulls_next(HA_KEYSEG *keyseg, uint64_t *notnull, |
481
by Brian Aker
Remove all of uchar. |
687 |
unsigned char *prev_key, unsigned char *last_key) |
1
by brian
clean slate |
688 |
{
|
482
by Brian Aker
Remove uint. |
689 |
uint32_t diffs[2]; |
690 |
uint32_t first_null_seg, kp; |
|
1
by brian
clean slate |
691 |
HA_KEYSEG *seg; |
692 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
693 |
/*
|
1
by brian
clean slate |
694 |
Find the first keypart where values are different or either of them is
|
695 |
NULL. We get results in diffs array:
|
|
696 |
diffs[0]= 1 + number of first different keypart
|
|
697 |
diffs[1]=offset: (last_key + diffs[1]) points to first value in
|
|
698 |
last_key that is NULL or different from corresponding
|
|
699 |
value in prev_key.
|
|
700 |
*/
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
701 |
ha_key_cmp(keyseg, prev_key, last_key, USE_WHOLE_KEY, |
1
by brian
clean slate |
702 |
SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, diffs); |
703 |
seg= keyseg + diffs[0] - 1; |
|
704 |
||
705 |
/* Find first NULL in last_key */
|
|
706 |
first_null_seg= ha_find_null(seg, last_key + diffs[1]) - keyseg; |
|
707 |
for (kp= 0; kp < first_null_seg; kp++) |
|
708 |
notnull[kp]++; |
|
709 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
710 |
/*
|
1
by brian
clean slate |
711 |
Return 1+ number of first key part where values differ. Don't care if
|
712 |
these were NULLs and not .... We compensate for that in
|
|
713 |
update_key_parts.
|
|
714 |
*/
|
|
715 |
return diffs[0]; |
|
716 |
}
|
|
717 |
||
718 |
||
719 |
/* Check if index is ok */
|
|
720 |
||
721 |
static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, |
|
481
by Brian Aker
Remove all of uchar. |
722 |
my_off_t page, unsigned char *buff, ha_rows *keys, |
482
by Brian Aker
Remove uint. |
723 |
ha_checksum *key_checksum, uint32_t level) |
1
by brian
clean slate |
724 |
{
|
725 |
int flag; |
|
482
by Brian Aker
Remove uint. |
726 |
uint32_t used_length,comp_flag,nod_flag,key_length=0; |
481
by Brian Aker
Remove all of uchar. |
727 |
unsigned char key[HA_MAX_POSSIBLE_KEY_BUFF],*temp_buff,*keypos,*old_keypos,*endpos; |
1
by brian
clean slate |
728 |
my_off_t next_page,record; |
729 |
char llbuff[22]; |
|
482
by Brian Aker
Remove uint. |
730 |
uint32_t diff_pos[2]; |
1
by brian
clean slate |
731 |
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
732 |
if (!(temp_buff=(unsigned char*) malloc(keyinfo->block_length))) |
1
by brian
clean slate |
733 |
{
|
734 |
mi_check_print_error(param,"Not enough memory for keyblock"); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
735 |
return(-1); |
1
by brian
clean slate |
736 |
}
|
737 |
||
738 |
if (keyinfo->flag & HA_NOSAME) |
|
739 |
comp_flag=SEARCH_FIND | SEARCH_UPDATE; /* Not real duplicates */ |
|
740 |
else
|
|
741 |
comp_flag=SEARCH_SAME; /* Keys in positionorder */ |
|
742 |
nod_flag=mi_test_if_nod(buff); |
|
743 |
used_length=mi_getint(buff); |
|
744 |
keypos=buff+2+nod_flag; |
|
745 |
endpos=buff+used_length; |
|
746 |
||
747 |
param->keydata+=used_length; param->totaldata+=keyinfo->block_length; /* INFO */ |
|
748 |
param->key_blocks++; |
|
749 |
if (level > param->max_level) |
|
750 |
param->max_level=level; |
|
751 |
||
752 |
if (used_length > keyinfo->block_length) |
|
753 |
{
|
|
754 |
mi_check_print_error(param,"Wrong pageinfo at page: %s", |
|
755 |
llstr(page,llbuff)); |
|
756 |
goto err; |
|
757 |
}
|
|
758 |
for ( ;; ) |
|
759 |
{
|
|
760 |
if (*killed_ptr(param)) |
|
761 |
goto err; |
|
212.6.12
by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove(). |
762 |
memcpy(info->lastkey,key,key_length); |
1
by brian
clean slate |
763 |
info->lastkey_length=key_length; |
764 |
if (nod_flag) |
|
765 |
{
|
|
766 |
next_page=_mi_kpos(nod_flag,keypos); |
|
767 |
if (chk_index_down(param,info,keyinfo,next_page, |
|
768 |
temp_buff,keys,key_checksum,level+1)) |
|
769 |
goto err; |
|
770 |
}
|
|
771 |
old_keypos=keypos; |
|
772 |
if (keypos >= endpos || |
|
773 |
(key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,key)) == 0) |
|
774 |
break; |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
775 |
assert(key_length <= sizeof(key)); |
1
by brian
clean slate |
776 |
if (keypos > endpos) |
777 |
{
|
|
778 |
mi_check_print_error(param,"Wrong key block length at page: %s",llstr(page,llbuff)); |
|
779 |
goto err; |
|
780 |
}
|
|
781 |
if ((*keys)++ && |
|
782 |
(flag=ha_key_cmp(keyinfo->seg,info->lastkey,key,key_length, |
|
783 |
comp_flag, diff_pos)) >=0) |
|
784 |
{
|
|
785 |
if (comp_flag & SEARCH_FIND && flag == 0) |
|
786 |
mi_check_print_error(param,"Found duplicated key at page %s",llstr(page,llbuff)); |
|
787 |
else
|
|
788 |
mi_check_print_error(param,"Key in wrong position at page %s",llstr(page,llbuff)); |
|
789 |
goto err; |
|
790 |
}
|
|
791 |
if (param->testflag & T_STATISTICS) |
|
792 |
{
|
|
793 |
if (*keys != 1L) /* not first_key */ |
|
794 |
{
|
|
795 |
if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL) |
|
796 |
ha_key_cmp(keyinfo->seg,info->lastkey,key,USE_WHOLE_KEY, |
|
797 |
SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, |
|
798 |
diff_pos); |
|
799 |
else if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS) |
|
800 |
{
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
801 |
diff_pos[0]= mi_collect_stats_nonulls_next(keyinfo->seg, |
1
by brian
clean slate |
802 |
param->notnull_count, |
803 |
info->lastkey, key); |
|
804 |
}
|
|
805 |
param->unique_count[diff_pos[0]-1]++; |
|
806 |
}
|
|
807 |
else
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
808 |
{
|
1
by brian
clean slate |
809 |
if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS) |
810 |
mi_collect_stats_nonulls_first(keyinfo->seg, param->notnull_count, |
|
811 |
key); |
|
812 |
}
|
|
813 |
}
|
|
481
by Brian Aker
Remove all of uchar. |
814 |
(*key_checksum)+= mi_byte_checksum((unsigned char*) key, |
1
by brian
clean slate |
815 |
key_length- info->s->rec_reflength); |
816 |
record= _mi_dpos(info,0,key+key_length); |
|
817 |
if (record >= info->state->data_file_length) |
|
818 |
{
|
|
819 |
mi_check_print_error(param,"Found key at page %s that points to record outside datafile",llstr(page,llbuff)); |
|
820 |
goto err; |
|
821 |
}
|
|
822 |
param->record_checksum+=(ha_checksum) record; |
|
823 |
}
|
|
824 |
if (keypos != endpos) |
|
825 |
{
|
|
826 |
mi_check_print_error(param,"Keyblock size at page %s is not correct. Block length: %d key length: %d", |
|
827 |
llstr(page,llbuff), used_length, (keypos - buff)); |
|
828 |
goto err; |
|
829 |
}
|
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
830 |
free(temp_buff); |
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
831 |
return(0); |
1
by brian
clean slate |
832 |
err: |
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
833 |
free(temp_buff); |
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
834 |
return(1); |
1
by brian
clean slate |
835 |
} /* chk_index */ |
836 |
||
837 |
||
838 |
/* Calculate a checksum of 1+2+3+4...N = N*(N+1)/2 without overflow */
|
|
839 |
||
840 |
static ha_checksum calc_checksum(ha_rows count) |
|
841 |
{
|
|
151
by Brian Aker
Ulonglong to uint64_t |
842 |
uint64_t sum,a,b; |
1
by brian
clean slate |
843 |
|
844 |
sum=0; |
|
845 |
a=count; b=count+1; |
|
846 |
if (a & 1) |
|
847 |
b>>=1; |
|
848 |
else
|
|
849 |
a>>=1; |
|
850 |
while (b) |
|
851 |
{
|
|
852 |
if (b & 1) |
|
853 |
sum+=a; |
|
854 |
a<<=1; b>>=1; |
|
855 |
}
|
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
856 |
return((ha_checksum) sum); |
1
by brian
clean slate |
857 |
} /* calc_checksum */ |
858 |
||
859 |
||
860 |
/* Calc length of key in normal isam */
|
|
861 |
||
482
by Brian Aker
Remove uint. |
862 |
static uint32_t isam_key_length(MI_INFO *info, register MI_KEYDEF *keyinfo) |
1
by brian
clean slate |
863 |
{
|
482
by Brian Aker
Remove uint. |
864 |
uint32_t length; |
1
by brian
clean slate |
865 |
HA_KEYSEG *keyseg; |
866 |
||
867 |
length= info->s->rec_reflength; |
|
868 |
for (keyseg=keyinfo->seg ; keyseg->type ; keyseg++) |
|
869 |
length+= keyseg->length; |
|
870 |
||
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
871 |
return(length); |
1
by brian
clean slate |
872 |
} /* key_length */ |
873 |
||
874 |
||
875 |
/* Check that record-link is ok */
|
|
876 |
||
877 |
int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend) |
|
878 |
{
|
|
879 |
int error,got_error,flag; |
|
880 |
uint key, left_length= 0, b_type,field; |
|
881 |
ha_rows records, del_blocks; |
|
882 |
my_off_t used, empty, pos, splits, start_recpos= 0, |
|
883 |
del_length, link_used, start_block; |
|
481
by Brian Aker
Remove all of uchar. |
884 |
unsigned char *record= NULL, *to= NULL; |
1
by brian
clean slate |
885 |
char llbuff[22],llbuff2[22],llbuff3[22]; |
886 |
ha_checksum intern_record_checksum; |
|
887 |
ha_checksum key_checksum[HA_MAX_POSSIBLE_KEY]; |
|
281
by Brian Aker
Converted myisam away from my_bool |
888 |
bool static_row_size; |
1
by brian
clean slate |
889 |
MI_KEYDEF *keyinfo; |
890 |
MI_BLOCK_INFO block_info; |
|
891 |
||
892 |
if (!(param->testflag & T_SILENT)) |
|
893 |
{
|
|
894 |
if (extend) |
|
895 |
puts("- check records and index references"); |
|
896 |
else
|
|
897 |
puts("- check record links"); |
|
898 |
}
|
|
899 |
||
900 |
if (!mi_alloc_rec_buff(info, -1, &record)) |
|
901 |
{
|
|
902 |
mi_check_print_error(param,"Not enough memory for record"); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
903 |
return(-1); |
1
by brian
clean slate |
904 |
}
|
905 |
records=del_blocks=0; |
|
906 |
used=link_used=splits=del_length=0; |
|
907 |
intern_record_checksum=param->glob_crc=0; |
|
908 |
got_error=error=0; |
|
909 |
empty=info->s->pack.header_length; |
|
910 |
||
911 |
/* Check how to calculate checksum of rows */
|
|
912 |
static_row_size=1; |
|
913 |
if (info->s->data_file_type == COMPRESSED_RECORD) |
|
914 |
{
|
|
915 |
for (field=0 ; field < info->s->base.fields ; field++) |
|
916 |
{
|
|
917 |
if (info->s->rec[field].base_type == FIELD_BLOB || |
|
918 |
info->s->rec[field].base_type == FIELD_VARCHAR) |
|
919 |
{
|
|
920 |
static_row_size=0; |
|
921 |
break; |
|
922 |
}
|
|
923 |
}
|
|
924 |
}
|
|
925 |
||
926 |
pos=my_b_tell(¶m->read_cache); |
|
212.6.12
by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove(). |
927 |
memset(key_checksum, 0, info->s->base.keys * sizeof(key_checksum[0])); |
1
by brian
clean slate |
928 |
while (pos < info->state->data_file_length) |
929 |
{
|
|
930 |
if (*killed_ptr(param)) |
|
931 |
goto err2; |
|
932 |
switch (info->s->data_file_type) { |
|
933 |
case STATIC_RECORD: |
|
481
by Brian Aker
Remove all of uchar. |
934 |
if (my_b_read(¶m->read_cache,(unsigned char*) record, |
1
by brian
clean slate |
935 |
info->s->base.pack_reclength)) |
936 |
goto err; |
|
937 |
start_recpos=pos; |
|
938 |
pos+=info->s->base.pack_reclength; |
|
939 |
splits++; |
|
940 |
if (*record == '\0') |
|
941 |
{
|
|
942 |
del_blocks++; |
|
943 |
del_length+=info->s->base.pack_reclength; |
|
944 |
continue; /* Record removed */ |
|
945 |
}
|
|
946 |
param->glob_crc+= mi_static_checksum(info,record); |
|
947 |
used+=info->s->base.pack_reclength; |
|
948 |
break; |
|
949 |
case DYNAMIC_RECORD: |
|
950 |
flag=block_info.second_read=0; |
|
951 |
block_info.next_filepos=pos; |
|
952 |
do
|
|
953 |
{
|
|
481
by Brian Aker
Remove all of uchar. |
954 |
if (_mi_read_cache(¶m->read_cache,(unsigned char*) block_info.header, |
1
by brian
clean slate |
955 |
(start_block=block_info.next_filepos), |
956 |
sizeof(block_info.header), |
|
957 |
(flag ? 0 : READING_NEXT) | READING_HEADER)) |
|
958 |
goto err; |
|
959 |
if (start_block & (MI_DYN_ALIGN_SIZE-1)) |
|
960 |
{
|
|
961 |
mi_check_print_error(param,"Wrong aligned block at %s", |
|
962 |
llstr(start_block,llbuff)); |
|
963 |
goto err2; |
|
964 |
}
|
|
965 |
b_type=_mi_get_block_info(&block_info,-1,start_block); |
|
966 |
if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR | |
|
967 |
BLOCK_FATAL_ERROR)) |
|
968 |
{
|
|
969 |
if (b_type & BLOCK_SYNC_ERROR) |
|
970 |
{
|
|
971 |
if (flag) |
|
972 |
{
|
|
973 |
mi_check_print_error(param,"Unexpected byte: %d at link: %s", |
|
974 |
(int) block_info.header[0], |
|
975 |
llstr(start_block,llbuff)); |
|
976 |
goto err2; |
|
977 |
}
|
|
978 |
pos=block_info.filepos+block_info.block_len; |
|
979 |
goto next; |
|
980 |
}
|
|
981 |
if (b_type & BLOCK_DELETED) |
|
982 |
{
|
|
983 |
if (block_info.block_len < info->s->base.min_block_length) |
|
984 |
{
|
|
985 |
mi_check_print_error(param, |
|
986 |
"Deleted block with impossible length %lu at %s", |
|
987 |
block_info.block_len,llstr(pos,llbuff)); |
|
988 |
goto err2; |
|
989 |
}
|
|
990 |
if ((block_info.next_filepos != HA_OFFSET_ERROR && |
|
991 |
block_info.next_filepos >= info->state->data_file_length) || |
|
992 |
(block_info.prev_filepos != HA_OFFSET_ERROR && |
|
993 |
block_info.prev_filepos >= info->state->data_file_length)) |
|
994 |
{
|
|
995 |
mi_check_print_error(param,"Delete link points outside datafile at %s", |
|
996 |
llstr(pos,llbuff)); |
|
997 |
goto err2; |
|
998 |
}
|
|
999 |
del_blocks++; |
|
1000 |
del_length+=block_info.block_len; |
|
1001 |
pos=block_info.filepos+block_info.block_len; |
|
1002 |
splits++; |
|
1003 |
goto next; |
|
1004 |
}
|
|
1005 |
mi_check_print_error(param,"Wrong bytesec: %d-%d-%d at linkstart: %s", |
|
1006 |
block_info.header[0],block_info.header[1], |
|
1007 |
block_info.header[2], |
|
1008 |
llstr(start_block,llbuff)); |
|
1009 |
goto err2; |
|
1010 |
}
|
|
1011 |
if (info->state->data_file_length < block_info.filepos+ |
|
1012 |
block_info.block_len) |
|
1013 |
{
|
|
1014 |
mi_check_print_error(param, |
|
1015 |
"Recordlink that points outside datafile at %s", |
|
1016 |
llstr(pos,llbuff)); |
|
1017 |
got_error=1; |
|
1018 |
break; |
|
1019 |
}
|
|
1020 |
splits++; |
|
1021 |
if (!flag++) /* First block */ |
|
1022 |
{
|
|
1023 |
start_recpos=pos; |
|
1024 |
pos=block_info.filepos+block_info.block_len; |
|
1025 |
if (block_info.rec_len > (uint) info->s->base.max_pack_length) |
|
1026 |
{
|
|
1027 |
mi_check_print_error(param,"Found too long record (%lu) at %s", |
|
1028 |
(ulong) block_info.rec_len, |
|
1029 |
llstr(start_recpos,llbuff)); |
|
1030 |
got_error=1; |
|
1031 |
break; |
|
1032 |
}
|
|
1033 |
if (info->s->base.blobs) |
|
1034 |
{
|
|
1035 |
if (!(to= mi_alloc_rec_buff(info, block_info.rec_len, |
|
1036 |
&info->rec_buff))) |
|
1037 |
{
|
|
1038 |
mi_check_print_error(param, |
|
1039 |
"Not enough memory (%lu) for blob at %s", |
|
1040 |
(ulong) block_info.rec_len, |
|
1041 |
llstr(start_recpos,llbuff)); |
|
1042 |
got_error=1; |
|
1043 |
break; |
|
1044 |
}
|
|
1045 |
}
|
|
1046 |
else
|
|
1047 |
to= info->rec_buff; |
|
1048 |
left_length=block_info.rec_len; |
|
1049 |
}
|
|
1050 |
if (left_length < block_info.data_len) |
|
1051 |
{
|
|
1052 |
mi_check_print_error(param,"Found too long record (%lu) at %s", |
|
1053 |
(ulong) block_info.data_len, |
|
1054 |
llstr(start_recpos,llbuff)); |
|
1055 |
got_error=1; |
|
1056 |
break; |
|
1057 |
}
|
|
481
by Brian Aker
Remove all of uchar. |
1058 |
if (_mi_read_cache(¶m->read_cache,(unsigned char*) to,block_info.filepos, |
1
by brian
clean slate |
1059 |
(uint) block_info.data_len, |
1060 |
flag == 1 ? READING_NEXT : 0)) |
|
1061 |
goto err; |
|
1062 |
to+=block_info.data_len; |
|
1063 |
link_used+= block_info.filepos-start_block; |
|
1064 |
used+= block_info.filepos - start_block + block_info.data_len; |
|
1065 |
empty+=block_info.block_len-block_info.data_len; |
|
1066 |
left_length-=block_info.data_len; |
|
1067 |
if (left_length) |
|
1068 |
{
|
|
1069 |
if (b_type & BLOCK_LAST) |
|
1070 |
{
|
|
1071 |
mi_check_print_error(param, |
|
1072 |
"Wrong record length %s of %s at %s", |
|
1073 |
llstr(block_info.rec_len-left_length,llbuff), |
|
1074 |
llstr(block_info.rec_len, llbuff2), |
|
1075 |
llstr(start_recpos,llbuff3)); |
|
1076 |
got_error=1; |
|
1077 |
break; |
|
1078 |
}
|
|
1079 |
if (info->state->data_file_length < block_info.next_filepos) |
|
1080 |
{
|
|
1081 |
mi_check_print_error(param, |
|
1082 |
"Found next-recordlink that points outside datafile at %s", |
|
1083 |
llstr(block_info.filepos,llbuff)); |
|
1084 |
got_error=1; |
|
1085 |
break; |
|
1086 |
}
|
|
1087 |
}
|
|
1088 |
} while (left_length); |
|
1089 |
if (! got_error) |
|
1090 |
{
|
|
1091 |
if (_mi_rec_unpack(info,record,info->rec_buff,block_info.rec_len) == |
|
1092 |
MY_FILE_ERROR) |
|
1093 |
{
|
|
1094 |
mi_check_print_error(param,"Found wrong record at %s", |
|
1095 |
llstr(start_recpos,llbuff)); |
|
1096 |
got_error=1; |
|
1097 |
}
|
|
1098 |
else
|
|
1099 |
{
|
|
1100 |
info->checksum=mi_checksum(info,record); |
|
1101 |
if (param->testflag & (T_EXTEND | T_MEDIUM | T_VERBOSE)) |
|
1102 |
{
|
|
1103 |
if (_mi_rec_check(info,record, info->rec_buff,block_info.rec_len, |
|
1104 |
test(info->s->calc_checksum))) |
|
1105 |
{
|
|
1106 |
mi_check_print_error(param,"Found wrong packed record at %s", |
|
1107 |
llstr(start_recpos,llbuff)); |
|
1108 |
got_error=1; |
|
1109 |
}
|
|
1110 |
}
|
|
1111 |
if (!got_error) |
|
1112 |
param->glob_crc+= info->checksum; |
|
1113 |
}
|
|
1114 |
}
|
|
1115 |
else if (!flag) |
|
1116 |
pos=block_info.filepos+block_info.block_len; |
|
1117 |
break; |
|
1118 |
case COMPRESSED_RECORD: |
|
1119 |
case BLOCK_RECORD: |
|
1120 |
assert(0); /* Impossible */ |
|
1121 |
} /* switch */ |
|
1122 |
if (! got_error) |
|
1123 |
{
|
|
1124 |
intern_record_checksum+=(ha_checksum) start_recpos; |
|
1125 |
records++; |
|
1126 |
if (param->testflag & T_WRITE_LOOP && records % WRITE_COUNT == 0) |
|
1127 |
{
|
|
398.1.10
by Monty Taylor
Actually removed VOID() this time. |
1128 |
printf("%s\r", llstr(records,llbuff)); fflush(stdout); |
1
by brian
clean slate |
1129 |
}
|
1130 |
||
1131 |
/* Check if keys match the record */
|
|
1132 |
||
1133 |
for (key=0,keyinfo= info->s->keyinfo; key < info->s->base.keys; |
|
1134 |
key++,keyinfo++) |
|
1135 |
{
|
|
1136 |
if (mi_is_key_active(info->s->state.key_map, key)) |
|
1137 |
{
|
|
1138 |
{
|
|
482
by Brian Aker
Remove uint. |
1139 |
uint32_t key_length=_mi_make_key(info,key,info->lastkey,record, |
1
by brian
clean slate |
1140 |
start_recpos); |
1141 |
if (extend) |
|
1142 |
{
|
|
1143 |
/* We don't need to lock the key tree here as we don't allow
|
|
1144 |
concurrent threads when running myisamchk
|
|
1145 |
*/
|
|
1146 |
int search_result= |
|
1147 |
_mi_search(info,keyinfo,info->lastkey,key_length, |
|
1148 |
SEARCH_SAME, info->s->state.key_root[key]); |
|
1149 |
if (search_result) |
|
1150 |
{
|
|
1151 |
mi_check_print_error(param,"Record at: %10s " |
|
1152 |
"Can't find key for index: %2d", |
|
1153 |
llstr(start_recpos,llbuff),key+1); |
|
1154 |
if (error++ > MAXERR || !(param->testflag & T_VERBOSE)) |
|
1155 |
goto err2; |
|
1156 |
}
|
|
1157 |
}
|
|
1158 |
else
|
|
481
by Brian Aker
Remove all of uchar. |
1159 |
key_checksum[key]+=mi_byte_checksum((unsigned char*) info->lastkey, |
1
by brian
clean slate |
1160 |
key_length); |
1161 |
}
|
|
1162 |
}
|
|
1163 |
}
|
|
1164 |
}
|
|
1165 |
else
|
|
1166 |
{
|
|
1167 |
got_error=0; |
|
1168 |
if (error++ > MAXERR || !(param->testflag & T_VERBOSE)) |
|
1169 |
goto err2; |
|
1170 |
}
|
|
1171 |
next:; /* Next record */ |
|
1172 |
}
|
|
1173 |
if (param->testflag & T_WRITE_LOOP) |
|
1174 |
{
|
|
398.1.10
by Monty Taylor
Actually removed VOID() this time. |
1175 |
fputs(" \r",stdout); fflush(stdout); |
1
by brian
clean slate |
1176 |
}
|
1177 |
if (records != info->state->records) |
|
1178 |
{
|
|
1179 |
mi_check_print_error(param,"Record-count is not ok; is %-10s Should be: %s", |
|
1180 |
llstr(records,llbuff), llstr(info->state->records,llbuff2)); |
|
1181 |
error=1; |
|
1182 |
}
|
|
1183 |
else if (param->record_checksum && |
|
1184 |
param->record_checksum != intern_record_checksum) |
|
1185 |
{
|
|
1186 |
mi_check_print_error(param, |
|
1187 |
"Keypointers and record positions doesn't match"); |
|
1188 |
error=1; |
|
1189 |
}
|
|
1190 |
else if (param->glob_crc != info->state->checksum && |
|
1191 |
(info->s->options & |
|
1192 |
(HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))) |
|
1193 |
{
|
|
1194 |
mi_check_print_warning(param, |
|
1195 |
"Record checksum is not the same as checksum stored in the index file\n"); |
|
1196 |
error=1; |
|
1197 |
}
|
|
1198 |
else if (!extend) |
|
1199 |
{
|
|
1200 |
for (key=0 ; key < info->s->base.keys; key++) |
|
1201 |
{
|
|
249
by Brian Aker
Random key cleanup (it is a friday...) |
1202 |
if (key_checksum[key] != param->key_crc[key]) |
1
by brian
clean slate |
1203 |
{
|
1204 |
mi_check_print_error(param,"Checksum for key: %2d doesn't match checksum for records", |
|
1205 |
key+1); |
|
1206 |
error=1; |
|
1207 |
}
|
|
1208 |
}
|
|
1209 |
}
|
|
1210 |
||
1211 |
if (del_length != info->state->empty) |
|
1212 |
{
|
|
1213 |
mi_check_print_warning(param, |
|
1214 |
"Found %s deleted space. Should be %s", |
|
1215 |
llstr(del_length,llbuff2), |
|
1216 |
llstr(info->state->empty,llbuff)); |
|
1217 |
}
|
|
1218 |
if (used+empty+del_length != info->state->data_file_length) |
|
1219 |
{
|
|
1220 |
mi_check_print_warning(param, |
|
1221 |
"Found %s record-data and %s unused data and %s deleted-data", |
|
1222 |
llstr(used,llbuff),llstr(empty,llbuff2), |
|
1223 |
llstr(del_length,llbuff3)); |
|
1224 |
mi_check_print_warning(param, |
|
1225 |
"Total %s, Should be: %s", |
|
1226 |
llstr((used+empty+del_length),llbuff), |
|
1227 |
llstr(info->state->data_file_length,llbuff2)); |
|
1228 |
}
|
|
1229 |
if (del_blocks != info->state->del) |
|
1230 |
{
|
|
1231 |
mi_check_print_warning(param, |
|
1232 |
"Found %10s deleted blocks Should be: %s", |
|
1233 |
llstr(del_blocks,llbuff), |
|
1234 |
llstr(info->state->del,llbuff2)); |
|
1235 |
}
|
|
1236 |
if (splits != info->s->state.split) |
|
1237 |
{
|
|
1238 |
mi_check_print_warning(param, |
|
1239 |
"Found %10s parts Should be: %s parts", |
|
1240 |
llstr(splits,llbuff), |
|
1241 |
llstr(info->s->state.split,llbuff2)); |
|
1242 |
}
|
|
1243 |
if (param->testflag & T_INFO) |
|
1244 |
{
|
|
1245 |
if (param->warning_printed || param->error_printed) |
|
1246 |
puts(""); |
|
1247 |
if (used != 0 && ! param->error_printed) |
|
1248 |
{
|
|
1249 |
printf("Records:%18s M.recordlength:%9lu Packed:%14.0f%%\n", |
|
1250 |
llstr(records,llbuff), (long)((used-link_used)/records), |
|
1251 |
(info->s->base.blobs ? 0.0 : |
|
151
by Brian Aker
Ulonglong to uint64_t |
1252 |
(uint64_t2double((uint64_t) info->s->base.reclength*records)- |
1
by brian
clean slate |
1253 |
my_off_t2double(used))/ |
151
by Brian Aker
Ulonglong to uint64_t |
1254 |
uint64_t2double((uint64_t) info->s->base.reclength*records)*100.0)); |
1
by brian
clean slate |
1255 |
printf("Recordspace used:%9.0f%% Empty space:%12d%% Blocks/Record: %6.2f\n", |
151
by Brian Aker
Ulonglong to uint64_t |
1256 |
(uint64_t2double(used-link_used)/uint64_t2double(used-link_used+empty)*100.0), |
1257 |
(!records ? 100 : (int) (uint64_t2double(del_length+empty)/ |
|
1
by brian
clean slate |
1258 |
my_off_t2double(used)*100.0)), |
151
by Brian Aker
Ulonglong to uint64_t |
1259 |
uint64_t2double(splits - del_blocks) / records); |
1
by brian
clean slate |
1260 |
}
|
1261 |
printf("Record blocks:%12s Delete blocks:%10s\n", |
|
1262 |
llstr(splits-del_blocks,llbuff),llstr(del_blocks,llbuff2)); |
|
1263 |
printf("Record data: %12s Deleted data: %10s\n", |
|
1264 |
llstr(used-link_used,llbuff),llstr(del_length,llbuff2)); |
|
1265 |
printf("Lost space: %12s Linkdata: %10s\n", |
|
1266 |
llstr(empty,llbuff),llstr(link_used,llbuff2)); |
|
1267 |
}
|
|
477
by Monty Taylor
Removed my_free(). It turns out that it had been def'd to ignore the flags passed to it in the second arg anyway. Gotta love that. |
1268 |
free(mi_get_rec_buff_ptr(info, record)); |
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
1269 |
return (error); |
1
by brian
clean slate |
1270 |
err: |
1271 |
mi_check_print_error(param,"got error: %d when reading datafile at record: %s",my_errno, llstr(records,llbuff)); |
|
1272 |
err2: |
|
477
by Monty Taylor
Removed my_free(). It turns out that it had been def'd to ignore the flags passed to it in the second arg anyway. Gotta love that. |
1273 |
free(mi_get_rec_buff_ptr(info, record)); |
1
by brian
clean slate |
1274 |
param->testflag|=T_RETRY_WITHOUT_QUICK; |
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
1275 |
return(1); |
1
by brian
clean slate |
1276 |
} /* chk_data_link */ |
1277 |
||
1278 |
||
1279 |
/**
|
|
1280 |
@brief Drop all indexes
|
|
1281 |
||
1282 |
@param[in] param check parameters
|
|
1283 |
@param[in] info MI_INFO handle
|
|
1284 |
@param[in] force if to force drop all indexes
|
|
1285 |
||
1286 |
@return status
|
|
1287 |
@retval 0 OK
|
|
1288 |
@retval != 0 Error
|
|
1289 |
||
1290 |
@note
|
|
1291 |
Once allocated, index blocks remain part of the key file forever.
|
|
1292 |
When indexes are disabled, no block is freed. When enabling indexes,
|
|
1293 |
no block is freed either. The new indexes are create from new
|
|
1294 |
blocks. (Bug #4692)
|
|
1295 |
||
1296 |
Before recreating formerly disabled indexes, the unused blocks
|
|
1297 |
must be freed. There are two options to do this:
|
|
1298 |
- Follow the tree of disabled indexes, add all blocks to the
|
|
1299 |
deleted blocks chain. Would require a lot of random I/O.
|
|
1300 |
- Drop all blocks by clearing all index root pointers and all
|
|
1301 |
delete chain pointers and resetting key_file_length to the end
|
|
1302 |
of the index file header. This requires to recreate all indexes,
|
|
1303 |
even those that may still be intact.
|
|
1304 |
The second method is probably faster in most cases.
|
|
1305 |
||
1306 |
When disabling indexes, MySQL disables either all indexes or all
|
|
1307 |
non-unique indexes. When MySQL [re-]enables disabled indexes
|
|
1308 |
(T_CREATE_MISSING_KEYS), then we either have "lost" blocks in the
|
|
1309 |
index file, or there are no non-unique indexes. In the latter case,
|
|
1310 |
mi_repair*() would not be called as there would be no disabled
|
|
1311 |
indexes.
|
|
1312 |
||
1313 |
If there would be more unique indexes than disabled (non-unique)
|
|
1314 |
indexes, we could do the first method. But this is not implemented
|
|
1315 |
yet. By now we drop and recreate all indexes when repair is called.
|
|
1316 |
||
1317 |
However, there is an exception. Sometimes MySQL disables non-unique
|
|
1318 |
indexes when the table is empty (e.g. when copying a table in
|
|
1319 |
mysql_alter_table()). When enabling the non-unique indexes, they
|
|
1320 |
are still empty. So there is no index block that can be lost. This
|
|
1321 |
optimization is implemented in this function.
|
|
1322 |
||
1323 |
Note that in normal repair (T_CREATE_MISSING_KEYS not set) we
|
|
1324 |
recreate all enabled indexes unconditonally. We do not change the
|
|
1325 |
key_map. Otherwise we invert the key map temporarily (outside of
|
|
1326 |
this function) and recreate the then "seemingly" enabled indexes.
|
|
1327 |
When we cannot use the optimization, and drop all indexes, we
|
|
1328 |
pretend that all indexes were disabled. By the inversion, we will
|
|
1329 |
then recrate all indexes.
|
|
1330 |
*/
|
|
1331 |
||
281
by Brian Aker
Converted myisam away from my_bool |
1332 |
static int mi_drop_all_indexes(MI_CHECK *param, MI_INFO *info, bool force) |
1
by brian
clean slate |
1333 |
{
|
1334 |
MYISAM_SHARE *share= info->s; |
|
1335 |
MI_STATE_INFO *state= &share->state; |
|
482
by Brian Aker
Remove uint. |
1336 |
uint32_t i; |
1
by brian
clean slate |
1337 |
int error; |
1338 |
||
1339 |
/*
|
|
1340 |
If any of the disabled indexes has a key block assigned, we must
|
|
1341 |
drop and recreate all indexes to avoid losing index blocks.
|
|
1342 |
||
1343 |
If we want to recreate disabled indexes only _and_ all of these
|
|
1344 |
indexes are empty, we don't need to recreate the existing indexes.
|
|
1345 |
*/
|
|
1346 |
if (!force && (param->testflag & T_CREATE_MISSING_KEYS)) |
|
1347 |
{
|
|
1348 |
for (i= 0; i < share->base.keys; i++) |
|
1349 |
{
|
|
1350 |
if ((state->key_root[i] != HA_OFFSET_ERROR) && |
|
1351 |
!mi_is_key_active(state->key_map, i)) |
|
1352 |
{
|
|
1353 |
/*
|
|
1354 |
This index has at least one key block and it is disabled.
|
|
1355 |
We would lose its block(s) if would just recreate it.
|
|
1356 |
So we need to drop and recreate all indexes.
|
|
1357 |
*/
|
|
1358 |
break; |
|
1359 |
}
|
|
1360 |
}
|
|
1361 |
if (i >= share->base.keys) |
|
1362 |
{
|
|
1363 |
/*
|
|
1364 |
All of the disabled indexes are empty. We can just recreate them.
|
|
1365 |
Flush dirty blocks of this index file from key cache and remove
|
|
1366 |
all blocks of this index file from key cache.
|
|
1367 |
*/
|
|
1368 |
error= flush_key_blocks(share->key_cache, share->kfile, |
|
1369 |
FLUSH_FORCE_WRITE); |
|
1370 |
goto end; |
|
1371 |
}
|
|
1372 |
/*
|
|
1373 |
We do now drop all indexes and declare them disabled. With the
|
|
1374 |
T_CREATE_MISSING_KEYS flag, mi_repair*() will recreate all
|
|
1375 |
disabled indexes and enable them.
|
|
1376 |
*/
|
|
1377 |
mi_clear_all_keys_active(state->key_map); |
|
1378 |
}
|
|
1379 |
||
1380 |
/* Remove all key blocks of this index file from key cache. */
|
|
1381 |
if ((error= flush_key_blocks(share->key_cache, share->kfile, |
|
1382 |
FLUSH_IGNORE_CHANGED))) |
|
1383 |
goto end; /* purecov: inspected */ |
|
1384 |
||
1385 |
/* Clear index root block pointers. */
|
|
1386 |
for (i= 0; i < share->base.keys; i++) |
|
1387 |
state->key_root[i]= HA_OFFSET_ERROR; |
|
1388 |
||
1389 |
/* Clear the delete chains. */
|
|
1390 |
for (i= 0; i < state->header.max_block_size_index; i++) |
|
1391 |
state->key_del[i]= HA_OFFSET_ERROR; |
|
1392 |
||
1393 |
/* Reset index file length to end of index file header. */
|
|
1394 |
info->state->key_file_length= share->base.keystart; |
|
1395 |
||
1396 |
/* error= 0; set by last (error= flush_key_bocks()). */
|
|
1397 |
||
1398 |
end: |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
1399 |
return(error); |
1
by brian
clean slate |
1400 |
}
|
1401 |
||
1402 |
||
1403 |
/* Recover old table by reading each record and writing all keys */
|
|
1404 |
/* Save new datafile-name in temp_filename */
|
|
1405 |
||
1406 |
int mi_repair(MI_CHECK *param, register MI_INFO *info, |
|
1407 |
char * name, int rep_quick) |
|
1408 |
{
|
|
1409 |
int error,got_error; |
|
1410 |
ha_rows start_records,new_header_length; |
|
1411 |
my_off_t del; |
|
1412 |
File new_file; |
|
1413 |
MYISAM_SHARE *share=info->s; |
|
1414 |
char llbuff[22],llbuff2[22]; |
|
1415 |
SORT_INFO sort_info; |
|
1416 |
MI_SORT_PARAM sort_param; |
|
1417 |
||
212.6.12
by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove(). |
1418 |
memset(&sort_info, 0, sizeof(sort_info)); |
1419 |
memset(&sort_param, 0, sizeof(sort_param)); |
|
1
by brian
clean slate |
1420 |
start_records=info->state->records; |
1421 |
new_header_length=(param->testflag & T_UNPACK) ? 0L : |
|
1422 |
share->pack.header_length; |
|
1423 |
got_error=1; |
|
1424 |
new_file= -1; |
|
1425 |
sort_param.sort_info=&sort_info; |
|
1426 |
||
1427 |
if (!(param->testflag & T_SILENT)) |
|
1428 |
{
|
|
1429 |
printf("- recovering (with keycache) MyISAM-table '%s'\n",name); |
|
1430 |
printf("Data records: %s\n", llstr(info->state->records,llbuff)); |
|
1431 |
}
|
|
1432 |
param->testflag|=T_REP; /* for easy checking */ |
|
1433 |
||
1434 |
if (info->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD)) |
|
1435 |
param->testflag|=T_CALC_CHECKSUM; |
|
1436 |
||
1437 |
if (!param->using_global_keycache) |
|
398.1.10
by Monty Taylor
Actually removed VOID() this time. |
1438 |
init_key_cache(dflt_key_cache, param->key_cache_block_size, |
1439 |
param->use_buffers, 0, 0); |
|
1
by brian
clean slate |
1440 |
|
1441 |
if (init_io_cache(¶m->read_cache,info->dfile, |
|
1442 |
(uint) param->read_buffer_length, |
|
1443 |
READ_CACHE,share->pack.header_length,1,MYF(MY_WME))) |
|
1444 |
{
|
|
212.6.1
by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file. |
1445 |
memset(&info->rec_cache, 0, sizeof(info->rec_cache)); |
1
by brian
clean slate |
1446 |
goto err; |
1447 |
}
|
|
1448 |
if (!rep_quick) |
|
1449 |
if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length, |
|
1450 |
WRITE_CACHE, new_header_length, 1, |
|
1451 |
MYF(MY_WME | MY_WAIT_IF_FULL))) |
|
1452 |
goto err; |
|
1453 |
info->opt_flag|=WRITE_CACHE_USED; |
|
1454 |
if (!mi_alloc_rec_buff(info, -1, &sort_param.record) || |
|
1455 |
!mi_alloc_rec_buff(info, -1, &sort_param.rec_buff)) |
|
1456 |
{
|
|
1457 |
mi_check_print_error(param, "Not enough memory for extra record"); |
|
1458 |
goto err; |
|
1459 |
}
|
|
1460 |
||
1461 |
if (!rep_quick) |
|
1462 |
{
|
|
1463 |
/* Get real path for data file */
|
|
489.1.6
by Monty Taylor
Removed RAID garbage. |
1464 |
if ((new_file=my_create(fn_format(param->temp_filename, |
1465 |
share->data_file_name, "", |
|
1466 |
DATA_TMP_EXT, 2+4), |
|
1467 |
0,param->tmpfile_createflag, |
|
1468 |
MYF(0))) < 0) |
|
1
by brian
clean slate |
1469 |
{
|
1470 |
mi_check_print_error(param,"Can't create new tempfile: '%s'", |
|
489.1.6
by Monty Taylor
Removed RAID garbage. |
1471 |
param->temp_filename); |
1
by brian
clean slate |
1472 |
goto err; |
1473 |
}
|
|
1474 |
if (new_header_length && |
|
1475 |
filecopy(param,new_file,info->dfile,0L,new_header_length, |
|
489.1.6
by Monty Taylor
Removed RAID garbage. |
1476 |
"datafile-header")) |
1
by brian
clean slate |
1477 |
goto err; |
1478 |
info->s->state.dellink= HA_OFFSET_ERROR; |
|
1479 |
info->rec_cache.file=new_file; |
|
1480 |
if (param->testflag & T_UNPACK) |
|
1481 |
{
|
|
1482 |
share->options&= ~HA_OPTION_COMPRESS_RECORD; |
|
1483 |
mi_int2store(share->state.header.options,share->options); |
|
1484 |
}
|
|
1485 |
}
|
|
1486 |
sort_info.info=info; |
|
1487 |
sort_info.param = param; |
|
1488 |
sort_param.read_cache=param->read_cache; |
|
1489 |
sort_param.pos=sort_param.max_pos=share->pack.header_length; |
|
1490 |
sort_param.filepos=new_header_length; |
|
1491 |
param->read_cache.end_of_file=sort_info.filelength= |
|
656.1.39
by Monty Taylor
Removed my_seek, my_tell, my_fwrite, my_fseek. |
1492 |
lseek(info->dfile,0L,SEEK_END); |
1
by brian
clean slate |
1493 |
sort_info.dupp=0; |
281
by Brian Aker
Converted myisam away from my_bool |
1494 |
sort_param.fix_datafile= (bool) (! rep_quick); |
1
by brian
clean slate |
1495 |
sort_param.master=1; |
1496 |
sort_info.max_records= ~(ha_rows) 0; |
|
1497 |
||
1498 |
set_data_file_type(&sort_info, share); |
|
1499 |
del=info->state->del; |
|
1500 |
info->state->records=info->state->del=share->state.split=0; |
|
1501 |
info->state->empty=0; |
|
1502 |
param->glob_crc=0; |
|
1503 |
if (param->testflag & T_CALC_CHECKSUM) |
|
1504 |
sort_param.calc_checksum= 1; |
|
1505 |
||
1506 |
info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED); |
|
1507 |
||
1508 |
/* This function always recreates all enabled indexes. */
|
|
1509 |
if (param->testflag & T_CREATE_MISSING_KEYS) |
|
1510 |
mi_set_all_keys_active(share->state.key_map, share->base.keys); |
|
163
by Brian Aker
Merge Monty's code. |
1511 |
mi_drop_all_indexes(param, info, true); |
1
by brian
clean slate |
1512 |
|
1513 |
lock_memory(param); /* Everything is alloced */ |
|
1514 |
||
1515 |
/* Re-create all keys, which are set in key_map. */
|
|
1516 |
while (!(error=sort_get_next_record(&sort_param))) |
|
1517 |
{
|
|
1518 |
if (writekeys(&sort_param)) |
|
1519 |
{
|
|
1520 |
if (my_errno != HA_ERR_FOUND_DUPP_KEY) |
|
1521 |
goto err; |
|
1522 |
mi_check_print_info(param,"Duplicate key %2d for record at %10s against new record at %10s", |
|
1523 |
info->errkey+1, |
|
1524 |
llstr(sort_param.start_recpos,llbuff), |
|
1525 |
llstr(info->dupp_key_pos,llbuff2)); |
|
1526 |
if (param->testflag & T_VERBOSE) |
|
1527 |
{
|
|
398.1.10
by Monty Taylor
Actually removed VOID() this time. |
1528 |
_mi_make_key(info,(uint) info->errkey,info->lastkey, |
1529 |
sort_param.record,0L); |
|
1
by brian
clean slate |
1530 |
}
|
1531 |
sort_info.dupp++; |
|
1532 |
if ((param->testflag & (T_FORCE_UNIQUENESS|T_QUICK)) == T_QUICK) |
|
1533 |
{
|
|
1534 |
param->testflag|=T_RETRY_WITHOUT_QUICK; |
|
1535 |
param->error_printed=1; |
|
1536 |
goto err; |
|
1537 |
}
|
|
1538 |
continue; |
|
1539 |
}
|
|
1540 |
if (sort_write_record(&sort_param)) |
|
1541 |
goto err; |
|
1542 |
}
|
|
281
by Brian Aker
Converted myisam away from my_bool |
1543 |
if (error > 0 || write_data_suffix(&sort_info, (bool)!rep_quick) || |
1
by brian
clean slate |
1544 |
flush_io_cache(&info->rec_cache) || param->read_cache.error < 0) |
1545 |
goto err; |
|
1546 |
||
1547 |
if (param->testflag & T_WRITE_LOOP) |
|
1548 |
{
|
|
398.1.10
by Monty Taylor
Actually removed VOID() this time. |
1549 |
fputs(" \r",stdout); fflush(stdout); |
1
by brian
clean slate |
1550 |
}
|
30
by Brian Aker
Large file and ftruncate() support |
1551 |
if (ftruncate(share->kfile, info->state->key_file_length)) |
1
by brian
clean slate |
1552 |
{
|
1553 |
mi_check_print_warning(param, |
|
1554 |
"Can't change size of indexfile, error: %d", |
|
1555 |
my_errno); |
|
1556 |
goto err; |
|
1557 |
}
|
|
1558 |
||
1559 |
if (rep_quick && del+sort_info.dupp != info->state->del) |
|
1560 |
{
|
|
1561 |
mi_check_print_error(param,"Couldn't fix table with quick recovery: Found wrong number of deleted records"); |
|
1562 |
mi_check_print_error(param,"Run recovery again without -q"); |
|
1563 |
got_error=1; |
|
1564 |
param->retry_repair=1; |
|
1565 |
param->testflag|=T_RETRY_WITHOUT_QUICK; |
|
1566 |
goto err; |
|
1567 |
}
|
|
1568 |
if (param->testflag & T_SAFE_REPAIR) |
|
1569 |
{
|
|
1570 |
/* Don't repair if we loosed more than one row */
|
|
1571 |
if (info->state->records+1 < start_records) |
|
1572 |
{
|
|
1573 |
info->state->records=start_records; |
|
1574 |
got_error=1; |
|
1575 |
goto err; |
|
1576 |
}
|
|
1577 |
}
|
|
1578 |
||
1579 |
if (!rep_quick) |
|
1580 |
{
|
|
1581 |
my_close(info->dfile,MYF(0)); |
|
1582 |
info->dfile=new_file; |
|
1583 |
info->state->data_file_length=sort_param.filepos; |
|
1584 |
share->state.version=(ulong) time((time_t*) 0); /* Force reopen */ |
|
1585 |
}
|
|
1586 |
else
|
|
1587 |
{
|
|
1588 |
info->state->data_file_length=sort_param.max_pos; |
|
1589 |
}
|
|
1590 |
if (param->testflag & T_CALC_CHECKSUM) |
|
1591 |
info->state->checksum=param->glob_crc; |
|
1592 |
||
1593 |
if (!(param->testflag & T_SILENT)) |
|
1594 |
{
|
|
1595 |
if (start_records != info->state->records) |
|
1596 |
printf("Data records: %s\n", llstr(info->state->records,llbuff)); |
|
1597 |
if (sort_info.dupp) |
|
1598 |
mi_check_print_warning(param, |
|
1599 |
"%s records have been removed", |
|
1600 |
llstr(sort_info.dupp,llbuff)); |
|
1601 |
}
|
|
1602 |
||
1603 |
got_error=0; |
|
1604 |
/* If invoked by external program that uses thr_lock */
|
|
1605 |
if (&share->state.state != info->state) |
|
1606 |
memcpy( &share->state.state, info->state, sizeof(*info->state)); |
|
1607 |
||
1608 |
err: |
|
1609 |
if (!got_error) |
|
1610 |
{
|
|
1611 |
/* Replace the actual file with the temporary file */
|
|
1612 |
if (new_file >= 0) |
|
1613 |
{
|
|
1614 |
my_close(new_file,MYF(0)); |
|
1615 |
info->dfile=new_file= -1; |
|
1616 |
if (change_to_newfile(share->data_file_name,MI_NAME_DEXT, |
|
1617 |
DATA_TMP_EXT, share->base.raid_chunks, |
|
1618 |
(param->testflag & T_BACKUP_DATA ? |
|
1619 |
MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) || |
|
1620 |
mi_open_datafile(info,share,-1)) |
|
1621 |
got_error=1; |
|
1622 |
}
|
|
1623 |
}
|
|
1624 |
if (got_error) |
|
1625 |
{
|
|
1626 |
if (! param->error_printed) |
|
1627 |
mi_check_print_error(param,"%d for record at pos %s",my_errno, |
|
1628 |
llstr(sort_param.start_recpos,llbuff)); |
|
1629 |
if (new_file >= 0) |
|
1630 |
{
|
|
398.1.10
by Monty Taylor
Actually removed VOID() this time. |
1631 |
my_close(new_file,MYF(0)); |
489.1.6
by Monty Taylor
Removed RAID garbage. |
1632 |
my_delete(param->temp_filename, MYF(MY_WME)); |
1
by brian
clean slate |
1633 |
info->rec_cache.file=-1; /* don't flush data to new_file, it's closed */ |
1634 |
}
|
|
1635 |
mi_mark_crashed_on_repair(info); |
|
1636 |
}
|
|
477
by Monty Taylor
Removed my_free(). It turns out that it had been def'd to ignore the flags passed to it in the second arg anyway. Gotta love that. |
1637 |
|
1638 |
void * rec_buff_ptr= NULL; |
|
1639 |
rec_buff_ptr= mi_get_rec_buff_ptr(info, sort_param.rec_buff); |
|
1640 |
if (rec_buff_ptr != NULL) |
|
1641 |
free(rec_buff_ptr); |
|
1642 |
rec_buff_ptr= mi_get_rec_buff_ptr(info, sort_param.record); |
|
1643 |
if (rec_buff_ptr != NULL) |
|
1644 |
free(rec_buff_ptr); |
|
1645 |
rec_buff_ptr= NULL; |
|
1646 |
||
1647 |
free(sort_info.buff); |
|
398.1.10
by Monty Taylor
Actually removed VOID() this time. |
1648 |
end_io_cache(¶m->read_cache); |
1
by brian
clean slate |
1649 |
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); |
398.1.10
by Monty Taylor
Actually removed VOID() this time. |
1650 |
end_io_cache(&info->rec_cache); |
1
by brian
clean slate |
1651 |
got_error|=flush_blocks(param, share->key_cache, share->kfile); |
1652 |
if (!got_error && param->testflag & T_UNPACK) |
|
1653 |
{
|
|
481
by Brian Aker
Remove all of uchar. |
1654 |
share->state.header.options[0]&= (unsigned char) ~HA_OPTION_COMPRESS_RECORD; |
1
by brian
clean slate |
1655 |
share->pack.header_length=0; |
1656 |
share->data_file_type=sort_info.new_data_file_type; |
|
1657 |
}
|
|
1658 |
share->state.changed|= (STATE_NOT_OPTIMIZED_KEYS | STATE_NOT_SORTED_PAGES | |
|
1659 |
STATE_NOT_ANALYZED); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
1660 |
return(got_error); |
1
by brian
clean slate |
1661 |
}
|
1662 |
||
1663 |
||
1664 |
/* Uppate keyfile when doing repair */
|
|
1665 |
||
1666 |
static int writekeys(MI_SORT_PARAM *sort_param) |
|
1667 |
{
|
|
482
by Brian Aker
Remove uint. |
1668 |
register uint32_t i; |
481
by Brian Aker
Remove all of uchar. |
1669 |
unsigned char *key; |
1
by brian
clean slate |
1670 |
MI_INFO *info= sort_param->sort_info->info; |
481
by Brian Aker
Remove all of uchar. |
1671 |
unsigned char *buff= sort_param->record; |
1
by brian
clean slate |
1672 |
my_off_t filepos= sort_param->filepos; |
1673 |
||
1674 |
key=info->lastkey+info->s->base.max_key_length; |
|
1675 |
for (i=0 ; i < info->s->base.keys ; i++) |
|
1676 |
{
|
|
1677 |
if (mi_is_key_active(info->s->state.key_map, i)) |
|
1678 |
{
|
|
1679 |
{
|
|
482
by Brian Aker
Remove uint. |
1680 |
uint32_t key_length=_mi_make_key(info,i,key,buff,filepos); |
1
by brian
clean slate |
1681 |
if (_mi_ck_write(info,i,key,key_length)) |
1682 |
goto err; |
|
1683 |
}
|
|
1684 |
}
|
|
1685 |
}
|
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
1686 |
return(0); |
1
by brian
clean slate |
1687 |
|
1688 |
err: |
|
1689 |
if (my_errno == HA_ERR_FOUND_DUPP_KEY) |
|
1690 |
{
|
|
1691 |
info->errkey=(int) i; /* This key was found */ |
|
1692 |
while ( i-- > 0 ) |
|
1693 |
{
|
|
1694 |
if (mi_is_key_active(info->s->state.key_map, i)) |
|
1695 |
{
|
|
1696 |
{
|
|
482
by Brian Aker
Remove uint. |
1697 |
uint32_t key_length=_mi_make_key(info,i,key,buff,filepos); |
1
by brian
clean slate |
1698 |
if (_mi_ck_delete(info,i,key,key_length)) |
1699 |
break; |
|
1700 |
}
|
|
1701 |
}
|
|
1702 |
}
|
|
1703 |
}
|
|
1704 |
/* Remove checksum that was added to glob_crc in sort_get_next_record */
|
|
1705 |
if (sort_param->calc_checksum) |
|
1706 |
sort_param->sort_info->param->glob_crc-= info->checksum; |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
1707 |
return(-1); |
1
by brian
clean slate |
1708 |
} /* writekeys */ |
1709 |
||
1710 |
||
1711 |
/* Change all key-pointers that points to a records */
|
|
1712 |
||
481
by Brian Aker
Remove all of uchar. |
1713 |
int movepoint(register MI_INFO *info, unsigned char *record, my_off_t oldpos, |
482
by Brian Aker
Remove uint. |
1714 |
my_off_t newpos, uint32_t prot_key) |
1
by brian
clean slate |
1715 |
{
|
482
by Brian Aker
Remove uint. |
1716 |
register uint32_t i; |
481
by Brian Aker
Remove all of uchar. |
1717 |
unsigned char *key; |
482
by Brian Aker
Remove uint. |
1718 |
uint32_t key_length; |
1
by brian
clean slate |
1719 |
|
1720 |
key=info->lastkey+info->s->base.max_key_length; |
|
1721 |
for (i=0 ; i < info->s->base.keys; i++) |
|
1722 |
{
|
|
1723 |
if (i != prot_key && mi_is_key_active(info->s->state.key_map, i)) |
|
1724 |
{
|
|
1725 |
key_length=_mi_make_key(info,i,key,record,oldpos); |
|
1726 |
if (info->s->keyinfo[i].flag & HA_NOSAME) |
|
1727 |
{ /* Change pointer direct */ |
|
482
by Brian Aker
Remove uint. |
1728 |
uint32_t nod_flag; |
1
by brian
clean slate |
1729 |
MI_KEYDEF *keyinfo; |
1730 |
keyinfo=info->s->keyinfo+i; |
|
1731 |
if (_mi_search(info,keyinfo,key,USE_WHOLE_KEY, |
|
1732 |
(uint) (SEARCH_SAME | SEARCH_SAVE_BUFF), |
|
1733 |
info->s->state.key_root[i])) |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
1734 |
return(-1); |
1
by brian
clean slate |
1735 |
nod_flag=mi_test_if_nod(info->buff); |
1736 |
_mi_dpointer(info,info->int_keypos-nod_flag- |
|
1737 |
info->s->rec_reflength,newpos); |
|
1738 |
if (_mi_write_keypage(info,keyinfo,info->last_keypage, |
|
1739 |
DFLT_INIT_HITS,info->buff)) |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
1740 |
return(-1); |
1
by brian
clean slate |
1741 |
}
|
1742 |
else
|
|
1743 |
{ /* Change old key to new */ |
|
1744 |
if (_mi_ck_delete(info,i,key,key_length)) |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
1745 |
return(-1); |
1
by brian
clean slate |
1746 |
key_length=_mi_make_key(info,i,key,record,newpos); |
1747 |
if (_mi_ck_write(info,i,key,key_length)) |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
1748 |
return(-1); |
1
by brian
clean slate |
1749 |
}
|
1750 |
}
|
|
1751 |
}
|
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
1752 |
return(0); |
1
by brian
clean slate |
1753 |
} /* movepoint */ |
1754 |
||
1755 |
||
1756 |
/* Tell system that we want all memory for our cache */
|
|
1757 |
||
779.3.1
by Monty Taylor
More cleanup. |
1758 |
void lock_memory(MI_CHECK *param) |
1
by brian
clean slate |
1759 |
{
|
1760 |
#ifdef SUN_OS /* Key-cacheing thrases on sun 4.1 */ |
|
1761 |
if (param->opt_lock_memory) |
|
1762 |
{
|
|
1763 |
int success = mlockall(MCL_CURRENT); /* or plock(DATLOCK); */ |
|
1764 |
if (geteuid() == 0 && success != 0) |
|
1765 |
mi_check_print_warning(param, |
|
1766 |
"Failed to lock memory. errno %d",my_errno); |
|
1767 |
}
|
|
779.3.1
by Monty Taylor
More cleanup. |
1768 |
#else
|
1769 |
(void)param; |
|
1
by brian
clean slate |
1770 |
#endif
|
1771 |
} /* lock_memory */ |
|
1772 |
||
1773 |
||
1774 |
/* Flush all changed blocks to disk */
|
|
1775 |
||
1776 |
int flush_blocks(MI_CHECK *param, KEY_CACHE *key_cache, File file) |
|
1777 |
{
|
|
1778 |
if (flush_key_blocks(key_cache, file, FLUSH_RELEASE)) |
|
1779 |
{
|
|
1780 |
mi_check_print_error(param,"%d when trying to write bufferts",my_errno); |
|
1781 |
return(1); |
|
1782 |
}
|
|
1783 |
if (!param->using_global_keycache) |
|
1784 |
end_key_cache(key_cache,1); |
|
1785 |
return 0; |
|
1786 |
} /* flush_blocks */ |
|
1787 |
||
1788 |
||
1789 |
/* Sort index for more efficent reads */
|
|
1790 |
||
1791 |
int mi_sort_index(MI_CHECK *param, register MI_INFO *info, char * name) |
|
1792 |
{
|
|
482
by Brian Aker
Remove uint. |
1793 |
register uint32_t key; |
1
by brian
clean slate |
1794 |
register MI_KEYDEF *keyinfo; |
1795 |
File new_file; |
|
1796 |
my_off_t index_pos[HA_MAX_POSSIBLE_KEY]; |
|
482
by Brian Aker
Remove uint. |
1797 |
uint32_t r_locks,w_locks; |
1
by brian
clean slate |
1798 |
int old_lock; |
1799 |
MYISAM_SHARE *share=info->s; |
|
1800 |
MI_STATE_INFO old_state; |
|
1801 |
||
1802 |
/* cannot sort index files with R-tree indexes */
|
|
1803 |
for (key= 0,keyinfo= &share->keyinfo[0]; key < share->base.keys ; |
|
1804 |
key++,keyinfo++) |
|
1805 |
||
1806 |
if (!(param->testflag & T_SILENT)) |
|
1807 |
printf("- Sorting index for MyISAM-table '%s'\n",name); |
|
1808 |
||
1809 |
/* Get real path for index file */
|
|
1810 |
fn_format(param->temp_filename,name,"", MI_NAME_IEXT,2+4+32); |
|
1811 |
if ((new_file=my_create(fn_format(param->temp_filename,param->temp_filename, |
|
1812 |
"", INDEX_TMP_EXT,2+4), |
|
1813 |
0,param->tmpfile_createflag,MYF(0))) <= 0) |
|
1814 |
{
|
|
1815 |
mi_check_print_error(param,"Can't create new tempfile: '%s'", |
|
1816 |
param->temp_filename); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
1817 |
return(-1); |
1
by brian
clean slate |
1818 |
}
|
1819 |
if (filecopy(param, new_file,share->kfile,0L, |
|
1820 |
(ulong) share->base.keystart, "headerblock")) |
|
1821 |
goto err; |
|
1822 |
||
1823 |
param->new_file_pos=share->base.keystart; |
|
1824 |
for (key= 0,keyinfo= &share->keyinfo[0]; key < share->base.keys ; |
|
1825 |
key++,keyinfo++) |
|
1826 |
{
|
|
1827 |
if (! mi_is_key_active(info->s->state.key_map, key)) |
|
1828 |
continue; |
|
1829 |
||
1830 |
if (share->state.key_root[key] != HA_OFFSET_ERROR) |
|
1831 |
{
|
|
1832 |
index_pos[key]=param->new_file_pos; /* Write first block here */ |
|
1833 |
if (sort_one_index(param,info,keyinfo,share->state.key_root[key], |
|
1834 |
new_file)) |
|
1835 |
goto err; |
|
1836 |
}
|
|
1837 |
else
|
|
1838 |
index_pos[key]= HA_OFFSET_ERROR; /* No blocks */ |
|
1839 |
}
|
|
1840 |
||
1841 |
/* Flush key cache for this file if we are calling this outside myisamchk */
|
|
1842 |
flush_key_blocks(share->key_cache,share->kfile, FLUSH_IGNORE_CHANGED); |
|
1843 |
||
1844 |
share->state.version=(ulong) time((time_t*) 0); |
|
1845 |
old_state= share->state; /* save state if not stored */ |
|
1846 |
r_locks= share->r_locks; |
|
1847 |
w_locks= share->w_locks; |
|
1848 |
old_lock= info->lock_type; |
|
1849 |
||
1850 |
/* Put same locks as old file */
|
|
1851 |
share->r_locks= share->w_locks= share->tot_locks= 0; |
|
1852 |
(void) _mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE); |
|
398.1.10
by Monty Taylor
Actually removed VOID() this time. |
1853 |
my_close(share->kfile,MYF(MY_WME)); |
1
by brian
clean slate |
1854 |
share->kfile = -1; |
398.1.10
by Monty Taylor
Actually removed VOID() this time. |
1855 |
my_close(new_file,MYF(MY_WME)); |
1
by brian
clean slate |
1856 |
if (change_to_newfile(share->index_file_name,MI_NAME_IEXT,INDEX_TMP_EXT,0, |
1857 |
MYF(0)) || |
|
1858 |
mi_open_keyfile(share)) |
|
1859 |
goto err2; |
|
1860 |
info->lock_type= F_UNLCK; /* Force mi_readinfo to lock */ |
|
1861 |
_mi_readinfo(info,F_WRLCK,0); /* Will lock the table */ |
|
1862 |
info->lock_type= old_lock; |
|
1863 |
share->r_locks= r_locks; |
|
1864 |
share->w_locks= w_locks; |
|
1865 |
share->tot_locks= r_locks+w_locks; |
|
1866 |
share->state= old_state; /* Restore old state */ |
|
1867 |
||
1868 |
info->state->key_file_length=param->new_file_pos; |
|
1869 |
info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED); |
|
1870 |
for (key=0 ; key < info->s->base.keys ; key++) |
|
1871 |
info->s->state.key_root[key]=index_pos[key]; |
|
1872 |
for (key=0 ; key < info->s->state.header.max_block_size_index ; key++) |
|
1873 |
info->s->state.key_del[key]= HA_OFFSET_ERROR; |
|
1874 |
||
1875 |
info->s->state.changed&= ~STATE_NOT_SORTED_PAGES; |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
1876 |
return(0); |
1
by brian
clean slate |
1877 |
|
1878 |
err: |
|
398.1.10
by Monty Taylor
Actually removed VOID() this time. |
1879 |
my_close(new_file,MYF(MY_WME)); |
1
by brian
clean slate |
1880 |
err2: |
398.1.10
by Monty Taylor
Actually removed VOID() this time. |
1881 |
my_delete(param->temp_filename,MYF(MY_WME)); |
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
1882 |
return(-1); |
1
by brian
clean slate |
1883 |
} /* mi_sort_index */ |
1884 |
||
1885 |
||
1886 |
/* Sort records recursive using one index */
|
|
1887 |
||
1888 |
static int sort_one_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, |
|
1889 |
my_off_t pagepos, File new_file) |
|
1890 |
{
|
|
482
by Brian Aker
Remove uint. |
1891 |
uint32_t length,nod_flag,used_length, key_length; |
481
by Brian Aker
Remove all of uchar. |
1892 |
unsigned char *buff,*keypos,*endpos; |
1893 |
unsigned char key[HA_MAX_POSSIBLE_KEY_BUFF]; |
|
1
by brian
clean slate |
1894 |
my_off_t new_page_pos,next_page; |
1895 |
char llbuff[22]; |
|
1896 |
||
1897 |
new_page_pos=param->new_file_pos; |
|
1898 |
param->new_file_pos+=keyinfo->block_length; |
|
1899 |
||
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
1900 |
if (!(buff=(unsigned char*) malloc(keyinfo->block_length))) |
1
by brian
clean slate |
1901 |
{
|
1902 |
mi_check_print_error(param,"Not enough memory for key block"); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
1903 |
return(-1); |
1
by brian
clean slate |
1904 |
}
|
1905 |
if (!_mi_fetch_keypage(info,keyinfo,pagepos,DFLT_INIT_HITS,buff,0)) |
|
1906 |
{
|
|
1907 |
mi_check_print_error(param,"Can't read key block from filepos: %s", |
|
1908 |
llstr(pagepos,llbuff)); |
|
1909 |
goto err; |
|
1910 |
}
|
|
249
by Brian Aker
Random key cleanup (it is a friday...) |
1911 |
if ((nod_flag=mi_test_if_nod(buff))) |
1
by brian
clean slate |
1912 |
{
|
1913 |
used_length=mi_getint(buff); |
|
1914 |
keypos=buff+2+nod_flag; |
|
1915 |
endpos=buff+used_length; |
|
1916 |
for ( ;; ) |
|
1917 |
{
|
|
1918 |
if (nod_flag) |
|
1919 |
{
|
|
1920 |
next_page=_mi_kpos(nod_flag,keypos); |
|
1921 |
_mi_kpointer(info,keypos-nod_flag,param->new_file_pos); /* Save new pos */ |
|
1922 |
if (sort_one_index(param,info,keyinfo,next_page,new_file)) |
|
1923 |
{
|
|
1924 |
goto err; |
|
1925 |
}
|
|
1926 |
}
|
|
1927 |
if (keypos >= endpos || |
|
1928 |
(key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,key)) == 0) |
|
1929 |
break; |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
1930 |
assert(keypos <= endpos); |
1
by brian
clean slate |
1931 |
}
|
1932 |
}
|
|
1933 |
||
1934 |
/* Fill block with zero and write it to the new index file */
|
|
1935 |
length=mi_getint(buff); |
|
212.6.12
by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove(). |
1936 |
memset(buff+length, 0, keyinfo->block_length-length); |
481
by Brian Aker
Remove all of uchar. |
1937 |
if (my_pwrite(new_file,(unsigned char*) buff,(uint) keyinfo->block_length, |
1
by brian
clean slate |
1938 |
new_page_pos,MYF(MY_NABP | MY_WAIT_IF_FULL))) |
1939 |
{
|
|
1940 |
mi_check_print_error(param,"Can't write indexblock, error: %d",my_errno); |
|
1941 |
goto err; |
|
1942 |
}
|
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
1943 |
free(buff); |
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
1944 |
return(0); |
1
by brian
clean slate |
1945 |
err: |
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
1946 |
free(buff); |
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
1947 |
return(1); |
1
by brian
clean slate |
1948 |
} /* sort_one_index */ |
1949 |
||
1950 |
||
1951 |
/*
|
|
1952 |
Let temporary file replace old file.
|
|
1953 |
This assumes that the new file was created in the same
|
|
1954 |
directory as given by realpath(filename).
|
|
1955 |
This will ensure that any symlinks that are used will still work.
|
|
1956 |
Copy stats from old file to new file, deletes orignal and
|
|
1957 |
changes new file name to old file name
|
|
1958 |
*/
|
|
1959 |
||
1960 |
int change_to_newfile(const char * filename, const char * old_ext, |
|
1961 |
const char * new_ext, |
|
779.3.1
by Monty Taylor
More cleanup. |
1962 |
uint32_t raid_chunks, |
1
by brian
clean slate |
1963 |
myf MyFlags) |
1964 |
{
|
|
779.3.1
by Monty Taylor
More cleanup. |
1965 |
(void)raid_chunks; |
1
by brian
clean slate |
1966 |
char old_filename[FN_REFLEN],new_filename[FN_REFLEN]; |
1967 |
/* Get real path to filename */
|
|
1968 |
(void) fn_format(old_filename,filename,"",old_ext,2+4+32); |
|
1969 |
return my_redel(old_filename, |
|
1970 |
fn_format(new_filename,old_filename,"",new_ext,2+4), |
|
1971 |
MYF(MY_WME | MY_LINK_WARNING | MyFlags)); |
|
1972 |
} /* change_to_newfile */ |
|
1973 |
||
1974 |
||
1975 |
||
1976 |
/* Copy a block between two files */
|
|
1977 |
||
1978 |
int filecopy(MI_CHECK *param, File to,File from,my_off_t start, |
|
1979 |
my_off_t length, const char *type) |
|
1980 |
{
|
|
1981 |
char tmp_buff[IO_SIZE],*buff; |
|
1982 |
ulong buff_length; |
|
1983 |
||
398.1.4
by Monty Taylor
Renamed max/min. |
1984 |
buff_length=(ulong) cmin(param->write_buffer_length,length); |
656.1.25
by Monty Taylor
Removed my_malloc stuff from storage/ |
1985 |
if (!(buff=malloc(buff_length))) |
1
by brian
clean slate |
1986 |
{
|
1987 |
buff=tmp_buff; buff_length=IO_SIZE; |
|
1988 |
}
|
|
1989 |
||
656.1.39
by Monty Taylor
Removed my_seek, my_tell, my_fwrite, my_fseek. |
1990 |
lseek(from,start,SEEK_SET); |
1
by brian
clean slate |
1991 |
while (length > buff_length) |
1992 |
{
|
|
481
by Brian Aker
Remove all of uchar. |
1993 |
if (my_read(from,(unsigned char*) buff,buff_length,MYF(MY_NABP)) || |
1994 |
my_write(to,(unsigned char*) buff,buff_length,param->myf_rw)) |
|
1
by brian
clean slate |
1995 |
goto err; |
1996 |
length-= buff_length; |
|
1997 |
}
|
|
481
by Brian Aker
Remove all of uchar. |
1998 |
if (my_read(from,(unsigned char*) buff,(uint) length,MYF(MY_NABP)) || |
1999 |
my_write(to,(unsigned char*) buff,(uint) length,param->myf_rw)) |
|
1
by brian
clean slate |
2000 |
goto err; |
2001 |
if (buff != tmp_buff) |
|
477
by Monty Taylor
Removed my_free(). It turns out that it had been def'd to ignore the flags passed to it in the second arg anyway. Gotta love that. |
2002 |
free(buff); |
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
2003 |
return(0); |
1
by brian
clean slate |
2004 |
err: |
2005 |
if (buff != tmp_buff) |
|
477
by Monty Taylor
Removed my_free(). It turns out that it had been def'd to ignore the flags passed to it in the second arg anyway. Gotta love that. |
2006 |
free(buff); |
1
by brian
clean slate |
2007 |
mi_check_print_error(param,"Can't copy %s to tempfile, error %d", |
2008 |
type,my_errno); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
2009 |
return(1); |
1
by brian
clean slate |
2010 |
}
|
2011 |
||
2012 |
||
2013 |
/*
|
|
2014 |
Repair table or given index using sorting
|
|
2015 |
||
2016 |
SYNOPSIS
|
|
2017 |
mi_repair_by_sort()
|
|
2018 |
param Repair parameters
|
|
2019 |
info MyISAM handler to repair
|
|
2020 |
name Name of table (for warnings)
|
|
2021 |
rep_quick set to <> 0 if we should not change data file
|
|
2022 |
||
2023 |
RESULT
|
|
2024 |
0 ok
|
|
2025 |
<>0 Error
|
|
2026 |
*/
|
|
2027 |
||
2028 |
int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, |
|
2029 |
const char * name, int rep_quick) |
|
2030 |
{
|
|
2031 |
int got_error; |
|
482
by Brian Aker
Remove uint. |
2032 |
uint32_t i; |
1
by brian
clean slate |
2033 |
ulong length; |
2034 |
ha_rows start_records; |
|
2035 |
my_off_t new_header_length,del; |
|
2036 |
File new_file; |
|
2037 |
MI_SORT_PARAM sort_param; |
|
2038 |
MYISAM_SHARE *share=info->s; |
|
2039 |
HA_KEYSEG *keyseg; |
|
2040 |
ulong *rec_per_key_part; |
|
2041 |
char llbuff[22]; |
|
2042 |
SORT_INFO sort_info; |
|
151
by Brian Aker
Ulonglong to uint64_t |
2043 |
uint64_t key_map= 0; |
1
by brian
clean slate |
2044 |
|
2045 |
start_records=info->state->records; |
|
2046 |
got_error=1; |
|
2047 |
new_file= -1; |
|
2048 |
new_header_length=(param->testflag & T_UNPACK) ? 0 : |
|
2049 |
share->pack.header_length; |
|
2050 |
if (!(param->testflag & T_SILENT)) |
|
2051 |
{
|
|
2052 |
printf("- recovering (with sort) MyISAM-table '%s'\n",name); |
|
2053 |
printf("Data records: %s\n", llstr(start_records,llbuff)); |
|
2054 |
}
|
|
2055 |
param->testflag|=T_REP; /* for easy checking */ |
|
2056 |
||
2057 |
if (info->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD)) |
|
2058 |
param->testflag|=T_CALC_CHECKSUM; |
|
2059 |
||
212.6.12
by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove(). |
2060 |
memset(&sort_info, 0, sizeof(sort_info)); |
2061 |
memset(&sort_param, 0, sizeof(sort_param)); |
|
1
by brian
clean slate |
2062 |
if (!(sort_info.key_block= |
2063 |
alloc_key_blocks(param, |
|
2064 |
(uint) param->sort_key_blocks, |
|
2065 |
share->base.max_key_block_length)) |
|
2066 |
|| init_io_cache(¶m->read_cache,info->dfile, |
|
2067 |
(uint) param->read_buffer_length, |
|
2068 |
READ_CACHE,share->pack.header_length,1,MYF(MY_WME)) || |
|
2069 |
(! rep_quick && |
|
2070 |
init_io_cache(&info->rec_cache,info->dfile, |
|
2071 |
(uint) param->write_buffer_length, |
|
2072 |
WRITE_CACHE,new_header_length,1, |
|
2073 |
MYF(MY_WME | MY_WAIT_IF_FULL) & param->myf_rw))) |
|
2074 |
goto err; |
|
2075 |
sort_info.key_block_end=sort_info.key_block+param->sort_key_blocks; |
|
2076 |
info->opt_flag|=WRITE_CACHE_USED; |
|
2077 |
info->rec_cache.file=info->dfile; /* for sort_delete_record */ |
|
2078 |
||
2079 |
if (!mi_alloc_rec_buff(info, -1, &sort_param.record) || |
|
2080 |
!mi_alloc_rec_buff(info, -1, &sort_param.rec_buff)) |
|
2081 |
{
|
|
2082 |
mi_check_print_error(param, "Not enough memory for extra record"); |
|
2083 |
goto err; |
|
2084 |
}
|
|
2085 |
if (!rep_quick) |
|
2086 |
{
|
|
2087 |
/* Get real path for data file */
|
|
489.1.6
by Monty Taylor
Removed RAID garbage. |
2088 |
if ((new_file=my_create(fn_format(param->temp_filename, |
2089 |
share->data_file_name, "", |
|
2090 |
DATA_TMP_EXT, 2+4), |
|
2091 |
0,param->tmpfile_createflag, |
|
2092 |
MYF(0))) < 0) |
|
1
by brian
clean slate |
2093 |
{
|
2094 |
mi_check_print_error(param,"Can't create new tempfile: '%s'", |
|
489.1.6
by Monty Taylor
Removed RAID garbage. |
2095 |
param->temp_filename); |
1
by brian
clean slate |
2096 |
goto err; |
2097 |
}
|
|
2098 |
if (new_header_length && |
|
2099 |
filecopy(param, new_file,info->dfile,0L,new_header_length, |
|
2100 |
"datafile-header")) |
|
2101 |
goto err; |
|
2102 |
if (param->testflag & T_UNPACK) |
|
2103 |
{
|
|
2104 |
share->options&= ~HA_OPTION_COMPRESS_RECORD; |
|
2105 |
mi_int2store(share->state.header.options,share->options); |
|
2106 |
}
|
|
2107 |
share->state.dellink= HA_OFFSET_ERROR; |
|
2108 |
info->rec_cache.file=new_file; |
|
2109 |
}
|
|
2110 |
||
2111 |
info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED); |
|
2112 |
||
2113 |
/* Optionally drop indexes and optionally modify the key_map. */
|
|
163
by Brian Aker
Merge Monty's code. |
2114 |
mi_drop_all_indexes(param, info, false); |
1
by brian
clean slate |
2115 |
key_map= share->state.key_map; |
2116 |
if (param->testflag & T_CREATE_MISSING_KEYS) |
|
2117 |
{
|
|
2118 |
/* Invert the copied key_map to recreate all disabled indexes. */
|
|
2119 |
key_map= ~key_map; |
|
2120 |
}
|
|
2121 |
||
2122 |
sort_info.info=info; |
|
2123 |
sort_info.param = param; |
|
2124 |
||
2125 |
set_data_file_type(&sort_info, share); |
|
2126 |
sort_param.filepos=new_header_length; |
|
2127 |
sort_info.dupp=0; |
|
2128 |
sort_info.buff=0; |
|
2129 |
param->read_cache.end_of_file=sort_info.filelength= |
|
656.1.39
by Monty Taylor
Removed my_seek, my_tell, my_fwrite, my_fseek. |
2130 |
lseek(param->read_cache.file,0L,SEEK_END); |
1
by brian
clean slate |
2131 |
|
2132 |
sort_param.wordlist=NULL; |
|
2133 |
||
2134 |
if (share->data_file_type == DYNAMIC_RECORD) |
|
398.1.4
by Monty Taylor
Renamed max/min. |
2135 |
length=cmax(share->base.min_pack_length+1,share->base.min_block_length); |
1
by brian
clean slate |
2136 |
else if (share->data_file_type == COMPRESSED_RECORD) |
2137 |
length=share->base.min_block_length; |
|
2138 |
else
|
|
2139 |
length=share->base.pack_reclength; |
|
2140 |
sort_info.max_records= |
|
2141 |
((param->testflag & T_CREATE_MISSING_KEYS) ? info->state->records : |
|
2142 |
(ha_rows) (sort_info.filelength/length+1)); |
|
2143 |
sort_param.key_cmp=sort_key_cmp; |
|
2144 |
sort_param.lock_in_memory=lock_memory; |
|
2145 |
sort_param.sort_info=&sort_info; |
|
281
by Brian Aker
Converted myisam away from my_bool |
2146 |
sort_param.fix_datafile= (bool) (! rep_quick); |
1
by brian
clean slate |
2147 |
sort_param.master =1; |
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
2148 |
|
1
by brian
clean slate |
2149 |
del=info->state->del; |
2150 |
param->glob_crc=0; |
|
2151 |
if (param->testflag & T_CALC_CHECKSUM) |
|
2152 |
sort_param.calc_checksum= 1; |
|
2153 |
||
2154 |
rec_per_key_part= param->rec_per_key_part; |
|
2155 |
for (sort_param.key=0 ; sort_param.key < share->base.keys ; |
|
2156 |
rec_per_key_part+=sort_param.keyinfo->keysegs, sort_param.key++) |
|
2157 |
{
|
|
2158 |
sort_param.read_cache=param->read_cache; |
|
2159 |
sort_param.keyinfo=share->keyinfo+sort_param.key; |
|
2160 |
sort_param.seg=sort_param.keyinfo->seg; |
|
2161 |
/*
|
|
2162 |
Skip this index if it is marked disabled in the copied
|
|
2163 |
(and possibly inverted) key_map.
|
|
2164 |
*/
|
|
2165 |
if (! mi_is_key_active(key_map, sort_param.key)) |
|
2166 |
{
|
|
2167 |
/* Remember old statistics for key */
|
|
212.6.12
by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove(). |
2168 |
assert(rec_per_key_part >= param->rec_per_key_part); |
2169 |
memcpy(rec_per_key_part, |
|
2170 |
(share->state.rec_per_key_part + |
|
2171 |
(rec_per_key_part - param->rec_per_key_part)), |
|
1
by brian
clean slate |
2172 |
sort_param.keyinfo->keysegs*sizeof(*rec_per_key_part)); |
2173 |
continue; |
|
2174 |
}
|
|
2175 |
||
2176 |
if ((!(param->testflag & T_SILENT))) |
|
2177 |
printf ("- Fixing index %d\n",sort_param.key+1); |
|
2178 |
sort_param.max_pos=sort_param.pos=share->pack.header_length; |
|
2179 |
keyseg=sort_param.seg; |
|
212.6.12
by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove(). |
2180 |
memset(sort_param.unique, 0, sizeof(sort_param.unique)); |
1
by brian
clean slate |
2181 |
sort_param.key_length=share->rec_reflength; |
2182 |
for (i=0 ; keyseg[i].type != HA_KEYTYPE_END; i++) |
|
2183 |
{
|
|
2184 |
sort_param.key_length+=keyseg[i].length; |
|
2185 |
if (keyseg[i].flag & HA_SPACE_PACK) |
|
2186 |
sort_param.key_length+=get_pack_length(keyseg[i].length); |
|
2187 |
if (keyseg[i].flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART)) |
|
2188 |
sort_param.key_length+=2 + test(keyseg[i].length >= 127); |
|
2189 |
if (keyseg[i].flag & HA_NULL_PART) |
|
2190 |
sort_param.key_length++; |
|
2191 |
}
|
|
2192 |
info->state->records=info->state->del=share->state.split=0; |
|
2193 |
info->state->empty=0; |
|
2194 |
||
2195 |
{
|
|
2196 |
sort_param.key_read=sort_key_read; |
|
2197 |
sort_param.key_write=sort_key_write; |
|
2198 |
}
|
|
2199 |
||
2200 |
if (_create_index_by_sort(&sort_param, |
|
281
by Brian Aker
Converted myisam away from my_bool |
2201 |
(bool) (!(param->testflag & T_VERBOSE)), |
1
by brian
clean slate |
2202 |
(uint) param->sort_buffer_length)) |
2203 |
{
|
|
2204 |
param->retry_repair=1; |
|
2205 |
goto err; |
|
2206 |
}
|
|
2207 |
/* No need to calculate checksum again. */
|
|
2208 |
sort_param.calc_checksum= 0; |
|
2209 |
free_root(&sort_param.wordroot, MYF(0)); |
|
2210 |
||
2211 |
/* Set for next loop */
|
|
2212 |
sort_info.max_records= (ha_rows) info->state->records; |
|
2213 |
||
2214 |
if (param->testflag & T_STATISTICS) |
|
2215 |
update_key_parts(sort_param.keyinfo, rec_per_key_part, sort_param.unique, |
|
2216 |
param->stats_method == MI_STATS_METHOD_IGNORE_NULLS? |
|
2217 |
sort_param.notnull: NULL, |
|
151
by Brian Aker
Ulonglong to uint64_t |
2218 |
(uint64_t) info->state->records); |
1
by brian
clean slate |
2219 |
/* Enable this index in the permanent (not the copied) key_map. */
|
2220 |
mi_set_key_active(share->state.key_map, sort_param.key); |
|
2221 |
||
2222 |
if (sort_param.fix_datafile) |
|
2223 |
{
|
|
2224 |
param->read_cache.end_of_file=sort_param.filepos; |
|
2225 |
if (write_data_suffix(&sort_info,1) || end_io_cache(&info->rec_cache)) |
|
2226 |
goto err; |
|
2227 |
if (param->testflag & T_SAFE_REPAIR) |
|
2228 |
{
|
|
2229 |
/* Don't repair if we loosed more than one row */
|
|
2230 |
if (info->state->records+1 < start_records) |
|
2231 |
{
|
|
2232 |
info->state->records=start_records; |
|
2233 |
goto err; |
|
2234 |
}
|
|
2235 |
}
|
|
2236 |
share->state.state.data_file_length = info->state->data_file_length= |
|
2237 |
sort_param.filepos; |
|
2238 |
/* Only whole records */
|
|
2239 |
share->state.version=(ulong) time((time_t*) 0); |
|
2240 |
my_close(info->dfile,MYF(0)); |
|
2241 |
info->dfile=new_file; |
|
2242 |
share->data_file_type=sort_info.new_data_file_type; |
|
2243 |
share->pack.header_length=(ulong) new_header_length; |
|
2244 |
sort_param.fix_datafile=0; |
|
2245 |
}
|
|
2246 |
else
|
|
2247 |
info->state->data_file_length=sort_param.max_pos; |
|
2248 |
||
2249 |
param->read_cache.file=info->dfile; /* re-init read cache */ |
|
2250 |
reinit_io_cache(¶m->read_cache,READ_CACHE,share->pack.header_length, |
|
2251 |
1,1); |
|
2252 |
}
|
|
2253 |
||
2254 |
if (param->testflag & T_WRITE_LOOP) |
|
2255 |
{
|
|
398.1.10
by Monty Taylor
Actually removed VOID() this time. |
2256 |
fputs(" \r",stdout); fflush(stdout); |
1
by brian
clean slate |
2257 |
}
|
2258 |
||
2259 |
if (rep_quick && del+sort_info.dupp != info->state->del) |
|
2260 |
{
|
|
2261 |
mi_check_print_error(param,"Couldn't fix table with quick recovery: Found wrong number of deleted records"); |
|
2262 |
mi_check_print_error(param,"Run recovery again without -q"); |
|
2263 |
got_error=1; |
|
2264 |
param->retry_repair=1; |
|
2265 |
param->testflag|=T_RETRY_WITHOUT_QUICK; |
|
2266 |
goto err; |
|
2267 |
}
|
|
2268 |
||
2269 |
if (rep_quick & T_FORCE_UNIQUENESS) |
|
2270 |
{
|
|
2271 |
my_off_t skr=info->state->data_file_length+ |
|
2272 |
(share->options & HA_OPTION_COMPRESS_RECORD ? |
|
2273 |
MEMMAP_EXTRA_MARGIN : 0); |
|
2274 |
#ifdef USE_RELOC
|
|
2275 |
if (share->data_file_type == STATIC_RECORD && |
|
2276 |
skr < share->base.reloc*share->base.min_pack_length) |
|
2277 |
skr=share->base.reloc*share->base.min_pack_length; |
|
2278 |
#endif
|
|
2279 |
if (skr != sort_info.filelength && !info->s->base.raid_type) |
|
30
by Brian Aker
Large file and ftruncate() support |
2280 |
if (ftruncate(info->dfile, skr)) |
1
by brian
clean slate |
2281 |
mi_check_print_warning(param, |
2282 |
"Can't change size of datafile, error: %d", |
|
2283 |
my_errno); |
|
2284 |
}
|
|
2285 |
if (param->testflag & T_CALC_CHECKSUM) |
|
2286 |
info->state->checksum=param->glob_crc; |
|
2287 |
||
30
by Brian Aker
Large file and ftruncate() support |
2288 |
if (ftruncate(share->kfile, info->state->key_file_length)) |
1
by brian
clean slate |
2289 |
mi_check_print_warning(param, |
2290 |
"Can't change size of indexfile, error: %d", |
|
2291 |
my_errno); |
|
2292 |
||
2293 |
if (!(param->testflag & T_SILENT)) |
|
2294 |
{
|
|
2295 |
if (start_records != info->state->records) |
|
2296 |
printf("Data records: %s\n", llstr(info->state->records,llbuff)); |
|
2297 |
if (sort_info.dupp) |
|
2298 |
mi_check_print_warning(param, |
|
2299 |
"%s records have been removed", |
|
2300 |
llstr(sort_info.dupp,llbuff)); |
|
2301 |
}
|
|
2302 |
got_error=0; |
|
2303 |
||
2304 |
if (&share->state.state != info->state) |
|
2305 |
memcpy( &share->state.state, info->state, sizeof(*info->state)); |
|
2306 |
||
2307 |
err: |
|
2308 |
got_error|= flush_blocks(param, share->key_cache, share->kfile); |
|
398.1.10
by Monty Taylor
Actually removed VOID() this time. |
2309 |
end_io_cache(&info->rec_cache); |
1
by brian
clean slate |
2310 |
if (!got_error) |
2311 |
{
|
|
2312 |
/* Replace the actual file with the temporary file */
|
|
2313 |
if (new_file >= 0) |
|
2314 |
{
|
|
2315 |
my_close(new_file,MYF(0)); |
|
2316 |
info->dfile=new_file= -1; |
|
2317 |
if (change_to_newfile(share->data_file_name,MI_NAME_DEXT, |
|
2318 |
DATA_TMP_EXT, share->base.raid_chunks, |
|
2319 |
(param->testflag & T_BACKUP_DATA ? |
|
2320 |
MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) || |
|
2321 |
mi_open_datafile(info,share,-1)) |
|
2322 |
got_error=1; |
|
2323 |
}
|
|
2324 |
}
|
|
2325 |
if (got_error) |
|
2326 |
{
|
|
2327 |
if (! param->error_printed) |
|
2328 |
mi_check_print_error(param,"%d when fixing table",my_errno); |
|
2329 |
if (new_file >= 0) |
|
2330 |
{
|
|
398.1.10
by Monty Taylor
Actually removed VOID() this time. |
2331 |
my_close(new_file,MYF(0)); |
489.1.6
by Monty Taylor
Removed RAID garbage. |
2332 |
my_delete(param->temp_filename, MYF(MY_WME)); |
1
by brian
clean slate |
2333 |
if (info->dfile == new_file) |
489.1.6
by Monty Taylor
Removed RAID garbage. |
2334 |
info->dfile= -1; |
1
by brian
clean slate |
2335 |
}
|
2336 |
mi_mark_crashed_on_repair(info); |
|
2337 |
}
|
|
2338 |
else if (key_map == share->state.key_map) |
|
2339 |
share->state.changed&= ~STATE_NOT_OPTIMIZED_KEYS; |
|
2340 |
share->state.changed|=STATE_NOT_SORTED_PAGES; |
|
2341 |
||
477
by Monty Taylor
Removed my_free(). It turns out that it had been def'd to ignore the flags passed to it in the second arg anyway. Gotta love that. |
2342 |
void * rec_buff_ptr= NULL; |
2343 |
rec_buff_ptr= mi_get_rec_buff_ptr(info, sort_param.rec_buff); |
|
2344 |
if (rec_buff_ptr != NULL) |
|
2345 |
free(rec_buff_ptr); |
|
2346 |
rec_buff_ptr= mi_get_rec_buff_ptr(info, sort_param.record); |
|
2347 |
if (rec_buff_ptr != NULL) |
|
2348 |
free(rec_buff_ptr); |
|
2349 |
rec_buff_ptr= NULL; |
|
2350 |
||
481
by Brian Aker
Remove all of uchar. |
2351 |
free((unsigned char*) sort_info.key_block); |
477
by Monty Taylor
Removed my_free(). It turns out that it had been def'd to ignore the flags passed to it in the second arg anyway. Gotta love that. |
2352 |
free(sort_info.buff); |
398.1.10
by Monty Taylor
Actually removed VOID() this time. |
2353 |
end_io_cache(¶m->read_cache); |
1
by brian
clean slate |
2354 |
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); |
2355 |
if (!got_error && (param->testflag & T_UNPACK)) |
|
2356 |
{
|
|
481
by Brian Aker
Remove all of uchar. |
2357 |
share->state.header.options[0]&= (unsigned char) ~HA_OPTION_COMPRESS_RECORD; |
1
by brian
clean slate |
2358 |
share->pack.header_length=0; |
2359 |
}
|
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
2360 |
return(got_error); |
1
by brian
clean slate |
2361 |
}
|
2362 |
||
2363 |
/*
|
|
2364 |
Threaded repair of table using sorting
|
|
2365 |
||
2366 |
SYNOPSIS
|
|
2367 |
mi_repair_parallel()
|
|
2368 |
param Repair parameters
|
|
2369 |
info MyISAM handler to repair
|
|
2370 |
name Name of table (for warnings)
|
|
2371 |
rep_quick set to <> 0 if we should not change data file
|
|
2372 |
||
2373 |
DESCRIPTION
|
|
2374 |
Same as mi_repair_by_sort but do it multithreaded
|
|
2375 |
Each key is handled by a separate thread.
|
|
2376 |
TODO: make a number of threads a parameter
|
|
2377 |
||
2378 |
In parallel repair we use one thread per index. There are two modes:
|
|
2379 |
||
2380 |
Quick
|
|
2381 |
||
2382 |
Only the indexes are rebuilt. All threads share a read buffer.
|
|
2383 |
Every thread that needs fresh data in the buffer enters the shared
|
|
2384 |
cache lock. The last thread joining the lock reads the buffer from
|
|
2385 |
the data file and wakes all other threads.
|
|
2386 |
||
2387 |
Non-quick
|
|
2388 |
||
2389 |
The data file is rebuilt and all indexes are rebuilt to point to
|
|
2390 |
the new record positions. One thread is the master thread. It
|
|
2391 |
reads from the old data file and writes to the new data file. It
|
|
2392 |
also creates one of the indexes. The other threads read from a
|
|
2393 |
buffer which is filled by the master. If they need fresh data,
|
|
2394 |
they enter the shared cache lock. If the masters write buffer is
|
|
2395 |
full, it flushes it to the new data file and enters the shared
|
|
2396 |
cache lock too. When all threads joined in the lock, the master
|
|
2397 |
copies its write buffer to the read buffer for the other threads
|
|
2398 |
and wakes them.
|
|
2399 |
||
2400 |
RESULT
|
|
2401 |
0 ok
|
|
2402 |
<>0 Error
|
|
2403 |
*/
|
|
2404 |
||
2405 |
int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, |
|
2406 |
const char * name, int rep_quick) |
|
2407 |
{
|
|
2408 |
int got_error; |
|
482
by Brian Aker
Remove uint. |
2409 |
uint32_t i,key, total_key_length, istep; |
1
by brian
clean slate |
2410 |
ulong rec_length; |
2411 |
ha_rows start_records; |
|
2412 |
my_off_t new_header_length,del; |
|
2413 |
File new_file; |
|
2414 |
MI_SORT_PARAM *sort_param=0; |
|
2415 |
MYISAM_SHARE *share=info->s; |
|
2416 |
ulong *rec_per_key_part; |
|
2417 |
HA_KEYSEG *keyseg; |
|
2418 |
char llbuff[22]; |
|
2419 |
IO_CACHE new_data_cache; /* For non-quick repair. */ |
|
2420 |
IO_CACHE_SHARE io_share; |
|
2421 |
SORT_INFO sort_info; |
|
151
by Brian Aker
Ulonglong to uint64_t |
2422 |
uint64_t key_map= 0; |
1
by brian
clean slate |
2423 |
pthread_attr_t thr_attr; |
2424 |
ulong max_pack_reclength; |
|
2425 |
||
2426 |
start_records=info->state->records; |
|
2427 |
got_error=1; |
|
2428 |
new_file= -1; |
|
2429 |
new_header_length=(param->testflag & T_UNPACK) ? 0 : |
|
2430 |
share->pack.header_length; |
|
2431 |
if (!(param->testflag & T_SILENT)) |
|
2432 |
{
|
|
2433 |
printf("- parallel recovering (with sort) MyISAM-table '%s'\n",name); |
|
2434 |
printf("Data records: %s\n", llstr(start_records,llbuff)); |
|
2435 |
}
|
|
2436 |
param->testflag|=T_REP; /* for easy checking */ |
|
2437 |
||
2438 |
if (info->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD)) |
|
2439 |
param->testflag|=T_CALC_CHECKSUM; |
|
2440 |
||
2441 |
/*
|
|
2442 |
Quick repair (not touching data file, rebuilding indexes):
|
|
2443 |
{
|
|
2444 |
Read cache is (MI_CHECK *param)->read_cache using info->dfile.
|
|
2445 |
}
|
|
2446 |
||
2447 |
Non-quick repair (rebuilding data file and indexes):
|
|
2448 |
{
|
|
2449 |
Master thread:
|
|
2450 |
||
2451 |
Read cache is (MI_CHECK *param)->read_cache using info->dfile.
|
|
2452 |
Write cache is (MI_INFO *info)->rec_cache using new_file.
|
|
2453 |
||
2454 |
Slave threads:
|
|
2455 |
||
2456 |
Read cache is new_data_cache synced to master rec_cache.
|
|
2457 |
||
2458 |
The final assignment of the filedescriptor for rec_cache is done
|
|
2459 |
after the cache creation.
|
|
2460 |
||
2461 |
Don't check file size on new_data_cache, as the resulting file size
|
|
2462 |
is not known yet.
|
|
2463 |
||
2464 |
As rec_cache and new_data_cache are synced, write_buffer_length is
|
|
2465 |
used for the read cache 'new_data_cache'. Both start at the same
|
|
2466 |
position 'new_header_length'.
|
|
2467 |
}
|
|
2468 |
*/
|
|
212.6.12
by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove(). |
2469 |
memset(&sort_info, 0, sizeof(sort_info)); |
1
by brian
clean slate |
2470 |
/* Initialize pthread structures before goto err. */
|
2471 |
pthread_mutex_init(&sort_info.mutex, MY_MUTEX_INIT_FAST); |
|
2472 |
pthread_cond_init(&sort_info.cond, 0); |
|
2473 |
||
2474 |
if (!(sort_info.key_block= |
|
2475 |
alloc_key_blocks(param, (uint) param->sort_key_blocks, |
|
2476 |
share->base.max_key_block_length)) || |
|
2477 |
init_io_cache(¶m->read_cache, info->dfile, |
|
2478 |
(uint) param->read_buffer_length, |
|
2479 |
READ_CACHE, share->pack.header_length, 1, MYF(MY_WME)) || |
|
2480 |
(!rep_quick && |
|
2481 |
(init_io_cache(&info->rec_cache, info->dfile, |
|
2482 |
(uint) param->write_buffer_length, |
|
2483 |
WRITE_CACHE, new_header_length, 1, |
|
2484 |
MYF(MY_WME | MY_WAIT_IF_FULL) & param->myf_rw) || |
|
2485 |
init_io_cache(&new_data_cache, -1, |
|
2486 |
(uint) param->write_buffer_length, |
|
2487 |
READ_CACHE, new_header_length, 1, |
|
2488 |
MYF(MY_WME | MY_DONT_CHECK_FILESIZE))))) |
|
2489 |
goto err; |
|
2490 |
sort_info.key_block_end=sort_info.key_block+param->sort_key_blocks; |
|
2491 |
info->opt_flag|=WRITE_CACHE_USED; |
|
2492 |
info->rec_cache.file=info->dfile; /* for sort_delete_record */ |
|
2493 |
||
2494 |
if (!rep_quick) |
|
2495 |
{
|
|
2496 |
/* Get real path for data file */
|
|
489.1.6
by Monty Taylor
Removed RAID garbage. |
2497 |
if ((new_file=my_create(fn_format(param->temp_filename, |
2498 |
share->data_file_name, "", |
|
2499 |
DATA_TMP_EXT, |
|
2500 |
2+4), |
|
2501 |
0,param->tmpfile_createflag, |
|
2502 |
MYF(0))) < 0) |
|
1
by brian
clean slate |
2503 |
{
|
2504 |
mi_check_print_error(param,"Can't create new tempfile: '%s'", |
|
2505 |
param->temp_filename); |
|
2506 |
goto err; |
|
2507 |
}
|
|
2508 |
if (new_header_length && |
|
2509 |
filecopy(param, new_file,info->dfile,0L,new_header_length, |
|
2510 |
"datafile-header")) |
|
2511 |
goto err; |
|
2512 |
if (param->testflag & T_UNPACK) |
|
2513 |
{
|
|
2514 |
share->options&= ~HA_OPTION_COMPRESS_RECORD; |
|
2515 |
mi_int2store(share->state.header.options,share->options); |
|
2516 |
}
|
|
2517 |
share->state.dellink= HA_OFFSET_ERROR; |
|
2518 |
info->rec_cache.file=new_file; |
|
2519 |
}
|
|
2520 |
||
2521 |
info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED); |
|
2522 |
||
2523 |
/* Optionally drop indexes and optionally modify the key_map. */
|
|
163
by Brian Aker
Merge Monty's code. |
2524 |
mi_drop_all_indexes(param, info, false); |
1
by brian
clean slate |
2525 |
key_map= share->state.key_map; |
2526 |
if (param->testflag & T_CREATE_MISSING_KEYS) |
|
2527 |
{
|
|
2528 |
/* Invert the copied key_map to recreate all disabled indexes. */
|
|
2529 |
key_map= ~key_map; |
|
2530 |
}
|
|
2531 |
||
2532 |
sort_info.info=info; |
|
2533 |
sort_info.param = param; |
|
2534 |
||
2535 |
set_data_file_type(&sort_info, share); |
|
2536 |
sort_info.dupp=0; |
|
2537 |
sort_info.buff=0; |
|
2538 |
param->read_cache.end_of_file=sort_info.filelength= |
|
656.1.39
by Monty Taylor
Removed my_seek, my_tell, my_fwrite, my_fseek. |
2539 |
lseek(param->read_cache.file,0L,SEEK_END); |
1
by brian
clean slate |
2540 |
|
2541 |
if (share->data_file_type == DYNAMIC_RECORD) |
|
398.1.4
by Monty Taylor
Renamed max/min. |
2542 |
rec_length=cmax(share->base.min_pack_length+1,share->base.min_block_length); |
1
by brian
clean slate |
2543 |
else if (share->data_file_type == COMPRESSED_RECORD) |
2544 |
rec_length=share->base.min_block_length; |
|
2545 |
else
|
|
2546 |
rec_length=share->base.pack_reclength; |
|
2547 |
/*
|
|
2548 |
+1 below is required hack for parallel repair mode.
|
|
2549 |
The info->state->records value, that is compared later
|
|
2550 |
to sort_info.max_records and cannot exceed it, is
|
|
2551 |
increased in sort_key_write. In mi_repair_by_sort, sort_key_write
|
|
2552 |
is called after sort_key_read, where the comparison is performed,
|
|
2553 |
but in parallel mode master thread can call sort_key_write
|
|
2554 |
before some other repair thread calls sort_key_read.
|
|
2555 |
Furthermore I'm not even sure +1 would be enough.
|
|
2556 |
May be sort_info.max_records shold be always set to max value in
|
|
2557 |
parallel mode.
|
|
2558 |
*/
|
|
2559 |
sort_info.max_records= |
|
2560 |
((param->testflag & T_CREATE_MISSING_KEYS) ? info->state->records + 1: |
|
2561 |
(ha_rows) (sort_info.filelength/rec_length+1)); |
|
2562 |
||
2563 |
del=info->state->del; |
|
2564 |
param->glob_crc=0; |
|
2565 |
/* for compressed tables */
|
|
2566 |
max_pack_reclength= share->base.pack_reclength; |
|
2567 |
if (share->options & HA_OPTION_COMPRESS_RECORD) |
|
2568 |
set_if_bigger(max_pack_reclength, share->max_pack_length); |
|
2569 |
if (!(sort_param=(MI_SORT_PARAM *) |
|
656.1.25
by Monty Taylor
Removed my_malloc stuff from storage/ |
2570 |
malloc(share->base.keys * |
2571 |
(sizeof(MI_SORT_PARAM) + max_pack_reclength)))) |
|
1
by brian
clean slate |
2572 |
{
|
2573 |
mi_check_print_error(param,"Not enough memory for key!"); |
|
2574 |
goto err; |
|
2575 |
}
|
|
656.1.25
by Monty Taylor
Removed my_malloc stuff from storage/ |
2576 |
memset(sort_param, 0, share->base.keys * |
2577 |
(sizeof(MI_SORT_PARAM) + max_pack_reclength)); |
|
1
by brian
clean slate |
2578 |
total_key_length=0; |
2579 |
rec_per_key_part= param->rec_per_key_part; |
|
2580 |
info->state->records=info->state->del=share->state.split=0; |
|
2581 |
info->state->empty=0; |
|
2582 |
||
2583 |
for (i=key=0, istep=1 ; key < share->base.keys ; |
|
2584 |
rec_per_key_part+=sort_param[i].keyinfo->keysegs, i+=istep, key++) |
|
2585 |
{
|
|
2586 |
sort_param[i].key=key; |
|
2587 |
sort_param[i].keyinfo=share->keyinfo+key; |
|
2588 |
sort_param[i].seg=sort_param[i].keyinfo->seg; |
|
2589 |
/*
|
|
2590 |
Skip this index if it is marked disabled in the copied
|
|
2591 |
(and possibly inverted) key_map.
|
|
2592 |
*/
|
|
2593 |
if (! mi_is_key_active(key_map, key)) |
|
2594 |
{
|
|
2595 |
/* Remember old statistics for key */
|
|
212.6.12
by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove(). |
2596 |
assert(rec_per_key_part >= param->rec_per_key_part); |
2597 |
memcpy(rec_per_key_part, |
|
2598 |
(share->state.rec_per_key_part + |
|
2599 |
(rec_per_key_part - param->rec_per_key_part)), |
|
1
by brian
clean slate |
2600 |
sort_param[i].keyinfo->keysegs*sizeof(*rec_per_key_part)); |
2601 |
istep=0; |
|
2602 |
continue; |
|
2603 |
}
|
|
2604 |
istep=1; |
|
2605 |
if ((!(param->testflag & T_SILENT))) |
|
2606 |
printf ("- Fixing index %d\n",key+1); |
|
2607 |
{
|
|
2608 |
sort_param[i].key_read=sort_key_read; |
|
2609 |
sort_param[i].key_write=sort_key_write; |
|
2610 |
}
|
|
2611 |
sort_param[i].key_cmp=sort_key_cmp; |
|
2612 |
sort_param[i].lock_in_memory=lock_memory; |
|
2613 |
sort_param[i].sort_info=&sort_info; |
|
2614 |
sort_param[i].master=0; |
|
2615 |
sort_param[i].fix_datafile=0; |
|
2616 |
sort_param[i].calc_checksum= 0; |
|
2617 |
||
2618 |
sort_param[i].filepos=new_header_length; |
|
2619 |
sort_param[i].max_pos=sort_param[i].pos=share->pack.header_length; |
|
2620 |
||
481
by Brian Aker
Remove all of uchar. |
2621 |
sort_param[i].record= (((unsigned char *)(sort_param+share->base.keys))+ |
1
by brian
clean slate |
2622 |
(max_pack_reclength * i)); |
2623 |
if (!mi_alloc_rec_buff(info, -1, &sort_param[i].rec_buff)) |
|
2624 |
{
|
|
2625 |
mi_check_print_error(param,"Not enough memory!"); |
|
2626 |
goto err; |
|
2627 |
}
|
|
2628 |
||
2629 |
sort_param[i].key_length=share->rec_reflength; |
|
2630 |
for (keyseg=sort_param[i].seg; keyseg->type != HA_KEYTYPE_END; |
|
2631 |
keyseg++) |
|
2632 |
{
|
|
2633 |
sort_param[i].key_length+=keyseg->length; |
|
2634 |
if (keyseg->flag & HA_SPACE_PACK) |
|
2635 |
sort_param[i].key_length+=get_pack_length(keyseg->length); |
|
2636 |
if (keyseg->flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART)) |
|
2637 |
sort_param[i].key_length+=2 + test(keyseg->length >= 127); |
|
2638 |
if (keyseg->flag & HA_NULL_PART) |
|
2639 |
sort_param[i].key_length++; |
|
2640 |
}
|
|
2641 |
total_key_length+=sort_param[i].key_length; |
|
2642 |
}
|
|
2643 |
sort_info.total_keys=i; |
|
2644 |
sort_param[0].master= 1; |
|
281
by Brian Aker
Converted myisam away from my_bool |
2645 |
sort_param[0].fix_datafile= (bool)(! rep_quick); |
1
by brian
clean slate |
2646 |
sort_param[0].calc_checksum= test(param->testflag & T_CALC_CHECKSUM); |
2647 |
||
2648 |
sort_info.got_error=0; |
|
2649 |
pthread_mutex_lock(&sort_info.mutex); |
|
2650 |
||
2651 |
/*
|
|
2652 |
Initialize the I/O cache share for use with the read caches and, in
|
|
2653 |
case of non-quick repair, the write cache. When all threads join on
|
|
2654 |
the cache lock, the writer copies the write cache contents to the
|
|
2655 |
read caches.
|
|
2656 |
*/
|
|
2657 |
if (i > 1) |
|
2658 |
{
|
|
2659 |
if (rep_quick) |
|
2660 |
init_io_cache_share(¶m->read_cache, &io_share, NULL, i); |
|
2661 |
else
|
|
2662 |
init_io_cache_share(&new_data_cache, &io_share, &info->rec_cache, i); |
|
2663 |
}
|
|
2664 |
else
|
|
2665 |
io_share.total_threads= 0; /* share not used */ |
|
2666 |
||
2667 |
(void) pthread_attr_init(&thr_attr); |
|
2668 |
(void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED); |
|
2669 |
||
2670 |
for (i=0 ; i < sort_info.total_keys ; i++) |
|
2671 |
{
|
|
2672 |
/*
|
|
2673 |
Copy the properly initialized IO_CACHE structure so that every
|
|
2674 |
thread has its own copy. In quick mode param->read_cache is shared
|
|
2675 |
for use by all threads. In non-quick mode all threads but the
|
|
2676 |
first copy the shared new_data_cache, which is synchronized to the
|
|
2677 |
write cache of the first thread. The first thread copies
|
|
2678 |
param->read_cache, which is not shared.
|
|
2679 |
*/
|
|
2680 |
sort_param[i].read_cache= ((rep_quick || !i) ? param->read_cache : |
|
2681 |
new_data_cache); |
|
2682 |
||
2683 |
/*
|
|
2684 |
two approaches: the same amount of memory for each thread
|
|
2685 |
or the memory for the same number of keys for each thread...
|
|
2686 |
In the second one all the threads will fill their sort_buffers
|
|
2687 |
(and call write_keys) at the same time, putting more stress on i/o.
|
|
2688 |
*/
|
|
2689 |
sort_param[i].sortbuff_size= |
|
2690 |
#ifndef USING_SECOND_APPROACH
|
|
2691 |
param->sort_buffer_length/sort_info.total_keys; |
|
2692 |
#else
|
|
2693 |
param->sort_buffer_length*sort_param[i].key_length/total_key_length; |
|
2694 |
#endif
|
|
2695 |
if (pthread_create(&sort_param[i].thr, &thr_attr, |
|
2696 |
thr_find_all_keys, |
|
2697 |
(void *) (sort_param+i))) |
|
2698 |
{
|
|
2699 |
mi_check_print_error(param,"Cannot start a repair thread"); |
|
2700 |
/* Cleanup: Detach from the share. Avoid others to be blocked. */
|
|
2701 |
if (io_share.total_threads) |
|
2702 |
remove_io_thread(&sort_param[i].read_cache); |
|
2703 |
sort_info.got_error=1; |
|
2704 |
}
|
|
2705 |
else
|
|
2706 |
sort_info.threads_running++; |
|
2707 |
}
|
|
2708 |
(void) pthread_attr_destroy(&thr_attr); |
|
2709 |
||
2710 |
/* waiting for all threads to finish */
|
|
2711 |
while (sort_info.threads_running) |
|
2712 |
pthread_cond_wait(&sort_info.cond, &sort_info.mutex); |
|
2713 |
pthread_mutex_unlock(&sort_info.mutex); |
|
2714 |
||
2715 |
if ((got_error= thr_write_keys(sort_param))) |
|
2716 |
{
|
|
2717 |
param->retry_repair=1; |
|
2718 |
goto err; |
|
2719 |
}
|
|
2720 |
got_error=1; /* Assume the following may go wrong */ |
|
2721 |
||
2722 |
if (sort_param[0].fix_datafile) |
|
2723 |
{
|
|
2724 |
/*
|
|
2725 |
Append some nuls to the end of a memory mapped file. Destroy the
|
|
2726 |
write cache. The master thread did already detach from the share
|
|
2727 |
by remove_io_thread() in sort.c:thr_find_all_keys().
|
|
2728 |
*/
|
|
2729 |
if (write_data_suffix(&sort_info,1) || end_io_cache(&info->rec_cache)) |
|
2730 |
goto err; |
|
2731 |
if (param->testflag & T_SAFE_REPAIR) |
|
2732 |
{
|
|
2733 |
/* Don't repair if we loosed more than one row */
|
|
2734 |
if (info->state->records+1 < start_records) |
|
2735 |
{
|
|
2736 |
info->state->records=start_records; |
|
2737 |
goto err; |
|
2738 |
}
|
|
2739 |
}
|
|
2740 |
share->state.state.data_file_length= info->state->data_file_length= |
|
2741 |
sort_param->filepos; |
|
2742 |
/* Only whole records */
|
|
2743 |
share->state.version=(ulong) time((time_t*) 0); |
|
2744 |
||
2745 |
/*
|
|
2746 |
Exchange the data file descriptor of the table, so that we use the
|
|
2747 |
new file from now on.
|
|
2748 |
*/
|
|
2749 |
my_close(info->dfile,MYF(0)); |
|
2750 |
info->dfile=new_file; |
|
2751 |
||
2752 |
share->data_file_type=sort_info.new_data_file_type; |
|
2753 |
share->pack.header_length=(ulong) new_header_length; |
|
2754 |
}
|
|
2755 |
else
|
|
2756 |
info->state->data_file_length=sort_param->max_pos; |
|
2757 |
||
2758 |
if (rep_quick && del+sort_info.dupp != info->state->del) |
|
2759 |
{
|
|
2760 |
mi_check_print_error(param,"Couldn't fix table with quick recovery: Found wrong number of deleted records"); |
|
2761 |
mi_check_print_error(param,"Run recovery again without -q"); |
|
2762 |
param->retry_repair=1; |
|
2763 |
param->testflag|=T_RETRY_WITHOUT_QUICK; |
|
2764 |
goto err; |
|
2765 |
}
|
|
2766 |
||
2767 |
if (rep_quick & T_FORCE_UNIQUENESS) |
|
2768 |
{
|
|
2769 |
my_off_t skr=info->state->data_file_length+ |
|
2770 |
(share->options & HA_OPTION_COMPRESS_RECORD ? |
|
2771 |
MEMMAP_EXTRA_MARGIN : 0); |
|
2772 |
#ifdef USE_RELOC
|
|
2773 |
if (share->data_file_type == STATIC_RECORD && |
|
2774 |
skr < share->base.reloc*share->base.min_pack_length) |
|
2775 |
skr=share->base.reloc*share->base.min_pack_length; |
|
2776 |
#endif
|
|
2777 |
if (skr != sort_info.filelength && !info->s->base.raid_type) |
|
30
by Brian Aker
Large file and ftruncate() support |
2778 |
if (ftruncate(info->dfile, skr)) |
1
by brian
clean slate |
2779 |
mi_check_print_warning(param, |
2780 |
"Can't change size of datafile, error: %d", |
|
2781 |
my_errno); |
|
2782 |
}
|
|
2783 |
if (param->testflag & T_CALC_CHECKSUM) |
|
2784 |
info->state->checksum=param->glob_crc; |
|
2785 |
||
30
by Brian Aker
Large file and ftruncate() support |
2786 |
if (ftruncate(share->kfile, info->state->key_file_length)) |
1
by brian
clean slate |
2787 |
mi_check_print_warning(param, |
2788 |
"Can't change size of indexfile, error: %d", my_errno); |
|
2789 |
||
2790 |
if (!(param->testflag & T_SILENT)) |
|
2791 |
{
|
|
2792 |
if (start_records != info->state->records) |
|
2793 |
printf("Data records: %s\n", llstr(info->state->records,llbuff)); |
|
2794 |
if (sort_info.dupp) |
|
2795 |
mi_check_print_warning(param, |
|
2796 |
"%s records have been removed", |
|
2797 |
llstr(sort_info.dupp,llbuff)); |
|
2798 |
}
|
|
2799 |
got_error=0; |
|
2800 |
||
2801 |
if (&share->state.state != info->state) |
|
2802 |
memcpy(&share->state.state, info->state, sizeof(*info->state)); |
|
2803 |
||
2804 |
err: |
|
2805 |
got_error|= flush_blocks(param, share->key_cache, share->kfile); |
|
2806 |
/*
|
|
2807 |
Destroy the write cache. The master thread did already detach from
|
|
2808 |
the share by remove_io_thread() or it was not yet started (if the
|
|
2809 |
error happend before creating the thread).
|
|
2810 |
*/
|
|
398.1.10
by Monty Taylor
Actually removed VOID() this time. |
2811 |
end_io_cache(&info->rec_cache); |
1
by brian
clean slate |
2812 |
/*
|
2813 |
Destroy the new data cache in case of non-quick repair. All slave
|
|
2814 |
threads did either detach from the share by remove_io_thread()
|
|
2815 |
already or they were not yet started (if the error happend before
|
|
2816 |
creating the threads).
|
|
2817 |
*/
|
|
2818 |
if (!rep_quick) |
|
398.1.10
by Monty Taylor
Actually removed VOID() this time. |
2819 |
end_io_cache(&new_data_cache); |
1
by brian
clean slate |
2820 |
if (!got_error) |
2821 |
{
|
|
2822 |
/* Replace the actual file with the temporary file */
|
|
2823 |
if (new_file >= 0) |
|
2824 |
{
|
|
2825 |
my_close(new_file,MYF(0)); |
|
2826 |
info->dfile=new_file= -1; |
|
2827 |
if (change_to_newfile(share->data_file_name,MI_NAME_DEXT, |
|
2828 |
DATA_TMP_EXT, share->base.raid_chunks, |
|
2829 |
(param->testflag & T_BACKUP_DATA ? |
|
2830 |
MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) || |
|
2831 |
mi_open_datafile(info,share,-1)) |
|
2832 |
got_error=1; |
|
2833 |
}
|
|
2834 |
}
|
|
2835 |
if (got_error) |
|
2836 |
{
|
|
2837 |
if (! param->error_printed) |
|
2838 |
mi_check_print_error(param,"%d when fixing table",my_errno); |
|
2839 |
if (new_file >= 0) |
|
2840 |
{
|
|
398.1.10
by Monty Taylor
Actually removed VOID() this time. |
2841 |
my_close(new_file,MYF(0)); |
489.1.6
by Monty Taylor
Removed RAID garbage. |
2842 |
my_delete(param->temp_filename, MYF(MY_WME)); |
1
by brian
clean slate |
2843 |
if (info->dfile == new_file) |
489.1.6
by Monty Taylor
Removed RAID garbage. |
2844 |
info->dfile= -1; |
1
by brian
clean slate |
2845 |
}
|
2846 |
mi_mark_crashed_on_repair(info); |
|
2847 |
}
|
|
2848 |
else if (key_map == share->state.key_map) |
|
2849 |
share->state.changed&= ~STATE_NOT_OPTIMIZED_KEYS; |
|
2850 |
share->state.changed|=STATE_NOT_SORTED_PAGES; |
|
2851 |
||
2852 |
pthread_cond_destroy (&sort_info.cond); |
|
2853 |
pthread_mutex_destroy(&sort_info.mutex); |
|
2854 |
||
481
by Brian Aker
Remove all of uchar. |
2855 |
free((unsigned char*) sort_info.key_block); |
2856 |
free((unsigned char*) sort_param); |
|
477
by Monty Taylor
Removed my_free(). It turns out that it had been def'd to ignore the flags passed to it in the second arg anyway. Gotta love that. |
2857 |
free(sort_info.buff); |
398.1.10
by Monty Taylor
Actually removed VOID() this time. |
2858 |
end_io_cache(¶m->read_cache); |
1
by brian
clean slate |
2859 |
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); |
2860 |
if (!got_error && (param->testflag & T_UNPACK)) |
|
2861 |
{
|
|
481
by Brian Aker
Remove all of uchar. |
2862 |
share->state.header.options[0]&= (unsigned char) ~HA_OPTION_COMPRESS_RECORD; |
1
by brian
clean slate |
2863 |
share->pack.header_length=0; |
2864 |
}
|
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
2865 |
return(got_error); |
1
by brian
clean slate |
2866 |
}
|
2867 |
||
2868 |
/* Read next record and return next key */
|
|
2869 |
||
2870 |
static int sort_key_read(MI_SORT_PARAM *sort_param, void *key) |
|
2871 |
{
|
|
2872 |
int error; |
|
2873 |
SORT_INFO *sort_info=sort_param->sort_info; |
|
2874 |
MI_INFO *info=sort_info->info; |
|
2875 |
||
2876 |
if ((error=sort_get_next_record(sort_param))) |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
2877 |
return(error); |
1
by brian
clean slate |
2878 |
if (info->state->records == sort_info->max_records) |
2879 |
{
|
|
2880 |
mi_check_print_error(sort_info->param, |
|
2881 |
"Key %d - Found too many records; Can't continue", |
|
2882 |
sort_param->key+1); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
2883 |
return(1); |
1
by brian
clean slate |
2884 |
}
|
2885 |
sort_param->real_key_length= |
|
2886 |
(info->s->rec_reflength+ |
|
481
by Brian Aker
Remove all of uchar. |
2887 |
_mi_make_key(info, sort_param->key, (unsigned char*) key, |
1
by brian
clean slate |
2888 |
sort_param->record, sort_param->filepos)); |
2889 |
#ifdef HAVE_purify
|
|
760.1.5
by Kristian Nielsen
Fix a few warnings when building with -DHAVE_purify |
2890 |
memset((unsigned char *)key+sort_param->real_key_length, 0, |
212.6.1
by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file. |
2891 |
(sort_param->key_length-sort_param->real_key_length)); |
1
by brian
clean slate |
2892 |
#endif
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
2893 |
return(sort_write_record(sort_param)); |
1
by brian
clean slate |
2894 |
} /* sort_key_read */ |
2895 |
||
2896 |
||
2897 |
/*
|
|
2898 |
Read next record from file using parameters in sort_info.
|
|
2899 |
||
2900 |
SYNOPSIS
|
|
2901 |
sort_get_next_record()
|
|
2902 |
sort_param Information about and for the sort process
|
|
2903 |
||
2904 |
NOTE
|
|
2905 |
||
2906 |
Dynamic Records With Non-Quick Parallel Repair
|
|
2907 |
||
2908 |
For non-quick parallel repair we use a synchronized read/write
|
|
2909 |
cache. This means that one thread is the master who fixes the data
|
|
2910 |
file by reading each record from the old data file and writing it
|
|
2911 |
to the new data file. By doing this the records in the new data
|
|
2912 |
file are written contiguously. Whenever the write buffer is full,
|
|
2913 |
it is copied to the read buffer. The slaves read from the read
|
|
2914 |
buffer, which is not associated with a file. Thus read_cache.file
|
|
2915 |
is -1. When using _mi_read_cache(), the slaves must always set
|
|
2916 |
flag to READING_NEXT so that the function never tries to read from
|
|
2917 |
file. This is safe because the records are contiguous. There is no
|
|
2918 |
need to read outside the cache. This condition is evaluated in the
|
|
2919 |
variable 'parallel_flag' for quick reference. read_cache.file must
|
|
2920 |
be >= 0 in every other case.
|
|
2921 |
||
2922 |
RETURN
|
|
2923 |
-1 end of file
|
|
2924 |
0 ok
|
|
2925 |
> 0 error
|
|
2926 |
*/
|
|
2927 |
||
2928 |
static int sort_get_next_record(MI_SORT_PARAM *sort_param) |
|
2929 |
{
|
|
2930 |
int searching; |
|
2931 |
int parallel_flag; |
|
482
by Brian Aker
Remove uint. |
2932 |
uint32_t found_record,b_type,left_length; |
1
by brian
clean slate |
2933 |
my_off_t pos; |
481
by Brian Aker
Remove all of uchar. |
2934 |
unsigned char *to= NULL; |
1
by brian
clean slate |
2935 |
MI_BLOCK_INFO block_info; |
2936 |
SORT_INFO *sort_info=sort_param->sort_info; |
|
2937 |
MI_CHECK *param=sort_info->param; |
|
2938 |
MI_INFO *info=sort_info->info; |
|
2939 |
MYISAM_SHARE *share=info->s; |
|
2940 |
char llbuff[22],llbuff2[22]; |
|
2941 |
||
2942 |
if (*killed_ptr(param)) |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
2943 |
return(1); |
1
by brian
clean slate |
2944 |
|
2945 |
switch (share->data_file_type) { |
|
2946 |
case STATIC_RECORD: |
|
2947 |
for (;;) |
|
2948 |
{
|
|
2949 |
if (my_b_read(&sort_param->read_cache,sort_param->record, |
|
2950 |
share->base.pack_reclength)) |
|
2951 |
{
|
|
2952 |
if (sort_param->read_cache.error) |
|
2953 |
param->out_flag |= O_DATA_LOST; |
|
2954 |
param->retry_repair=1; |
|
2955 |
param->testflag|=T_RETRY_WITHOUT_QUICK; |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
2956 |
return(-1); |
1
by brian
clean slate |
2957 |
}
|
2958 |
sort_param->start_recpos=sort_param->pos; |
|
2959 |
if (!sort_param->fix_datafile) |
|
2960 |
{
|
|
2961 |
sort_param->filepos=sort_param->pos; |
|
2962 |
if (sort_param->master) |
|
2963 |
share->state.split++; |
|
2964 |
}
|
|
2965 |
sort_param->max_pos=(sort_param->pos+=share->base.pack_reclength); |
|
2966 |
if (*sort_param->record) |
|
2967 |
{
|
|
2968 |
if (sort_param->calc_checksum) |
|
2969 |
param->glob_crc+= (info->checksum= |
|
2970 |
mi_static_checksum(info,sort_param->record)); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
2971 |
return(0); |
1
by brian
clean slate |
2972 |
}
|
2973 |
if (!sort_param->fix_datafile && sort_param->master) |
|
2974 |
{
|
|
2975 |
info->state->del++; |
|
2976 |
info->state->empty+=share->base.pack_reclength; |
|
2977 |
}
|
|
2978 |
}
|
|
2979 |
case DYNAMIC_RECORD: |
|
2980 |
pos= sort_param->pos; |
|
2981 |
searching= (sort_param->fix_datafile && (param->testflag & T_EXTEND)); |
|
2982 |
parallel_flag= (sort_param->read_cache.file < 0) ? READING_NEXT : 0; |
|
2983 |
for (;;) |
|
2984 |
{
|
|
2985 |
found_record=block_info.second_read= 0; |
|
2986 |
left_length=1; |
|
2987 |
if (searching) |
|
2988 |
{
|
|
2989 |
pos=MY_ALIGN(pos,MI_DYN_ALIGN_SIZE); |
|
2990 |
param->testflag|=T_RETRY_WITHOUT_QUICK; |
|
2991 |
sort_param->start_recpos=pos; |
|
2992 |
}
|
|
2993 |
do
|
|
2994 |
{
|
|
2995 |
if (pos > sort_param->max_pos) |
|
2996 |
sort_param->max_pos=pos; |
|
2997 |
if (pos & (MI_DYN_ALIGN_SIZE-1)) |
|
2998 |
{
|
|
2999 |
if ((param->testflag & T_VERBOSE) || searching == 0) |
|
3000 |
mi_check_print_info(param,"Wrong aligned block at %s", |
|
3001 |
llstr(pos,llbuff)); |
|
3002 |
if (searching) |
|
3003 |
goto try_next; |
|
3004 |
}
|
|
3005 |
if (found_record && pos == param->search_after_block) |
|
3006 |
mi_check_print_info(param,"Block: %s used by record at %s", |
|
3007 |
llstr(param->search_after_block,llbuff), |
|
3008 |
llstr(sort_param->start_recpos,llbuff2)); |
|
3009 |
if (_mi_read_cache(&sort_param->read_cache, |
|
481
by Brian Aker
Remove all of uchar. |
3010 |
(unsigned char*) block_info.header,pos, |
1
by brian
clean slate |
3011 |
MI_BLOCK_INFO_HEADER_LENGTH, |
3012 |
(! found_record ? READING_NEXT : 0) | |
|
3013 |
parallel_flag | READING_HEADER)) |
|
3014 |
{
|
|
3015 |
if (found_record) |
|
3016 |
{
|
|
3017 |
mi_check_print_info(param, |
|
3018 |
"Can't read whole record at %s (errno: %d)", |
|
3019 |
llstr(sort_param->start_recpos,llbuff),errno); |
|
3020 |
goto try_next; |
|
3021 |
}
|
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3022 |
return(-1); |
1
by brian
clean slate |
3023 |
}
|
3024 |
if (searching && ! sort_param->fix_datafile) |
|
3025 |
{
|
|
3026 |
param->error_printed=1; |
|
3027 |
param->retry_repair=1; |
|
3028 |
param->testflag|=T_RETRY_WITHOUT_QUICK; |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3029 |
return(1); /* Something wrong with data */ |
1
by brian
clean slate |
3030 |
}
|
3031 |
b_type=_mi_get_block_info(&block_info,-1,pos); |
|
3032 |
if ((b_type & (BLOCK_ERROR | BLOCK_FATAL_ERROR)) || |
|
3033 |
((b_type & BLOCK_FIRST) && |
|
3034 |
(block_info.rec_len < (uint) share->base.min_pack_length || |
|
3035 |
block_info.rec_len > (uint) share->base.max_pack_length))) |
|
3036 |
{
|
|
482
by Brian Aker
Remove uint. |
3037 |
uint32_t i; |
1
by brian
clean slate |
3038 |
if (param->testflag & T_VERBOSE || searching == 0) |
3039 |
mi_check_print_info(param, |
|
3040 |
"Wrong bytesec: %3d-%3d-%3d at %10s; Skipped", |
|
3041 |
block_info.header[0],block_info.header[1], |
|
3042 |
block_info.header[2],llstr(pos,llbuff)); |
|
3043 |
if (found_record) |
|
3044 |
goto try_next; |
|
3045 |
block_info.second_read=0; |
|
3046 |
searching=1; |
|
3047 |
/* Search after block in read header string */
|
|
3048 |
for (i=MI_DYN_ALIGN_SIZE ; |
|
3049 |
i < MI_BLOCK_INFO_HEADER_LENGTH ; |
|
3050 |
i+= MI_DYN_ALIGN_SIZE) |
|
3051 |
if (block_info.header[i] >= 1 && |
|
3052 |
block_info.header[i] <= MI_MAX_DYN_HEADER_BYTE) |
|
3053 |
break; |
|
3054 |
pos+=(ulong) i; |
|
3055 |
sort_param->start_recpos=pos; |
|
3056 |
continue; |
|
3057 |
}
|
|
3058 |
if (b_type & BLOCK_DELETED) |
|
3059 |
{
|
|
281
by Brian Aker
Converted myisam away from my_bool |
3060 |
bool error=0; |
1
by brian
clean slate |
3061 |
if (block_info.block_len+ (uint) (block_info.filepos-pos) < |
3062 |
share->base.min_block_length) |
|
3063 |
{
|
|
3064 |
if (!searching) |
|
3065 |
mi_check_print_info(param, |
|
3066 |
"Deleted block with impossible length %u at %s", |
|
3067 |
block_info.block_len,llstr(pos,llbuff)); |
|
3068 |
error=1; |
|
3069 |
}
|
|
3070 |
else
|
|
3071 |
{
|
|
3072 |
if ((block_info.next_filepos != HA_OFFSET_ERROR && |
|
3073 |
block_info.next_filepos >= |
|
3074 |
info->state->data_file_length) || |
|
3075 |
(block_info.prev_filepos != HA_OFFSET_ERROR && |
|
3076 |
block_info.prev_filepos >= info->state->data_file_length)) |
|
3077 |
{
|
|
3078 |
if (!searching) |
|
3079 |
mi_check_print_info(param, |
|
3080 |
"Delete link points outside datafile at %s", |
|
3081 |
llstr(pos,llbuff)); |
|
3082 |
error=1; |
|
3083 |
}
|
|
3084 |
}
|
|
3085 |
if (error) |
|
3086 |
{
|
|
3087 |
if (found_record) |
|
3088 |
goto try_next; |
|
3089 |
searching=1; |
|
3090 |
pos+= MI_DYN_ALIGN_SIZE; |
|
3091 |
sort_param->start_recpos=pos; |
|
3092 |
block_info.second_read=0; |
|
3093 |
continue; |
|
3094 |
}
|
|
3095 |
}
|
|
3096 |
else
|
|
3097 |
{
|
|
3098 |
if (block_info.block_len+ (uint) (block_info.filepos-pos) < |
|
3099 |
share->base.min_block_length || |
|
3100 |
block_info.block_len > (uint) share->base.max_pack_length+ |
|
3101 |
MI_SPLIT_LENGTH) |
|
3102 |
{
|
|
3103 |
if (!searching) |
|
3104 |
mi_check_print_info(param, |
|
3105 |
"Found block with impossible length %u at %s; Skipped", |
|
3106 |
block_info.block_len+ (uint) (block_info.filepos-pos), |
|
3107 |
llstr(pos,llbuff)); |
|
3108 |
if (found_record) |
|
3109 |
goto try_next; |
|
3110 |
searching=1; |
|
3111 |
pos+= MI_DYN_ALIGN_SIZE; |
|
3112 |
sort_param->start_recpos=pos; |
|
3113 |
block_info.second_read=0; |
|
3114 |
continue; |
|
3115 |
}
|
|
3116 |
}
|
|
3117 |
if (b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR)) |
|
3118 |
{
|
|
3119 |
if (!sort_param->fix_datafile && sort_param->master && |
|
3120 |
(b_type & BLOCK_DELETED)) |
|
3121 |
{
|
|
3122 |
info->state->empty+=block_info.block_len; |
|
3123 |
info->state->del++; |
|
3124 |
share->state.split++; |
|
3125 |
}
|
|
3126 |
if (found_record) |
|
3127 |
goto try_next; |
|
3128 |
if (searching) |
|
3129 |
{
|
|
3130 |
pos+=MI_DYN_ALIGN_SIZE; |
|
3131 |
sort_param->start_recpos=pos; |
|
3132 |
}
|
|
3133 |
else
|
|
3134 |
pos=block_info.filepos+block_info.block_len; |
|
3135 |
block_info.second_read=0; |
|
3136 |
continue; |
|
3137 |
}
|
|
3138 |
||
3139 |
if (!sort_param->fix_datafile && sort_param->master) |
|
3140 |
share->state.split++; |
|
3141 |
if (! found_record++) |
|
3142 |
{
|
|
3143 |
sort_param->find_length=left_length=block_info.rec_len; |
|
3144 |
sort_param->start_recpos=pos; |
|
3145 |
if (!sort_param->fix_datafile) |
|
3146 |
sort_param->filepos=sort_param->start_recpos; |
|
3147 |
if (sort_param->fix_datafile && (param->testflag & T_EXTEND)) |
|
3148 |
sort_param->pos=block_info.filepos+1; |
|
3149 |
else
|
|
3150 |
sort_param->pos=block_info.filepos+block_info.block_len; |
|
3151 |
if (share->base.blobs) |
|
3152 |
{
|
|
3153 |
if (!(to=mi_alloc_rec_buff(info,block_info.rec_len, |
|
3154 |
&(sort_param->rec_buff)))) |
|
3155 |
{
|
|
3156 |
if (param->max_record_length >= block_info.rec_len) |
|
3157 |
{
|
|
3158 |
mi_check_print_error(param,"Not enough memory for blob at %s (need %lu)", |
|
3159 |
llstr(sort_param->start_recpos,llbuff), |
|
3160 |
(ulong) block_info.rec_len); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3161 |
return(1); |
1
by brian
clean slate |
3162 |
}
|
3163 |
else
|
|
3164 |
{
|
|
3165 |
mi_check_print_info(param,"Not enough memory for blob at %s (need %lu); Row skipped", |
|
3166 |
llstr(sort_param->start_recpos,llbuff), |
|
3167 |
(ulong) block_info.rec_len); |
|
3168 |
goto try_next; |
|
3169 |
}
|
|
3170 |
}
|
|
3171 |
}
|
|
3172 |
else
|
|
3173 |
to= sort_param->rec_buff; |
|
3174 |
}
|
|
3175 |
if (left_length < block_info.data_len || ! block_info.data_len) |
|
3176 |
{
|
|
3177 |
mi_check_print_info(param, |
|
3178 |
"Found block with too small length at %s; Skipped", |
|
3179 |
llstr(sort_param->start_recpos,llbuff)); |
|
3180 |
goto try_next; |
|
3181 |
}
|
|
3182 |
if (block_info.filepos + block_info.data_len > |
|
3183 |
sort_param->read_cache.end_of_file) |
|
3184 |
{
|
|
3185 |
mi_check_print_info(param, |
|
3186 |
"Found block that points outside data file at %s", |
|
3187 |
llstr(sort_param->start_recpos,llbuff)); |
|
3188 |
goto try_next; |
|
3189 |
}
|
|
3190 |
/*
|
|
3191 |
Copy information that is already read. Avoid accessing data
|
|
3192 |
below the cache start. This could happen if the header
|
|
3193 |
streched over the end of the previous buffer contents.
|
|
3194 |
*/
|
|
3195 |
{
|
|
482
by Brian Aker
Remove uint. |
3196 |
uint32_t header_len= (uint) (block_info.filepos - pos); |
3197 |
uint32_t prefetch_len= (MI_BLOCK_INFO_HEADER_LENGTH - header_len); |
|
1
by brian
clean slate |
3198 |
|
3199 |
if (prefetch_len > block_info.data_len) |
|
3200 |
prefetch_len= block_info.data_len; |
|
3201 |
if (prefetch_len) |
|
3202 |
{
|
|
3203 |
memcpy(to, block_info.header + header_len, prefetch_len); |
|
3204 |
block_info.filepos+= prefetch_len; |
|
3205 |
block_info.data_len-= prefetch_len; |
|
3206 |
left_length-= prefetch_len; |
|
3207 |
to+= prefetch_len; |
|
3208 |
}
|
|
3209 |
}
|
|
3210 |
if (block_info.data_len && |
|
3211 |
_mi_read_cache(&sort_param->read_cache,to,block_info.filepos, |
|
3212 |
block_info.data_len, |
|
3213 |
(found_record == 1 ? READING_NEXT : 0) | |
|
3214 |
parallel_flag)) |
|
3215 |
{
|
|
3216 |
mi_check_print_info(param, |
|
3217 |
"Read error for block at: %s (error: %d); Skipped", |
|
3218 |
llstr(block_info.filepos,llbuff),my_errno); |
|
3219 |
goto try_next; |
|
3220 |
}
|
|
3221 |
left_length-=block_info.data_len; |
|
3222 |
to+=block_info.data_len; |
|
3223 |
pos=block_info.next_filepos; |
|
3224 |
if (pos == HA_OFFSET_ERROR && left_length) |
|
3225 |
{
|
|
3226 |
mi_check_print_info(param,"Wrong block with wrong total length starting at %s", |
|
3227 |
llstr(sort_param->start_recpos,llbuff)); |
|
3228 |
goto try_next; |
|
3229 |
}
|
|
3230 |
if (pos + MI_BLOCK_INFO_HEADER_LENGTH > sort_param->read_cache.end_of_file) |
|
3231 |
{
|
|
3232 |
mi_check_print_info(param,"Found link that points at %s (outside data file) at %s", |
|
3233 |
llstr(pos,llbuff2), |
|
3234 |
llstr(sort_param->start_recpos,llbuff)); |
|
3235 |
goto try_next; |
|
3236 |
}
|
|
3237 |
} while (left_length); |
|
3238 |
||
3239 |
if (_mi_rec_unpack(info,sort_param->record,sort_param->rec_buff, |
|
3240 |
sort_param->find_length) != MY_FILE_ERROR) |
|
3241 |
{
|
|
3242 |
if (sort_param->read_cache.error < 0) |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3243 |
return(1); |
1
by brian
clean slate |
3244 |
if (sort_param->calc_checksum) |
3245 |
info->checksum= mi_checksum(info, sort_param->record); |
|
3246 |
if ((param->testflag & (T_EXTEND | T_REP)) || searching) |
|
3247 |
{
|
|
3248 |
if (_mi_rec_check(info, sort_param->record, sort_param->rec_buff, |
|
3249 |
sort_param->find_length, |
|
3250 |
(param->testflag & T_QUICK) && |
|
3251 |
sort_param->calc_checksum && |
|
3252 |
test(info->s->calc_checksum))) |
|
3253 |
{
|
|
3254 |
mi_check_print_info(param,"Found wrong packed record at %s", |
|
3255 |
llstr(sort_param->start_recpos,llbuff)); |
|
3256 |
goto try_next; |
|
3257 |
}
|
|
3258 |
}
|
|
3259 |
if (sort_param->calc_checksum) |
|
3260 |
param->glob_crc+= info->checksum; |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3261 |
return(0); |
1
by brian
clean slate |
3262 |
}
|
3263 |
if (!searching) |
|
3264 |
mi_check_print_info(param,"Key %d - Found wrong stored record at %s", |
|
3265 |
sort_param->key+1, |
|
3266 |
llstr(sort_param->start_recpos,llbuff)); |
|
3267 |
try_next: |
|
3268 |
pos=(sort_param->start_recpos+=MI_DYN_ALIGN_SIZE); |
|
3269 |
searching=1; |
|
3270 |
}
|
|
3271 |
case COMPRESSED_RECORD: |
|
3272 |
case BLOCK_RECORD: |
|
3273 |
assert(0); /* Impossible */ |
|
3274 |
}
|
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3275 |
return(1); /* Impossible */ |
1
by brian
clean slate |
3276 |
}
|
3277 |
||
3278 |
||
3279 |
/*
|
|
3280 |
Write record to new file.
|
|
3281 |
||
3282 |
SYNOPSIS
|
|
3283 |
sort_write_record()
|
|
3284 |
sort_param Sort parameters.
|
|
3285 |
||
3286 |
NOTE
|
|
3287 |
This is only called by a master thread if parallel repair is used.
|
|
3288 |
||
3289 |
RETURN
|
|
3290 |
0 OK
|
|
3291 |
1 Error
|
|
3292 |
*/
|
|
3293 |
||
3294 |
int sort_write_record(MI_SORT_PARAM *sort_param) |
|
3295 |
{
|
|
3296 |
int flag; |
|
3297 |
ulong block_length,reclength; |
|
481
by Brian Aker
Remove all of uchar. |
3298 |
unsigned char *from; |
1
by brian
clean slate |
3299 |
SORT_INFO *sort_info=sort_param->sort_info; |
3300 |
MI_CHECK *param=sort_info->param; |
|
3301 |
MI_INFO *info=sort_info->info; |
|
3302 |
MYISAM_SHARE *share=info->s; |
|
3303 |
||
3304 |
if (sort_param->fix_datafile) |
|
3305 |
{
|
|
3306 |
switch (sort_info->new_data_file_type) { |
|
3307 |
case STATIC_RECORD: |
|
3308 |
if (my_b_write(&info->rec_cache,sort_param->record, |
|
3309 |
share->base.pack_reclength)) |
|
3310 |
{
|
|
3311 |
mi_check_print_error(param,"%d when writing to datafile",my_errno); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3312 |
return(1); |
1
by brian
clean slate |
3313 |
}
|
3314 |
sort_param->filepos+=share->base.pack_reclength; |
|
3315 |
info->s->state.split++; |
|
3316 |
/* sort_info->param->glob_crc+=mi_static_checksum(info, sort_param->record); */
|
|
3317 |
break; |
|
3318 |
case DYNAMIC_RECORD: |
|
3319 |
if (! info->blobs) |
|
3320 |
from=sort_param->rec_buff; |
|
3321 |
else
|
|
3322 |
{
|
|
3323 |
/* must be sure that local buffer is big enough */
|
|
3324 |
reclength=info->s->base.pack_reclength+ |
|
3325 |
_my_calc_total_blob_length(info,sort_param->record)+ |
|
3326 |
ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+ |
|
3327 |
MI_DYN_DELETE_BLOCK_HEADER; |
|
3328 |
if (sort_info->buff_length < reclength) |
|
3329 |
{
|
|
656.1.47
by Monty Taylor
More malloc return check fixes. |
3330 |
void *tmpptr= NULL; |
673.3.16
by Stewart Smith
fix realloc in mi_check causing crash in repair use_frm |
3331 |
tmpptr= realloc(sort_info->buff, reclength); |
3332 |
if(tmpptr) |
|
3333 |
{
|
|
656.1.47
by Monty Taylor
More malloc return check fixes. |
3334 |
sort_info->buff_length=reclength; |
673.3.16
by Stewart Smith
fix realloc in mi_check causing crash in repair use_frm |
3335 |
sort_info->buff= tmpptr; |
3336 |
}
|
|
3337 |
else
|
|
3338 |
{
|
|
3339 |
mi_check_print_error(param,"Could not realloc() sort_info->buff " |
|
3340 |
" to %ul bytes", reclength); |
|
3341 |
return(1); |
|
3342 |
}
|
|
1
by brian
clean slate |
3343 |
}
|
3344 |
from= sort_info->buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER); |
|
3345 |
}
|
|
3346 |
/* We can use info->checksum here as only one thread calls this. */
|
|
3347 |
info->checksum=mi_checksum(info,sort_param->record); |
|
3348 |
reclength=_mi_rec_pack(info,from,sort_param->record); |
|
3349 |
flag=0; |
|
3350 |
/* sort_info->param->glob_crc+=info->checksum; */
|
|
3351 |
||
3352 |
do
|
|
3353 |
{
|
|
3354 |
block_length=reclength+ 3 + test(reclength >= (65520-3)); |
|
3355 |
if (block_length < share->base.min_block_length) |
|
3356 |
block_length=share->base.min_block_length; |
|
3357 |
info->update|=HA_STATE_WRITE_AT_END; |
|
3358 |
block_length=MY_ALIGN(block_length,MI_DYN_ALIGN_SIZE); |
|
3359 |
if (block_length > MI_MAX_BLOCK_LENGTH) |
|
3360 |
block_length=MI_MAX_BLOCK_LENGTH; |
|
3361 |
if (_mi_write_part_record(info,0L,block_length, |
|
3362 |
sort_param->filepos+block_length, |
|
3363 |
&from,&reclength,&flag)) |
|
3364 |
{
|
|
3365 |
mi_check_print_error(param,"%d when writing to datafile",my_errno); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3366 |
return(1); |
1
by brian
clean slate |
3367 |
}
|
3368 |
sort_param->filepos+=block_length; |
|
3369 |
info->s->state.split++; |
|
3370 |
} while (reclength); |
|
3371 |
/* sort_info->param->glob_crc+=info->checksum; */
|
|
3372 |
break; |
|
3373 |
case COMPRESSED_RECORD: |
|
3374 |
case BLOCK_RECORD: |
|
3375 |
assert(0); /* Impossible */ |
|
3376 |
}
|
|
3377 |
}
|
|
3378 |
if (sort_param->master) |
|
3379 |
{
|
|
3380 |
info->state->records++; |
|
3381 |
if ((param->testflag & T_WRITE_LOOP) && |
|
3382 |
(info->state->records % WRITE_COUNT) == 0) |
|
3383 |
{
|
|
3384 |
char llbuff[22]; |
|
3385 |
printf("%s\r", llstr(info->state->records,llbuff)); |
|
398.1.10
by Monty Taylor
Actually removed VOID() this time. |
3386 |
fflush(stdout); |
1
by brian
clean slate |
3387 |
}
|
3388 |
}
|
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3389 |
return(0); |
1
by brian
clean slate |
3390 |
} /* sort_write_record */ |
3391 |
||
3392 |
||
3393 |
/* Compare two keys from _create_index_by_sort */
|
|
3394 |
||
3395 |
static int sort_key_cmp(MI_SORT_PARAM *sort_param, const void *a, |
|
3396 |
const void *b) |
|
3397 |
{
|
|
482
by Brian Aker
Remove uint. |
3398 |
uint32_t not_used[2]; |
481
by Brian Aker
Remove all of uchar. |
3399 |
return (ha_key_cmp(sort_param->seg, *((unsigned char* const *) a), *((unsigned char* const *) b), |
1
by brian
clean slate |
3400 |
USE_WHOLE_KEY, SEARCH_SAME, not_used)); |
3401 |
} /* sort_key_cmp */ |
|
3402 |
||
3403 |
||
3404 |
static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a) |
|
3405 |
{
|
|
482
by Brian Aker
Remove uint. |
3406 |
uint32_t diff_pos[2]; |
1
by brian
clean slate |
3407 |
char llbuff[22],llbuff2[22]; |
3408 |
SORT_INFO *sort_info=sort_param->sort_info; |
|
3409 |
MI_CHECK *param= sort_info->param; |
|
3410 |
int cmp; |
|
3411 |
||
3412 |
if (sort_info->key_block->inited) |
|
3413 |
{
|
|
3414 |
cmp=ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey, |
|
481
by Brian Aker
Remove all of uchar. |
3415 |
(unsigned char*) a, USE_WHOLE_KEY,SEARCH_FIND | SEARCH_UPDATE, |
1
by brian
clean slate |
3416 |
diff_pos); |
3417 |
if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL) |
|
3418 |
ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey, |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3419 |
(unsigned char*) a, USE_WHOLE_KEY, |
1
by brian
clean slate |
3420 |
SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, diff_pos); |
3421 |
else if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS) |
|
3422 |
{
|
|
3423 |
diff_pos[0]= mi_collect_stats_nonulls_next(sort_param->seg, |
|
3424 |
sort_param->notnull, |
|
3425 |
sort_info->key_block->lastkey, |
|
481
by Brian Aker
Remove all of uchar. |
3426 |
(unsigned char*)a); |
1
by brian
clean slate |
3427 |
}
|
3428 |
sort_param->unique[diff_pos[0]-1]++; |
|
3429 |
}
|
|
3430 |
else
|
|
3431 |
{
|
|
3432 |
cmp= -1; |
|
3433 |
if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS) |
|
3434 |
mi_collect_stats_nonulls_first(sort_param->seg, sort_param->notnull, |
|
481
by Brian Aker
Remove all of uchar. |
3435 |
(unsigned char*)a); |
1
by brian
clean slate |
3436 |
}
|
3437 |
if ((sort_param->keyinfo->flag & HA_NOSAME) && cmp == 0) |
|
3438 |
{
|
|
3439 |
sort_info->dupp++; |
|
3440 |
sort_info->info->lastpos=get_record_for_key(sort_info->info, |
|
3441 |
sort_param->keyinfo, |
|
481
by Brian Aker
Remove all of uchar. |
3442 |
(unsigned char*) a); |
1
by brian
clean slate |
3443 |
mi_check_print_warning(param, |
3444 |
"Duplicate key for record at %10s against record at %10s", |
|
3445 |
llstr(sort_info->info->lastpos,llbuff), |
|
3446 |
llstr(get_record_for_key(sort_info->info, |
|
3447 |
sort_param->keyinfo, |
|
3448 |
sort_info->key_block-> |
|
3449 |
lastkey), |
|
3450 |
llbuff2)); |
|
3451 |
param->testflag|=T_RETRY_WITHOUT_QUICK; |
|
3452 |
return (sort_delete_record(sort_param)); |
|
3453 |
}
|
|
3454 |
return (sort_insert_key(sort_param,sort_info->key_block, |
|
481
by Brian Aker
Remove all of uchar. |
3455 |
(unsigned char*) a, HA_OFFSET_ERROR)); |
1
by brian
clean slate |
3456 |
} /* sort_key_write */ |
3457 |
||
3458 |
||
3459 |
/* get pointer to record from a key */
|
|
3460 |
||
3461 |
static my_off_t get_record_for_key(MI_INFO *info, MI_KEYDEF *keyinfo, |
|
481
by Brian Aker
Remove all of uchar. |
3462 |
unsigned char *key) |
1
by brian
clean slate |
3463 |
{
|
3464 |
return _mi_dpos(info,0,key+_mi_keylength(keyinfo,key)); |
|
3465 |
} /* get_record_for_key */ |
|
3466 |
||
3467 |
||
3468 |
/* Insert a key in sort-key-blocks */
|
|
3469 |
||
3470 |
static int sort_insert_key(MI_SORT_PARAM *sort_param, |
|
481
by Brian Aker
Remove all of uchar. |
3471 |
register SORT_KEY_BLOCKS *key_block, unsigned char *key, |
1
by brian
clean slate |
3472 |
my_off_t prev_block) |
3473 |
{
|
|
482
by Brian Aker
Remove uint. |
3474 |
uint32_t a_length,t_length,nod_flag; |
1
by brian
clean slate |
3475 |
my_off_t filepos,key_file_length; |
481
by Brian Aker
Remove all of uchar. |
3476 |
unsigned char *anc_buff,*lastkey; |
1
by brian
clean slate |
3477 |
MI_KEY_PARAM s_temp; |
3478 |
MI_INFO *info; |
|
3479 |
MI_KEYDEF *keyinfo=sort_param->keyinfo; |
|
3480 |
SORT_INFO *sort_info= sort_param->sort_info; |
|
3481 |
MI_CHECK *param=sort_info->param; |
|
3482 |
||
3483 |
anc_buff=key_block->buff; |
|
3484 |
info=sort_info->info; |
|
3485 |
lastkey=key_block->lastkey; |
|
3486 |
nod_flag= (key_block == sort_info->key_block ? 0 : |
|
3487 |
info->s->base.key_reflength); |
|
3488 |
||
3489 |
if (!key_block->inited) |
|
3490 |
{
|
|
3491 |
key_block->inited=1; |
|
3492 |
if (key_block == sort_info->key_block_end) |
|
3493 |
{
|
|
3494 |
mi_check_print_error(param,"To many key-block-levels; Try increasing sort_key_blocks"); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3495 |
return(1); |
1
by brian
clean slate |
3496 |
}
|
3497 |
a_length=2+nod_flag; |
|
3498 |
key_block->end_pos=anc_buff+2; |
|
3499 |
lastkey=0; /* No previous key in block */ |
|
3500 |
}
|
|
3501 |
else
|
|
3502 |
a_length=mi_getint(anc_buff); |
|
3503 |
||
3504 |
/* Save pointer to previous block */
|
|
3505 |
if (nod_flag) |
|
3506 |
_mi_kpointer(info,key_block->end_pos,prev_block); |
|
3507 |
||
3508 |
t_length=(*keyinfo->pack_key)(keyinfo,nod_flag, |
|
481
by Brian Aker
Remove all of uchar. |
3509 |
(unsigned char*) 0,lastkey,lastkey,key, |
1
by brian
clean slate |
3510 |
&s_temp); |
3511 |
(*keyinfo->store_key)(keyinfo, key_block->end_pos+nod_flag,&s_temp); |
|
3512 |
a_length+=t_length; |
|
3513 |
mi_putint(anc_buff,a_length,nod_flag); |
|
3514 |
key_block->end_pos+=t_length; |
|
3515 |
if (a_length <= keyinfo->block_length) |
|
3516 |
{
|
|
398.1.10
by Monty Taylor
Actually removed VOID() this time. |
3517 |
_mi_move_key(keyinfo,key_block->lastkey,key); |
1
by brian
clean slate |
3518 |
key_block->last_length=a_length-t_length; |
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3519 |
return(0); |
1
by brian
clean slate |
3520 |
}
|
3521 |
||
3522 |
/* Fill block with end-zero and write filled block */
|
|
3523 |
mi_putint(anc_buff,key_block->last_length,nod_flag); |
|
212.6.12
by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove(). |
3524 |
memset(anc_buff+key_block->last_length, 0, |
3525 |
keyinfo->block_length - key_block->last_length); |
|
1
by brian
clean slate |
3526 |
key_file_length=info->state->key_file_length; |
3527 |
if ((filepos=_mi_new(info,keyinfo,DFLT_INIT_HITS)) == HA_OFFSET_ERROR) |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3528 |
return(1); |
1
by brian
clean slate |
3529 |
|
3530 |
/* If we read the page from the key cache, we have to write it back to it */
|
|
3531 |
if (key_file_length == info->state->key_file_length) |
|
3532 |
{
|
|
3533 |
if (_mi_write_keypage(info, keyinfo, filepos, DFLT_INIT_HITS, anc_buff)) |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3534 |
return(1); |
1
by brian
clean slate |
3535 |
}
|
481
by Brian Aker
Remove all of uchar. |
3536 |
else if (my_pwrite(info->s->kfile,(unsigned char*) anc_buff, |
1
by brian
clean slate |
3537 |
(uint) keyinfo->block_length,filepos, param->myf_rw)) |
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3538 |
return(1); |
1
by brian
clean slate |
3539 |
|
3540 |
/* Write separator-key to block in next level */
|
|
3541 |
if (sort_insert_key(sort_param,key_block+1,key_block->lastkey,filepos)) |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3542 |
return(1); |
1
by brian
clean slate |
3543 |
|
3544 |
/* clear old block and write new key in it */
|
|
3545 |
key_block->inited=0; |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3546 |
return(sort_insert_key(sort_param, key_block,key,prev_block)); |
1
by brian
clean slate |
3547 |
} /* sort_insert_key */ |
3548 |
||
3549 |
||
3550 |
/* Delete record when we found a duplicated key */
|
|
3551 |
||
3552 |
static int sort_delete_record(MI_SORT_PARAM *sort_param) |
|
3553 |
{
|
|
482
by Brian Aker
Remove uint. |
3554 |
uint32_t i; |
1
by brian
clean slate |
3555 |
int old_file,error; |
481
by Brian Aker
Remove all of uchar. |
3556 |
unsigned char *key; |
1
by brian
clean slate |
3557 |
SORT_INFO *sort_info=sort_param->sort_info; |
3558 |
MI_CHECK *param=sort_info->param; |
|
3559 |
MI_INFO *info=sort_info->info; |
|
3560 |
||
3561 |
if ((param->testflag & (T_FORCE_UNIQUENESS|T_QUICK)) == T_QUICK) |
|
3562 |
{
|
|
3563 |
mi_check_print_error(param, |
|
3564 |
"Quick-recover aborted; Run recovery without switch -q or with switch -qq"); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3565 |
return(1); |
1
by brian
clean slate |
3566 |
}
|
3567 |
if (info->s->options & HA_OPTION_COMPRESS_RECORD) |
|
3568 |
{
|
|
3569 |
mi_check_print_error(param, |
|
3570 |
"Recover aborted; Can't run standard recovery on compressed tables with errors in data-file. Use switch 'myisamchk --safe-recover' to fix it\n",stderr);; |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3571 |
return(1); |
1
by brian
clean slate |
3572 |
}
|
3573 |
||
3574 |
old_file=info->dfile; |
|
3575 |
info->dfile=info->rec_cache.file; |
|
3576 |
if (sort_info->current_key) |
|
3577 |
{
|
|
3578 |
key=info->lastkey+info->s->base.max_key_length; |
|
3579 |
if ((error=(*info->s->read_rnd)(info,sort_param->record,info->lastpos,0)) && |
|
3580 |
error != HA_ERR_RECORD_DELETED) |
|
3581 |
{
|
|
3582 |
mi_check_print_error(param,"Can't read record to be removed"); |
|
3583 |
info->dfile=old_file; |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3584 |
return(1); |
1
by brian
clean slate |
3585 |
}
|
3586 |
||
3587 |
for (i=0 ; i < sort_info->current_key ; i++) |
|
3588 |
{
|
|
482
by Brian Aker
Remove uint. |
3589 |
uint32_t key_length=_mi_make_key(info,i,key,sort_param->record,info->lastpos); |
1
by brian
clean slate |
3590 |
if (_mi_ck_delete(info,i,key,key_length)) |
3591 |
{
|
|
3592 |
mi_check_print_error(param,"Can't delete key %d from record to be removed",i+1); |
|
3593 |
info->dfile=old_file; |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3594 |
return(1); |
1
by brian
clean slate |
3595 |
}
|
3596 |
}
|
|
3597 |
if (sort_param->calc_checksum) |
|
3598 |
param->glob_crc-=(*info->s->calc_checksum)(info, sort_param->record); |
|
3599 |
}
|
|
3600 |
error=flush_io_cache(&info->rec_cache) || (*info->s->delete_record)(info); |
|
3601 |
info->dfile=old_file; /* restore actual value */ |
|
3602 |
info->state->records--; |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3603 |
return(error); |
1
by brian
clean slate |
3604 |
} /* sort_delete_record */ |
3605 |
||
3606 |
/* Fix all pending blocks and flush everything to disk */
|
|
3607 |
||
3608 |
int flush_pending_blocks(MI_SORT_PARAM *sort_param) |
|
3609 |
{
|
|
482
by Brian Aker
Remove uint. |
3610 |
uint32_t nod_flag,length; |
1
by brian
clean slate |
3611 |
my_off_t filepos,key_file_length; |
3612 |
SORT_KEY_BLOCKS *key_block; |
|
3613 |
SORT_INFO *sort_info= sort_param->sort_info; |
|
3614 |
myf myf_rw=sort_info->param->myf_rw; |
|
3615 |
MI_INFO *info=sort_info->info; |
|
3616 |
MI_KEYDEF *keyinfo=sort_param->keyinfo; |
|
3617 |
||
3618 |
filepos= HA_OFFSET_ERROR; /* if empty file */ |
|
3619 |
nod_flag=0; |
|
3620 |
for (key_block=sort_info->key_block ; key_block->inited ; key_block++) |
|
3621 |
{
|
|
3622 |
key_block->inited=0; |
|
3623 |
length=mi_getint(key_block->buff); |
|
3624 |
if (nod_flag) |
|
3625 |
_mi_kpointer(info,key_block->end_pos,filepos); |
|
3626 |
key_file_length=info->state->key_file_length; |
|
212.6.12
by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove(). |
3627 |
memset(key_block->buff+length, 0, keyinfo->block_length-length); |
1
by brian
clean slate |
3628 |
if ((filepos=_mi_new(info,keyinfo,DFLT_INIT_HITS)) == HA_OFFSET_ERROR) |
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3629 |
return(1); |
1
by brian
clean slate |
3630 |
|
3631 |
/* If we read the page from the key cache, we have to write it back */
|
|
3632 |
if (key_file_length == info->state->key_file_length) |
|
3633 |
{
|
|
3634 |
if (_mi_write_keypage(info, keyinfo, filepos, |
|
3635 |
DFLT_INIT_HITS, key_block->buff)) |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3636 |
return(1); |
1
by brian
clean slate |
3637 |
}
|
481
by Brian Aker
Remove all of uchar. |
3638 |
else if (my_pwrite(info->s->kfile,(unsigned char*) key_block->buff, |
1
by brian
clean slate |
3639 |
(uint) keyinfo->block_length,filepos, myf_rw)) |
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3640 |
return(1); |
1
by brian
clean slate |
3641 |
nod_flag=1; |
3642 |
}
|
|
3643 |
info->s->state.key_root[sort_param->key]=filepos; /* Last is root for tree */ |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3644 |
return(0); |
1
by brian
clean slate |
3645 |
} /* flush_pending_blocks */ |
3646 |
||
3647 |
/* alloc space and pointers for key_blocks */
|
|
3648 |
||
482
by Brian Aker
Remove uint. |
3649 |
static SORT_KEY_BLOCKS *alloc_key_blocks(MI_CHECK *param, uint32_t blocks, |
3650 |
uint32_t buffer_length) |
|
1
by brian
clean slate |
3651 |
{
|
482
by Brian Aker
Remove uint. |
3652 |
register uint32_t i; |
1
by brian
clean slate |
3653 |
SORT_KEY_BLOCKS *block; |
3654 |
||
656.1.25
by Monty Taylor
Removed my_malloc stuff from storage/ |
3655 |
if (!(block=(SORT_KEY_BLOCKS*) malloc((sizeof(SORT_KEY_BLOCKS)+ |
3656 |
buffer_length+IO_SIZE)*blocks))) |
|
1
by brian
clean slate |
3657 |
{
|
3658 |
mi_check_print_error(param,"Not enough memory for sort-key-blocks"); |
|
3659 |
return(0); |
|
3660 |
}
|
|
3661 |
for (i=0 ; i < blocks ; i++) |
|
3662 |
{
|
|
3663 |
block[i].inited=0; |
|
481
by Brian Aker
Remove all of uchar. |
3664 |
block[i].buff=(unsigned char*) (block+blocks)+(buffer_length+IO_SIZE)*i; |
1
by brian
clean slate |
3665 |
}
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3666 |
return(block); |
1
by brian
clean slate |
3667 |
} /* alloc_key_blocks */ |
3668 |
||
3669 |
||
3670 |
/* Check if file is almost full */
|
|
3671 |
||
3672 |
int test_if_almost_full(MI_INFO *info) |
|
3673 |
{
|
|
3674 |
if (info->s->options & HA_OPTION_COMPRESS_RECORD) |
|
3675 |
return 0; |
|
656.1.39
by Monty Taylor
Removed my_seek, my_tell, my_fwrite, my_fseek. |
3676 |
return (my_off_t)(lseek(info->s->kfile, 0L, SEEK_END) / 10 * 9) > |
1
by brian
clean slate |
3677 |
(my_off_t) info->s->base.max_key_file_length || |
656.1.39
by Monty Taylor
Removed my_seek, my_tell, my_fwrite, my_fseek. |
3678 |
(my_off_t)(lseek(info->dfile, 0L, SEEK_END) / 10 * 9) > |
1
by brian
clean slate |
3679 |
(my_off_t) info->s->base.max_data_file_length; |
3680 |
}
|
|
3681 |
||
3682 |
/* Recreate table with bigger more alloced record-data */
|
|
3683 |
||
3684 |
int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename) |
|
3685 |
{
|
|
3686 |
int error; |
|
3687 |
MI_INFO info; |
|
3688 |
MYISAM_SHARE share; |
|
3689 |
MI_KEYDEF *keyinfo,*key,*key_end; |
|
3690 |
HA_KEYSEG *keysegs,*keyseg; |
|
3691 |
MI_COLUMNDEF *recdef,*rec,*end; |
|
3692 |
MI_UNIQUEDEF *uniquedef,*u_ptr,*u_end; |
|
3693 |
MI_STATUS_INFO status_info; |
|
482
by Brian Aker
Remove uint. |
3694 |
uint32_t unpack,key_parts; |
1
by brian
clean slate |
3695 |
ha_rows max_records; |
151
by Brian Aker
Ulonglong to uint64_t |
3696 |
uint64_t file_length,tmp_length; |
1
by brian
clean slate |
3697 |
MI_CREATE_INFO create_info; |
3698 |
||
3699 |
error=1; /* Default error */ |
|
3700 |
info= **org_info; |
|
3701 |
status_info= (*org_info)->state[0]; |
|
3702 |
info.state= &status_info; |
|
3703 |
share= *(*org_info)->s; |
|
3704 |
unpack= (share.options & HA_OPTION_COMPRESS_RECORD) && |
|
3705 |
(param->testflag & T_UNPACK); |
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
3706 |
if (!(keyinfo=(MI_KEYDEF*) malloc(sizeof(MI_KEYDEF)*share.base.keys))) |
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3707 |
return(0); |
212.6.12
by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove(). |
3708 |
memcpy(keyinfo,share.keyinfo,sizeof(MI_KEYDEF)*share.base.keys); |
1
by brian
clean slate |
3709 |
|
3710 |
key_parts= share.base.all_key_parts; |
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
3711 |
if (!(keysegs=(HA_KEYSEG*) malloc(sizeof(HA_KEYSEG)* |
3712 |
(key_parts+share.base.keys)))) |
|
1
by brian
clean slate |
3713 |
{
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
3714 |
free(keyinfo); |
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3715 |
return(1); |
1
by brian
clean slate |
3716 |
}
|
3717 |
if (!(recdef=(MI_COLUMNDEF*) |
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
3718 |
malloc(sizeof(MI_COLUMNDEF)*(share.base.fields+1)))) |
1
by brian
clean slate |
3719 |
{
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
3720 |
free(keyinfo); |
3721 |
free(keysegs); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3722 |
return(1); |
1
by brian
clean slate |
3723 |
}
|
3724 |
if (!(uniquedef=(MI_UNIQUEDEF*) |
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
3725 |
malloc(sizeof(MI_UNIQUEDEF)*(share.state.header.uniques+1)))) |
1
by brian
clean slate |
3726 |
{
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
3727 |
free(recdef); |
3728 |
free(keyinfo); |
|
3729 |
free(keysegs); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3730 |
return(1); |
1
by brian
clean slate |
3731 |
}
|
3732 |
||
3733 |
/* Copy the column definitions */
|
|
212.6.12
by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove(). |
3734 |
memcpy(recdef, share.rec, sizeof(MI_COLUMNDEF)*(share.base.fields+1)); |
1
by brian
clean slate |
3735 |
for (rec=recdef,end=recdef+share.base.fields; rec != end ; rec++) |
3736 |
{
|
|
3737 |
if (unpack && !(share.options & HA_OPTION_PACK_RECORD) && |
|
3738 |
rec->type != FIELD_BLOB && |
|
3739 |
rec->type != FIELD_VARCHAR && |
|
3740 |
rec->type != FIELD_CHECK) |
|
3741 |
rec->type=(int) FIELD_NORMAL; |
|
3742 |
}
|
|
3743 |
||
3744 |
/* Change the new key to point at the saved key segments */
|
|
212.6.12
by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove(). |
3745 |
memcpy(keysegs,share.keyparts, |
3746 |
sizeof(HA_KEYSEG)*(key_parts+share.base.keys+ |
|
3747 |
share.state.header.uniques)); |
|
1
by brian
clean slate |
3748 |
keyseg=keysegs; |
3749 |
for (key=keyinfo,key_end=keyinfo+share.base.keys; key != key_end ; key++) |
|
3750 |
{
|
|
3751 |
key->seg=keyseg; |
|
3752 |
for (; keyseg->type ; keyseg++) |
|
3753 |
{
|
|
3754 |
if (param->language) |
|
3755 |
keyseg->language=param->language; /* change language */ |
|
3756 |
}
|
|
3757 |
keyseg++; /* Skip end pointer */ |
|
3758 |
}
|
|
3759 |
||
3760 |
/* Copy the unique definitions and change them to point at the new key
|
|
3761 |
segments*/
|
|
212.6.12
by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove(). |
3762 |
memcpy(uniquedef,share.uniqueinfo, |
3763 |
sizeof(MI_UNIQUEDEF)*(share.state.header.uniques)); |
|
1
by brian
clean slate |
3764 |
for (u_ptr=uniquedef,u_end=uniquedef+share.state.header.uniques; |
3765 |
u_ptr != u_end ; u_ptr++) |
|
3766 |
{
|
|
3767 |
u_ptr->seg=keyseg; |
|
3768 |
keyseg+=u_ptr->keysegs+1; |
|
3769 |
}
|
|
3770 |
if (share.options & HA_OPTION_COMPRESS_RECORD) |
|
3771 |
share.base.records=max_records=info.state->records; |
|
3772 |
else if (share.base.min_pack_length) |
|
656.1.39
by Monty Taylor
Removed my_seek, my_tell, my_fwrite, my_fseek. |
3773 |
max_records=(ha_rows) (lseek(info.dfile,0L,SEEK_END) / |
1
by brian
clean slate |
3774 |
(ulong) share.base.min_pack_length); |
3775 |
else
|
|
3776 |
max_records=0; |
|
3777 |
unpack= (share.options & HA_OPTION_COMPRESS_RECORD) && |
|
3778 |
(param->testflag & T_UNPACK); |
|
3779 |
share.options&= ~HA_OPTION_TEMP_COMPRESS_RECORD; |
|
3780 |
||
656.1.39
by Monty Taylor
Removed my_seek, my_tell, my_fwrite, my_fseek. |
3781 |
file_length=(uint64_t) lseek(info.dfile,0L,SEEK_END); |
1
by brian
clean slate |
3782 |
tmp_length= file_length+file_length/10; |
3783 |
set_if_bigger(file_length,param->max_data_file_length); |
|
3784 |
set_if_bigger(file_length,tmp_length); |
|
151
by Brian Aker
Ulonglong to uint64_t |
3785 |
set_if_bigger(file_length,(uint64_t) share.base.max_data_file_length); |
1
by brian
clean slate |
3786 |
|
398.1.10
by Monty Taylor
Actually removed VOID() this time. |
3787 |
mi_close(*org_info); |
212.6.12
by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove(). |
3788 |
memset(&create_info, 0, sizeof(create_info)); |
398.1.4
by Monty Taylor
Renamed max/min. |
3789 |
create_info.max_rows=cmax(max_records,share.base.records); |
1
by brian
clean slate |
3790 |
create_info.reloc_rows=share.base.reloc; |
3791 |
create_info.old_options=(share.options | |
|
3792 |
(unpack ? HA_OPTION_TEMP_COMPRESS_RECORD : 0)); |
|
3793 |
||
3794 |
create_info.data_file_length=file_length; |
|
3795 |
create_info.auto_increment=share.state.auto_increment; |
|
3796 |
create_info.language = (param->language ? param->language : |
|
3797 |
share.state.header.language); |
|
3798 |
create_info.key_file_length= status_info.key_file_length; |
|
3799 |
/*
|
|
3800 |
Allow for creating an auto_increment key. This has an effect only if
|
|
3801 |
an auto_increment key exists in the original table.
|
|
3802 |
*/
|
|
163
by Brian Aker
Merge Monty's code. |
3803 |
create_info.with_auto_increment= true; |
1
by brian
clean slate |
3804 |
/* We don't have to handle symlinks here because we are using
|
3805 |
HA_DONT_TOUCH_DATA */
|
|
3806 |
if (mi_create(filename, |
|
3807 |
share.base.keys - share.state.header.uniques, |
|
3808 |
keyinfo, share.base.fields, recdef, |
|
3809 |
share.state.header.uniques, uniquedef, |
|
3810 |
&create_info, |
|
3811 |
HA_DONT_TOUCH_DATA)) |
|
3812 |
{
|
|
3813 |
mi_check_print_error(param,"Got error %d when trying to recreate indexfile",my_errno); |
|
3814 |
goto end; |
|
3815 |
}
|
|
3816 |
*org_info=mi_open(filename,O_RDWR, |
|
3817 |
(param->testflag & T_WAIT_FOREVER) ? HA_OPEN_WAIT_IF_LOCKED : |
|
3818 |
(param->testflag & T_DESCRIPT) ? HA_OPEN_IGNORE_IF_LOCKED : |
|
3819 |
HA_OPEN_ABORT_IF_LOCKED); |
|
3820 |
if (!*org_info) |
|
3821 |
{
|
|
3822 |
mi_check_print_error(param,"Got error %d when trying to open re-created indexfile", |
|
3823 |
my_errno); |
|
3824 |
goto end; |
|
3825 |
}
|
|
3826 |
/* We are modifing */
|
|
3827 |
(*org_info)->s->options&= ~HA_OPTION_READ_ONLY_DATA; |
|
398.1.10
by Monty Taylor
Actually removed VOID() this time. |
3828 |
_mi_readinfo(*org_info,F_WRLCK,0); |
1
by brian
clean slate |
3829 |
(*org_info)->state->records=info.state->records; |
3830 |
if (share.state.create_time) |
|
3831 |
(*org_info)->s->state.create_time=share.state.create_time; |
|
3832 |
(*org_info)->s->state.unique=(*org_info)->this_unique= |
|
3833 |
share.state.unique; |
|
3834 |
(*org_info)->state->checksum=info.state->checksum; |
|
3835 |
(*org_info)->state->del=info.state->del; |
|
3836 |
(*org_info)->s->state.dellink=share.state.dellink; |
|
3837 |
(*org_info)->state->empty=info.state->empty; |
|
3838 |
(*org_info)->state->data_file_length=info.state->data_file_length; |
|
3839 |
if (update_state_info(param,*org_info,UPDATE_TIME | UPDATE_STAT | |
|
3840 |
UPDATE_OPEN_COUNT)) |
|
3841 |
goto end; |
|
3842 |
error=0; |
|
3843 |
end: |
|
656.1.1
by Monty Taylor
OOOh doggie. Got rid of my_alloca. |
3844 |
free(uniquedef); |
3845 |
free(keyinfo); |
|
3846 |
free(recdef); |
|
3847 |
free(keysegs); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3848 |
return(error); |
1
by brian
clean slate |
3849 |
}
|
3850 |
||
3851 |
||
3852 |
/* write suffix to data file if neaded */
|
|
3853 |
||
281
by Brian Aker
Converted myisam away from my_bool |
3854 |
int write_data_suffix(SORT_INFO *sort_info, bool fix_datafile) |
1
by brian
clean slate |
3855 |
{
|
3856 |
MI_INFO *info=sort_info->info; |
|
3857 |
||
3858 |
if (info->s->options & HA_OPTION_COMPRESS_RECORD && fix_datafile) |
|
3859 |
{
|
|
481
by Brian Aker
Remove all of uchar. |
3860 |
unsigned char buff[MEMMAP_EXTRA_MARGIN]; |
212.6.1
by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file. |
3861 |
memset(buff, 0, sizeof(buff)); |
1
by brian
clean slate |
3862 |
if (my_b_write(&info->rec_cache,buff,sizeof(buff))) |
3863 |
{
|
|
3864 |
mi_check_print_error(sort_info->param, |
|
3865 |
"%d when writing to datafile",my_errno); |
|
3866 |
return 1; |
|
3867 |
}
|
|
3868 |
sort_info->param->read_cache.end_of_file+=sizeof(buff); |
|
3869 |
}
|
|
3870 |
return 0; |
|
3871 |
}
|
|
3872 |
||
3873 |
/* Update state and myisamchk_time of indexfile */
|
|
3874 |
||
482
by Brian Aker
Remove uint. |
3875 |
int update_state_info(MI_CHECK *param, MI_INFO *info,uint32_t update) |
1
by brian
clean slate |
3876 |
{
|
3877 |
MYISAM_SHARE *share=info->s; |
|
3878 |
||
3879 |
if (update & UPDATE_OPEN_COUNT) |
|
3880 |
{
|
|
3881 |
share->state.open_count=0; |
|
3882 |
share->global_changed=0; |
|
3883 |
}
|
|
3884 |
if (update & UPDATE_STAT) |
|
3885 |
{
|
|
482
by Brian Aker
Remove uint. |
3886 |
uint32_t i, key_parts= mi_uint2korr(share->state.header.key_parts); |
1
by brian
clean slate |
3887 |
share->state.rec_per_key_rows=info->state->records; |
3888 |
share->state.changed&= ~STATE_NOT_ANALYZED; |
|
3889 |
if (info->state->records) |
|
3890 |
{
|
|
3891 |
for (i=0; i<key_parts; i++) |
|
3892 |
{
|
|
3893 |
if (!(share->state.rec_per_key_part[i]=param->rec_per_key_part[i])) |
|
3894 |
share->state.changed|= STATE_NOT_ANALYZED; |
|
3895 |
}
|
|
3896 |
}
|
|
3897 |
}
|
|
3898 |
if (update & (UPDATE_STAT | UPDATE_SORT | UPDATE_TIME | UPDATE_AUTO_INC)) |
|
3899 |
{
|
|
3900 |
if (update & UPDATE_TIME) |
|
3901 |
{
|
|
3902 |
share->state.check_time= (long) time((time_t*) 0); |
|
3903 |
if (!share->state.create_time) |
|
3904 |
share->state.create_time=share->state.check_time; |
|
3905 |
}
|
|
3906 |
/*
|
|
3907 |
When tables are locked we haven't synched the share state and the
|
|
3908 |
real state for a while so we better do it here before synching
|
|
3909 |
the share state to disk. Only when table is write locked is it
|
|
3910 |
necessary to perform this synch.
|
|
3911 |
*/
|
|
3912 |
if (info->lock_type == F_WRLCK) |
|
3913 |
share->state.state= *info->state; |
|
3914 |
if (mi_state_info_write(share->kfile,&share->state,1+2)) |
|
3915 |
goto err; |
|
3916 |
share->changed=0; |
|
3917 |
}
|
|
3918 |
{ /* Force update of status */ |
|
3919 |
int error; |
|
482
by Brian Aker
Remove uint. |
3920 |
uint32_t r_locks=share->r_locks,w_locks=share->w_locks; |
1
by brian
clean slate |
3921 |
share->r_locks= share->w_locks= share->tot_locks= 0; |
3922 |
error=_mi_writeinfo(info,WRITEINFO_NO_UNLOCK); |
|
3923 |
share->r_locks=r_locks; |
|
3924 |
share->w_locks=w_locks; |
|
3925 |
share->tot_locks=r_locks+w_locks; |
|
3926 |
if (!error) |
|
3927 |
return 0; |
|
3928 |
}
|
|
3929 |
err: |
|
3930 |
mi_check_print_error(param,"%d when updating keyfile",my_errno); |
|
3931 |
return 1; |
|
3932 |
}
|
|
3933 |
||
3934 |
/*
|
|
3935 |
Update auto increment value for a table
|
|
3936 |
When setting the 'repair_only' flag we only want to change the
|
|
3937 |
old auto_increment value if its wrong (smaller than some given key).
|
|
3938 |
The reason is that we shouldn't change the auto_increment value
|
|
3939 |
for a table without good reason when only doing a repair; If the
|
|
3940 |
user have inserted and deleted rows, the auto_increment value
|
|
3941 |
may be bigger than the biggest current row and this is ok.
|
|
3942 |
||
3943 |
If repair_only is not set, we will update the flag to the value in
|
|
3944 |
param->auto_increment is bigger than the biggest key.
|
|
3945 |
*/
|
|
3946 |
||
3947 |
void update_auto_increment_key(MI_CHECK *param, MI_INFO *info, |
|
281
by Brian Aker
Converted myisam away from my_bool |
3948 |
bool repair_only) |
1
by brian
clean slate |
3949 |
{
|
481
by Brian Aker
Remove all of uchar. |
3950 |
unsigned char *record= 0; |
1
by brian
clean slate |
3951 |
|
3952 |
if (!info->s->base.auto_key || |
|
3953 |
! mi_is_key_active(info->s->state.key_map, info->s->base.auto_key - 1)) |
|
3954 |
{
|
|
3955 |
if (!(param->testflag & T_VERY_SILENT)) |
|
3956 |
mi_check_print_info(param, |
|
3957 |
"Table: %s doesn't have an auto increment key\n", |
|
3958 |
param->isam_file_name); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3959 |
return; |
1
by brian
clean slate |
3960 |
}
|
3961 |
if (!(param->testflag & T_SILENT) && |
|
3962 |
!(param->testflag & T_REP)) |
|
3963 |
printf("Updating MyISAM file: %s\n", param->isam_file_name); |
|
3964 |
/*
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
3965 |
We have to use an allocated buffer instead of info->rec_buff as
|
1
by brian
clean slate |
3966 |
_mi_put_key_in_record() may use info->rec_buff
|
3967 |
*/
|
|
3968 |
if (!mi_alloc_rec_buff(info, -1, &record)) |
|
3969 |
{
|
|
3970 |
mi_check_print_error(param,"Not enough memory for extra record"); |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3971 |
return; |
1
by brian
clean slate |
3972 |
}
|
3973 |
||
3974 |
mi_extra(info,HA_EXTRA_KEYREAD,0); |
|
3975 |
if (mi_rlast(info, record, info->s->base.auto_key-1)) |
|
3976 |
{
|
|
3977 |
if (my_errno != HA_ERR_END_OF_FILE) |
|
3978 |
{
|
|
3979 |
mi_extra(info,HA_EXTRA_NO_KEYREAD,0); |
|
477
by Monty Taylor
Removed my_free(). It turns out that it had been def'd to ignore the flags passed to it in the second arg anyway. Gotta love that. |
3980 |
free(mi_get_rec_buff_ptr(info, record)); |
1
by brian
clean slate |
3981 |
mi_check_print_error(param,"%d when reading last record",my_errno); |
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3982 |
return; |
1
by brian
clean slate |
3983 |
}
|
3984 |
if (!repair_only) |
|
3985 |
info->s->state.auto_increment=param->auto_increment_value; |
|
3986 |
}
|
|
3987 |
else
|
|
3988 |
{
|
|
151
by Brian Aker
Ulonglong to uint64_t |
3989 |
uint64_t auto_increment= retrieve_auto_increment(info, record); |
1
by brian
clean slate |
3990 |
set_if_bigger(info->s->state.auto_increment,auto_increment); |
3991 |
if (!repair_only) |
|
3992 |
set_if_bigger(info->s->state.auto_increment, param->auto_increment_value); |
|
3993 |
}
|
|
3994 |
mi_extra(info,HA_EXTRA_NO_KEYREAD,0); |
|
477
by Monty Taylor
Removed my_free(). It turns out that it had been def'd to ignore the flags passed to it in the second arg anyway. Gotta love that. |
3995 |
free(mi_get_rec_buff_ptr(info, record)); |
1
by brian
clean slate |
3996 |
update_state_info(param, info, UPDATE_AUTO_INC); |
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
3997 |
return; |
1
by brian
clean slate |
3998 |
}
|
3999 |
||
4000 |
||
4001 |
/*
|
|
4002 |
Update statistics for each part of an index
|
|
4003 |
||
4004 |
SYNOPSIS
|
|
4005 |
update_key_parts()
|
|
4006 |
keyinfo IN Index information (only key->keysegs used)
|
|
4007 |
rec_per_key_part OUT Store statistics here
|
|
4008 |
unique IN Array of (#distinct tuples)
|
|
4009 |
notnull_tuples IN Array of (#tuples), or NULL
|
|
4010 |
records Number of records in the table
|
|
4011 |
||
4012 |
DESCRIPTION
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4013 |
This function is called produce index statistics values from unique and
|
1
by brian
clean slate |
4014 |
notnull_tuples arrays after these arrays were produced with sequential
|
4015 |
index scan (the scan is done in two places: chk_index() and
|
|
4016 |
sort_key_write()).
|
|
4017 |
||
4018 |
This function handles all 3 index statistics collection methods.
|
|
4019 |
||
4020 |
Unique is an array:
|
|
4021 |
unique[0]= (#different values of {keypart1}) - 1
|
|
4022 |
unique[1]= (#different values of {keypart1,keypart2} tuple)-unique[0]-1
|
|
4023 |
...
|
|
4024 |
||
4025 |
For MI_STATS_METHOD_IGNORE_NULLS method, notnull_tuples is an array too:
|
|
4026 |
notnull_tuples[0]= (#of {keypart1} tuples such that keypart1 is not NULL)
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4027 |
notnull_tuples[1]= (#of {keypart1,keypart2} tuples such that all
|
1
by brian
clean slate |
4028 |
keypart{i} are not NULL)
|
4029 |
...
|
|
4030 |
For all other statistics collection methods notnull_tuples==NULL.
|
|
4031 |
||
4032 |
Output is an array:
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4033 |
rec_per_key_part[k] =
|
4034 |
= E(#records in the table such that keypart_1=c_1 AND ... AND
|
|
4035 |
keypart_k=c_k for arbitrary constants c_1 ... c_k)
|
|
4036 |
||
1
by brian
clean slate |
4037 |
= {assuming that values have uniform distribution and index contains all
|
4038 |
tuples from the domain (or that {c_1, ..., c_k} tuple is choosen from
|
|
4039 |
index tuples}
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4040 |
|
1
by brian
clean slate |
4041 |
= #tuples-in-the-index / #distinct-tuples-in-the-index.
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4042 |
|
4043 |
The #tuples-in-the-index and #distinct-tuples-in-the-index have different
|
|
1
by brian
clean slate |
4044 |
meaning depending on which statistics collection method is used:
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4045 |
|
1
by brian
clean slate |
4046 |
MI_STATS_METHOD_* how are nulls compared? which tuples are counted?
|
4047 |
NULLS_EQUAL NULL == NULL all tuples in table
|
|
4048 |
NULLS_NOT_EQUAL NULL != NULL all tuples in table
|
|
4049 |
IGNORE_NULLS n/a tuples that don't have NULLs
|
|
4050 |
*/
|
|
4051 |
||
4052 |
void update_key_parts(MI_KEYDEF *keyinfo, ulong *rec_per_key_part, |
|
151
by Brian Aker
Ulonglong to uint64_t |
4053 |
uint64_t *unique, uint64_t *notnull, |
4054 |
uint64_t records) |
|
1
by brian
clean slate |
4055 |
{
|
151
by Brian Aker
Ulonglong to uint64_t |
4056 |
uint64_t count=0,tmp, unique_tuples; |
4057 |
uint64_t tuples= records; |
|
482
by Brian Aker
Remove uint. |
4058 |
uint32_t parts; |
1
by brian
clean slate |
4059 |
for (parts=0 ; parts < keyinfo->keysegs ; parts++) |
4060 |
{
|
|
4061 |
count+=unique[parts]; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4062 |
unique_tuples= count + 1; |
1
by brian
clean slate |
4063 |
if (notnull) |
4064 |
{
|
|
4065 |
tuples= notnull[parts]; |
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4066 |
/*
|
4067 |
#(unique_tuples not counting tuples with NULLs) =
|
|
4068 |
#(unique_tuples counting tuples with NULLs as different) -
|
|
1
by brian
clean slate |
4069 |
#(tuples with NULLs)
|
4070 |
*/
|
|
4071 |
unique_tuples -= (records - notnull[parts]); |
|
4072 |
}
|
|
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4073 |
|
1
by brian
clean slate |
4074 |
if (unique_tuples == 0) |
4075 |
tmp= 1; |
|
4076 |
else if (count == 0) |
|
4077 |
tmp= tuples; /* 1 unique tuple */ |
|
4078 |
else
|
|
4079 |
tmp= (tuples + unique_tuples/2) / unique_tuples; |
|
4080 |
||
660.1.3
by Eric Herman
removed trailing whitespace with simple script: |
4081 |
/*
|
4082 |
for some weird keys (e.g. FULLTEXT) tmp can be <1 here.
|
|
1
by brian
clean slate |
4083 |
let's ensure it is not
|
4084 |
*/
|
|
4085 |
set_if_bigger(tmp,1); |
|
151
by Brian Aker
Ulonglong to uint64_t |
4086 |
if (tmp >= (uint64_t) ~(ulong) 0) |
4087 |
tmp=(uint64_t) ~(ulong) 0; |
|
1
by brian
clean slate |
4088 |
|
4089 |
*rec_per_key_part=(ulong) tmp; |
|
4090 |
rec_per_key_part++; |
|
4091 |
}
|
|
4092 |
}
|
|
4093 |
||
4094 |
||
482
by Brian Aker
Remove uint. |
4095 |
static ha_checksum mi_byte_checksum(const unsigned char *buf, uint32_t length) |
1
by brian
clean slate |
4096 |
{
|
4097 |
ha_checksum crc; |
|
481
by Brian Aker
Remove all of uchar. |
4098 |
const unsigned char *end=buf+length; |
1
by brian
clean slate |
4099 |
for (crc=0; buf != end; buf++) |
481
by Brian Aker
Remove all of uchar. |
4100 |
crc=((crc << 1) + *((unsigned char*) buf)) + |
1
by brian
clean slate |
4101 |
test(crc & (((ha_checksum) 1) << (8*sizeof(ha_checksum)-1))); |
4102 |
return crc; |
|
4103 |
}
|
|
4104 |
||
281
by Brian Aker
Converted myisam away from my_bool |
4105 |
static bool mi_too_big_key_for_sort(MI_KEYDEF *key, ha_rows rows) |
1
by brian
clean slate |
4106 |
{
|
482
by Brian Aker
Remove uint. |
4107 |
uint32_t key_maxlength=key->maxlength; |
249
by Brian Aker
Random key cleanup (it is a friday...) |
4108 |
return (key->flag & (HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY) && |
151
by Brian Aker
Ulonglong to uint64_t |
4109 |
((uint64_t) rows * key_maxlength > |
4110 |
(uint64_t) myisam_max_temp_length)); |
|
1
by brian
clean slate |
4111 |
}
|
4112 |
||
4113 |
/*
|
|
4114 |
Deactivate all not unique index that can be recreated fast
|
|
4115 |
These include packed keys on which sorting will use more temporary
|
|
4116 |
space than the max allowed file length or for which the unpacked keys
|
|
4117 |
will take much more space than packed keys.
|
|
4118 |
Note that 'rows' may be zero for the case when we don't know how many
|
|
4119 |
rows we will put into the file.
|
|
4120 |
*/
|
|
4121 |
||
4122 |
void mi_disable_non_unique_index(MI_INFO *info, ha_rows rows) |
|
4123 |
{
|
|
4124 |
MYISAM_SHARE *share=info->s; |
|
4125 |
MI_KEYDEF *key=share->keyinfo; |
|
482
by Brian Aker
Remove uint. |
4126 |
uint32_t i; |
1
by brian
clean slate |
4127 |
|
51.1.92
by Jay Pipes
Removed/replaced DBUG symbols and TRUE/FALSE |
4128 |
assert(info->state->records == 0 && |
1
by brian
clean slate |
4129 |
(!rows || rows >= MI_MIN_ROWS_TO_DISABLE_INDEXES)); |
4130 |
for (i=0 ; i < share->base.keys ; i++,key++) |
|
4131 |
{
|
|
249
by Brian Aker
Random key cleanup (it is a friday...) |
4132 |
if (!(key->flag & (HA_NOSAME | HA_AUTO_KEY)) && |
1
by brian
clean slate |
4133 |
! mi_too_big_key_for_sort(key,rows) && info->s->base.auto_key != i+1) |
4134 |
{
|
|
4135 |
mi_clear_key_active(share->state.key_map, i); |
|
4136 |
info->update|= HA_STATE_CHANGED; |
|
4137 |
}
|
|
4138 |
}
|
|
4139 |
}
|
|
4140 |
||
4141 |
||
4142 |
/*
|
|
163
by Brian Aker
Merge Monty's code. |
4143 |
Return true if we can use repair by sorting
|
1
by brian
clean slate |
4144 |
One can set the force argument to force to use sorting
|
4145 |
even if the temporary file would be quite big!
|
|
4146 |
*/
|
|
4147 |
||
281
by Brian Aker
Converted myisam away from my_bool |
4148 |
bool mi_test_if_sort_rep(MI_INFO *info, ha_rows rows, |
4149 |
uint64_t key_map, bool force) |
|
1
by brian
clean slate |
4150 |
{
|
4151 |
MYISAM_SHARE *share=info->s; |
|
4152 |
MI_KEYDEF *key=share->keyinfo; |
|
482
by Brian Aker
Remove uint. |
4153 |
uint32_t i; |
1
by brian
clean slate |
4154 |
|
4155 |
/*
|
|
4156 |
mi_repair_by_sort only works if we have at least one key. If we don't
|
|
4157 |
have any keys, we should use the normal repair.
|
|
4158 |
*/
|
|
4159 |
if (! mi_is_any_key_active(key_map)) |
|
163
by Brian Aker
Merge Monty's code. |
4160 |
return false; /* Can't use sort */ |
1
by brian
clean slate |
4161 |
for (i=0 ; i < share->base.keys ; i++,key++) |
4162 |
{
|
|
4163 |
if (!force && mi_too_big_key_for_sort(key,rows)) |
|
163
by Brian Aker
Merge Monty's code. |
4164 |
return false; |
1
by brian
clean slate |
4165 |
}
|
163
by Brian Aker
Merge Monty's code. |
4166 |
return true; |
1
by brian
clean slate |
4167 |
}
|
4168 |
||
4169 |
||
4170 |
static void |
|
4171 |
set_data_file_type(SORT_INFO *sort_info, MYISAM_SHARE *share) |
|
4172 |
{
|
|
4173 |
if ((sort_info->new_data_file_type=share->data_file_type) == |
|
4174 |
COMPRESSED_RECORD && sort_info->param->testflag & T_UNPACK) |
|
4175 |
{
|
|
4176 |
MYISAM_SHARE tmp; |
|
4177 |
||
4178 |
if (share->options & HA_OPTION_PACK_RECORD) |
|
4179 |
sort_info->new_data_file_type = DYNAMIC_RECORD; |
|
4180 |
else
|
|
4181 |
sort_info->new_data_file_type = STATIC_RECORD; |
|
4182 |
||
4183 |
/* Set delete_function for sort_delete_record() */
|
|
212.6.12
by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove(). |
4184 |
memcpy(&tmp, share, sizeof(*share)); |
1
by brian
clean slate |
4185 |
tmp.options= ~HA_OPTION_COMPRESS_RECORD; |
4186 |
mi_setup_functions(&tmp); |
|
4187 |
share->delete_record=tmp.delete_record; |
|
4188 |
}
|
|
4189 |
}
|