~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to extra/innochecksum.c

  • Committer: Monty Taylor
  • Date: 2009-05-23 23:12:39 UTC
  • mto: This revision was merged to the branch mainline in revision 1039.
  • Revision ID: mordred@inaugust.com-20090523231239-htfbqw86hppv9vwy
Removed my_print_defaults, innochecksum and mysql_waitpid. Two are crap - one does't belong here.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2000-2005 MySQL AB & Innobase Oy
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
 
/*
17
 
  InnoDB offline file checksum utility.  85% of the code in this file
18
 
  was taken wholesale fron the InnoDB codebase.
19
 
 
20
 
  The final 15% was originally written by Mark Smith of Danga
21
 
  Interactive, Inc. <junior@danga.com>
22
 
 
23
 
  Published with a permission.
24
 
*/
25
 
 
26
 
#include <stdio.h>
27
 
#include <stdlib.h>
28
 
#include <time.h>
29
 
#include <sys/types.h>
30
 
#include <sys/stat.h>
31
 
#include <unistd.h>
32
 
#include <stdint.h>
33
 
#include <inttypes.h>
34
 
 
35
 
/* all of these ripped from InnoDB code from MySQL 4.0.22 */
36
 
#define UT_HASH_RANDOM_MASK     1463735687
37
 
#define UT_HASH_RANDOM_MASK2    1653893711
38
 
#define FIL_PAGE_LSN          16
39
 
#define FIL_PAGE_FILE_FLUSH_LSN 26
40
 
#define FIL_PAGE_OFFSET     4
41
 
#define FIL_PAGE_DATA       38
42
 
#define FIL_PAGE_END_LSN_OLD_CHKSUM 8
43
 
#define FIL_PAGE_SPACE_OR_CHKSUM 0
44
 
#define UNIV_PAGE_SIZE          (2 * 8192)
45
 
 
46
 
/* command line argument to do page checks (that's it) */
47
 
/* another argument to specify page ranges... seek to right spot and go from there */
48
 
 
49
 
/* innodb function in name; modified slightly to not have the ASM version (lots of #ifs that didn't apply) */
50
 
static uint32_t mach_read_from_4(unsigned char *b)
51
 
{
52
 
  return( ((uint32_t)(b[0]) << 24)
53
 
          + ((uint32_t)(b[1]) << 16)
54
 
          + ((uint32_t)(b[2]) << 8)
55
 
          + (uint32_t)(b[3])
56
 
          );
57
 
}
58
 
 
59
 
static uint32_t
60
 
ut_fold_uint32_t_pair(
61
 
/*===============*/
62
 
            /* out: folded value */
63
 
    uint32_t   n1, /* in: uint32_t */
64
 
    uint32_t   n2) /* in: uint32_t */
65
 
{
66
 
    return(((((n1 ^ n2 ^ UT_HASH_RANDOM_MASK2) << 8) + n1)
67
 
                        ^ UT_HASH_RANDOM_MASK) + n2);
68
 
}
69
 
 
70
 
static uint32_t
71
 
ut_fold_binary(
72
 
/*===========*/
73
 
            /* out: folded value */
74
 
    unsigned char*   str,    /* in: string of bytes */
75
 
    uint32_t   len)    /* in: length */
76
 
{
77
 
    uint32_t   i;
78
 
    uint32_t   fold= 0;
79
 
 
80
 
    for (i= 0; i < len; i++)
81
 
    {
82
 
      fold= ut_fold_uint32_t_pair(fold, (uint32_t)(*str));
83
 
 
84
 
      str++;
85
 
    }
86
 
 
87
 
    return(fold);
88
 
}
89
 
 
90
 
static uint32_t
91
 
buf_calc_page_new_checksum(
92
 
/*=======================*/
93
 
               /* out: checksum */
94
 
    unsigned char*    page) /* in: buffer page */
95
 
{
96
 
    uint32_t checksum;
97
 
 
98
 
    /* Since the fields FIL_PAGE_FILE_FLUSH_LSN and ..._ARCH_LOG_NO
99
 
    are written outside the buffer pool to the first pages of data
100
 
    files, we have to skip them in the page checksum calculation.
101
 
    We must also skip the field FIL_PAGE_SPACE_OR_CHKSUM where the
102
 
    checksum is stored, and also the last 8 bytes of page because
103
 
    there we store the old formula checksum. */
104
 
 
105
 
    checksum= ut_fold_binary(page + FIL_PAGE_OFFSET,
106
 
                             FIL_PAGE_FILE_FLUSH_LSN - FIL_PAGE_OFFSET)
107
 
            + ut_fold_binary(page + FIL_PAGE_DATA,
108
 
                             UNIV_PAGE_SIZE - FIL_PAGE_DATA
109
 
                             - FIL_PAGE_END_LSN_OLD_CHKSUM);
110
 
    checksum= checksum & 0xFFFFFFFF;
111
 
 
112
 
    return(checksum);
113
 
}
114
 
 
115
 
static uint32_t
116
 
buf_calc_page_old_checksum(
117
 
/*=======================*/
118
 
               /* out: checksum */
119
 
    unsigned char*    page) /* in: buffer page */
120
 
{
121
 
    uint32_t checksum;
122
 
 
123
 
    checksum= ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN);
124
 
 
125
 
    checksum= checksum & 0xFFFFFFFF;
126
 
 
127
 
    return(checksum);
128
 
}
129
 
 
130
 
 
131
 
int main(int argc, char **argv)
132
 
{
133
 
  FILE *f;                     /* our input file */
134
 
  unsigned char *p;                     /* storage of pages read */
135
 
  int bytes;                   /* bytes read count */
136
 
  uint32_t ct;                    /* current page number (0 based) */
137
 
  int now;                     /* current time */
138
 
  int lastt;                   /* last time */
139
 
  uint32_t oldcsum, oldcsumfield, csum, csumfield, logseq, logseqfield; /* uint32_ts for checksum storage */
140
 
  struct stat st;              /* for stat, if you couldn't guess */
141
 
  uint64_t size; /* size of file (has to be 64 bits) */
142
 
  uint32_t pages;                 /* number of pages in file */
143
 
  uint32_t start_page= 0, end_page= 0, use_end_page= 0; /* for starting and ending at certain pages */
144
 
  off_t offset= 0;
145
 
  int just_count= 0;          /* if true, just print page count */
146
 
  int verbose= 0;
147
 
  int debug= 0;
148
 
  int c;
149
 
  int fd;
150
 
 
151
 
  /* remove arguments */
152
 
  while ((c= getopt(argc, argv, "cvds:e:p:")) != -1)
153
 
  {
154
 
    switch (c)
155
 
    {
156
 
    case 'v':
157
 
      verbose= 1;
158
 
      break;
159
 
    case 'c':
160
 
      just_count= 1;
161
 
      break;
162
 
    case 's':
163
 
      start_page= atoi(optarg);
164
 
      break;
165
 
    case 'e':
166
 
      end_page= atoi(optarg);
167
 
      use_end_page= 1;
168
 
      break;
169
 
    case 'p':
170
 
      start_page= atoi(optarg);
171
 
      end_page= atoi(optarg);
172
 
      use_end_page= 1;
173
 
      break;
174
 
    case 'd':
175
 
      debug= 1;
176
 
      break;
177
 
    case ':':
178
 
      fprintf(stderr, "option -%c requires an argument\n", optopt);
179
 
      return 1;
180
 
    case '?':
181
 
      fprintf(stderr, "unrecognized option: -%c\n", optopt);
182
 
      return 1;
183
 
    }
184
 
  }
185
 
 
186
 
  /* debug implies verbose... */
187
 
  if (debug) verbose= 1;
188
 
 
189
 
  /* make sure we have the right arguments */
190
 
  if (optind >= argc)
191
 
  {
192
 
    printf("InnoDB offline file checksum utility.\n");
193
 
    printf("usage: %s [-c] [-s <start page>] [-e <end page>] [-p <page>] [-v] [-d] <filename>\n", argv[0]);
194
 
    printf("\t-c\tprint the count of pages in the file\n");
195
 
    printf("\t-s n\tstart on this page number (0 based)\n");
196
 
    printf("\t-e n\tend at this page number (0 based)\n");
197
 
    printf("\t-p n\tcheck only this page (0 based)\n");
198
 
    printf("\t-v\tverbose (prints progress every 5 seconds)\n");
199
 
    printf("\t-d\tdebug mode (prints checksums for each page)\n");
200
 
    return 1;
201
 
  }
202
 
 
203
 
  /* stat the file to get size and page count */
204
 
  if (stat(argv[optind], &st))
205
 
  {
206
 
    perror("error statting file");
207
 
    return 1;
208
 
  }
209
 
  size= st.st_size;
210
 
  pages= size / UNIV_PAGE_SIZE;
211
 
  if (just_count)
212
 
  {
213
 
    printf("%u\n", pages);
214
 
    return 0;
215
 
  }
216
 
  else if (verbose)
217
 
  {
218
 
    printf("file %s= %"PRIu64" bytes (%u pages)...\n", argv[1], size, pages);
219
 
    printf("checking pages in range %u to %u\n", start_page, use_end_page ? end_page : (pages - 1));
220
 
  }
221
 
 
222
 
  /* open the file for reading */
223
 
  f= fopen(argv[optind], "r");
224
 
  if (!f)
225
 
  {
226
 
    perror("error opening file");
227
 
    return 1;
228
 
  }
229
 
 
230
 
  /* seek to the necessary position */
231
 
  if (start_page)
232
 
  {
233
 
    fd= fileno(f);
234
 
    if (!fd)
235
 
    {
236
 
      perror("unable to obtain file descriptor number");
237
 
      return 1;
238
 
    }
239
 
 
240
 
    offset= (off_t)start_page * (off_t)UNIV_PAGE_SIZE;
241
 
 
242
 
    if (lseek(fd, offset, SEEK_SET) != offset)
243
 
    {
244
 
      perror("unable to seek to necessary offset");
245
 
      return 1;
246
 
    }
247
 
  }
248
 
 
249
 
  /* allocate buffer for reading (so we don't realloc every time) */
250
 
  p= (unsigned char *)malloc(UNIV_PAGE_SIZE);
251
 
 
252
 
  /* main checksumming loop */
253
 
  ct= start_page;
254
 
  lastt= 0;
255
 
  while (!feof(f))
256
 
  {
257
 
    bytes= fread(p, 1, UNIV_PAGE_SIZE, f);
258
 
    if (!bytes && feof(f)) return 0;
259
 
    if (bytes != UNIV_PAGE_SIZE)
260
 
    {
261
 
      fprintf(stderr, "bytes read (%d) doesn't match universal page size (%d)\n", bytes, UNIV_PAGE_SIZE);
262
 
      return 1;
263
 
    }
264
 
 
265
 
    /* check the "stored log sequence numbers" */
266
 
    logseq= mach_read_from_4(p + FIL_PAGE_LSN + 4);
267
 
    logseqfield= mach_read_from_4(p + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM + 4);
268
 
    if (debug)
269
 
      printf("page %u: log sequence number: first = %u; second = %u\n", ct, logseq, logseqfield);
270
 
    if (logseq != logseqfield)
271
 
    {
272
 
      fprintf(stderr, "page %u invalid (fails log sequence number check)\n", ct);
273
 
      return 1;
274
 
    }
275
 
 
276
 
    /* check old method of checksumming */
277
 
    oldcsum= buf_calc_page_old_checksum(p);
278
 
    oldcsumfield= mach_read_from_4(p + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM);
279
 
    if (debug)
280
 
      printf("page %u: old style: calculated = %u; recorded = %u\n", ct, oldcsum, oldcsumfield);
281
 
    if (oldcsumfield != mach_read_from_4(p + FIL_PAGE_LSN) && oldcsumfield != oldcsum)
282
 
    {
283
 
      fprintf(stderr, "page %u invalid (fails old style checksum)\n", ct);
284
 
      return 1;
285
 
    }
286
 
 
287
 
    /* now check the new method */
288
 
    csum= buf_calc_page_new_checksum(p);
289
 
    csumfield= mach_read_from_4(p + FIL_PAGE_SPACE_OR_CHKSUM);
290
 
    if (debug)
291
 
      printf("page %u: new style: calculated = %u; recorded = %u\n", ct, csum, csumfield);
292
 
    if (csumfield != 0 && csum != csumfield)
293
 
    {
294
 
      fprintf(stderr, "page %u invalid (fails new style checksum)\n", ct);
295
 
      return 1;
296
 
    }
297
 
 
298
 
    /* end if this was the last page we were supposed to check */
299
 
    if (use_end_page && (ct >= end_page))
300
 
      return 0;
301
 
 
302
 
    /* do counter increase and progress printing */
303
 
    ct++;
304
 
    if (verbose)
305
 
    {
306
 
      if (ct % 64 == 0)
307
 
      {
308
 
        now= time(0);
309
 
        if (!lastt) lastt= now;
310
 
        if (now - lastt >= 1)
311
 
        {
312
 
          printf("page %u okay: %.3f%% done\n", (ct - 1), (float) ct / pages * 100);
313
 
          lastt= now;
314
 
        }
315
 
      }
316
 
    }
317
 
  }
318
 
  return 0;
319
 
}
320