~drizzle-trunk/drizzle/development

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