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