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 |
/* write whats in isam.log */
|
|
17 |
||
18 |
#ifndef USE_MY_FUNC
|
|
19 |
#define USE_MY_FUNC
|
|
20 |
#endif
|
|
21 |
||
22 |
#include "myisamdef.h" |
|
23 |
#include <my_tree.h> |
|
24 |
#include <stdarg.h> |
|
25 |
#ifdef HAVE_GETRUSAGE
|
|
26 |
#include <sys/resource.h> |
|
27 |
#endif
|
|
28 |
||
29 |
#define FILENAME(A) (A ? A->show_name : "Unknown")
|
|
30 |
||
31 |
struct file_info { |
|
32 |
long process; |
|
33 |
int filenr,id; |
|
34 |
uint rnd; |
|
35 |
char *name, *show_name; |
|
36 |
uchar *record; |
|
37 |
MI_INFO *isam; |
|
38 |
my_bool closed, used; |
|
39 |
ulong accessed; |
|
40 |
};
|
|
41 |
||
42 |
struct test_if_open_param { |
|
43 |
char * name; |
|
44 |
int max_id; |
|
45 |
};
|
|
46 |
||
47 |
struct st_access_param |
|
48 |
{
|
|
49 |
ulong min_accessed; |
|
50 |
struct file_info *found; |
|
51 |
};
|
|
52 |
||
53 |
#define NO_FILEPOS (ulong) ~0L
|
|
54 |
||
55 |
extern int main(int argc,char * *argv); |
|
56 |
static void get_options(int *argc,char ***argv); |
|
57 |
static int examine_log(char * file_name,char **table_names); |
|
58 |
static int read_string(IO_CACHE *file,uchar* *to,uint length); |
|
59 |
static int file_info_compare(void *cmp_arg, void *a,void *b); |
|
60 |
static int test_if_open(struct file_info *key,element_count count, |
|
61 |
struct test_if_open_param *param); |
|
62 |
static void fix_blob_pointers(MI_INFO *isam,uchar *record); |
|
63 |
static int test_when_accessed(struct file_info *key,element_count count, |
|
64 |
struct st_access_param *access_param); |
|
65 |
static void file_info_free(struct file_info *info); |
|
66 |
static int close_some_file(TREE *tree); |
|
67 |
static int reopen_closed_file(TREE *tree,struct file_info *file_info); |
|
68 |
static int find_record_with_key(struct file_info *file_info,uchar *record); |
|
69 |
static void printf_log(const char *str,...); |
|
70 |
static my_bool cmp_filename(struct file_info *file_info,char * name); |
|
71 |
||
72 |
static uint verbose=0,update=0,test_info=0,max_files=0,re_open_count=0, |
|
73 |
recover=0,prefix_remove=0,opt_processes=0; |
|
74 |
static char *log_filename=0, *filepath=0, *write_filename=0; |
|
75 |
static char *record_pos_file= 0; |
|
76 |
static ulong com_count[10][3],number_of_commands=(ulong) ~0L, |
|
77 |
isamlog_process; |
|
78 |
static my_off_t isamlog_filepos,start_offset=0,record_pos= HA_OFFSET_ERROR; |
|
79 |
static const char *command_name[]= |
|
80 |
{"open","write","update","delete","close","extra","lock","re-open", |
|
81 |
"delete-all", NullS}; |
|
82 |
||
83 |
||
84 |
int main(int argc, char **argv) |
|
85 |
{
|
|
86 |
int error,i,first; |
|
87 |
ulong total_count,total_error,total_recover; |
|
88 |
MY_INIT(argv[0]); |
|
89 |
||
90 |
log_filename=myisam_log_filename; |
|
91 |
get_options(&argc,&argv); |
|
92 |
/* Number of MyISAM files we can have open at one time */
|
|
93 |
max_files= (my_set_max_open_files(min(max_files,8))-6)/2; |
|
94 |
if (update) |
|
95 |
printf("Trying to %s MyISAM files according to log '%s'\n", |
|
96 |
(recover ? "recover" : "update"),log_filename); |
|
97 |
error= examine_log(log_filename,argv); |
|
98 |
if (update && ! error) |
|
99 |
puts("Tables updated successfully"); |
|
100 |
total_count=total_error=total_recover=0; |
|
101 |
for (i=first=0 ; command_name[i] ; i++) |
|
102 |
{
|
|
103 |
if (com_count[i][0]) |
|
104 |
{
|
|
105 |
if (!first++) |
|
106 |
{
|
|
107 |
if (verbose || update) |
|
108 |
puts(""); |
|
109 |
puts("Commands Used count Errors Recover errors"); |
|
110 |
}
|
|
111 |
printf("%-12s%9ld%10ld%17ld\n",command_name[i],com_count[i][0], |
|
112 |
com_count[i][1],com_count[i][2]); |
|
113 |
total_count+=com_count[i][0]; |
|
114 |
total_error+=com_count[i][1]; |
|
115 |
total_recover+=com_count[i][2]; |
|
116 |
}
|
|
117 |
}
|
|
118 |
if (total_count) |
|
119 |
printf("%-12s%9ld%10ld%17ld\n","Total",total_count,total_error, |
|
120 |
total_recover); |
|
121 |
if (re_open_count) |
|
122 |
printf("Had to do %d re-open because of too few possibly open files\n", |
|
123 |
re_open_count); |
|
124 |
VOID(mi_panic(HA_PANIC_CLOSE)); |
|
125 |
my_free_open_file_info(); |
|
126 |
my_end(test_info ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR); |
|
127 |
exit(error); |
|
128 |
return 0; /* No compiler warning */ |
|
129 |
} /* main */ |
|
130 |
||
131 |
||
132 |
static void get_options(register int *argc, register char ***argv) |
|
133 |
{
|
|
134 |
int help,version; |
|
135 |
const char *pos,*usage; |
|
136 |
char option; |
|
137 |
||
138 |
help=0; |
|
139 |
usage="Usage: %s [-?iruvDIV] [-c #] [-f #] [-F filepath/] [-o #] [-R file recordpos] [-w write_file] [log-filename [table ...]] \n"; |
|
140 |
pos=""; |
|
141 |
||
142 |
while (--*argc > 0 && *(pos = *(++*argv)) == '-' ) { |
|
143 |
while (*++pos) |
|
144 |
{
|
|
145 |
version=0; |
|
146 |
switch((option=*pos)) { |
|
147 |
case '#': |
|
148 |
DBUG_PUSH (++pos); |
|
149 |
pos=" "; /* Skip rest of arg */ |
|
150 |
break; |
|
151 |
case 'c': |
|
152 |
if (! *++pos) |
|
153 |
{
|
|
154 |
if (!--*argc) |
|
155 |
goto err; |
|
156 |
else
|
|
157 |
pos= *(++*argv); |
|
158 |
}
|
|
159 |
number_of_commands=(ulong) atol(pos); |
|
160 |
pos=" "; |
|
161 |
break; |
|
162 |
case 'u': |
|
163 |
update=1; |
|
164 |
break; |
|
165 |
case 'f': |
|
166 |
if (! *++pos) |
|
167 |
{
|
|
168 |
if (!--*argc) |
|
169 |
goto err; |
|
170 |
else
|
|
171 |
pos= *(++*argv); |
|
172 |
}
|
|
173 |
max_files=(uint) atoi(pos); |
|
174 |
pos=" "; |
|
175 |
break; |
|
176 |
case 'i': |
|
177 |
test_info=1; |
|
178 |
break; |
|
179 |
case 'o': |
|
180 |
if (! *++pos) |
|
181 |
{
|
|
182 |
if (!--*argc) |
|
183 |
goto err; |
|
184 |
else
|
|
185 |
pos= *(++*argv); |
|
186 |
}
|
|
187 |
start_offset=(my_off_t) strtoll(pos,NULL,10); |
|
188 |
pos=" "; |
|
189 |
break; |
|
190 |
case 'p': |
|
191 |
if (! *++pos) |
|
192 |
{
|
|
193 |
if (!--*argc) |
|
194 |
goto err; |
|
195 |
else
|
|
196 |
pos= *(++*argv); |
|
197 |
}
|
|
198 |
prefix_remove=atoi(pos); |
|
199 |
break; |
|
200 |
case 'r': |
|
201 |
update=1; |
|
202 |
recover++; |
|
203 |
break; |
|
204 |
case 'P': |
|
205 |
opt_processes=1; |
|
206 |
break; |
|
207 |
case 'R': |
|
208 |
if (! *++pos) |
|
209 |
{
|
|
210 |
if (!--*argc) |
|
211 |
goto err; |
|
212 |
else
|
|
213 |
pos= *(++*argv); |
|
214 |
}
|
|
215 |
record_pos_file=(char*) pos; |
|
216 |
if (!--*argc) |
|
217 |
goto err; |
|
218 |
record_pos=(my_off_t) strtoll(*(++*argv),NULL,10); |
|
219 |
pos=" "; |
|
220 |
break; |
|
221 |
case 'v': |
|
222 |
verbose++; |
|
223 |
break; |
|
224 |
case 'w': |
|
225 |
if (! *++pos) |
|
226 |
{
|
|
227 |
if (!--*argc) |
|
228 |
goto err; |
|
229 |
else
|
|
230 |
pos= *(++*argv); |
|
231 |
}
|
|
232 |
write_filename=(char*) pos; |
|
233 |
pos=" "; |
|
234 |
break; |
|
235 |
case 'F': |
|
236 |
if (! *++pos) |
|
237 |
{
|
|
238 |
if (!--*argc) |
|
239 |
goto err; |
|
240 |
else
|
|
241 |
pos= *(++*argv); |
|
242 |
}
|
|
243 |
filepath= (char*) pos; |
|
244 |
pos=" "; |
|
245 |
break; |
|
246 |
case 'V': |
|
247 |
version=1; |
|
248 |
/* Fall through */
|
|
249 |
case 'I': |
|
250 |
case '?': |
|
251 |
#include <help_start.h> |
|
252 |
printf("%s Ver 1.4 for %s at %s\n",my_progname,SYSTEM_TYPE, |
|
253 |
MACHINE_TYPE); |
|
254 |
puts("By Monty, for your professional use\n"); |
|
255 |
if (version) |
|
256 |
break; |
|
257 |
puts("Write info about whats in a MyISAM log file."); |
|
258 |
printf("If no file name is given %s is used\n",log_filename); |
|
259 |
puts(""); |
|
260 |
printf(usage,my_progname); |
|
261 |
puts(""); |
|
262 |
puts("Options: -? or -I \"Info\" -V \"version\" -c \"do only # commands\""); |
|
263 |
puts(" -f \"max open files\" -F \"filepath\" -i \"extra info\""); |
|
264 |
puts(" -o \"offset\" -p # \"remove # components from path\""); |
|
265 |
puts(" -r \"recover\" -R \"file recordposition\""); |
|
266 |
puts(" -u \"update\" -v \"verbose\" -w \"write file\""); |
|
267 |
puts(" -D \"myisam compiled with DBUG\" -P \"processes\""); |
|
268 |
puts("\nOne can give a second and a third '-v' for more verbose."); |
|
269 |
puts("Normaly one does a update (-u)."); |
|
270 |
puts("If a recover is done all writes and all possibly updates and deletes is done\nand errors are only counted."); |
|
271 |
puts("If one gives table names as arguments only these tables will be updated\n"); |
|
272 |
help=1; |
|
273 |
#include <help_end.h> |
|
274 |
break; |
|
275 |
default: |
|
276 |
printf("illegal option: \"-%c\"\n",*pos); |
|
277 |
break; |
|
278 |
}
|
|
279 |
}
|
|
280 |
}
|
|
281 |
if (! *argc) |
|
282 |
{
|
|
283 |
if (help) |
|
284 |
exit(0); |
|
285 |
(*argv)++; |
|
286 |
}
|
|
287 |
if (*argc >= 1) |
|
288 |
{
|
|
289 |
log_filename=(char*) pos; |
|
290 |
(*argc)--; |
|
291 |
(*argv)++; |
|
292 |
}
|
|
293 |
return; |
|
294 |
err: |
|
295 |
VOID(fprintf(stderr,"option \"%c\" used without or with wrong argument\n", |
|
296 |
option)); |
|
297 |
exit(1); |
|
298 |
}
|
|
299 |
||
300 |
||
301 |
static int examine_log(char * file_name, char **table_names) |
|
302 |
{
|
|
303 |
uint command,result,files_open; |
|
304 |
ulong access_time,length; |
|
305 |
my_off_t filepos; |
|
306 |
int lock_command,mi_result; |
|
307 |
char isam_file_name[FN_REFLEN],llbuff[21],llbuff2[21]; |
|
308 |
uchar head[20]; |
|
309 |
uchar* buff; |
|
310 |
struct test_if_open_param open_param; |
|
311 |
IO_CACHE cache; |
|
312 |
File file; |
|
313 |
FILE *write_file; |
|
314 |
enum ha_extra_function extra_command; |
|
315 |
TREE tree; |
|
316 |
struct file_info file_info,*curr_file_info; |
|
317 |
DBUG_ENTER("examine_log"); |
|
318 |
||
319 |
if ((file=my_open(file_name,O_RDONLY,MYF(MY_WME))) < 0) |
|
320 |
DBUG_RETURN(1); |
|
321 |
write_file=0; |
|
322 |
if (write_filename) |
|
323 |
{
|
|
324 |
if (!(write_file=my_fopen(write_filename,O_WRONLY,MYF(MY_WME)))) |
|
325 |
{
|
|
326 |
my_close(file,MYF(0)); |
|
327 |
DBUG_RETURN(1); |
|
328 |
}
|
|
329 |
}
|
|
330 |
||
331 |
init_io_cache(&cache,file,0,READ_CACHE,start_offset,0,MYF(0)); |
|
332 |
bzero((uchar*) com_count,sizeof(com_count)); |
|
333 |
init_tree(&tree,0,0,sizeof(file_info),(qsort_cmp2) file_info_compare,1, |
|
334 |
(tree_element_free) file_info_free, NULL); |
|
335 |
VOID(init_key_cache(dflt_key_cache,KEY_CACHE_BLOCK_SIZE,KEY_CACHE_SIZE, |
|
336 |
0, 0)); |
|
337 |
||
338 |
files_open=0; access_time=0; |
|
339 |
while (access_time++ != number_of_commands && |
|
340 |
!my_b_read(&cache,(uchar*) head,9)) |
|
341 |
{
|
|
342 |
isamlog_filepos=my_b_tell(&cache)-9L; |
|
343 |
file_info.filenr= mi_uint2korr(head+1); |
|
344 |
isamlog_process=file_info.process=(long) mi_uint4korr(head+3); |
|
345 |
if (!opt_processes) |
|
346 |
file_info.process=0; |
|
347 |
result= mi_uint2korr(head+7); |
|
348 |
if ((curr_file_info=(struct file_info*) tree_search(&tree, &file_info, |
|
349 |
tree.custom_arg))) |
|
350 |
{
|
|
351 |
curr_file_info->accessed=access_time; |
|
352 |
if (update && curr_file_info->used && curr_file_info->closed) |
|
353 |
{
|
|
354 |
if (reopen_closed_file(&tree,curr_file_info)) |
|
355 |
{
|
|
356 |
command=sizeof(com_count)/sizeof(com_count[0][0])/3; |
|
357 |
result=0; |
|
358 |
goto com_err; |
|
359 |
}
|
|
360 |
}
|
|
361 |
}
|
|
362 |
command=(uint) head[0]; |
|
363 |
if (command < sizeof(com_count)/sizeof(com_count[0][0])/3 && |
|
364 |
(!table_names[0] || (curr_file_info && curr_file_info->used))) |
|
365 |
{
|
|
366 |
com_count[command][0]++; |
|
367 |
if (result) |
|
368 |
com_count[command][1]++; |
|
369 |
}
|
|
370 |
switch ((enum myisam_log_commands) command) { |
|
371 |
case MI_LOG_OPEN: |
|
372 |
if (!table_names[0]) |
|
373 |
{
|
|
374 |
com_count[command][0]--; /* Must be counted explicite */ |
|
375 |
if (result) |
|
376 |
com_count[command][1]--; |
|
377 |
}
|
|
378 |
||
379 |
if (curr_file_info) |
|
380 |
printf("\nWarning: %s is opened with same process and filenumber\n" |
|
381 |
"Maybe you should use the -P option ?\n", |
|
382 |
curr_file_info->show_name); |
|
383 |
if (my_b_read(&cache,(uchar*) head,2)) |
|
384 |
goto err; |
|
385 |
file_info.name=0; |
|
386 |
file_info.show_name=0; |
|
387 |
file_info.record=0; |
|
388 |
if (read_string(&cache,(uchar**) &file_info.name, |
|
389 |
(uint) mi_uint2korr(head))) |
|
390 |
goto err; |
|
391 |
{
|
|
392 |
uint i; |
|
393 |
char *pos,*to; |
|
394 |
||
395 |
/* Fix if old DOS files to new format */
|
|
396 |
for (pos=file_info.name; (pos=strchr(pos,'\\')) ; pos++) |
|
397 |
*pos= '/'; |
|
398 |
||
399 |
pos=file_info.name; |
|
400 |
for (i=0 ; i < prefix_remove ; i++) |
|
401 |
{
|
|
402 |
char *next; |
|
403 |
if (!(next=strchr(pos,'/'))) |
|
404 |
break; |
|
405 |
pos=next+1; |
|
406 |
}
|
|
407 |
to=isam_file_name; |
|
408 |
if (filepath) |
|
409 |
to=convert_dirname(isam_file_name,filepath,NullS); |
|
410 |
strmov(to,pos); |
|
411 |
fn_ext(isam_file_name)[0]=0; /* Remove extension */ |
|
412 |
}
|
|
413 |
open_param.name=file_info.name; |
|
414 |
open_param.max_id=0; |
|
415 |
VOID(tree_walk(&tree,(tree_walk_action) test_if_open,(void*) &open_param, |
|
416 |
left_root_right)); |
|
417 |
file_info.id=open_param.max_id+1; |
|
418 |
/*
|
|
419 |
* In the line below +10 is added to accomodate '<' and '>' chars
|
|
420 |
* plus '\0' at the end, so that there is place for 7 digits.
|
|
421 |
* It is improbable that same table can have that many entries in
|
|
422 |
* the table cache.
|
|
423 |
* The additional space is needed for the sprintf commands two lines
|
|
424 |
* below.
|
|
425 |
*/
|
|
426 |
file_info.show_name=my_memdup(isam_file_name, |
|
427 |
(uint) strlen(isam_file_name)+10, |
|
428 |
MYF(MY_WME)); |
|
429 |
if (file_info.id > 1) |
|
430 |
sprintf(strend(file_info.show_name),"<%d>",file_info.id); |
|
431 |
file_info.closed=1; |
|
432 |
file_info.accessed=access_time; |
|
433 |
file_info.used=1; |
|
434 |
if (table_names[0]) |
|
435 |
{
|
|
436 |
char **name; |
|
437 |
file_info.used=0; |
|
438 |
for (name=table_names ; *name ; name++) |
|
439 |
{
|
|
440 |
if (!strcmp(*name,isam_file_name)) |
|
441 |
file_info.used=1; /* Update/log only this */ |
|
442 |
}
|
|
443 |
}
|
|
444 |
if (update && file_info.used) |
|
445 |
{
|
|
446 |
if (files_open >= max_files) |
|
447 |
{
|
|
448 |
if (close_some_file(&tree)) |
|
449 |
goto com_err; |
|
450 |
files_open--; |
|
451 |
}
|
|
452 |
if (!(file_info.isam= mi_open(isam_file_name,O_RDWR, |
|
453 |
HA_OPEN_WAIT_IF_LOCKED))) |
|
454 |
goto com_err; |
|
455 |
if (!(file_info.record=my_malloc(file_info.isam->s->base.reclength, |
|
456 |
MYF(MY_WME)))) |
|
457 |
goto end; |
|
458 |
files_open++; |
|
459 |
file_info.closed=0; |
|
460 |
}
|
|
461 |
VOID(tree_insert(&tree, (uchar*) &file_info, 0, tree.custom_arg)); |
|
462 |
if (file_info.used) |
|
463 |
{
|
|
464 |
if (verbose && !record_pos_file) |
|
465 |
printf_log("%s: open -> %d",file_info.show_name, file_info.filenr); |
|
466 |
com_count[command][0]++; |
|
467 |
if (result) |
|
468 |
com_count[command][1]++; |
|
469 |
}
|
|
470 |
break; |
|
471 |
case MI_LOG_CLOSE: |
|
472 |
if (verbose && !record_pos_file && |
|
473 |
(!table_names[0] || (curr_file_info && curr_file_info->used))) |
|
474 |
printf_log("%s: %s -> %d",FILENAME(curr_file_info), |
|
475 |
command_name[command],result); |
|
476 |
if (curr_file_info) |
|
477 |
{
|
|
478 |
if (!curr_file_info->closed) |
|
479 |
files_open--; |
|
480 |
VOID(tree_delete(&tree, (uchar*) curr_file_info, 0, tree.custom_arg)); |
|
481 |
}
|
|
482 |
break; |
|
483 |
case MI_LOG_EXTRA: |
|
484 |
if (my_b_read(&cache,(uchar*) head,1)) |
|
485 |
goto err; |
|
486 |
extra_command=(enum ha_extra_function) head[0]; |
|
487 |
if (verbose && !record_pos_file && |
|
488 |
(!table_names[0] || (curr_file_info && curr_file_info->used))) |
|
489 |
printf_log("%s: %s(%d) -> %d",FILENAME(curr_file_info), |
|
490 |
command_name[command], (int) extra_command,result); |
|
491 |
if (update && curr_file_info && !curr_file_info->closed) |
|
492 |
{
|
|
493 |
if (mi_extra(curr_file_info->isam, extra_command, 0) != (int) result) |
|
494 |
{
|
|
495 |
fflush(stdout); |
|
496 |
VOID(fprintf(stderr, |
|
497 |
"Warning: error %d, expected %d on command %s at %s\n", |
|
498 |
my_errno,result,command_name[command], |
|
499 |
llstr(isamlog_filepos,llbuff))); |
|
500 |
fflush(stderr); |
|
501 |
}
|
|
502 |
}
|
|
503 |
break; |
|
504 |
case MI_LOG_DELETE: |
|
505 |
if (my_b_read(&cache,(uchar*) head,8)) |
|
506 |
goto err; |
|
507 |
filepos=mi_sizekorr(head); |
|
508 |
if (verbose && (!record_pos_file || |
|
509 |
((record_pos == filepos || record_pos == NO_FILEPOS) && |
|
510 |
!cmp_filename(curr_file_info,record_pos_file))) && |
|
511 |
(!table_names[0] || (curr_file_info && curr_file_info->used))) |
|
512 |
printf_log("%s: %s at %ld -> %d",FILENAME(curr_file_info), |
|
513 |
command_name[command],(long) filepos,result); |
|
514 |
if (update && curr_file_info && !curr_file_info->closed) |
|
515 |
{
|
|
516 |
if (mi_rrnd(curr_file_info->isam,curr_file_info->record,filepos)) |
|
517 |
{
|
|
518 |
if (!recover) |
|
519 |
goto com_err; |
|
520 |
if (verbose) |
|
521 |
printf_log("error: Didn't find row to delete with mi_rrnd"); |
|
522 |
com_count[command][2]++; /* Mark error */ |
|
523 |
}
|
|
524 |
mi_result=mi_delete(curr_file_info->isam,curr_file_info->record); |
|
525 |
if ((mi_result == 0 && result) || |
|
526 |
(mi_result && (uint) my_errno != result)) |
|
527 |
{
|
|
528 |
if (!recover) |
|
529 |
goto com_err; |
|
530 |
if (mi_result) |
|
531 |
com_count[command][2]++; /* Mark error */ |
|
532 |
if (verbose) |
|
533 |
printf_log("error: Got result %d from mi_delete instead of %d", |
|
534 |
mi_result, result); |
|
535 |
}
|
|
536 |
}
|
|
537 |
break; |
|
538 |
case MI_LOG_WRITE: |
|
539 |
case MI_LOG_UPDATE: |
|
540 |
if (my_b_read(&cache,(uchar*) head,12)) |
|
541 |
goto err; |
|
542 |
filepos=mi_sizekorr(head); |
|
543 |
length=mi_uint4korr(head+8); |
|
544 |
buff=0; |
|
545 |
if (read_string(&cache,&buff,(uint) length)) |
|
546 |
goto err; |
|
547 |
if ((!record_pos_file || |
|
548 |
((record_pos == filepos || record_pos == NO_FILEPOS) && |
|
549 |
!cmp_filename(curr_file_info,record_pos_file))) && |
|
550 |
(!table_names[0] || (curr_file_info && curr_file_info->used))) |
|
551 |
{
|
|
552 |
if (write_file && |
|
553 |
(my_fwrite(write_file,buff,length,MYF(MY_WAIT_IF_FULL | MY_NABP)))) |
|
554 |
goto end; |
|
555 |
if (verbose) |
|
556 |
printf_log("%s: %s at %ld, length=%ld -> %d", |
|
557 |
FILENAME(curr_file_info), |
|
558 |
command_name[command], filepos,length,result); |
|
559 |
}
|
|
560 |
if (update && curr_file_info && !curr_file_info->closed) |
|
561 |
{
|
|
562 |
if (curr_file_info->isam->s->base.blobs) |
|
563 |
fix_blob_pointers(curr_file_info->isam,buff); |
|
564 |
if ((enum myisam_log_commands) command == MI_LOG_UPDATE) |
|
565 |
{
|
|
566 |
if (mi_rrnd(curr_file_info->isam,curr_file_info->record,filepos)) |
|
567 |
{
|
|
568 |
if (!recover) |
|
569 |
{
|
|
570 |
result=0; |
|
571 |
goto com_err; |
|
572 |
}
|
|
573 |
if (verbose) |
|
574 |
printf_log("error: Didn't find row to update with mi_rrnd"); |
|
575 |
if (recover == 1 || result || |
|
576 |
find_record_with_key(curr_file_info,buff)) |
|
577 |
{
|
|
578 |
com_count[command][2]++; /* Mark error */ |
|
579 |
break; |
|
580 |
}
|
|
581 |
}
|
|
582 |
mi_result=mi_update(curr_file_info->isam,curr_file_info->record, |
|
583 |
buff); |
|
584 |
if ((mi_result == 0 && result) || |
|
585 |
(mi_result && (uint) my_errno != result)) |
|
586 |
{
|
|
587 |
if (!recover) |
|
588 |
goto com_err; |
|
589 |
if (verbose) |
|
590 |
printf_log("error: Got result %d from mi_update instead of %d", |
|
591 |
mi_result, result); |
|
592 |
if (mi_result) |
|
593 |
com_count[command][2]++; /* Mark error */ |
|
594 |
}
|
|
595 |
}
|
|
596 |
else
|
|
597 |
{
|
|
598 |
mi_result=mi_write(curr_file_info->isam,buff); |
|
599 |
if ((mi_result == 0 && result) || |
|
600 |
(mi_result && (uint) my_errno != result)) |
|
601 |
{
|
|
602 |
if (!recover) |
|
603 |
goto com_err; |
|
604 |
if (verbose) |
|
605 |
printf_log("error: Got result %d from mi_write instead of %d", |
|
606 |
mi_result, result); |
|
607 |
if (mi_result) |
|
608 |
com_count[command][2]++; /* Mark error */ |
|
609 |
}
|
|
610 |
if (!recover && filepos != curr_file_info->isam->lastpos) |
|
611 |
{
|
|
612 |
printf("error: Wrote at position: %s, should have been %s", |
|
613 |
llstr(curr_file_info->isam->lastpos,llbuff), |
|
614 |
llstr(filepos,llbuff2)); |
|
615 |
goto end; |
|
616 |
}
|
|
617 |
}
|
|
618 |
}
|
|
619 |
my_free(buff,MYF(0)); |
|
620 |
break; |
|
621 |
case MI_LOG_LOCK: |
|
622 |
if (my_b_read(&cache,(uchar*) head,sizeof(lock_command))) |
|
623 |
goto err; |
|
624 |
memcpy_fixed(&lock_command,head,sizeof(lock_command)); |
|
625 |
if (verbose && !record_pos_file && |
|
626 |
(!table_names[0] || (curr_file_info && curr_file_info->used))) |
|
627 |
printf_log("%s: %s(%d) -> %d\n",FILENAME(curr_file_info), |
|
628 |
command_name[command],lock_command,result); |
|
629 |
if (update && curr_file_info && !curr_file_info->closed) |
|
630 |
{
|
|
631 |
if (mi_lock_database(curr_file_info->isam,lock_command) != |
|
632 |
(int) result) |
|
633 |
goto com_err; |
|
634 |
}
|
|
635 |
break; |
|
636 |
case MI_LOG_DELETE_ALL: |
|
637 |
if (verbose && !record_pos_file && |
|
638 |
(!table_names[0] || (curr_file_info && curr_file_info->used))) |
|
639 |
printf_log("%s: %s -> %d\n",FILENAME(curr_file_info), |
|
640 |
command_name[command],result); |
|
641 |
break; |
|
642 |
default: |
|
643 |
fflush(stdout); |
|
644 |
VOID(fprintf(stderr, |
|
645 |
"Error: found unknown command %d in logfile, aborted\n", |
|
646 |
command)); |
|
647 |
fflush(stderr); |
|
648 |
goto end; |
|
649 |
}
|
|
650 |
}
|
|
651 |
end_key_cache(dflt_key_cache,1); |
|
652 |
delete_tree(&tree); |
|
653 |
VOID(end_io_cache(&cache)); |
|
654 |
VOID(my_close(file,MYF(0))); |
|
655 |
if (write_file && my_fclose(write_file,MYF(MY_WME))) |
|
656 |
DBUG_RETURN(1); |
|
657 |
DBUG_RETURN(0); |
|
658 |
||
659 |
err: |
|
660 |
fflush(stdout); |
|
661 |
VOID(fprintf(stderr,"Got error %d when reading from logfile\n",my_errno)); |
|
662 |
fflush(stderr); |
|
663 |
goto end; |
|
664 |
com_err: |
|
665 |
fflush(stdout); |
|
666 |
VOID(fprintf(stderr,"Got error %d, expected %d on command %s at %s\n", |
|
667 |
my_errno,result,command_name[command], |
|
668 |
llstr(isamlog_filepos,llbuff))); |
|
669 |
fflush(stderr); |
|
670 |
end: |
|
671 |
end_key_cache(dflt_key_cache, 1); |
|
672 |
delete_tree(&tree); |
|
673 |
VOID(end_io_cache(&cache)); |
|
674 |
VOID(my_close(file,MYF(0))); |
|
675 |
if (write_file) |
|
676 |
VOID(my_fclose(write_file,MYF(MY_WME))); |
|
677 |
DBUG_RETURN(1); |
|
678 |
}
|
|
679 |
||
680 |
||
681 |
static int read_string(IO_CACHE *file, register uchar* *to, register uint length) |
|
682 |
{
|
|
683 |
DBUG_ENTER("read_string"); |
|
684 |
||
685 |
if (*to) |
|
686 |
my_free((uchar*) *to,MYF(0)); |
|
687 |
if (!(*to= (uchar*) my_malloc(length+1,MYF(MY_WME))) || |
|
688 |
my_b_read(file,(uchar*) *to,length)) |
|
689 |
{
|
|
690 |
if (*to) |
|
691 |
my_free(*to,MYF(0)); |
|
692 |
*to= 0; |
|
693 |
DBUG_RETURN(1); |
|
694 |
}
|
|
695 |
*((char*) *to+length)= '\0'; |
|
696 |
DBUG_RETURN (0); |
|
697 |
} /* read_string */ |
|
698 |
||
699 |
||
700 |
static int file_info_compare(void* cmp_arg __attribute__((unused)), |
|
701 |
void *a, void *b) |
|
702 |
{
|
|
703 |
long lint; |
|
704 |
||
705 |
if ((lint=((struct file_info*) a)->process - |
|
706 |
((struct file_info*) b)->process)) |
|
707 |
return lint < 0L ? -1 : 1; |
|
708 |
return ((struct file_info*) a)->filenr - ((struct file_info*) b)->filenr; |
|
709 |
}
|
|
710 |
||
711 |
/* ARGSUSED */
|
|
712 |
||
713 |
static int test_if_open (struct file_info *key, |
|
714 |
element_count count __attribute__((unused)), |
|
715 |
struct test_if_open_param *param) |
|
716 |
{
|
|
717 |
if (!strcmp(key->name,param->name) && key->id > param->max_id) |
|
718 |
param->max_id=key->id; |
|
719 |
return 0; |
|
720 |
}
|
|
721 |
||
722 |
||
723 |
static void fix_blob_pointers(MI_INFO *info, uchar *record) |
|
724 |
{
|
|
725 |
uchar *pos; |
|
726 |
MI_BLOB *blob,*end; |
|
727 |
||
728 |
pos=record+info->s->base.reclength; |
|
729 |
for (end=info->blobs+info->s->base.blobs, blob= info->blobs; |
|
730 |
blob != end ; |
|
731 |
blob++) |
|
732 |
{
|
|
733 |
memcpy_fixed(record+blob->offset+blob->pack_length,&pos,sizeof(char*)); |
|
734 |
pos+=_mi_calc_blob_length(blob->pack_length,record+blob->offset); |
|
735 |
}
|
|
736 |
}
|
|
737 |
||
738 |
/* close the file with hasn't been accessed for the longest time */
|
|
739 |
/* ARGSUSED */
|
|
740 |
||
741 |
static int test_when_accessed (struct file_info *key, |
|
742 |
element_count count __attribute__((unused)), |
|
743 |
struct st_access_param *access_param) |
|
744 |
{
|
|
745 |
if (key->accessed < access_param->min_accessed && ! key->closed) |
|
746 |
{
|
|
747 |
access_param->min_accessed=key->accessed; |
|
748 |
access_param->found=key; |
|
749 |
}
|
|
750 |
return 0; |
|
751 |
}
|
|
752 |
||
753 |
||
754 |
static void file_info_free(struct file_info *fileinfo) |
|
755 |
{
|
|
756 |
DBUG_ENTER("file_info_free"); |
|
757 |
if (update) |
|
758 |
{
|
|
759 |
if (!fileinfo->closed) |
|
760 |
VOID(mi_close(fileinfo->isam)); |
|
761 |
if (fileinfo->record) |
|
762 |
my_free(fileinfo->record,MYF(0)); |
|
763 |
}
|
|
764 |
my_free(fileinfo->name,MYF(0)); |
|
765 |
my_free(fileinfo->show_name,MYF(0)); |
|
766 |
DBUG_VOID_RETURN; |
|
767 |
}
|
|
768 |
||
769 |
||
770 |
||
771 |
static int close_some_file(TREE *tree) |
|
772 |
{
|
|
773 |
struct st_access_param access_param; |
|
774 |
||
775 |
access_param.min_accessed=LONG_MAX; |
|
776 |
access_param.found=0; |
|
777 |
||
778 |
VOID(tree_walk(tree,(tree_walk_action) test_when_accessed, |
|
779 |
(void*) &access_param,left_root_right)); |
|
780 |
if (!access_param.found) |
|
781 |
return 1; /* No open file that is possibly to close */ |
|
782 |
if (mi_close(access_param.found->isam)) |
|
783 |
return 1; |
|
784 |
access_param.found->closed=1; |
|
785 |
return 0; |
|
786 |
}
|
|
787 |
||
788 |
||
789 |
static int reopen_closed_file(TREE *tree, struct file_info *fileinfo) |
|
790 |
{
|
|
791 |
char name[FN_REFLEN]; |
|
792 |
if (close_some_file(tree)) |
|
793 |
return 1; /* No file to close */ |
|
794 |
strmov(name,fileinfo->show_name); |
|
795 |
if (fileinfo->id > 1) |
|
796 |
*strrchr(name,'<')='\0'; /* Remove "<id>" */ |
|
797 |
||
798 |
if (!(fileinfo->isam= mi_open(name,O_RDWR,HA_OPEN_WAIT_IF_LOCKED))) |
|
799 |
return 1; |
|
800 |
fileinfo->closed=0; |
|
801 |
re_open_count++; |
|
802 |
return 0; |
|
803 |
}
|
|
804 |
||
805 |
/* Try to find record with uniq key */
|
|
806 |
||
807 |
static int find_record_with_key(struct file_info *file_info, uchar *record) |
|
808 |
{
|
|
809 |
uint key; |
|
810 |
MI_INFO *info=file_info->isam; |
|
811 |
uchar tmp_key[MI_MAX_KEY_BUFF]; |
|
812 |
||
813 |
for (key=0 ; key < info->s->base.keys ; key++) |
|
814 |
{
|
|
815 |
if (mi_is_key_active(info->s->state.key_map, key) && |
|
816 |
info->s->keyinfo[key].flag & HA_NOSAME) |
|
817 |
{
|
|
818 |
VOID(_mi_make_key(info,key,tmp_key,record,0L)); |
|
819 |
return mi_rkey(info,file_info->record,(int) key,tmp_key,0, |
|
820 |
HA_READ_KEY_EXACT); |
|
821 |
}
|
|
822 |
}
|
|
823 |
return 1; |
|
824 |
}
|
|
825 |
||
826 |
||
827 |
static void printf_log(const char *format,...) |
|
828 |
{
|
|
829 |
char llbuff[21]; |
|
830 |
va_list args; |
|
831 |
va_start(args,format); |
|
832 |
if (verbose > 2) |
|
833 |
printf("%9s:",llstr(isamlog_filepos,llbuff)); |
|
834 |
if (verbose > 1) |
|
835 |
printf("%5ld ",isamlog_process); /* Write process number */ |
|
836 |
(void) vprintf((char*) format,args); |
|
837 |
putchar('\n'); |
|
838 |
va_end(args); |
|
839 |
}
|
|
840 |
||
841 |
||
842 |
static my_bool cmp_filename(struct file_info *file_info, char * name) |
|
843 |
{
|
|
844 |
if (!file_info) |
|
845 |
return 1; |
|
846 |
return strcmp(file_info->name,name) ? 1 : 0; |
|
847 |
}
|
|
848 |
||
849 |
#include "mi_extrafunc.h" |