void buf_flush_init_for_writing( /*=======================*/ byte* page, /* in: page */ dulint newest_lsn, /* in: newest modification lsn to the page */ ulint space, /* in: space id */ ulint page_no) /* in: page number */ { /* Write the newest modification lsn to the page header and trailer */ mach_write_to_8(page + FIL_PAGE_LSN, newest_lsn); mach_write_to_8(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM, newest_lsn); /* Write the page number and the space id */ mach_write_to_4(page + FIL_PAGE_OFFSET, page_no); mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, space); /* Store the new formula checksum */ mach_write_to_4(page + FIL_PAGE_SPACE_OR_CHKSUM, srv_use_checksums ? buf_calc_page_new_checksum(page) : BUF_NO_CHECKSUM_MAGIC); /* We overwrite the first 4 bytes of the end lsn field to store the old formula checksum. Since it depends also on the field FIL_PAGE_SPACE_OR_CHKSUM, it has to be calculated after storing the new formula checksum. */ mach_write_to_4(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM, srv_use_checksums ? buf_calc_page_old_checksum(page) : BUF_NO_CHECKSUM_MAGIC); }
int main(int argc, char **argv) { FILE *f; /* our input file */ uchar *p; /* storage of pages read */ int bytes; /* bytes read count */ ulint ct; /* current page number (0 based) */ int now; /* current time */ int lastt; /* last time */ ulint oldcsum, oldcsumfield, csum, csumfield, logseq, logseqfield; /* ulints for checksum storage */ struct stat st; /* for stat, if you couldn't guess */ unsigned long long int size; /* size of file (has to be 64 bits) */ ulint pages; /* number of pages in file */ ulint start_page= 0, end_page= 0, use_end_page= 0; /* for starting and ending at certain pages */ off_t offset= 0; int just_count= 0; /* if true, just print page count */ int verbose= 0; int debug= 0; int c; int fd; /* remove arguments */ while ((c= getopt(argc, argv, "cvds:e:p:")) != -1) { switch (c) { case 'v': verbose= 1; break; case 'c': just_count= 1; break; case 's': start_page= atoi(optarg); break; case 'e': end_page= atoi(optarg); use_end_page= 1; break; case 'p': start_page= atoi(optarg); end_page= atoi(optarg); use_end_page= 1; break; case 'd': debug= 1; break; case ':': fprintf(stderr, "option -%c requires an argument\n", optopt); return 1; break; case '?': fprintf(stderr, "unrecognized option: -%c\n", optopt); return 1; break; } } /* debug implies verbose... */ if (debug) verbose= 1; /* make sure we have the right arguments */ if (optind >= argc) { printf("InnoDB offline file checksum utility.\n"); printf("usage: %s [-c] [-s <start page>] [-e <end page>] [-p <page>] [-v] [-d] <filename>\n", argv[0]); printf("\t-c\tprint the count of pages in the file\n"); printf("\t-s n\tstart on this page number (0 based)\n"); printf("\t-e n\tend at this page number (0 based)\n"); printf("\t-p n\tcheck only this page (0 based)\n"); printf("\t-v\tverbose (prints progress every 5 seconds)\n"); printf("\t-d\tdebug mode (prints checksums for each page)\n"); return 1; } /* stat the file to get size and page count */ if (stat(argv[optind], &st)) { perror("error statting file"); return 1; } size= st.st_size; pages= size / UNIV_PAGE_SIZE; if (just_count) { printf("%lu\n", pages); return 0; } else if (verbose) { printf("file %s = %llu bytes (%lu pages)...\n", argv[optind], size, pages); printf("checking pages in range %lu to %lu\n", start_page, use_end_page ? end_page : (pages - 1)); } /* open the file for reading */ f= fopen(argv[optind], "r"); if (!f) { perror("error opening file"); return 1; } /* seek to the necessary position */ if (start_page) { fd= fileno(f); if (!fd) { perror("unable to obtain file descriptor number"); return 1; } offset= (off_t)start_page * (off_t)UNIV_PAGE_SIZE; if (lseek(fd, offset, SEEK_SET) != offset) { perror("unable to seek to necessary offset"); return 1; } } /* allocate buffer for reading (so we don't realloc every time) */ p= (uchar *)malloc(UNIV_PAGE_SIZE); /* main checksumming loop */ ct= start_page; lastt= 0; while (!feof(f)) { bytes= fread(p, 1, UNIV_PAGE_SIZE, f); if (!bytes && feof(f)) return 0; if (bytes != UNIV_PAGE_SIZE) { fprintf(stderr, "bytes read (%d) doesn't match universal page size (%d)\n", bytes, UNIV_PAGE_SIZE); return 1; } /* check the "stored log sequence numbers" */ logseq= mach_read_from_4(p + FIL_PAGE_LSN + 4); logseqfield= mach_read_from_4(p + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM + 4); if (debug) printf("page %lu: log sequence number: first = %lu; second = %lu\n", ct, logseq, logseqfield); if (logseq != logseqfield) { fprintf(stderr, "page %lu invalid (fails log sequence number check)\n", ct); return 1; } /* check old method of checksumming */ oldcsum= buf_calc_page_old_checksum(p); oldcsumfield= mach_read_from_4(p + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM); if (debug) printf("page %lu: old style: calculated = %lu; recorded = %lu\n", ct, oldcsum, oldcsumfield); if (oldcsumfield != mach_read_from_4(p + FIL_PAGE_LSN) && oldcsumfield != oldcsum) { fprintf(stderr, "page %lu invalid (fails old style checksum)\n", ct); return 1; } /* now check the new method */ csum= buf_calc_page_new_checksum(p); csumfield= mach_read_from_4(p + FIL_PAGE_SPACE_OR_CHKSUM); if (debug) printf("page %lu: new style: calculated = %lu; recorded = %lu\n", ct, csum, csumfield); if (csumfield != 0 && csum != csumfield) { fprintf(stderr, "page %lu invalid (fails new style checksum)\n", ct); return 1; } /* end if this was the last page we were supposed to check */ if (use_end_page && (ct >= end_page)) return 0; /* do counter increase and progress printing */ ct++; if (verbose) { if (ct % 64 == 0) { now= time(0); if (!lastt) lastt= now; if (now - lastt >= 1) { printf("page %lu okay: %.3f%% done\n", (ct - 1), (float) ct / pages * 100); lastt= now; } } } } return 0; }