in storage/myisam/myisamlog.cc [318:643]
static int examine_log(const char *file_name, char **table_names) {
uint command, result, files_open;
ulong access_time, length;
my_off_t filepos;
int lock_command, mi_result;
char isam_file_name[FN_REFLEN], llbuff[21], llbuff2[21];
uchar head[20];
uchar *buff;
struct test_if_open_param open_param;
IO_CACHE cache;
File file;
FILE *write_file;
enum ha_extra_function extra_command;
TREE tree;
struct file_info file_info, *curr_file_info;
DBUG_TRACE;
if ((file = my_open(file_name, O_RDONLY, MYF(MY_WME))) < 0) return 1;
write_file = nullptr;
if (write_filename) {
if (!(write_file = my_fopen(write_filename, O_WRONLY, MYF(MY_WME)))) {
my_close(file, MYF(0));
return 1;
}
}
init_io_cache(&cache, file, 0, READ_CACHE, start_offset, false, MYF(0));
memset(com_count, 0, sizeof(com_count));
init_tree(&tree, 0, sizeof(file_info), file_info_compare, true,
file_info_free, nullptr);
(void)init_key_cache(dflt_key_cache, KEY_CACHE_BLOCK_SIZE, KEY_CACHE_SIZE, 0,
0);
files_open = 0;
access_time = 0;
while (access_time++ != number_of_commands &&
!my_b_read(&cache, (uchar *)head, 9)) {
isamlog_filepos = my_b_tell(&cache) - 9L;
file_info.filenr = mi_uint2korr(head + 1);
isamlog_process = file_info.process = (long)mi_uint4korr(head + 3);
if (!opt_processes) file_info.process = 0;
result = mi_uint2korr(head + 7);
if ((curr_file_info = (struct file_info *)tree_search(&tree, &file_info,
tree.custom_arg))) {
curr_file_info->accessed = access_time;
if (update && curr_file_info->used && curr_file_info->closed) {
if (reopen_closed_file(&tree, curr_file_info)) {
command = sizeof(com_count) / sizeof(com_count[0][0]) / 3;
result = 0;
goto com_err;
}
}
}
command = (uint)head[0];
if (command < sizeof(com_count) / sizeof(com_count[0][0]) / 3 &&
(!table_names[0] || (curr_file_info && curr_file_info->used))) {
com_count[command][0]++;
if (result) com_count[command][1]++;
}
switch ((enum myisam_log_commands)command) {
case MI_LOG_OPEN:
if (!table_names[0]) {
com_count[command][0]--; /* Must be counted explicitly */
if (result) com_count[command][1]--;
}
if (curr_file_info)
printf(
"\nWarning: %s is opened with same process and filenumber\n"
"Maybe you should use the -P option ?\n",
curr_file_info->show_name);
if (my_b_read(&cache, (uchar *)head, 2)) goto err;
buff = nullptr;
file_info.name = nullptr;
file_info.show_name = nullptr;
file_info.record = nullptr;
if (read_string(&cache, &buff, (uint)mi_uint2korr(head))) goto err;
{
uint i;
char *pos, *to;
/* Fix if old DOS files to new format */
for (pos = file_info.name = (char *)buff; (pos = strchr(pos, '\\'));
pos++)
*pos = '/';
pos = file_info.name;
for (i = 0; i < prefix_remove; i++) {
char *next;
if (!(next = strchr(pos, '/'))) break;
pos = next + 1;
}
to = isam_file_name;
if (filepath) to = convert_dirname(isam_file_name, filepath, NullS);
my_stpcpy(to, pos);
fn_ext(isam_file_name)[0] = 0; /* Remove extension */
}
open_param.name = file_info.name;
open_param.max_id = 0;
(void)tree_walk(&tree, test_if_open, &open_param, left_root_right);
file_info.id = open_param.max_id + 1;
/*
* In the line below +10 is added to accommodate '<' and '>' chars
* plus '\0' at the end, so that there is place for 7 digits.
* It is improbable that same table can have that many entries in
* the table cache.
* The additional space is needed for the sprintf commands two lines
* below.
*/
file_info.show_name =
(char *)my_memdup(PSI_NOT_INSTRUMENTED, isam_file_name,
(uint)strlen(isam_file_name) + 10, MYF(MY_WME));
if (file_info.id > 1)
sprintf(strend(file_info.show_name), "<%d>", file_info.id);
file_info.closed = true;
file_info.accessed = access_time;
file_info.used = true;
if (table_names[0]) {
char **name;
file_info.used = false;
for (name = table_names; *name; name++) {
if (!strcmp(*name, isam_file_name))
file_info.used = true; /* Update/log only this */
}
}
if (update && file_info.used) {
if (files_open >= max_files) {
if (close_some_file(&tree)) goto com_err;
files_open--;
}
if (!(file_info.isam =
mi_open(isam_file_name, O_RDWR, HA_OPEN_WAIT_IF_LOCKED)))
goto com_err;
if (!(file_info.record = (uchar *)my_malloc(
PSI_NOT_INSTRUMENTED, file_info.isam->s->base.reclength,
MYF(MY_WME))))
goto end;
files_open++;
file_info.closed = false;
}
(void)tree_insert(&tree, (uchar *)&file_info, 0, tree.custom_arg);
if (file_info.used) {
if (verbose && !record_pos_file)
printf_log("%s: open -> %d", file_info.show_name, file_info.filenr);
com_count[command][0]++;
if (result) com_count[command][1]++;
}
break;
case MI_LOG_CLOSE:
if (verbose && !record_pos_file &&
(!table_names[0] || (curr_file_info && curr_file_info->used)))
printf_log("%s: %s -> %d", FILENAME(curr_file_info),
command_name[command], result);
if (curr_file_info) {
if (!curr_file_info->closed) files_open--;
(void)tree_delete(&tree, (uchar *)curr_file_info, 0, tree.custom_arg);
}
break;
case MI_LOG_EXTRA:
if (my_b_read(&cache, (uchar *)head, 1)) goto err;
extra_command = (enum ha_extra_function)head[0];
if (verbose && !record_pos_file &&
(!table_names[0] || (curr_file_info && curr_file_info->used)))
printf_log("%s: %s(%d) -> %d", FILENAME(curr_file_info),
command_name[command], (int)extra_command, result);
if (update && curr_file_info && !curr_file_info->closed) {
if (mi_extra(curr_file_info->isam, extra_command, nullptr) !=
(int)result) {
fflush(stdout);
(void)fprintf(
stderr, "Warning: error %d, expected %d on command %s at %s\n",
my_errno(), result, command_name[command],
llstr(isamlog_filepos, llbuff));
fflush(stderr);
}
}
break;
case MI_LOG_DELETE:
if (my_b_read(&cache, (uchar *)head, 8)) goto err;
filepos = mi_sizekorr(head);
if (verbose &&
(!record_pos_file ||
((record_pos == filepos || record_pos == NO_FILEPOS) &&
!cmp_filename(curr_file_info, record_pos_file))) &&
(!table_names[0] || (curr_file_info && curr_file_info->used)))
printf_log("%s: %s at %ld -> %d", FILENAME(curr_file_info),
command_name[command], (long)filepos, result);
if (update && curr_file_info && !curr_file_info->closed) {
if (mi_rrnd(curr_file_info->isam, curr_file_info->record, filepos)) {
if (!recover) goto com_err;
if (verbose)
printf_log("error: Didn't find row to delete with mi_rrnd");
com_count[command][2]++; /* Mark error */
}
mi_result = mi_delete(curr_file_info->isam, curr_file_info->record);
if ((mi_result == 0 && result) ||
(mi_result && (uint)my_errno() != result)) {
if (!recover) goto com_err;
if (mi_result) com_count[command][2]++; /* Mark error */
if (verbose)
printf_log("error: Got result %d from mi_delete instead of %d",
mi_result, result);
}
}
break;
case MI_LOG_WRITE:
case MI_LOG_UPDATE:
if (my_b_read(&cache, (uchar *)head, 12)) goto err;
filepos = mi_sizekorr(head);
length = mi_uint4korr(head + 8);
buff = nullptr;
if (read_string(&cache, &buff, (uint)length)) goto err;
if ((!record_pos_file ||
((record_pos == filepos || record_pos == NO_FILEPOS) &&
!cmp_filename(curr_file_info, record_pos_file))) &&
(!table_names[0] || (curr_file_info && curr_file_info->used))) {
if (write_file && (my_fwrite(write_file, buff, length,
MYF(MY_WAIT_IF_FULL | MY_NABP))))
goto end;
if (verbose)
printf_log("%s: %s at %ld, length=%ld -> %d",
FILENAME(curr_file_info), command_name[command],
(long)filepos, length, result);
}
if (update && curr_file_info && !curr_file_info->closed) {
if (curr_file_info->isam->s->base.blobs)
fix_blob_pointers(curr_file_info->isam, buff);
if ((enum myisam_log_commands)command == MI_LOG_UPDATE) {
if (mi_rrnd(curr_file_info->isam, curr_file_info->record,
filepos)) {
if (!recover) {
result = 0;
goto com_err;
}
if (verbose)
printf_log("error: Didn't find row to update with mi_rrnd");
if (recover == 1 || result ||
find_record_with_key(curr_file_info, buff)) {
com_count[command][2]++; /* Mark error */
break;
}
}
mi_result =
mi_update(curr_file_info->isam, curr_file_info->record, buff);
if ((mi_result == 0 && result) ||
(mi_result && (uint)my_errno() != result)) {
if (!recover) goto com_err;
if (verbose)
printf_log("error: Got result %d from mi_update instead of %d",
mi_result, result);
if (mi_result) com_count[command][2]++; /* Mark error */
}
} else {
mi_result = mi_write(curr_file_info->isam, buff);
if ((mi_result == 0 && result) ||
(mi_result && (uint)my_errno() != result)) {
if (!recover) goto com_err;
if (verbose)
printf_log("error: Got result %d from mi_write instead of %d",
mi_result, result);
if (mi_result) com_count[command][2]++; /* Mark error */
}
if (!recover && filepos != curr_file_info->isam->lastpos) {
printf("error: Wrote at position: %s, should have been %s",
llstr(curr_file_info->isam->lastpos, llbuff),
llstr(filepos, llbuff2));
goto end;
}
}
}
my_free(buff);
break;
case MI_LOG_LOCK:
if (my_b_read(&cache, (uchar *)head, sizeof(lock_command))) goto err;
memcpy(&lock_command, head, sizeof(lock_command));
if (verbose && !record_pos_file &&
(!table_names[0] || (curr_file_info && curr_file_info->used)))
printf_log("%s: %s(%d) -> %d\n", FILENAME(curr_file_info),
command_name[command], lock_command, result);
if (update && curr_file_info && !curr_file_info->closed) {
if (mi_lock_database(curr_file_info->isam, lock_command) !=
(int)result)
goto com_err;
}
break;
case MI_LOG_DELETE_ALL:
if (verbose && !record_pos_file &&
(!table_names[0] || (curr_file_info && curr_file_info->used)))
printf_log("%s: %s -> %d\n", FILENAME(curr_file_info),
command_name[command], result);
break;
default:
fflush(stdout);
(void)fprintf(stderr,
"Error: found unknown command %d in logfile, aborted\n",
command);
fflush(stderr);
goto end;
}
}
end_key_cache(dflt_key_cache, true);
delete_tree(&tree);
(void)end_io_cache(&cache);
(void)my_close(file, MYF(0));
if (write_file && my_fclose(write_file, MYF(MY_WME))) return 1;
return 0;
err:
fflush(stdout);
(void)fprintf(stderr, "Got error %d when reading from logfile\n", my_errno());
fflush(stderr);
goto end;
com_err:
fflush(stdout);
(void)fprintf(stderr, "Got error %d, expected %d on command %s at %s\n",
my_errno(), result, command_name[command],
llstr(isamlog_filepos, llbuff));
fflush(stderr);
end:
end_key_cache(dflt_key_cache, true);
delete_tree(&tree);
(void)end_io_cache(&cache);
(void)my_close(file, MYF(0));
if (write_file) (void)my_fclose(write_file, MYF(MY_WME));
return 1;
}