static int examine_log()

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;
}